JAVA——多态

本文参照教科书《Java语言程序设计与数据结构(第11版)》以及网上资料进行编写。
参考网址:https://www.runoob.com/java/java-polymorphism.html
https://www.bilibili.com/video/BV134411Q7iD?p=42

JAVA——多态

本文关键词:JAVA、多态

一、多态的简介

1.JAVA的多态

多态(polymorphism)顾名思义:多态就是多种形式、多种状态,在面向对象语言中,接口的多种不同的实现方式即为多态,它是面向对象的程序设计语言最核心的特征。多态是多种状态的现象,不是代表具体的一句代码,例如:金鱼可以说是一种海洋动物,也可以说是一条鱼等等。下面让我们一起走进Java多态的世界。

  • 编译时多态
    • 编译期间决定目标方法
    • 通过overloading重载实现
    • 方法名相同,参数不同
      eg:编译时,根据参数不同执行不同的程序
  • 运行时多态
    • 运行期间决定目标方法
    • 同名同参
    • overriding和继承实现
    • JVM决定目标方法

2.多态三要素

  • 继承或者实现的关系
//创建Dog类,继承Animal类
public class Dog extends Animal{
//代码
}
  • 方法重写
//方法重写,具体到子类
@Override
public void run() {
   System.out.println("Dog runs fast!");
}
  • 父类引用指向子类对象
//父类引用指向子类对象
Animal dog = new Dog(); //体现多态

3.多态的成员访问

  • 成员变量:编译时看父类、运行时看父类
    • 直接通过对象名称访问成员变量:等号左边优先用
    • 间接通过成员方法访问
  • 成员方法:编译时看父类、运行时看子类

4.多态的优点

优点:

  • 可以作为方法提高代码的拓展性和维护性
  • 降低类之间的耦合性,使代码的关联变少
  • 接口性
  • 灵活性
  • 可扩充性
  • 简化性

弊端:

  • 无法访问子类特有的成员(可以被解决)

二、JAVA多态实例

代码中来体现多态性:父类引用指向子类对象。

  • 格式:
  • 父类名称 对象名 =new 子类名称();
  • 接口名称 对象名 =new 实现类名称();

实例:
首先创建一个polymorphism包,里面建立一个Animal类,定义方法run和变量size。

package polymorphism;

public class Animal {
	int size= 10;
	//定义方法run
	public void run() {
		System.out.println("run run run!");
	}
}

接着我们来创建一个Dog子类,继承Animal类

package polymorphism;

//创建Dog类,继承Animal类
public class Dog extends Animal{
	
	//成员变量访问
	int size =5;
	
	//方法重写,具体到子类
	@Override
	public void run() {
		System.out.println("Dog runs fast!");
	}
}

在包内创建一个text类,来进行JAVA实例演示

  • 成员访问:
package polymorphism;

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//父类引用指向子类对象
		Animal dog = new Dog(); //体现多态
		
		//成员变量访问:编译看父类,运行看父类
		System.out.println(dog.size);
		
		//成员方法访问:编译看父类(父类有则正常编译),运行看子类
		dog.run();
	}
}

运行结果如下
10
Dog runs fast!
可以看出,进行成员变量访问时,编译和运行都要取决于父类,而进行成员方法访问时,运行要取决于子类,但是编译还是要看父类中有无此方法定义。

  • JAVA多态优点体现
  • 降低类之间的耦合性,提高代码扩展性

我们继续创建一个新的子类Cat,同样进行方法重写。

package polymorphism;

public class Cat extends Animal{
   @Override
   public void run() {
   	System.out.println("Cat runs slowly!");
   }
}

当我们想访问子类的成员方法时,创建一个method方法来继续进行。
方法一:

package polymorphism;

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Dog dog=new Dog();
		method(dog);
		
		Cat cat=new Cat();
		method(cat);
	
	}

	public static void method(Dog dog) {
		dog.run();
	}
	public static void method(Cat cat) {
		cat.run();
	}
}

运行结果
Dog runs fast!
Cat runs slowly!
运用多态时:

package polymorphism;

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Dog dog=new Dog();
		method(dog);
		
		Cat cat=new Cat();
		method(cat);
	
	}
	//运用多态——提高代码的扩展性
	public static void method(Animal animal) {
		animal.run();
	}
}

运行结果
Dog runs fast!
Cat runs slowly!

我们可以看到两个方法实际上是一样的效果,当子类较多时,多态优势便更加显著的体现出来。

三、多态的实现方式

1.重写或重载

  • 重载意味着使用同样的名字但是不同的签名来定义多个方法。重写意味着在子类中提供一个对方法的新的实现。
  • 重写
//方法重写
public class Test1 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		A a=new A();
		a.p(10);
		a.p(10.0);
	}
}
class B{
	public void p(double i) {
		System.out.println(i*2);
	}
}

class A extends B{
	//This method overrides the method in B
	public void p(double i) {
		System.out.println(i);
	}
}

输出结果
10.0
10.0

  • 重载
//方法重载
public class Test2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		C c=new C();
		c.p(10);
		c.p(10.0);
	}
}
class D{
	public void p(double i) {
		System.out.println(i*2);
	}
}

class C extends D{
	//This method overloads the method in B
	public void p(int i) {
		System.out.println(i);
	}
}

输出结果
10
20.0

  • 注意:
  • 方法重写发生在具有继承关系的不同类
  • 方法重载可以发生在同一个类中,也可以发生在具有继承关系的不同类中。
  • 参数列表与被重写方法的参数列表必须完全相同
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类
  • 访问权限不能比父类中被重写的方法的访问权限更低。比如父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
    .> - 父类的成员方法只能被它的子类重写。
  • 声明为final的方法不能被重写
  • 声明为static的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类的所有方法,除了声明为private和final的方法
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为publicprotected非final方法。
  • 重写方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能重写
  • 如果不能继承一个类,则不能重写该类的方法

2.接口

生活中的接口最具代表性的是插座
Java中的接口类似于生活中的接口,即一些方法特征的集合。

3.抽象类和抽象方法

继承抽象方法的子类必须重写方法。否则,该子类也必须声明为抽象类。

四、多态的转型

1.向上转型

  • 格式:父类名称 对象名 = new 子类名称();
  • 含义: 右侧创建一个子类对象,把它当做父类来看待使用
  • 注意:向上转型一定是安全的,从小范围转向了大范围,例如:从一条鱼向上转换为一个海洋动物。
  • 当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作,通常使用向上转型。
  • 类似于:自动类型转换:double x=2;
//向上转型
Animal animal=new Dog();

2.向下转型

  • 格式:子类名称 对象名 = (子类名称)父类对象;
  • 含义:将父类对象还原成为本来的子类对象
  • 注意事项:
    • 必须保证对象创建时就是小范围对象,被认为是大范围对象,才能向下转型成为原本的小范围对象;例如,创建一个海洋动物是一条金鱼,那么这条金鱼就可以还原为金鱼。
    • 如果对象创建时不是本来的小范围对象,要强制向下转型为原来的小范围对象,则会报错ClassCastException
  • 当要使用子类特有功能时,就需要使用向下转型。
  • 类似于:强制类型转换:int a=(int)10.5;(不可以转换)
//向下转型
Dog dog= (Dog) animal;

本文就到此结束啦,谢谢观看~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值