第七讲 继承与多态
1.
源码:
class Grandparent {
public Grandparent() {
System.out.println("GrandParent Created.");
}
public Grandparent(String string) {
System.out.println("GrandParent Created.String:" + string);
}
}
class Parent extends Grandparent {
public Parent() {
//super("Hello.Grandparent.");
System.out.println("Parent Created");
// super("Hello.Grandparent.");
}
}
class Child extends Parent {
public Child() {
System.out.println("Child Created");
}
}
public class TestInherits {
public static void main(String args[]) {
Child c = new Child();
}
}
运行结果:
修改之前:
修改之后:
在java语言的继承中,在执行子类的构造方法之前,会先调用父类没有参数的构造方法,其目的是为了要帮助继承自父类的成员做初始化操作。子类的构造方法通过super()来调用父类特定的构造方法(如果没有super语句还是会自动调用父类没有参数的构造方法),调用父类特定的构造方法的super语句必须写在子类构造方法的第一行,否则编译时出错,如果父类只定义了有参数的构造方法,而在子类中又没有用super关键字来调用父类的特定构造方法,则编译时出错。
又问:
子类是通过父类继承过来的,所以子类有父类的所有非私有的属性和方法,如果不调用父类的构造方法,那么不能初始化父类中定义的属性,就给父类的属性分配内存空间 ,如果父类的属性没有分配内存空间,那么子类访问父类的属性,就会报错。
2.
自行编写代码测试以下特性(动手动脑):
在子类中,若要调用父类中被覆盖的方法,可以使用super关键字。
(1)覆盖方法的允许访问范围不能小于原方法。
(2)覆盖方法所抛出的异常不能比原方法更多。
(3)声明为final方法不允许覆盖。
例如,Object的getClass()方法不能覆盖。
(4)不能覆盖静态方法。
3.
m=d; //编译正确,因为子类对象可以直接赋给基类变量。
d=m; //编译错误,基类对象要赋给子类对象变量,必须执行类型转换(子类对象变量=(子类名)基类对象名;)
d=(Dog)m; //编译正确,基类对象要赋给子类对象变量,必须执行类型转换
d=c; //编译错误,不同子类之间不能复制
c=(Cat)m; //m已经转换成Dog, Dog和Cat子类之间不能转换
4.
(1)运行结果:
(2)解释:
在调用的时候,对象是子类的,就调用子类的方法,对象是父类的,就调用父类的方法。父类对象访问子类成员,调用相同的函数名的函数属于子类的;父类的变量进行相关的原算,但是,如果这时父类变量指向子类对象,继续调用得方法和变量仍然是子类覆盖后的新的变量和方法的,例如如果将代码改为:
则第三个结果为:101
最后一个输出为父类强转为子类对象,调用的是子类的变量和方法输出。
(3)
父类对象可以访问子类的成员,当然只限于”覆盖”发生时,调用的时候,对象是子类的,就调用子类的方法,对象是父类的,就调用父类的方法。当然还有如下特性:
1.当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。这个特性实际上就是面向对象“多态”特性的具体表现。
2.如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。
3.如果子类被当作父类使用,则通过子类访问的字段是父类的.
5.
源码:
class Parent
{
public int value=100;
public void Introduce()
{
System.out.println("I'm father");
}
}
class Son extends Parent
{
public int value=101;
public void Introduce()
{
System.out.println("I'm son");
}
}
class Daughter extends Parent
{
public int value=102;
public void Introduce()
{
System.out.println("I'm daughter");
}
}
public class TestPolymorphism
{
public static void main(String args[])
{
Parent p=new Parent();
p.Introduce();
System.out.println(p.value);
p=new Son();
p.Introduce();
System.out.println(p.value);
p=new Daughter();
p.Introduce();
System.out.println(p.value);
}
}
结果:
多态依赖于类型和实现的分离,多用来把接口和实现分离。
6.(多态:多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。)
运行结果如:
虽然猴子和鸽子有数量的变化,定义固定长度的数组使用不方便,长度有限。
(接口)固定数组实现
public class Denglu
{
public static void main(String args[])
{
Feeder f = new Feeder("小李");
// 饲养员小李喂养一只狮子
f.eat();
// 饲养员小李喂养十只猴子
for (int i = 0; i < 10; i++)
{
f.eat1();
}
// 饲养员小李喂养5只鸽子
for (int i = 0; i < 5; i++)
{
f.eat3();
}
}
}
interface Lion
{
abstract void eat();
}
interface Monkey
{
abstract void eat1() ;
}
interface Pigeon extends Lion,Monkey
{
abstract void eat3() ;
}
class Feeder implements Pigeon
{
public String name;
public Feeder(String name)
{
this.name = name;
}
public void eat()
{
System.out.println("我不吃肉谁敢吃肉!");
}
public void eat1()
{
System.out.println("我什么都吃,尤其喜欢香蕉。");
}
public void eat3()
{
System.out.println("我要减肥,所以每天只吃一点大米。");
}
}
运行结果: