Skip to content

多态

多态

一个事物,有多种表现形态。

例如: cat 是一只猫 是一个宠物 是一个动物。

1.多态在实际使用中,需要建立继承关系,建立接口和实现类的关系。

java
public class Test {
	public static void main(String[] args) {
		Cat cat = new Cat();
		Dog dog = new Dog();
		Master master = new Master();
		master.setPet(cat);
		master.feed(); 
		master.setPet(dog);
		master.feed(); 
	}
}
java
public class Master {
	private Pet pet;

	public Pet getPet() {
		return pet;
	}

	public void setPet(Pet pet) {
		this.pet = pet;
	}

	public void feed() {
		this.pet.feed();
	}
}
java
public class Pet {
	public void feed() {
		System.out.println("给宠物喂食");
	}
}
java
public class Dog extends Pet{
	@Override
	public void feed() {
		System.out.println("给狗喂了两根骨头");
	}
}
java
public class Cat extends Pet{
	@Override
	public void feed() {
		System.out.println("给猫喂了两条鱼");
	}
}

当一个程序因为需求的变化而需要频繁修改代码的时候,则表示改程序的可扩展性和可维护性很差,使用多态可以对其优化。

继承和方法重写是实现多态的基础 形参(形式参数) 实参(实际参数) 方法定义时参数列表中的数据就是形参 在调用方法时传入的数据就是实参

2.多态的使用:

1)定义方法形参(形式参数)的数据类型为父类,实际调用方法时传入子类实参。

2)定义方法返回值类型为父类,外部调用该方法时使用子类对象来接收返回值。

java
public class Test {
	public static void main(String[] args) {
		Master master = new Master();
		Dog dog2 = (Dog) master.buy(1000);
		dog2.show();
		Cat cat2 = (Cat) master.buy(800);
		cat2.show();
	}
}
java
public class Master {
	private Pet pet;
	
	public Pet getPet() {
		return pet;
	}

	public void setPet(Pet pet) {
		this.pet = pet;
	}
	
	/**
	 * 1000买狗,800买猫
	 * @return
	 */
	public Pet buy(int money) {
		if(money == 1000) {
			Dog dog = new Dog();
			return dog;
		}else if(money == 800){
			Cat cat = new Cat();
			return cat;
		}
		return null;
	}
}
java
public abstract class Pet {
	public abstract void show();
}
java
public class Dog extends Pet{
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("一只狗");
	}
}
java
public class Cat extends Pet{
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("一只猫");
	}
}

3.由多态衍生出另外一个概念:抽象

在多态的场景下,父类方法会被子类方法所重写,所以父类的方法体是没有任何意义的,即不需要定义父类的方法体,没有方法体(方法实现)的方法叫做抽象方法

一旦某个类中定义了一个抽象方法,则必须将该类定义为抽象类。抽象类不能被实例化。

抽象类不能在外部通过调用构造函数的方式实例化。 我们在实例化其子类的时候,会自动实例化抽象类的对象。

4.抽象方法和抽象类

使用abstract修饰的方法叫做抽象方法,没有方法体。 使用abstract修饰的类叫做抽象类,抽象类中可以包含非抽象方法,抽象类中全部是非抽象方法也是可以的,非抽象方法中一定不能由抽象方法。

只要一个类中包含抽象方法,则该类一定是抽象类。

一个非抽象类继承了一个抽象类,若父类中存在抽象方法,则子类一定要对其进行重写。

java
public class Test {
	public static void main(String[] args) {
		Cat cat = new Cat();
		Dog dog = new Dog();
		Master master = new Master();
		master.setPet(cat);
		master.feed(); 
		master.setPet(dog);
		master.feed(); 
	}
}
java
public class Master {
	private Pet pet;

	public Pet getPet() {
		return pet;
	}

	public void setPet(Pet pet) {
		this.pet = pet;
	}

	public void feed() {
		this.pet.feed();
	}
}
java
public abstract class Pet {
	public abstract void feed();
}
java
public class Dog extends Pet{
	@Override
	public void feed() {
		System.out.println("给狗喂了两根骨头");
	}
}
java
public class Cat extends Pet{
	@Override
	public void feed() {
		System.out.println("给猫喂了两条鱼");
	}
}

