继承
继承概述

Fu
public class Fu {
public void show() {
System.out.println("show方法被调用");
}
}
Zi
public class Zi extends Fu {
public void method() {
System.out.println("method方法被调用");
}
}
Demo
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Fu f = new Fu();
f.show();
Zi z = new Zi();
z.method();
z.show();
}
}

继承的好处和弊端

继承的访问特点

super


super内存图





继承中构造方法访问特点

Fu
public class Fu {
/*
public Fu() {
System.out.println("Fu中无参构造方法被调用");
}
*/
public Fu() {}
public Fu(int age) {
System.out.println("Fu中带参构造方法被调用");
}
}
Zi
public class Zi extends Fu {
public Zi() {
// super();
// super(20);
System.out.println("Zi中无参构造方法被调用");
}
public Zi(int age) {
// super();
// super(20);
System.out.println("Zi中带参构造方法被调用");
}
}
Demo
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
//创建对象
Zi z = new Zi();
Zi z2 = new Zi(20);
}
}

继承中成员方法访问特点

Fu
public class Fu {
public void show() {
System.out.println("Fu中show()方法被调用");
}
}
Zi
public class Zi extends Fu {
public void method() {
System.out.println("Zi中method()方法被调用");
}
public void show() {
super.show();
System.out.println("Zi中show()方法被调用");
}
}
Demo
/*
测试类
*/
public class Demo {
public static void main(String[] args) {
//创建对象,调用方法
Zi z = new Zi();
z.method();
z.show();
//报错
// z.test();
}
}

继承中注意事项

方法重写

Phone
/*
手机类
*/
public class Phone {
public void call(String name) {
System.out.println("给" + name + "打电话");
}
}
NewPhone
/*
新手机
*/
public class NewPhone extends Phone {
/*
public void call(String name) {
System.out.println("开启视频功能");
// System.out.println("给" + name + "打电话");
super.call(name);
}
*/
@Override
public void call(String name) {
System.out.println("开启视频功能");
// System.out.println("给" + name + "打电话");
super.call(name);
}
}
PhoneDemo
/*
测试类
*/
public class PhoneDemo {
public static void main(String[] args) {
//创建对象,调用方法
Phone p = new Phone();
p.call("林青霞");
System.out.println("--------");
NewPhone np = new NewPhone();
np.call("林青霞");
}
}

方法重写注意事项

Fu
public class Fu {
private void show() {
System.out.println("Fu中show()方法被调用");
}
/*
public void method() {
System.out.println("Fu中method()方法被调用");
}
*/
void method() {
System.out.println("Fu中method()方法被调用");
}
}
Zi
public class Zi extends Fu {
/*
@Override
private void show() {
System.out.println("Zi中show()方法被调用");
}
*/
/*
@Override
public void method() {
System.out.println("Zi中method()方法被调用");
}
*/
@Override
public void method() {
System.out.println("Zi中method()方法被调用");
}
}
案例


