1. 如果B继承A,在new B()时候,java代码的执行顺序:
JVM装载 |
初始化父类的静态成员变量 |
初始化父类的静态代码块 |
初始化子类的静态成员变量 |
初始化子类的静态代码块 |
初始化父类的非静态成员变量 |
初始化父类的非静态代码块 |
调用父类的默认构造方法 |
初始化子类的非静态成员变量 |
初始化子类的非静态代码块 |
调用子类的构造方法 |
测试代码:
package com; public class TestHello { static class A { public int a1 = 21; static int a = 2; { System.out.println("父类的非静态代码块正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a); } static { System.out.println("父类的静态代码块正在运行,静态变量的a的值为=" + a); } public A() { System.out.println(a1 + "父类构造函数正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a); } } static class B extends A { public int a1 = 31; static int a = 3; { System.out.println("子类的非静态代码块正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a); } static { System.out.println("子类的静态代码块正在运行,静态变量的a的值为=" + a); } public B() { System.out.println(a1 + "子类构造函数正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a); } } public static void main(String[] args) { B b = new B(); } }
执行结果为:
父类的静态代码块正在运行,静态变量的a的值为=2 子类的静态代码块正在运行,静态变量的a的值为=3 父类的非静态代码块正在运行,非静态变量a1的值为=21 静态变量的a的值为=2 21父类构造函数正在运行,非静态变量a1的值为=21 静态变量的a的值为=2 子类的非静态代码块正在运行,非静态变量a1的值为=31 静态变量的a的值为=3 31子类构造函数正在运行,非静态变量a1的值为=31 静态变量的a的值为=3
2)若果想要显式调用父类的构造方法则可以使用super(),来调用,但是super关键字必须放在构造放的第一行,而且只能放在第一行,不然编译不通过。
3)this 指针指向的是当前的实例
package com.base; class Base { private int i = 2 ; public Base(){ this.display() ; } public void display(){ System.out.println(i); } } class Derived extends Base { private int i = 22 ; public Derived(){ i = 222 ; } public void display(){ System.out.println(i); } } public class Test { public static void main(String[] args) { new Derived() ; } }输出结果为:0
怎么会是0 呢?
当我们调用new Derived() ;创建Derived实例的时候,系统会为Derived对象分配内存空间,Derived会有两个i实例变量,会分配两个空间来保存i的值。分配完空间以后i的值为0,如果有引用类型则引用类型的值为null。
接下来程序在执行Derived的构造器之前会执行Base的构造器,表面上看Base的构造器中只有一行代码,但是在父类中定义i的时候执行的初始值2,因此经过编译之后,该构造方法中应该包含如下两行代码:
i =2 ;
this.display() ;
程序先将Base中的i赋值为2,然后执行display方法。此处有一个关键字this,this到底代表谁呢?表面上看this代表的是Base的当前实例,但是实际上代码是放在Derived的构造器中的,所以this最终代表的是Derived的当前实例(编译类型是Base而实际引用一个Derived对象),所以如果在父类的构造方法中直接输出System.out.println(this.i) ;则输出的结果为2。但是调用this.display()方法,此时调用的是
子类中重写的display方法,输出的变量i也是子类中的i,但是此时子类中的变量i还没有赋值,所以输出结果为0。
为了详细的看清楚this变量到底代表什么实例,我们将Base的构造方法修改如下:
public Base(){
System.out.println(this.i);
System.out.println(this.getClass());
this.display() ;
}
再次运行程序,结果为:
2
class edu.qichao.chapter2.Derived
0
可以看到this代表的是Derived的实例,但是编译的时候类型为Base,所以输出this.i的值为2。
4)继承成员变量和成员方法的区别
package com.base; class Animal { private String desc ; public Animal(){ this.desc = getDesc() ; } public String getDesc(){ return "Animal" ; } public String toString(){ return desc ; } } public class Wolf extends Animal { private String name ; private double weight ; public Wolf(String name , double weight){ this.name = name ; this.weight = weight ; } public String getDesc(){ return "Wolf[name=" + name + ",weight=" + weight + "]" ; } public static void main(String[] args){ System.out.println(new Wolf("灰太狼" , 3)); } }
程序运行结果为:
2
2
-----------------
20
20
-----------------
2
20
-----------------
2
在上面的程序中,不管是d变量、还是bd变量、还是都d2b变量。只要他们指向一个Derived对象,则不管他们声明时用了什么类型,当通过这些变量调用方法时,方法的行为总是表现出他们的实际类型的行为,但是如果通过这些变量来访问他们所指向对象的实例变量的时候,这些实例变量的值总是表现出声明这些变量所用类型的行为。
由此可见,java处理成员变量和成员方法的继承时是有区别的。
相关推荐
在构造子类对象时,会自动调用父类的构造函数,此时在父类的构造函数中的this指针所指向的是子类对象地址 10、AfxWinMain函数 MFC程序的WinMain函数是通过调用AfxWinMain函数来完成它的功能的 注:Afx前缀的函数代表...
(3) super.([paramlist]) //调用父类中的构造函数 在类方法中(static),不能使用this或super修饰符 " Q0045 Java中是怎样捕获异常的? "try { //statement01 } catch(Exception e) { //statement02 } finally { ...
5.9.2 初始化块和构造器 161 5.9.3 静态初始化块 162 5.10 本章小结 165 本章练习 165 第6章 面向对象(下) 166 6.1 基本数据类型的包装类 167 6.2 处理对象 170 6.2.1 打印对象和toString方法 170 6.2.2 =...
7.7 匿名函数捕获变量值 7.8 减少可调用对象的参数个数 7.9 将单方法的类转换为函数 7.10 带额外状态信息的回调函数 7.11 内联回调函数 7.12 访问闭包中定义的变量 第八章:类与对象 8.1 改变对象的字符串...
4.5.2使用super调用父类的构造方法157 4.6继承的内部处理158 4.7多态的基本概念159 4.8重载159 4.8.1普通方法的重载160 4.8.2构造方法的重载161 4.8.3重载的解析163 4.8.4重载与覆盖的区别165 4.9运行时多态...
不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。 接口(interface)...
11 在子类中调用父类方法 12 super调用父类的方法 13 选择系统作业讲解 第26章 01 学生自主复习 02 分享列表 03 多态 04 封装 05 面向对象概念总结 06 反射 07 反射及动态导入模块 08 类的内置attr属性 09 类内置...
不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。 接口(interface...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 71、说出一些常用的类,包,接口,请各举5个 72、java中有几种...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 52 71、说出一些常用的类,包,接口,请各举5个 54 72、java中有...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中...
70、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常! 48 71、说出一些常用的类,包,接口,请各举5个 49 72、java中有...