子类为抽象类,实现或不实现父类的抽象方法均可。子类为非抽象类,必须实现父类的抽象方法。

5.案例:

需求如下: Pet饿了,Master需要为宠物喂食,使用多态/抽象实现该过程。 不同的Pet吃的东西不一样 不同的Pet吃完东西之后恢复的体力值不同 当体力值到达100时,停止喂食 每次喂食dog体力值+5,penguin体力值+3

java
public class Test {
	public static void main(String[] args) {
		Dog dog = new Dog();
		Penguin penguin = new Penguin();
		Master master = new Master();
		master.feed(penguin);
	}
}
java
public class Master {
	// 多态
	public void feed(Animal animal) {
		do {
			animal.feed();
		}while(animal.getHealth()<100);
	}
}
java
public abstract class Animal {
	private int health;

	public int getHealth() {
		return health;
	}

	public void setHealth(int health) {
		this.health = health;
	}
	
	public abstract void feed();
}
java
public class Dog extends Animal{

	@Override
	public void feed() {
		// TODO Auto-generated method stub
		System.out.println("给狗狗喂了一根骨头");
		//this super一样,都是指向父类
		this.setHealth(super.getHealth()+5);
		System.out.println("狗狗当前的体力值:"+this.getHealth());
	}

}
```java
public class Penguin extends Animal{

@Override
public void feed() {
	// TODO Auto-generated method stub
	System.out.println("给企鹅喂了3条小鱼");
	setHealth(getHealth()+3);
	System.out.println("企鹅当前的体力值:"+this.getHealth());
}

} ```

6.对象之间的数据类型转换:

1.向上转型:父类的引用指向子类对象,自动完成数据类型转换,将子类对象转为父类。 2.向下转型:子类的引用指向父类对象,强制完成数据类型转换,将父类对象转为子类。

java
public class Test2 {
	public static void main(String[] args) {
		//向上转型,自动完成
		Cat cat = new Cat();
		Pet pet = cat;
		
		//向下转型,强制完成
		Pet pet = new Pet();
		Cat cat = (Cat)pet;
		
		int num = 1;
		float num2 = 1.1f;

		num = (int) num2;
		num2 = num;
		
	}
}

抽象类

在一个类中,如果包含抽象方法,则该类为抽象类。

特点:

1.抽象类不能被实例化,不能在外部通过new创建其实例对象。 一个普通类继承了该抽象类,实例化子类的时候,可以通过super()来调用抽象类的构造函数。 2.抽象类中可以没有抽象方法,但是包含了抽象方法的类一定是抽象类。 3.一个普通类继续了抽象类,则该子类必须实现抽象类中的所有抽象方法。 4.如果继承了抽象类的子类也是一个抽象类,则不用实现父类的抽象方法。 5.没有抽象的构造方法,也没有抽象的静态static方法。 6.抽象类中可以包含非抽象的构造方法,创建子类实例对象时可以调用。

接口

面向接口编程是常见的一种开发方式。

面向接口编程就是将程序的业务逻辑提取出来,以接口的形式去对接不同的业务模块,接口只串联不实现,真正的业务逻辑交给接口的实现类来完成,当用户需求发生变更时,只需切换不同的实现类即可。

低耦合:降低模块之间的链接的紧密程度,模块之间是一种非常松散的状态,利于维护和扩展。 高内聚:将相关的业务逻辑尽量集中到一个模块中。

面向接口编程的优点: 1.能够最大限度的解耦,降低程序的耦合性。 2.使用程序易于扩展。 3.有利于程序的后期维护。

如何定义接口 接口是Java中独立存在的一种结构,类似于类,使用接口,首先需要创建一个接口文件,Java中用class来标示类,用interface来标示接口。

基本语法:

public interface 接口名{ public abstract 返回值 方法名(参数列表); }

接口中不能有普通方法,全部是抽象方法,因为接口中全部都是抽象方法,所以每一个方法的abstract关键字都可以省略。

