继承。多态。抽象类。接口
继承:
class A extends B{
}
1、派生类继承了基类的除了 基类的构造函数 的其他数据成员??????
2、super(): 调用基类的构造函数
* super.data: 访问我基类的数据成员
* super.func(): 访问我基类的成员方法
class Base{//基类 父类 超类 public int ma;//数据成员 static{ System.out.println("Base.static init!!"); } { System.out.println("Base.instance init!!!"); } public Base(int a){ System.out.println("Base init!!!"); this.ma = a; } } //Derive子类 派生类 class Derive extends Base{ private int mb; static{ System.out.println("Derive.static init!!"); } { System.out.println("Derive.instance init!!!"); } //派生类继承了基类的除了 基类的构造函数 的其他数据成员 public Derive(int a,int b){ super(a);//基类的构造函数 第一行 如果此时没有super(),那么Derive构造函数就会报错 /*super(): 调用基类的构造函数 super.data: 访问我基类的数据成员 super.func(): 访问我基类的成员方法*/ //int i = super.ma; //ma = a;//error this.mb = b; System.out.println("Derive init!!!"); } }
3、类---》对象 初始化顺序:::
* 1.静态数据成员 简单类型 : 引用类型 null
* 2.静态代码块初始化
* 3.实例数据成员
* 4.实例代码块初始化
* 5.调用合适的构造函数
4、派生类继承基类后的打印顺序????静态(只初始化一次)
* --- 》 实例----》构造函数
public static void main(String[] args) { //实例化两个子类的对象 /*Derive d = new Derive(10,20); System.out.println("================"); Derive d2 = new Derive(10,20);*/ //初始化顺序 先static代码块初始化 再父类实例代码块初始化 再父类构造函数初始化 再子类实例代码块初始化 再子类构造函数初始化 /*Base.static init!! Derive.static init!! Base.instance init!!! Base init!!! Derive.instance init!!! Derive init!!! ================ //静态代码块只能初始化一次 Base.instance init!!! Base init!!! Derive.instance init!!! Derive init!!!*/ //实例化一个父类对象 /*Base b = new Base(10);*/ //父类的初始化顺序 /*Base.static init!! Base.instance init!!! Base init!!!*/ //实例化一个子类对象 /*Derive d = new Derive(10,20);*/ //子类的初始化顺序 /*Base.static init!! Derive.static init!! Base.instance init!!! Base init!!! Derive.instance init!!! Derive init!!! */ /*Derive d = new Derive(10,20); Base b = new Base(10);*/ /*Base.static init!! Derive.static init!! Base.instance init!!! Base init!!! Derive.instance init!!! Derive init!!! Base.instance init!!! Base init!!!*/
5、基类数据成员在派生类当中的访问权限
* 同包子类 同包非子类 不同包子类 不同包非子类
* public 可以 可以 可以 可以
*
* protected 可以 可以 可以 不可以
* (包访问权限,继承当中 ) (继承)
*
* private 不可以 不可以 不可以 不可以
*
* 默认权限 可以 可以 不可以 不可以
* (包访问权限)
6、派生类和基类之间相互赋值
子类对象可以给父类对象赋值,父类对象不能给子类对象赋值
public static void main(String[] args) { Derive d = new Derive(10,20); Base b = new Base(10);*/ /*Base.static init!! Derive.static init!! Base.instance init!!! Base init!!! Derive.instance init!!! Derive init!!! Base.instance init!!! Base init!!!*/ //子类对象可以给父类对象赋值,父类对象不能给子类对象赋值 //b = d;// true 人 学生 从下到上的转换 //d = b;// error 学生 人
7.7、invokevitural invokestatic invokespecial
java中除了构造函数和静态函数,其他成员函数都被处理为虚函数也就是invokevitural
class Base1{ private int ma; public Base1(int a){ this.ma = a; fun1(); } public void fun1(){//实例方法 System.out.println("Base.fun1!!!"); } public static void fun2(){//类方法 System.out.println("Base.fun2!!!"); } } class Derive1 extends Base1{ private int mb; public Derive1(int a,int b){ super(a); this.mb = b; } //重载 public void fun1(int i){ System.out.println("Derive1.fun1(int)!!"); } } class Derive2 extends Base1{ private int mc; public Derive2(int a,int c){ super(a); this.mc = c; fun1(); } public void fun1(){//实例方法 System.out.println("Derive2.fun1!!!"); } public static void fun2(){//类方法 System.out.println("Derive2.fun2!!!"); } }
public static void main(String[] args) { Base1 b = new Base1(10);//通过反汇编发现关键字invokespecial System.out.println(b); 结果:
Base.fun1!!!
renben.Base1@feb48
b.fun1();//invokevirtual
Base.fun2();//invokestatic
8.派生类和基类同名方法的关系
(1)重载 函数名相同 参数列表不同 返回值无要求
(2)重写、覆盖 函数名相同 参数列表相同 返回值相同
class Base1{ private int ma; public Base1(int a){ this.ma = a; fun1(); } public void fun1(){//实例方法 System.out.println("Base.fun1!!!"); } public static void fun2(){//类方法 System.out.println("Base.fun2!!!"); } } class Derive1 extends Base1{ private int mb; public Derive1(int a,int b){ super(a); this.mb = b; } //重载 public void fun1(int i){ System.out.println("Derive1.fun1(int)!!"); } } class Derive2 extends Base1{ private int mc; public Derive2(int a,int c){ super(a); this.mc = c; fun1(); } //重写 public void fun1(){//实例方法 System.out.println("Derive2.fun1!!!"); } public static void fun2(){//类方法 System.out.println("Derive2.fun2!!!"); } }
重载: main{ Base1 b = new Base1(10); Derive1 d = new Derive1(10,20); d.fun1(); d.fun1(10); } 结果:Base1.fun1!!!
Derive1.fun1(int)!!
重写:
main{
Base1 b1=new Base1(10);
Derive2 d2=new Derive2(10,40);
Base1 b2=new Derive2(10,40);
b1.fun1();
d2.fun1();
b2.fun1();
}
结果:
Base1.fun1!!! Derive2.fun1!!!
Derive2.fun1!!! 通过javap -c反汇编发现:
43行发现:显示的是Base为什么打印的是Derive2.fun1!!!呢??? 这是因为发生了动态绑定:编译期间不知道调用谁所以叫做动态绑定
类加载器加载产生class对象→静态代码块初始化→实例代码块初始化→构造函数初始化
静态绑定:
main{
Base1 b2=new Derive2(10,40);
b2.fun2();
b2.fun1();
}
结果:
Base1.fun2!!! Derive2.fun1!!!
那为什么静态绑定打印出来的是Base.fun2!!!呢?而动态打印是Derive2.fun1!!!?
这是因为方法表本身在编译期间产生,fun2是静态方法,它在编译期间产生,所以不会发生动态绑定
而动态绑定发生在运行期间 需要new
10.构造函数可以发生动态绑定