Java多态

   多态性

Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量
时使用的类型决定,运行时类型由实际 赋给该变量的对象决定。如果编译时类型和运行时类型不
一致,就可 能出现所谓的多态(Polymorphism)。
先看下面程序。
  上面程序的main()方法中显式创建了三个引用变量,对于前两个引用变量bc和sc,它们编译时类
型和运行时类型完全相同,因此调用 它们的成员变量和方法非常正常,完全没有任何问题。但第
三个引用 变量ploymophicBc则比较特殊,它的编译时类型是BaseClass,而运行 时类型是
SubClass,当调用该引用变量的test()方法(BaseClass类中 定义了该方法,子类SubClass覆盖了
父类的该方法)时,实际执行的 是SubClass类中覆盖后的test()方法,这就可能出现多态了。
  
     因为子类其实是一种特殊的父类,因此Java允许把一个子类对象 直接赋给一个父类引用变量,
无须任何类型转换,或者被称为向上转 型(upcasting),向上转型由系统自动完成
    
    
      当把一个子类对象直接赋给父类引用变量时,例如上面的
BaseClass ploymophicBc=newSubClass();,这个ploymophicBc引用 变量的编译时类型是
BaseClass,而运行时类型是SubClass,当运行时 调用该引用变量的方法时,其方法行为总是表
现出子类方法的行为特 征,而不是父类方法的行为特征,这就可能出现:相同类型的变量、 调用
同一个方法时呈现出多种不同的行为特征,这就是多态。
    
   上面的main()方法中注释了ploymophicBc.sub();,这行代码会在编译时引发错误。虽然
ploymophicBc引用变量实际上确实包含sub()方 法(例如,可以通过反射来执行该方法),但因为
它的编译时类型为 BaseClass,因此编译时无法调用sub()方法。
   
    与方法不同的是,对象的实例变量则不具备多态性。比如上面的ploymophicBc引用变量,程序
中输出它的book实例变量时,并不是输 出SubClass类里定义的实例变量,而是输出BaseClass类
的实例变量。
注意:
引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所
具有的方法。因此,编写Java代码 时,引用变量只能调用声明该变量时所用类里包含的方
法。
例如, 通过Object p=new Person()代码定义一个变量p,则这个p只能调用 Object类的方
法,而不能调用Person类里定义的方法。
注意: 通过引用变量来访问其包含的实例变量时,系统总是试图访问 它编译时类型所定义的
成员变量,而不是它运行时类型所定义的成 员变量。

 引用变量的强制类型转换

       编写Java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,
即使它实际所引用的对象确实包含该方 法。如果需要让这个引用变量调用它运行时类型的方法,
则必须把它 强制类型转换成运行时类型,强制类型转换需要借助于类型转换运算 符。
        类 型 转 换 运 算 符 是 小 括 号 , 类 型 转 换 运 算 符 的 用 法 是 :(type)variable,这种用
法可以将variable变量转换成一个type类型 的变量。前面在介绍基本类型的强制类型转换时,已经
看到了使用这 种类型转换运算符的用法,类型转换运算符可以将一个基本类型变量 转换成另一个
类型。
除此之外,这个类型转换运算符还可以将一个引用类型变量转换成其子类类型。这种强制类
型转换不是万能的,当进行强制类型转换 时需要注意:
基本类型之间的转换只能在数值类型之间进行,这里所说的数 值类型包括整数型、字符型和浮点型。但数值类型和布尔类型 之间不能进行类型转换。
引用类型之间的转换只能在具有继承关系的两个类型之间进 行,如果是两个没有任何继承关系的类型,则无法进行类型转 换,否则编译时就会出现错误。如果试图把一个父类实例转换 成子类类型,则这个对象必须实际上是子类实例才行(即编译 时类型为父类类型,而运行时类型是子类类型),否则将在运 行时引发ClassCastException异常。

 

下面是进行强制类型转换的示范程序。下面程序详细说明了哪些情况可以进行类型转换,哪些情况
不可以进行类型转换。

 

  考虑到进行强制类型转换时可能出现异常,因此进行类型转换之前应先通过instanceof运算符来判
