动手动脑---继承与多态

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动手动脑---继承与多态相关的知识,希望对你有一定的参考价值。

一.为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?
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();
  }
}

技术分享

 

构造函数(constructor)是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。
特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。构造函数的功能主要用于在类的对象创建时定义初始化的状态。
因为子类继承自父类,会沿用父类的东西(没被覆盖的函数以及可见的成员变量等),而这些东西子类是没有的,需要先初始化父类才能被使用。
构造一个对象,先调用其构造方法,来初始化其成员函数和成员变量。
子类拥有父的成员变量和成员方法,如果不调用,则从父类继承而来的成员变量和成员方法得不到正确的初始化。
不能反过来调用也是这个原因,因为父类根本不知道子类有神魔变量而且这样一来子类也得不到初始化的父类变量,导致程序运行出错!

二.
public class ExplorationJDKSource {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(new A());
    }

}

class A{}

  

技术分享

 

反编译结果:

技术分享

 

使用Eclipse打开JDK源码:

技术分享

打开object

技术分享

这与课件给出基本相同

 

三.
class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

结果:

技术分享

 

总结:

(1)覆盖方法的允许访问范围不能小于原方法。

(2)覆盖方法所抛出的异常不能比原方法更多。

(3)声明为final方法不允许覆盖。 例如,Object的getClass()方法不能覆盖。

(4)不能覆盖静态方法。

 

 四.下列语句哪一个将引起编译错误?为什么?哪一个会引起运行时错误?为什么?

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;

    }
}

加//的都为出错项,子类可赋值给父类,父类不能赋值给子类,需进行类型转换

 

总结:

子类对象可以直接赋给基类变量。

基类对象要赋给子类对象变量,必须执行类型转换,

其语法是: 子类对象变量=(子类名)基类对象名;

也不能乱转换。如果类型转换失败Java会抛出以下这种异常: ClassCastException

 

五.1. 左边的程序运行结果是什么? 2. 你如何解释会得到这样的输出? 3. 计算机是不会出错的,之所以得 到这样的运行结果也是有原因的, 那么从这些运行结果中,你能总 结出Java的哪些语法特性?

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);
    }
}

预测:100  200  200  201  202

结果:

技术分享

 

第一个值:父类Parent调用自己的方法;

第二个值:子类child调用方自己的方法;

第三个值:子类将自己的方法赋给父类,父类虽然名字不变,但已经是子类了,因而实际调用的是子类的方法;

第四个值:父类中的值MyValue加一,但是父类调用的是子类的方法,因而无影响;

第五个值:强制转化,父类将值赋给子类,调用的仍然是子类的方法,只是值加一

 

总结:

当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。 这个特性实际上就是面向对象“多态”特性的具体表现。

如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。 如果子类被当作父类使用,则通过子类访问的字段是父类的! 牢记:在实际开发中,要避免在子类中定义与父类同名 的字段。不要自找麻烦!——但考试除外,考试 中出这种题还是可以的。

 

 六.请使用javap查看编译器为TestPolymorphism.java生成的字节码指令,然后通过互联网搜索资料,尝试从底层开始理解Java编译器是如何为多态代码生成字节码指令,在程序运行过程中,多态特性又是如何实现的。

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);
    }
}

结果:

技术分享

总结:

◆强制的:一种隐 式做类型转换的方法。

◆重载的:将一个标志符用作多个意义。

◆参数的:为不同类型的参数提供相同的操作。

◆包含的:类包含关系的抽象操作。

多态依赖于类型和实现的分离,多用来把接口和实现分离。

 

















以上是关于动手动脑---继承与多态的主要内容,如果未能解决你的问题,请参考以下文章

继承与多态———动手动脑

动手动脑---继承与多态

继承与多态 动手动脑

06-继承与多态(动手动脑与验证)

继承与多态,动手动脑

课堂(继承与多态)动手动脑