接口其实就是一个极度抽象的抽象类,抽象类中可以包含非抽象方法,抽象类中也可以没有抽象方法, 接口中不能有任何非抽象方法的存在,接口中的方法必须全部是抽象方法,到达了一种极致,所以可以称为极度抽象的抽象类。

定义接口时的abstract关键字和接口中方法的abstarct关键字都可以省略,一般在开发中,都是省略的状态。

接口中可以定义成员变量,但是有要求如下:

1.不能定义private和protected修饰的成员变量,只能定义public和默认修饰的成员变量。 2.接口中的成员变量在定义时必须被初始化。 3.接口中的成员变量必须是静态static,同时该成员还必须是一个常量,即可以直接通过接口访问,同时值不能被修改。(由于都是static final,故static和final也可以被省略,例如写作public int id = 1;)

抽象类可以被普通类继承,接口只能被接口继承。

如何使用接口

因为接口不能被实例化,它描述的是抽象的信息,抽象的信息一定是没有实例,我们需要实例化的是接口的实现类。

实现类就是对接口的抽象方法进行具体实现的一个类,实现类就是一个普通的Java类

基本语法:

public class 实现类名 implements 接口名{ //实现接口的抽象方法 public 返回值 方法名(参数列表){

}

}

抽象类不能继承接口。 只有接口才能继承接口,但无实际意义。 抽象类可以实现接口,同时不去实现接口的抽象方法。

java
// 接口
public interface MyInterface {
	public int id = 1;
	public void test();
}
java
// 实现类
public class MyImplements implements MyInterface{
	@Override
	public void test() {
		System.out.println("test...");
	}
}
java
public class Test {
	public static void main(String[] args) {
		MyInterface my = new MyImplements();
		my.test();
	}
}

可以将实现类的实例对象赋给接口的引用,是多态的另外一种表现实现。

多态的基础是父子类接口实现类这两种方式。

java
// 接口
public interface MyInterface {
	public int id = 1;
	public void test();
}
java
// 实现类1
public class MyImplements implements MyInterface{
	@Override
	public void test() {
		System.out.println("test111");
	}
}
java
// 实现类2
public class MyImplements2 implements MyInterface{
	@Override
	public void test() {
		System.out.println("test222");
	}
}
java
public class Test {
	public static void main(String[] args) {
		MyInterface my = new MyImplements();
		my.test(); // test111
		MyInterface my2 = new MyImplements2();
		my2.test(); // test222
	}
}

继承只能完成单继承,接口可以多实现,接口实际就是用来描述功能的,但是不实现功能,可以让某个类实现一个接口,就可以理解为该类具备了某个功能,一个类可以同时实现多个接口,从而具备多个功能。

接口可以继承接口,接口不能实现接口。

java
// 接口1
public interface MyInterface1 {
	public void fly();
}
java
// 接口2
public interface MyInterface2 {
	public void run();
}
java
// 实现类实现接口1和接口2
public class MyImplements implements MyInterface1,MyInterface2{

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("实现了fly的功能");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("实现了run的功能");
	}
}
java
public class Test {
	public static void main(String[] args) {
		MyImplements mi = new MyImplements();
		mi.fly();
		mi.run();
	}
}

面向接口编程的实际应用

例1

第一代手机:打电话 发短信 第二代手机:拍照 听音乐 第三代手机:上网 播放视频 分析:将手机的功能定义成三个接口,定义手机的实体类,让实体类实现不同的接口,就表示该手机的功能有了迭代。

java
public interface FirstGeneration {
	public void call();
	public void message();
}
java
public interface SecondGeneration {
	public void photo();
	public void playMusic();
}
java
public interface ThirdGeneration {
	public void playVideo();
	public void Internet();
}
java
public class Mobile implements FirstGeneration,SecondGeneration,ThirdGeneration{
	@Override
	public void call() {
		// TODO Auto-generated method stub
		System.out.println("打电话");
	}

	@Override
	public void message() {
		// TODO Auto-generated method stub
		System.out.println("发短信");
	}

