多态、静态初始化块

面向对象编程进阶-----多态性、静态初始化块

多态性:

多态机制是面向对象技术的精华之一,它是建立在继承基础之上的。所谓多态(polymorphism),子类的对象可以代替父类的对象使用。

  思想基础

      在类的继承中,子类在父类的基础上进行扩充和改造,父类拥有的成员子类中都有,因而可以认为子类比父类的功能强,或者说子类的对象应该比父类的对象功能强,因而子类的对象应可以替代父类的对象被使用。

5.6 多态性使用举例1

源文件:Person.javaStudent.java

public class Test{

public static void main(String[] args){

Person p=new Student();  //

System.out.println(p.getInfo());

}

}(变量p声明为父类Person的类型,但实际指向的却是子类Student类型的对象)

一个对象只能属于一种确定的数据类型,该类型自对象创建直至销毁不能改变。

一个引用类型变量可能引用(指向)多种不同类型的对象—既可以引用其声明类型的对象,也可以引用其声明类型的子类的对象。

Object o=new String(hello); //Object是所有类的父类 p

Person p1=new String(hello);  ×//Person类和String类之间不存在继承关系

Student s=new Person(); × //子类变量不能引用父类对象

注意:由于父类对象未包含子类中添加的成员,因而功能较弱,也就无法替代子类对象使用。p.getSchool()  ×

5.7 多态性使用举例2

public class Test{

public void show(Person p)(方法的形参声明为Person类型){

System.out.println(p.getInfo());

}

public static void main(String[] args){

Person p=new Person();

Student s=new Student();//调用时实参既可以是Person类型,也可以是其子类Student类型

Test t=new Test();

t.show(p);  p            t.show(s);   p

}

}

注意:show方法既可以处理Person类型的数据,也可以处理Student类型的数据,乃至未来定义的任何Person子类类型的数据,这样就不必为相关的每一种类型单独声明一个处理方法,提高了代码的通用性。

在多态情况下,一个引用类型的变量如果声明为父类的类型,但实际引用的是子类对象,则该变量就不能访问子类中添加的属性和方法。可是如果此时调用的是父类中声明过,且在子类中又重写过的方法,情况又将如何?

Book

nameprice

setName()

getName()

setPrice()

getPrice()

show()

Novel

author

setAuthor()

getAuthor()

show()

例:(B既可引用Book类对象,又可引用Novel对象,则这时调用的到底是Book类中的show方法还是Novel类中的show方法?)

public class TestNovel{

public void process(Book b){

b.show();

}

public static void main(String[] args){

TestNovel t=new TestNovel();

Book b=new Book();  b.setName(English Language);

b.setPrice(34);

t.process(b); //方法体中的b.show()输出结果?

}

}

若增加如下代码:

Novel n=new Novel();

n.setName(the Great Wall);    n.setPrice(46.7);

n.setAuthor(Zhangsan);

t.process(n);        //方法体中的b.show()的输出结果?

结论:系统依据运行时对象的真正类型来确定具体调用哪一个方法—父类对象调用父类中的show方法,子类对象调用子类中重写过的show方法。

对象造型

      在多态的情况下,由于对象以其父类的身份出现,对子类中新添加成员的访问受到限制,有时我们可能需要恢复一个对象的本来面目—造型(Casting),以发挥其全部潜力。

5.9 多态性示例4

Public class Test{

public void cast(Person p){

//System.out.println(p.getSchool()); 非法

Student st=(Student)p;     //造型

System.out.println(st.getSchool());  //正确

}

}

