Java——类的继承与多态
1. 在子类中,若要调用父类中被覆盖的方法,可以使用super关键字。
以以下代码为例解释:
package homework;
class Grandfather{
public Grandfather(){
System.out.println("Grandfather created. ");
}
}
class TestParent extends Grandfather{
public TestParent(){
System.out.println("Father created. ");
}
public void show() {
System.out.println("This is father's words ");
}
}
class TestChild extends TestParent{
public TestChild(){
System.out.println("Child created. ");
}
public void show() {
super.show();
System.out.println("This is my words ");
}
}
public class TestClassP_C {
public static void main(String[] args) {
// TODO Auto-generated method stub
TestChild c=new TestChild();
//依次继承
c.show();
//调用TestChild中show()函数,由于函数中有super,因此调用父类中被覆盖的show()方法
}
}
(1)关于子类的创建:
若父类及父类的父类有默认构造函数,则从最底层(最开始的父类)开始继承,直到传递到子类。
(2)关于super的使用:
首先super主要用来调用父类的方法,必须放在每一个子类构造函数的第一句,并不是指类中的第一句。
其次,若是子类函数想调用父类中被覆盖的函数方法,可通过“super.方法名()”调用到父类中的函数;若是子类构造函数,则直接使用“super()”(无参时)或者“super(参数值)”(有参时)调用父类的构造函数。
(3)编译错误分析:
在编译时,不断尝试不同的构造方法和调用方法,发现以下错误:
若父类多了一个有参的构造函数,要么子类构造函数保持一致,super(参数值)调用,要么不写子类构造函数。否则会显示错误。具体如下:
父类构造函数有参
使用无参super会错误,即使没有使用super也错误。
Super和子类构造函数均加参数才正确
2.子类与父类的类型转换与使用总结:
观察以下代码:
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;//错误!父类m赋值给子类d,需要进行(Dog)m强制类型转换。
d=(Dog)m;
//d=c;//错误!两个子类不能能相互赋值。
// c=(Cat)m;//编译正确,通过强制类型转换,可以将父类变量赋给子类。
}
}
总结:
子类可以给父类直接赋值,比如“m=d;”;但是若父类需要给子类赋值,需要进行类的强制类型转换。可以想象成现实中的亲子关系,父母给孩子是爱的表达,这里面表达了很多;而孩子给父母是天经地义,可以直接给,加强记忆。
另外两个派生类之间没有关联,不予赋值,就像亲兄妹,没有义务给予经济支持。
3. 接口多态:使用接口代替抽象基类
首先区分接口与抽象基类的定义。
接口:在表面上由几个没有主体代码的方法定义成的集合体,有唯一的名称,可以被继承或其他接口所实现。使用接口主要实现多态性。一个类一次可以实现若干个接口,但一个类只能继承一个父类。需要注意的是,定义在接口中的常量必须被初始化。
抽象类则是为了使代码复用,可根据实际的编程环境,选择方法。
4. .分析下方的程序运行结果是什么,并解释会得到这样的输出。
假设parent.myvalue=100,child.myvalue=200。
第一次新建Parent和Child类时,会调用各自的printvalue()函数;分别输出100,200.
当“Parent=child”时,将child的对象赋给parent,于是再调用“parent.printvalue()”,输出child.myvalue=200;执行“parent.myValue++”,则为parent的myvalue=101。由于子类中重新定义了printValue()方法,覆盖掉了父类中的方法,故即使再调用“Parent.printValue()”依旧输出child.myValue=200。当执行“((child)parent).myValue++”,意思为将parent转化为child,实际调用child.myValue++即201,再次由于父类方法被覆盖,“parent.printValu()”依旧输出child.myValue=201。
总结:
当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定。这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。
如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。如果子类被当作父类使用,则通过子类访问的字段是父类的!
实际运用中,尽量避免命名与父类相同的方法。