	@Override
	public void photo() {
		// TODO Auto-generated method stub
		System.out.println("拍照");
	}

	@Override
	public void playMusic() {
		// TODO Auto-generated method stub
		System.out.println("听音乐");
	}

	@Override
	public void playVideo() {
		// TODO Auto-generated method stub
		System.out.println("播放视频");
	}

	@Override
	public void Internet() {
		// TODO Auto-generated method stub
		System.out.println("上网");
	}
}
java
public class Pad implements SecondGeneration,ThirdGeneration{
	@Override
	public void playVideo() {
		// TODO Auto-generated method stub
		System.out.println("播放视频");
	}

	@Override
	public void Internet() {
		// TODO Auto-generated method stub
		System.out.println("上网");
	}

	@Override
	public void photo() {
		// TODO Auto-generated method stub
		System.out.println("拍照");
	}

	@Override
	public void playMusic() {
		// TODO Auto-generated method stub
		System.out.println("播放音乐");
	}
	
}
java
public class Test {
	public static void main(String[] args) {
		Mobile mobile = new Mobile();
		mobile.call();
		mobile.message();
		mobile.photo();
		mobile.playMusic();
		mobile.playVideo();
		mobile.Internet();
		Pad pad = new Pad();
		pad.photo();
		pad.playMusic();
		pad.playVideo();
		pad.Internet();
	}
}

例2

组装电脑: 电脑的主要组成包括CPU,硬盘,内存,现在用程序模拟组装一台电脑的过程。 1.定义CPU类,属性:price,speed 2.定义HardDisk类,属性:price,size 3.定义Memory类,属性:price,size 4.定义Computer类,属性:CPU,HardDisk,Memory

1.仅使用类

java
public class CPU {
	private double price;
	private String speed;
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getSpeed() {
		return speed;
	}
	public void setSpeed(String speed) {
		this.speed = speed;
	}
	public CPU(double price, String speed) {
		super();
		this.price = price;
		this.speed = speed;
	}
	public void show() {
		System.out.println("CPU信息【价格:"+this.price+",主频:"+this.speed+"】");
	}
}
java
public class HardDisk {
	private double price;
	private String size;
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getSize() {
		return size;
	}
	public void setSize(String size) {
		this.size = size;
	}
	public HardDisk(double price, String size) {
		super();
		this.price = price;
		this.size = size;
	}
	public void show() {
		System.out.println("硬盘信息【价格:"+this.price+",容量:"+this.size+"】");
	}
}
java
public class Memory {
	private double price;
	private String size;
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getSize() {
		return size;
	}
	public void setSize(String size) {
		this.size = size;
	}
	public Memory(double price, String size) {
		super();
		this.price = price;
		this.size = size;
	}
	public void show() {
		System.out.println("内存信息【价格:"+this.price+",容量:"+this.size+"】");
	}
}
java
public class Computer {
//	private CPU cpu;
	private NewCPU cpu;
	private HardDisk hardDisk;
	private Memory memory;
	
	public NewCPU getCpu() {
		return cpu;
	}
	public void setCpu(NewCPU cpu) {
		this.cpu = cpu;
	}
	//	public CPU getCpu() {
	//		return cpu;
	//	}
	//	public void setCpu(CPU cpu) {
	//		this.cpu = cpu;
	//	}
	public HardDisk getHardDisk() {
		return hardDisk;
	}
	public void setHardDisk(HardDisk hardDisk) {
		this.hardDisk = hardDisk;
	}
	public Memory getMemory() {
		return memory;
	}
	public void setMemory(Memory memory) {
		this.memory = memory;
	}
	public Computer(NewCPU cpu, HardDisk hardDisk, Memory memory) {
		super();
		this.cpu = cpu;
		this.hardDisk = hardDisk;
		this.memory = memory;
	}
	public void show() {
		System.out.println("电脑配置如下:");
		this.cpu.show();
		this.hardDisk.show();
		this.memory.show();
	}
}
java
public class Test {
	public static void main(String[] args) {
		// 组装电脑的过程
		// 创建零件
		// CPU cpu = new CPU(2600,"3.7GHz");
		NewCPU newCPU = new NewCPU(3000, "3.7GHz", "12MB");
		HardDisk hardDisk = new HardDisk(299,"1TB");
		Memory memory = new Memory(699, "8GB");
		//创建电脑,将零件进行组装
		Computer computer = new Computer(newCPU, hardDisk, memory);
		computer.show();
	}
}
java
public class NewCPU {
	private double price;
	private String speed;
	private String thirdCache;
	public NewCPU(double price, String speed, String thirdCache) {
		super();
		this.price = price;
		this.speed = speed;
		this.thirdCache = thirdCache;
	}
	public void show() {
		System.out.println("CPU信息【价格:"+this.price+",主频:"+this.speed+",三级缓存:"+this.thirdCache+"】");
	}
}

