习题一
class Perss { private String name; private int age; Perss() { // 基类无参构造方法 System.out.println("基类无参"); } Perss(String name, int age) { // 基类有参构造方法 System.out.println("基类有参"); this.name = name; this.age = age; } public void show() { System.out.println("姓名:" + name + ",年龄:" + age); } } class Student extends Perss { private String school; Student() { // 子类无参构造方法 System.out.println("子类无参"); } Student(String name, int age) { // 子类有参构造方法 System.out.println("子类有参A"); } Student(String name, int age, String sch) { // 子类有参构造方法 this(name, age); // 显式调用语句 school = sch; System.out.println("我是" + school + "的"); System.out.println("子类有参B"); } } public class Zy4_1 { public static void main(String[] args) { Student stud = new Student("Li", 18, "经管学院"); stud.show(); } }
输出结果:
基类无参 子类有参A 我是经管学院的 子类有参B 姓名:null,年龄:0
分析:
首先第一句话:“基类无参”,说明当子类创建对象时,在调用子类的构造函数之前一定会先调用父类的构造函数,这里是默认使用父类无参的构造函数。
第二句输出“子类有参A”,是因为 this(name, age);因此在子类的构造函数内部调用了自己的其他构造函数。
第三句话“我是经管学院的”,是因为在创建stud对象的时候使用了有参的构造函数Student(String name, int age, String sch),并且赋值了。
最重要的是最后一句:姓名:null,年龄:0,为什么这里不是姓名:Li,年龄:18,因为这里的name, age都是父类私有的成员变量,只能通过调用父类的有参构造方法来赋值,因此这里为null和0
习题二
class Parent{ int x = 100; void m() { System.out.println(x); } } class Child extends Parent{ int x = 200; //与基类x同名 void m() { //重写基类的m() System.out.println("x="+x); System.out.println("super.x="+super.x); super.m(); //调用基类的m() } } public class Zy4_2 { public static void main(String[ ] args) { Parent a = new Child(); //转型 a.m(); //转型对象调用的是子类重写基类的m() System.out.println(a.x); } }
结果:
x=200 super.x=100 100 100
分析:这里使用了向上转型,即父类的引用变量指向了一个子类的对象。
首先,由于子类与父类有相同名字的成员变量,但此处两者是不同的,分别占用了不同的内存空间。
2.由于子类与父类有同名,同参数的方法,因此子类对父类的m方法进行了重写,因此 a.m(); 调用的是子类的构造方法。
接着通过 super.m();调用父类的m方法
习题三
class Aw { int m; int getM() { return m;} int seeM() { return m;} } class Bw extends Aw { int m; int getM() { return m+10; } //重写 int f() { return m; } //子类新增 } public class Zy4_3 { public static void main(String[ ] args) { Bw b = new Bw (); b.m = 20; System.out.println(b.getM()); Aw a = b; //转型 a.m = -10; //基类引用变量访问的是基类的m System.out.println(a.getM()); //调用的是子类重写基类的方法 System.out.println(b.seeM()); //基类方法访问的是基类m System.out.println(b.f()); //子类新增的方法访问的是子类的m System.out.println(a.equals(b)); } }
结果:
30 30 -10 20 true
分析:
首先第一个b.getM()输出的就是30,由于发生了Aw a = b;的向上转型,因此a指向了b的对象,a.getM(),调用的是子类重写父类的方法。
2.关于 b.f(),由于父类没有此方法,因此不能写成a.f()
由于Aw a = b;,因此a与b指向相同的地址,因此用equals函数时是true。
而关于子类对象赋值给父类,有以下总结:
将子类对象赋值给父类对象,所得到对象是这样的一个对象:
它是一个编译是为父类对象,但运行却是一个子类对象,具体特征如下.
1.被声明为父类对象
2.拥有父类属性
3.占用子类的内存空间
4.子类方法覆盖父类的方法时,此时对象调用的是子类的方法;否则,自动调用继承父类的方法.
5.我人认为这个对象既不是父类对象,也不是子类对象.当我们用到它的方法时,
我便把它看成子类对象;若用到它的属性时,我把它看成父类对象.
它是一个占用父类属性,而使用子类方法的对象.至于到底是什么对象,我认为还是得根据声明来,它应算是父类对象,但拥有子类方法