Animal
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Cat
public class Cat extends Animal {
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
Dog
public class Dog extends Animal {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
public void lookDoor() {
System.out.println("狗看门");
}
}
AnimalDemo
/*
测试类
*/
public class AnimalDemo {
public static void main(String[] args) {
//创建猫类对象并进行测试
Cat c1 = new Cat();
c1.setName("加菲猫");
c1.setAge(5);
System.out.println(c1.getName() + "," + c1.getAge());
c1.catchMouse();
Cat c2 = new Cat("加菲猫", 5);
System.out.println(c2.getName() + "," + c2.getAge());
c2.catchMouse();
System.out.println("-----");
Dog dog = new Dog();
dog.setAge(2);
dog.setName("旺旺");
System.out.println(dog.getName()+","+dog.getAge());
dog.lookDoor();
Dog dog2 = new Dog("嘻嘻", 5);
System.out.println(dog2.getName()+","+dog2.getAge());
dog2.lookDoor();
}
}

显隐式子类初始化
接下来重点学习一下两种方式
子类对象的隐式初始化(implicit)
隐式初始化,JVM自动调用,无需我们手动操作
条件为
-
父类中有默认的构造方法
- 子类的构造器中没有显式调用父类的构造方法
-
达成上述两个条件,则JVM在初始化子类对象时进行隐式初始化
- 永远先执行父类的构造方法,顺序为
- 最上层的父类(Object)
- 其他父类(继承链中越处于上流越先执行)
- 所有父类的构造方法都执行完毕,开始执行子类构造方法
- 永远先执行父类的构造方法,顺序为
需要注意的是
- 隐式初始化,JVM总是调用父类的无参构造,如果父类没有,就要报错
- Object类也有默认无参
- 隐式初始化总是不传参数,如果我们想要对参数进行赋值,就必须使用显式的子类初始化
子类对象的显式初始化(Explicit )
显式初始化,需要程序员手动写代码,告诉JVM调用哪个父类构造器
如何使用?
-
必须在子类构造器的第一行,显式的调用父类构造方法,那么如何调用父类构造器?
-
使用super关键字调用
-
语法
super(父类构造器参数);
-
什么是super关键字?
- super代表当前类的父类的引用
- this代表当前类的对象
- 两者的使用没有明显差别,只是
- this在当前类中不受访问权限控制,super访问父类成员,受访问权限控制
- 因为当前类中即便是private仍然可以访问,但是super就不在当前类中了
this VS super
this关键字:表示当前对象的引用 super关键字:super代表父类对象的引用
this调用当前类中定义的构造方法:this(实参列表)
super调用父类中定义的构造方法:super(实参列表)
this访问当前对象的成员变量值 super访问父类对象中,成员变量的值
this访问当前对象的成员方法 super访问父类对象,成员方法
super与this关键字
this关键字概念:
this代表所在类的对象引用。
记住: 方法被哪个对象调用,this就代表哪个对象。
1.super可以在子类中 调用父类中名称相同的 成员方法和成员变量
2.this可以在方法中调用 类中的与方法内局部变量名称相同 的成员方法和成员变量
3.super和this的区别
(a).this 代表当前类的对象
代表对象的内存空间标识(用来存储当前类定义的内容,成员变量、方法)
(b).super (代表父类对象) 可以这么理解,实际并不代表父类对象
代表对象的内存空间的标识(用来存储父类定义的内容,成员变量、方法)
使用场景:
当局部变量和成员变量名字相同时用this,子类变量和父类变量名字相同时用super
super用法:(this和super均适用)
1.访问成员变量
this.成员变量 super.成员变量 (局部变量直接调用不需要修饰符)
2.访问构造方法
this(…) super(…) 如果是有参方法,()里面写参数
3.访问成员方法
this.成员方法() super.成员方法()
super和this使用情况内存图
1.main方法入栈,建立一个Son类型变量son,然后在堆上创建Son类型对象new Son()
2.对象的内存空间有两个标识,this空间存储子类的成员变量num1=10,num2=20,super空间存储父类变量num1=1,num2=2;
son调用show方法,show()入栈,它的局部变量为num1=100,num2=200;,调用不同的变量需要在变量名前加上标识符,如super.num1, this.num2
隐式子类对象创建:
条件:
a. 当父类提供了默认的构造函数(无参构造方法)
b. 子类的构造方法中, 没有显式调用父类的其它构造方法
结果:
JVM自动在子类构造方法第一句加上 “ super() “
在执行子类的构造方法之前,JVM会自动执行父类
显式子类对象创建:
程序员写代码告诉JVM在调用子类构造器之前调用父类构造方法
可以在子类构造器的第一行使用super关键字,调用父类的构造方法
总结:
1,无论是隐式还是显式,最终都是为了保证父类构造器先于子类执行
2,若父类中不存在默认构造方法,则必须在子类构造方法中使用super关键字调用父类构造器
3,在子类构造方法中,super语句必须在第一行
4,在子类构造方法中,也可以用this调用自身构造,也必须在第一行
5,this和super不能共存
6,构造代码块和静态代码块也是“先父后子”
为什么this和super都必须在第一行?
因为子类构造器第一行永远都有一个super关键字调用,如果你自己的super和this不在第一行,会形成循环
分析程序:
public class Demo {
public static void main(String[] args) {
PrimaryStudent primaryStudent = new PrimaryStudent(666,888,"hello");
System.out.println(primaryStudent.psVar);
}
}
class Person {
public Person() {
System.out.println("Person类的无参构造");
}
}
class Student extends Person {
int sVar;
String sVarString;
public Student() {
System.out.println("Student类无参构造");
}
public Student(int sVar) {
System.out.println("Student int构造方法");
this.sVar = sVar;
}
public Student(int sVar, String sVarString) {
this(sVar);
System.out.println("Student int String构造方法");
this.sVarString = sVarString;
}
}
class PrimaryStudent extends Student {
int psVar = 10;
public PrimaryStudent(int psVar, int sVar, String sVarString) {
super(sVar, sVarString);
System.out.println("PrimaryStudent类的 三参构造");
this.psVar = psVar = 100;
}
}
ends Student {
int psVar = 10;
public PrimaryStudent(int psVar, int sVar, String sVarString) {
super(sVar, sVarString);
System.out.println("PrimaryStudent类的 三参构造");
this.psVar = psVar = 100;
}
}
输出:
Person类的无参构造
Student int构造方法
Student int String构造方法
PrimaryStudent类的 三参构造
100

本文围绕Java继承展开,介绍了继承的好处、弊端、访问特点等内容。重点讲解了子类对象的隐式和显式初始化,隐式初始化由JVM自动调用,显式初始化需程序员手动操作。还阐述了super和this关键字的使用及区别,总结了子类构造方法中super和this的使用规则。
2万+

被折叠的 条评论
为什么被折叠?



