子类不能继承父类非私有的构造方法
子类如果继承父类的构造方法,那么构造方法的类名和子类的类名不一样,所以父类构造方法不能被子类继承。
构造方法是用于创建对象并初始化对象的特殊方法,它在创建对象时自动调用,并且由于构造方法与类名相同,因此不能被子类继承。
子类只能继承父类的非私有成员变量和非私有方法,但构造方法不属于类的成员变量和方法,所以子类无法继承父类的构造方法。每个类都必须有自己的构造方法来初始化自己的对象。
然而,子类可以通过调用父类的构造方法来初始化父类的成员变量,使用super关键字来调用父类的构造方法。这样的操作可以在子类中创建父类的对象,并且在子类的构造方法中调用父类的构造方法来初始化父类的成员变量。这被称为构造方法的重载。
代码案例分析:
带参构造创建子类对象会报错,因为子类中没有对应的参数,idea会建议构造一个方法,所以子类不能继承父类的构造方法,如果子类可以继承父类的构造方法,那么利用有参构造创建子类对象就不会报错。
如果一个类中没有构造方法,虚拟机会自动添加一个空参构造,所以在利用空参构造创建子类对象的时候没有报错。
子类可以继承父类的私有和非私有的成员变量,只不过私有的子类不能直接使用而已,通过对应的set,get方法使用
非私有的时候的内存分析图:
与之前的内存分析图不一样的地方:
1、在加载字节码文件的时候,会将父类的也加载进来
2、在创建对象的时候,一部分用来存储从父类继承下来的成员变量,另一部分是用来存储自己子类里的成员变量
设为私有的时候的内存分析图:
标红的那两行是idea报错的位置
执行下两行代码的时候,在堆中寻找name和age,由于是私有的所以不能找到进行赋值,就会报错
虽然继承下来了,但是不能使用
成员方法非私有可以继承,私有的不可以继承
引入虚方法表:
虚方法表的主要用途是实现动态绑定(Dynamic Binding),也就是在运行时根据对象的类型来确定调用哪个方法。当一个类定义了虚方法时,编译器会在虚方法表中为该方法创建一个条目,并将实际的方法地址存储在该条目中。当调用一个虚方法时,会根据对象的类型在虚方法表中查找对应的方法地址,然后调用该方法。
使用虚方法表可以实现多态性,即一个对象可以在不同的情况下表现出不同的行为。通过将方法的实现绑定到对象的类型,而不是变量的类型,可以实现在运行时根据对象的实际类型来选择调用的方法。这样,可以实现更灵活的代码,并且可以简化代码的编写和维护。
内存图分析:
从object的虚方法表有5个,然后给fu类,fu类有两个方法,一个是public修饰,另一个是private修饰,private修饰的方法不是虚方法,所以给zi类的虚方法表里面就有public的方法,所以一共是6个,所以zi类一共有7个方法,有6个是继承下来的,还有一个是自己的zishow();
最后由于fushow2()是私有的,并不在虚方法中,从父类找发现是私有的,无法继承,所以会报错。
内存分析工具:
代码:
代码解释:
键盘录入是为了在这里停止下来,然后可以用内存分析工具;
代码运行结果:
输出的是对象z的地址值:
点击下方的Terminal,输入jps,显示的就是现在进程的id:
再打开一个窗口,输入内存分析工具(jhsdb hsdb):
点击file,选择第一个
点击进去:可以写入进程的id
输入7000:
然后再选择Tools,选择Memory Viewer,是一个内存分析工具:
出现以下界面:可以在address输入对象z的地址:
输入对象z的地址:
第二行中的111对应的是a 的 0x111,第三行中的222,333分别对应的b和c,所以对于父类的私有和非私有的成员变量都继承下来了。
再打开inspector:
输入子类的地址:(后八位,在前面补8),出现的就是关于子类的字节码文件信息:
子类的虚方法表的长度是7:
子类的成员个数数量是1:
非静态的成员变量有三个:(自己的加上父类的)
父类的信息:(super class)
虚方法表个数是6:
再找到里面的super class:
这里可以看到object的虚方法表长度是5: