zoukankan      html  css  js  c++  java
  • java基础:父类与子类之间变量和方法的调用

    1)父类构造函数

    java中当调用某个类的构造方法的时候,系统总会调用父类的非静态初始化块进行初始化,这个调用是隐式的,而且父类的静态初始化代码

    块总是会被执行,接着调用父类的一个或者多个构造器执行初始化,这个调用也可以通过super进行显式调用。

    例如:

    父类代码如下:

    public class Creature {//父类

    {//非静态代码块

    System.out.println("creature的非静态代码块正在执行");

    }

     

    public Creature(){

    System.out.println("creature的构造函数正在执行");

    }

    }

    子类代码如下:

    public class Animal extends Creature {

    {

    System.out.println("animal的初始化代码块正在执行");

    }

    public Animal(){

    System.out.println("animal的构造方法正在执行");

    }

     

    public static void main(String[] args){

    Animal a = new Animal()  ;

    }

    }

    则运行程序后的结果为:

    creature的非静态代码块正在执行

    creature的构造函数正在执行

    animal的初始化代码块正在执行

    animal的构造方法正在执行

    从结果中可以看出:调用某个类的构造方法的时候总是会先执行父类的非静态代码块,然后执行父类的构造方法,最后才是执行当前类的

    非静态代码块和构造方法。执行过程中有先后顺序。

    若果想要显式调用父类的构造方法则可以使用super(),来调用,但是super关键字和this关键字都必须放在构造放的第一行,而且只能使

    用一个,为什么要放在第一行呢?因为如果不放在第一行则先调用子类的初始化代码,再调用父类的初始化代码,则父类中的初始化后的值

    会覆盖子类中的初始化的值。

    注:super用于显式调用父类的构造器,this可以显式调用本类中的重载的构造器。

     

     

    2)访问子类对象的实例变量

    子类的方法可以访问父类中的实例变量,这是因为子类继承父类就会获得父类中的成员变量和方法,但是父类方法不能访问子类的实例变量

    ,因为父类根本无法知道它将被哪个类继承,它的子类将会增加怎么样的成员变量。但是,在极端的情况下,父类也可以访问子类中的变量。

    例如:

    父类代码如下:

    public class Base {//父类

    private int i = 2 ;

    public Base(){

    this.display() ;

    }

    public void display(){

    System.out.println(i);

    }

    }

    子类中代码如下:

    public class Derived extends Base {

    private int i = 22 ;

    public Derived(){

    i = 222 ;

    }

    public void display(){

    System.out.println(i);

    }

    }

    测试用例如下:

    public class Test {

    public static void main(String[] args) {

    new Derived() ;

    }

    }

    程序的执行结果为:

    0

    也许你会感到奇怪,为什么不是2?22?222?怎么会是0呢,下面我们看一下程序的执行过程。当我们调用new Derived() ;创建Derived

    实例的时候,系统会为Derived对象分配内存空间,Derived会有两个i实例变量,会分配两个空间来保存i的值。分配完空间以后i的值为0

    ,如果有引用类型则引用类型的值为null。接下来程序在执行Derived的构造器之前会执行Base的构造器,表面上看Base的构造器中只有

    一行代码,但是在父类中定义i的时候执行的初始值2,因此经过编译之后,该构造方法中应该包含如下两行代码:

    i =2 ;

    this.display() ;

    程序先将Base中的i赋值为2,然后执行display方法。此处有一个关键字this,this到底代表谁呢?表面上看this代表的是Base的当前实例,

    但是实际上代码是放在Derived的构造器中的,所以this最终代表的是Derived的当前实例(编译类型是Base而实际引用一个Derived对象),

    所以如果在父类的构造方法中直接输出System.out.println(this.i) ;则输出的结果为2。但是调用this.display()方法,此时调用的是

    子类中重写的display方法,输出的变量i也是子类中的i,但是此时子类中的变量i还没有赋值,所以输出结果为0。

    为了详细的看清楚this变量到底代表什么实例,我们将Base的构造方法修改如下:

    public Base(){

    System.out.println(this.i);

    System.out.println(this.getClass());

    this.display() ;

    }

    再次运行程序,结果为:

    2

    class edu.qichao.chapter2.Derived

    0

    可以看到this代表的是Derived的实例,但是编译的时候类型为Base,所以输出this.i的值为2。

     

     

    3)调用被子类重写的方法

    默认情况下,子类可以调用父类的方法,但是父类不能调用子类的方法,因为父类不知道它将被哪个子类继承,也不知道子类将增加怎么

    样的方法。

    例如:

    父类Animal的代码如下:

    public class Animal {

    private String desc ;

     

    public Animal(){

    this.desc = getDesc() ;

    }

     

    public String getDesc(){

    return "Animal" ;

    }

     

    public String toString(){

    return desc ;

    }

    }

    子类Wolf的代码如下:

    public class Wolf extends Animal {

    private String name ;

    private double weight ;

    public Wolf(String name , double weight){

    this.name = name ;

    this.weight = weight ;

    }

    public String getDesc(){

    return "Wolf[name=" + name + ",weight=" + weight + "]" ;

    }

     

    public static void main(String[] args){

    System.out.println(new Wolf("灰太狼" , 3));

    }

    }

    程序的运行结果为:

    Wolf[name=null,weight=0.0]

    现在我们分析一下程序执行的过程。在main方法中通过new Wolf("灰太狼" , 3);来创建一个Wolf的实例,子类会隐式调用父类的构造方

    法,在父类构造方法中初始化desc变量this.desc = getDesc() ;此处需要注意this变量,虽然这个this放在Animal的构造放中,但是是在

    Wolf的构造方法中调用父类的构造方法,所以this编译时类型为Animal,运行时类型为Wolf,此处调用的getDesc方法是子类Wolf的方法,

    但是子类中的name和weight变量都没有初始化,默认为null和0.0.所以程序的最终结果为:Wolf[name=null,weight=0.0]

     

     

    4)继承成员变量和成员方法的区别

    java中队成员变量的继承和成员方法的继承是不同的。

    例如:

    父类代码如下:

    public class Base {

    int count = 2 ;

    public void display(){

    System.out.println(this.count);

    }

    }

    子类代码如下:

    public class Derived extends Base {

    int count = 20 ;

    @Override

    public void display(){

    System.out.println(this.count);

    }

    }

    测试用例如下:

    public class Test {

    public static void main(String[] args) {

    Base b = new Base() ;

    System.out.println(b.count);

    b.display() ;

    System.out.println("-----------------");

    Derived d = new Derived() ;

    System.out.println(d.count);

    d.display() ;

    System.out.println("-----------------");

    Base bd = new Derived() ;

    System.out.println(bd.count);

    bd.display() ;

    System.out.println("-----------------");

    Base d2b = d ;

    System.out.println(d2b.count);

    }

    }

    程序运行结果为:

    2

    2

    -----------------

    20

    20

    -----------------

    2

    20

    -----------------

    2

    在上面的程序中,不管是d变量、还是bd变量、还是都d2b变量。只要他们指向一个Derived对象,则不管他们声明时用了什么类型,当通过

    这些变量调用方法时,方法的行为总是表现出他们的实际类型的行为,但是如果通过这些变量来访问他们所指向对象的实例变量的时候,

    这些实例变量的值总是表现出声明这些变量所用类型的行为。由此可见,java处理成员变量和成员方法的继承时是有区别的。

  • 相关阅读:
    Jquery easyui datagrid 删除多行问题
    Winform 程序部署生成
    20120915
    Winform 程序部署生成
    Jquery EasyUi datagridwindowform数据问题
    eclipse快捷键大全(转)
    c/c++ 图像RGB位存储,位操作
    常用的几款在线代码转换工具
    WPF基础之路由事件一
    WPF中的依赖属性与附加属性
  • 原文地址:https://www.cnblogs.com/gaoxiangde/p/4379888.html
Copyright © 2011-2022 走看看