断是否可以成功转换。例如,上面 的var str=(String)objPri;代码运行时会引发
ClassCastException 异常,这是因为objPri不可转换成String类型。为了让程序更加健 壮,可以将
代码改为如下:
在进行强制类型转换之前,先用instanceof运算符判断是否可以成功转换,从而避免出现
ClassCastException异常,这样可以保证程 序更加健壮。
注意:
当 把 子 类 对 象 赋 给 父 类 引 用 变 量 时 , 被 称 为 向 上 转 型(upcasting),这种转型
总是可以成功的,这也从另一个侧面证实 了子类是一种特殊的父类。这种转型只是表明这个
引用变量的编译 时类型是父类,但实际执行它的方法时,依然表现出子类对象的行 为方式。
但把一个父类对象赋给子类引用变量时,就需要进行强制 类型转换,而且还可能在运行时产
生ClassCastException异常,使 用instanceof运算符可以让强制类型转换更安全。
instanceof和类型转换运算符一样,都是Java提供的运算符,与+、-等算术运算符的用法大致相
似,下面具体介绍该运算符的用法。

 

 

instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以
是接口,可以把接口理解成一种特 殊的类),它用于判断前面的对象是否是后面的类,或者其子
类、实 现类的实例。如果是,则返回true,否则返回false。 在使用instanceof运算符时需要注
意:instanceof运算符前面操 作数的编译时类型要么与后面的类相同,要么与后面的类具有父子
关系,否则会引起编译错误。下面程序示范了instanceof运算符的 用法。

 

上面程序通过Object hello="Hello";代码定义了一个hello变量,这个变量的编译时类型是Object
类,但实际类型是String。因为 Object类是所有类、接口的父类,因此可以执行hello instanceof
String和hello instanceof Math等。
但如果使用var a="Hello";代码定义的变量a,就不能执行a instanceof Math,因为编译器会推断出a
的编译类型是String, String类型既不是Math类型,也不是Math类型的父类,所以这行代码 编译就
会出错
instanceof运算符的作用是:在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实
例,是否可以成功转换,从而保证 代码更加健壮。 instanceof和(type)是Java提供的两个相关的运
算符,通常先用 instanceof判断一个对象是否可以强制类型转换,然后再使用(type) 运算符进行强
制类型转换,从而保证程序不会出现错误
Java多态指的是同一个方法名可以根据不同的对象调用出不同的行为。具体来说,多态是一种面向对象编程的特性,实现多态的方式主要有两种:方法重载和方法覆盖。方法重载指的是在一个类中定义多个同名方法,但这些方法有不同的参数列表,编译器会根据参数列表的不同选择合适的方法进行调用。方法覆盖指的是子类重写父类的方法,使得在使用父类对象调用该方法时,实际调用的是子类中的方法。 多态的好处在于,它可以提高代码的灵活性和可扩展性。通过多态,我们可以为不同的对象提供不同的行为,从而使得程序更加具有扩展性。此外,多态还可以让程序的调用更加简洁、清晰,提高了代码的可读性和可维护性。 下面是一个简单的Java多态的例子: ```Java class Animal { public void makeSound() { System.out.println("动物发出声音"); } } class Cat extends Animal { public void makeSound() { System.out.println("猫发出“喵喵”的声音"); } } class Dog extends Animal { public void makeSound() { System.out.println("狗发出“汪汪”的声音"); } } public class PolymorphismExample { public static void main(String[] args) { Animal animal1 = new Animal(); Animal animal2 = new Cat(); Animal animal3 = new Dog(); animal1.makeSound(); // 动物发出声音 animal2.makeSound(); // 猫发出“喵喵”的声音 animal3.makeSound(); // 狗发出“汪汪”的声音 } } ``` 在上面的例子中,Animal是一个父类,Cat和Dog是Animal的子类。Animal类中定义了一个makeSound()方法,Cat和Dog类分别重写了这个方法。在main()方法中,我们创建了三个Animal类型的对象,并分别调用它们的makeSound()方法。由于animal2和animal3都是Animal类型的对象,但实际上它们分别是Cat和Dog类型的对象,因此在调用它们的makeSound()方法时,实际上是调用了它们各自的实现,也就是Cat类和Dog类中重写的makeSound()方法。这就是Java多态的表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值