1,思考
class Grandparent { public Grandparent() { System.out.println("GrandParent Created."); } public Grandparent(String string) { System.out.println("GrandParent Created.String:" + string); } } class Parent2 extends Grandparent { public Parent2() { //super("Hello.Grandparent."); System.out.println("Parent Created"); // super("Hello.Grandparent."); } public Parent2(String a) { System.out.println("PPP"+a); } } class Child2 extends Parent2 { public Child2() { //super("GGG"); System.out.println("Child Created"); } } public class TestInherits { public static void main(String args[]) { Child2 c = new Child2(); } }
运行结果为:
显然运行子类的构造函数会先执行父类的构造函数。若将//super("Hello.Grandparent.");前//去掉之后运行就结果就会变成:
有了super()语句会执行其调用的构造函数,若将其放在第二行,则会报错
(构造函数调用必须是构造函数中的第一个语句)这是显示的错误。
总结:通过 super 调用父类构造方法,必须是子类构造方法中的第一个语句。若父类中同时存在有参构造函数和无参构造函数,若子类构造函数什么也没写则默认调用无参构造函数,若加上super(),则根据super()来确定,若父类只有有参构造函数,则必须在写子类构造函数时加上super();
2,思考
构造函数(constructor)是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。构造函数的功能主要用于在类的对象创建时定义初始化的状态。构造一个对象,先调用其构造方法,来初始化其成员函数和成员变量。子类拥有父的成员变量和成员方法,如果不调用,则从父类继承而来的成员变量和成员方法得不到正确的初始化。不能反过来调用也是这个原因,因为父类根本不知道子类有神魔变量而且这样一来子类也得不到初始化的父类变量,导致程序运行出错!
3,解密
public class ExplorationJDKSource { /** * @param args */ public static void main(String[] args) { System.out.println(new A()); } } class A{}
通过javap反编译得:
可以看到println()那条语句到底调用了Ljava/lang/Object使用Eclipse打开JDK源码,查看真正被执行的代码是
4,探索:观看以下代码,,注意最后一句,一个字串和一个对象“相加”
得到的结果为:
分析:示例中,Fruit类覆盖了Object类的toString方法。在“+”运算中,当任何一个对象与一个String对象,连接时,会隐式地调用其toString()方法,默认情况下,此方法返回“类名 @ + hashCode”。为了返回有意义的信息,子类可以重写toString()方法。若不重写结果为:
5,请自行编写代码测试以下特性(动手动脑): 在子类中,若要调用父类中被覆盖的方法,可以使用super关键字。
代码如下:
class ddd { int num; ddd() { this.num=1; } void shuchu() { System.out.println("父类"+num); } } class aaa extends ddd { aaa() { this.num=2; } void shuchu() { super.shuchu(); System.out.println("子类"+num); } } public class demo { public static void main(String[]args) { aaa wa=new aaa(); wa.shuchu(); } }
运行结果为:
若将super.shuchu()注释掉,结果为:
6,怎样判断对象是否可以转换?
可以使用instanceof运算符判断一个对象是否可以转换为指定的类型: Object obj="Hello"; if(obj instanceof String) System.out.println("obj对象可以被转换为字符串");
public class TestInstanceof { public static void main(String[] args) { //声明hello时使用Object类,则hello的编译类型是Object,Object是所有类的父类 //但hello变量的实际类型是String Object hello = "Hello"; //String是Object类的子类,所以返回true。 System.out.println("字符串是否是Object类的实例:" + (hello instanceof Object)); //返回true。 System.out.println("字符串是否是String类的实例:" + (hello instanceof String)); //返回false。 System.out.println("字符串是否是Math类的实例:" + (hello instanceof Math)); //String实现了Comparable接口,所以返回true。 System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable)); String a = "Hello"; //String类既不是Math类,也不是Math类的父类,所以下面代码编译无法通过 //System.out.println("字符串是否是Math类的实例:" + (a instanceof Math)); } }
结果为:
7,小测试:
现在有三个类: class Mammal{} class Dog extends Mammal {} class Cat extends Mammal{} 针对每个类定义三个变量并进行初始化 Mammal m=null ; Dog d=new Dog(); Cat c=new Cat();
下列语句哪一个将引起编译错误?为什么?哪一个会引起运行时错误?为什么? m=d; d=m; d=(Dog)m; d=c; c=(Cat)m;
我认为第一句不出错,可以用子类给父类赋值,因为子类里有父类里所有的变量;第二句会出错,不能用父类变量来给子类赋值,父类里面不一定包含不全子类里所有的变量;第三句不会出错若要用子类给父类赋值必须强转;第四句出错,这两个变量间没有直接关系;第五句对同第三句。
class Mammal{} class Dog extends Mammal {} class Cat extends Mammal{} public class TestCast { public static void main(String args[]) { Mammal m; Dog d=new Dog(); Cat c=new Cat(); m=d; //d=m; d=(Dog)m; //d=c; //c=(Cat)m; } }
结果:
第二句错误显示为:类型不匹配:不能从 Mammal 转换为 Dog
第三句错误显示为:类型不匹配:不能从 Cat 转换为 Dog
8,动动手:
public class ParentChildTest { public static void main(String[] args) { Parent parent=new Parent(); parent.printValue(); Child child=new Child(); child.printValue(); parent=child; parent.printValue(); parent.myValue++; parent.printValue(); ((Child)parent).myValue++; parent.printValue(); } } class Parent{ public int myValue=100; public void printValue() { System.out.println("Parent.printValue(),myValue="+myValue); } } class Child extends Parent{ public int myValue=200; public void printValue() { System.out.println("Child.printValue(),myValue="+myValue); } }
结果:
解释:
先定义了一个父类对象以及子类变量,输出就显示出来第一二句,然后用children对象给parent对象赋值,parent对象的myValue变为200;parent函数printvalue也被覆盖,于是就有了第三句,value++是先输出再加一,于是输出第四句,然后强转输出,这是value已经是201,先输出在加一有了第五句。
思考:但我又加了一行代码如下:
运行结果如下:
发现父类对象的数据值加了1
之后再改如下:
结果为:
我在网上查了查发现过程为:
第一个100:是parent调用PrintValue方法输出parent类中myValue值为100;
第二个200:是child调用PrintValue方法输出child类中myValue值为200;
第三个200:是parent = child,将子类对象的赋值给父类,但此时parent只能调用子类的方法,调用子类PrintValue时,输出的当然是子类的myValue值200。
第四个200:虽然parent = child,但parent不能调用子类的变量,所以parent.myValue++;只是将父类对象中的变量myValue值+1但不能改变子类的myValue值,但调用的是子类PrintValue方法时,输出的是子类的myValue值200。
第五个201:(Child)parent,强制转化parent为child对象,此时parent完全成为child对象,所以输出值为201。
原因:
(1):当子类和父类拥有同名方法时,并且让一个父类变量引用一个子类对象时,调用哪个方法由自己的真实类型来决定。
(2):如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。