(在main方法中:Test t=new Test();

Student s=new Student();  s.setSchool(THU);

t.cast(s);

所谓的造型其实就是引用类型数据值之间的强制类型转换。

注意:

从子类到父类的类型转换可以自动进行;

在多态的情况下,从父类到子类转换必须通过造型(强制类型转换)实现;

无继承关系的引用类型间的转换是非法的。

String str=hello,world;Person p=(Person)str; ×

特别强调:从父类到子类的造型也不是都能成功—只有当对象的真正类型本就是子类类型,只是在多态的情况下,被一个声明为父类类型的变量所引用,才可以进行造型处理,即再恢复该对象的本来面目,而一个对象如果其真正类型就是父类类型,是不能被造型为子类类型的。

例如,Person p1=new Person();

Student stu=(Student)p1;  //编译没错,但运行出错

instanceof运算符

      再看例5.9Test类的cast方法:

public void cast(Person p){

//System.out.println(p.getSchool()); 非法

Student st=(Student)p;     //造型

System.out.println(st.getSchool());  //正确

}

      调用方法时如果实参是子类Student的对象,则造型是正确的,若实参是父类Person的对象,则造型失败!

       if(p instanceof Student){

                   Student st=(Student)p;   st.getSchool();

       }

运算符instanceof用于检测一个对象的真正类型。

格式:<变量名> instanceof <类型>

功能:如果instanceof操作符左侧的变量当前时刻所引用对象的真正类型是其右侧给出的类型、或是其子类,则整个表达式结果为true,否则结果为false

5.10 多态性示例5。在Test类中的cast方法可改写为:

public void cast(Person p){

               if(p instanceof Graduate)

                         ...

               else if(p instanceof Student)

                         …

      }

静态初始化块:

Java使用构造方法来对单个对象进行初始化操作。与构造方法作用非常类似的是初始化块,它也可以对对象进行初始化操作。

  使用初始化块

      初始化块是Java类里可以出现的第四种成员。语法格式:

class 类名{

[修饰符](只能是static,静态初始化块

{

//初始化块的可执行代码(可以定义局部变量、调用其他对象的方法、使用分支、循环语句等

}

一个类里可以有多个初始化块;

相同类型的初始化块之间有顺序,前面定义的初始化块先执行,后面定义的初始化块后执行。

5.7 初始化块的使用。

分析:

当创建Java对象时,系统总是先调用该类里定义的初始化块;

如果一个类里定义了两个普通初始化块,则前面定义的初始化块先执行,后面定义的初始化块后执行。

初始化块虽然也是Java类里的一种成员,但它没有名字,也就没有标识,因此无法通过类、对象来调用初始化块;

初始化块只能在创建对象时自动执行而且在执行构造方法之前执行。 

5.8 初始化块的使用。

注意:初始块和声明实例属性时所指定的初始值都是该实例的初始化代码,它们的执行顺序与源程序中排列顺序相同。

      初始化块和构造方法的不同:初始化块是一段固定的执行代码,它不能接受任何参数。因此初始化块对同一个类内的属性所进行的初始化处理完全相同。

      用法:如果多个构造方法里有相同的初始化代码,这些代码无需接受参数,那就可以把他们放在初始化块中定义。能更好的提高初始化块的复用,提高整个应用的可维护性。

      创建一个Java对象时,不仅会执行该类的初始化块和构造方法,系统会先执行其父类的初始化块和构造方法。 

静态初始化块

      如果定义初始化块时使用了static修饰符,则这个初始化块就变成了静态初始化块,也被称为类初始化块。

静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行,因此静态初始块总是比普通初始化块先执行。

静态初始块属于类的静态成员,用于对类属性执行初始化处理,不能对实例属性进行初始化处理。

系统在类初始化阶段执行静态初始化时,不仅会执行本类的静态初始化块,还会一直上溯到Object类(如果它包含静态初始化块)。经过这个过程,才完成了对类的初始化过程。  

5.9 写出程序的运行结果。

第一次创建一个Leaf对象时,系统中不存在Leaf类,因此需要先加载类并初始化,初始化Leaf类时先执行顶层父类的静态初始化块,然后执行其直接父类的静态初始化块,最后才执行Leaf本身的静态初始块。

每次创建一个Leaf对象时,都需要执行最顶层父类的初始化块、构造方法,然后执行父类的初始化块、构造方法…最后执行Leaf类的初始化块和构造方法。

5.10 静态初始化块的使用。

注意:静态初始块和声明静态属性时所指定的初始值都是该类的初始化代码,它们的执行顺序与源程序中排列顺序相同 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值