291-296继承的细节/继承的本质
一、面向对象-继承的细节
细节七
java所有类都是Object类的子类
Object是所有类的基类
前面讲过Ctrl + H可以看到所有类的继承关系
将鼠标放到Sub类上面Ctrl+H可以看到继承关系
或者看Arrays.sort()
的Arrays类的父类是不是Object
第八个细节
父类构造器的调用不限于直接父类!将一直往上追溯到Object类(顶级父类)
比如现在Sub的父类是Base,Base的父类是Object,我们可以显示的Base extends继承Object,也可以不写,自动继承
这里再创建一个类TopBase.java
编写一个无参构造器
public TopBase() {
System.out.println("构造器TopBase()被调用...");
}
我们让Base继承TopBase
先输出的第一句话是TopBase这里的无参构造器中的
然后回到Base的String int有参构造器中输出
在回到子类的Sub的String int中输出
一共输出三句话


细节九
子类最多只能继承一个父类(直接继承),即Java中是单继承机制。思考:如何让A类继承B类和C类?
可以让A继承B,让B继承C即可
细节十
不能滥用继承,子类和父类之间必须要满足is-a的逻辑关系
Person is a Music?
Person Music
Music extends Person 不合理
Animal
Cat extents Animal合理
二、继承的本质
继承的本质分析(重要)
案例
来看一个案例来分析当子类继承父类,创建子类对象的时候,内存中到底发生了什么?当子类对象创建好之后,建立查找的关系
com.hspedu.extend_包:ExtendsTheory.java
在这个文件中写三个类
class GrandPa {
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {
String name = "大头爸爸";
int age = 39;
}
class Son extends Father {
String name = "大头儿子";
}
创建一个Son对象,加载Sun信息的时候,首先加载父类信息,第一个加载的首先是Object类型,然后加载爷爷类,然后加载父亲类,加载完成之后再加载Son
而且它们之间也有关联关系
Son继承Father,Father继承GrandPa,GrandPa继承了Object
在堆中创建Son的空间,这里是有两个父类,空间中到底有什么属性,这里有两个空间一个是父亲一个是爷爷,因为名字是一个引用类型,所以常量池中还有字符串的分配
对于子类而言有一个属性name,也要有一个空间
然后栈中再指向堆中的对象空间
创建的过程中先加载类,从根开始,然后分配空间,按照爷爷类,父类,自己的属性,最后返回给主方法的son指向堆中的空间
当我们使用son访问这里面的是什么规则呢?
我们执行
System.out.println(son.name);输出的是什么呢?
这个时候需要按照查找关系来返回数据信息
首先看子类的属性
当前子类有这个属性是可以直接访问到的
如果访问age呢?
因为子类中没有但是父类中有也是可以找到的
如果访问hobby是从爷爷类中继承过来的,子类,父类都没有,直接在爷爷类中查,有返回
但是我们要能够访问,如果不能访问就不行
如果我们的父亲将age私有化了,就不能直接访问了
这里需要思考一个问题,就是如果我们的父类将自己的属性设置成为私有了,这里在我们堆中对象的空间中是否存在这个私有的age的空间呢?
是有的,但是不能访问,不是意味着访问不到,父类同样可以写一个共有的方法来提供访问私有属性
public int getAge() {
return age;
}
son.getAge();
注意,访问属性的时候,如果子类没有往父类去找,如果父类的这个属性是私有的就会直接报错了,并不会还要往父类的父类上面去找。
课堂练习
放在com.hspedu.extend_.exercise包下
1、案例1ExtendsExercise01.java
class A {
A(){System.out.println("a");}
A(String name){System.out.println("a name");}
}
class B extends A{
B(){this("abc");System.out.println("b");}
B(String name){System.out.println("b name");}
}
main函数中:B b = new B();会输出什么?
答案:
关键在于有一个隐藏的super()
而无参的构造器中为什么没有super是因为有了复用的this所以没有super了
第二题
class A {
public A() {
System.out.println("我是A类");
}
}
class B extends A{
public B() {
System.out.println("我是B类的无参构造");
}
public B(String name) {
System.out.println(name + "我是B类的有参构造");
}
}
class C extends B {
public C() {
this("hello");
}
System.out.println("我是C类的无参构造");
}
public C(String name) {
super("hahah");
System.out.println("我是C类的有参构造");
}
main中执行
C c = new C();输出什么
第三题
编写Computer类,包含CPU,内存,硬盘等属性,getDetails方法用于返回Computer的详细信息
编写PC子类,继承Computer类,添加特有属性【品牌brand】
编写NotePad子类,继承Computer类,添加特有属性【color】
编写Test类,在main方法中创建PC和NotePad对象,分别给对象中特有的属性赋值,以及从Computer类继承的属性赋值,并使用方法并打印输出信息。
编写Computer类,包含CPU,内存,硬盘等属性,getDetails方法用于返回Computer的详细信息
public class Computer {
private String cpu;
private int memory;
private int disk;
public Computer(String cpu, int memory, int disk) {
this.cpu = cpu;
this.memory = memory;
this.disk = disk;
}
然后Alt + i得到get set方法
}
还需要一个返回详细信息的方法
public String getDetails() {
return "cpu="+cpu+"memory="+memory+"disk="+disk;
}
再创建一个PC类继承Computer类
private String brand;
public PC(String cpu, int memory, int disk, String brand) {
super(cpu, memory, disk);
this.brand = brand;
}
继承设计的基本思想,父类的构造器完成父类属性初始化,子类的构造器完成子类的属性的初始化
同样添加brand的setget方法
PC中再来一个打印的方法
public void printInfo() {
System.out.println("PC信息=");
System.out.println(getDetails() + " brand=" + brand);
}
NotePad同理
main
PC pc = new PC("intel", 16, 500, "IBM");
pc.printInfo();







浙公网安备 33010602011771号