2.使用接口
java
public interface CPU {
	public void show();
}
java
public interface HardDisk {
	public void show();
}
java
public interface Memory {
	public void show();
}
java
public class CPUImpl implements CPU{
	private double price;
	private String speed;
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getSpeed() {
		return speed;
	}
	public void setSpeed(String speed) {
		this.speed = speed;
	}
	public CPUImpl(double price, String speed) {
		super();
		this.price = price;
		this.speed = speed;
	}
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("CPU信息【价格:"+this.price+",主频:"+this.speed+"】");
	}

}
java
public class HardDiskImpl implements HardDisk{
	private double price;
	private String size;
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getSize() {
		return size;
	}
	public void setSize(String size) {
		this.size = size;
	}
	public HardDiskImpl(double price, String size) {
		super();
		this.price = price;
		this.size = size;
	}
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("硬盘信息【价格:"+this.price+",容量:"+this.size+"】");
	}

}
java
public class MemoryImpl implements Memory{
	private double price;
	private String size;
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public String getSize() {
		return size;
	}
	public void setSize(String size) {
		this.size = size;
	}
	public MemoryImpl(double price, String size) {
		super();
		this.price = price;
		this.size = size;
	}
	@Override
	public void show() {
		System.out.println("内存信息【价格:"+this.price+",容量:"+this.size+"】");
	}
}
java
public class Computer {
	private CPU cpu;
	private HardDisk hardDisk;
	private Memory memory;

	public CPU getCpu() {
		return cpu;
	}
	
	public void setCpu(CPU cpu) {
		this.cpu = cpu;
	}
	public HardDisk getHardDisk() {
		return hardDisk;
	}
	public void setHardDisk(HardDisk hardDisk) {
		this.hardDisk = hardDisk;
	}
	public Memory getMemory() {
		return memory;
	}
	public void setMemory(Memory memory) {
		this.memory = memory;
	}
	public Computer(CPU cpu, HardDisk hardDisk, Memory memory) {
		super();
		this.cpu = cpu;
		this.hardDisk = hardDisk;
		this.memory = memory;
	}
	public void show() {
		System.out.println("电脑配置如下:");
		this.cpu.show();
		this.hardDisk.show();
		this.memory.show();
	}
}
java
public class Test {
	public static void main(String[] args) {
		//创建零件
		// CPU cpu = new CPUImpl(2600, "3.7GHz");
		
		// 修改cpu仅修改实现类即可
		CPU cpu = new NewCPUImpl(3000, "3.7GHz", "12MB");
		HardDisk hardDisk = new HardDiskImpl(299,"1TB");
		Memory memory = new MemoryImpl(699, "8GB");
		// 创建电脑,组装零件
		Computer computer = new Computer(cpu, hardDisk, memory);
		computer.show();
	}
}
java
public class NewCPUImpl implements CPU{
	private double price;
	private String speed;
	private String thirdCache;
	public NewCPUImpl(double price, String speed, String thirdCache) {
		super();
		this.price = price;
		this.speed = speed;
		this.thirdCache = thirdCache;
	}
	public void show() {
		System.out.println("CPU信息【价格:"+this.price+",主频:"+this.speed+",三级缓存:"+this.thirdCache+"】");
	}
}