java-多态

发布于:2025-05-10 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、多态的来历


我们先来了解一个业务场景:请设计一个系统,描述主人喂养宠物的场景,首先在这个场景当中应该有”宠物对象“,“宠物对象”应该有一个吃的行为,另外还需要一个“主人对象”,主人应该有一个喂的行为,请看代码:

//小猫

public class Cat{
    String name;
    public Cat(String name) {
    	this.name=name;
    }
    public  void eat() {
    	System.out.println(this.name+"正在吃鱼");
    }
    
}

//主人

public class Person {
      String name;
      public Person(String name) {
    	  this.name=name;
      }
      public void feed(Cat cat) {
    	  System.out.println(this.name+"拿出来了好多小鱼");
    	  cat.eat();
    	  System.out.println(cat.name+"十秒钟吃了10条小鱼");
      }
}

//测试类

public class Test1 {
     public static void main(String[] args) {
		Cat cat = new Cat("小花");
		
		Person person1= new Person("小明");
		person1.feed(cat);
		
	}
     
}

测试结果:

现在我们已经创建了一个喂养宠物的场景,但是我们想一想,假如家里又来了几只宠物你会怎么办

与小猫类的代码一样,我们可以创建小狗类,小猪类,小牛类........


public class Pig {
    String name;
    ...
    }
    //吃的行为
    public void eat(){
        ...
    }
}


public class Dog {
    String name;
    ...
    }
    //吃的行为
    public void eat(){
        ...
    }
}

public class Cow {
    String name;
    ...
    }
    //吃的行为
    public void eat(){
        ...
    }
}

 如果主人想要喂养它们,我们还需要主人的源代码,这是让程序员无法容忍的,如果这个人养了上千种动物,就意味着你需要增改上千次

//主人

 

public class Person {
      String name;
      public Person(String name) {
    	  this.name=name;
      }
      public void feed(Cat cat) {
    	  System.out.println(this.name+"拿出来了好多小鱼");
    	  cat.eat();
    	  System.out.println(cat.name+"十秒钟吃了10条小鱼");
      }
      
      public void feed(Dog dog) {
    	  System.out.println(this.name+"拿出来了好多骨头");
    	  dog.eat();
    	  System.out.println(dog.name+"十秒钟吃了10根骨头");
      }
      
      //feed pig.....
      //feed cow..........这个博主有点小懒
}

 //测试类

public class Test1 {
     public static void main(String[] args) {
		Cat cat = new Cat("小花");
		Dog dog = new Dog("旺财"); 
		Person person1= new Person("小明");
		person1.feed(cat);
		
		person1.feed(dog);
		
		
		//person1.feed(pig)   person1.feed(Cow);
		System.out.println("   ");
		System.out.print("博主省略了猪和牛,就知道多繁琐了");
	}
     
}

测试结果:
 

  那么如何解决这个问题呢????????你猜对了-------就是多态!

我们都知道小猫小狗...都属于宠物,也就是说宠物类是单个宠物的父类

请看代码:
 

public class Pet {
    String name;
    //吃的行为
    public void eat(){
    }
}

//小猫

public class Cat extends Pet{
    public Cat(String name) {
    	this.name=name;
    }
    public  void eat() {
    	System.out.println(this.name+"正在吃鱼");
    }
    
}

//小狗

public class Dog  extends Pet{

	public Dog(String name) {
		this.name=name;
	}
	public void eat() {
		System.out.println(this.name+"正在啃骨头");
	}
}


//主人

public class Person {
      String name;
      public Person(String name) {
    	  this.name=name;
      }
      public void feed(Pet pet) {
    	 System.out.println("主人正在喂食");
    	 pet.eat();
    	 System.out.println("主人喂食完毕");
      }
      
}

//测试类
 

public class Person {
      String name;
      public Person(String name) {
    	  this.name=name;
      }
      public void feed(Pet pet) {
    	 System.out.println("主人正在喂食");
    	 pet.eat();
    	 System.out.println("主人喂食完毕");
      }
      
}

测试结果 


 

与上面的结果是等价的,在主人类中我们节省了很多力气

 

总结,上面的程序代码中,主人(Person类)中的feed(Pet pet)的参数类型定义为更加抽象的Pet类型,而不是具体的Cat宠物,或者Dog宠物。那假如说主人又养了一个小牛,我们要增加一个”小牛类“,然后Pig 继承宠物类Pet,并重写eat()方法,然后修改一下测试类就行了,整个过程我们不需要修改Person类,只是额外增加了一个新的类

public class Pig extends Pet{
       public Pig(String name) {
    	   this.name=name;
       }
       public void eat() {
    	   System.out.println(this.name+"小猪正在进食");
       }
}

//测试类

public class Test1 {
     public static void main(String[] args) {
		Cat cat = new Cat("小花");
		Dog dog = new Dog("旺财"); 
		Pig pig = new Pig("猪哼哼");
		Person person1= new Person("小明");
		
		person1.feed(cat);
		person1.feed(dog);
	    person1.feed(pig);
		
		
	}
     
}

 测试结果:

从上面例子表可以感受到多态的使用大大节省了内存与算力!

二、那究竟什么是多态?

多态是同一个行为具有多个不同表现形式和形态的能力
 

三、多态实现的必要条件

1.子类必须继承父类

2.必须有重写

3.父类引用指向子类对象------>向上转型

我在下面将采用内存图的形式向你展示,多态的过程,方便你理解

我们首先要知道,多态语句的构成

Pet cat=new Cat();

//Pet:类名

//cat:变量

//new:关键字

//Cat():构造器

Pet cat=new Cat();

会在堆区生成一个Pet对象 cat存储Pet对象的地址,而不是存储Cat对象的地址

重点:父类方法被重写之后,会生成一个指针指向子类重写的方法

//小猫类

public class Cat extends Pet{
    public Cat(String name) {
    	this.name=name;
    }
    public  void eat() {
    	System.out.println(this.name+"正在吃鱼");
    }
    public void jump() {
    	System.out.println("小猫跳的很高");
    }
    
}

//父类

public class Pet {
      String name;
      //吃的行为
      public void eat() {
    	  
      }
}

//主人

public class Person {
      String name;
      public Person(String name) {
    	  this.name=name;
      }
      public void feed(Pet pet) {
    	 System.out.println("主人正在喂食");
    	 pet.eat();
    	 System.out.println("主人喂食完毕");
      }
      
}

//测试类

public class Test1 {
     public static void main(String[] args) {
		Pet cat = new Cat("小花");
		cat.eat();	
	}
     
}

结果:

 

接下来我们来画一下内存图

看到 cat变量指向的是Pet类,Cat对eat()方法进行了重写,指针指向,所以才能调取到Cat类中的eat()方法

那就有人会问了 能不能调用jump()方法呢

试一试!
 

答案是不行,因为我们观察内存图,jump()方法并未被调取,除非jump()方法是对父类方法的重写! 

四、测试练习!

//父类

public class A {
      public String show(D obj) {
    	  return "A and D";
      }
      public String show(A obj) {
    	  return "A and A";
      }
}

//各子类

public class B extends A{
	public String show(Object obj) {
		return "B and B";
	}
	public String show(A obj) {
		return "B and A";
	}

}
public class D extends B{

}

public class C extends B{

}

//测试类

public class Test {
	public static void main(String[] args) {
	     A a1=new A();
	     A a2 = new B();
	     B b = new B();
	     C c= new C();
	     D d= new D();
	     
	     System.out.println(a1.show(b));
	     System.out.println(a1.show(c));
	     System.out.println(a1.show(d));
	     
	     
	     System.out.println(a2.show(b));
	     System.out.println(a2.show(c));
	     System.out.println(a2.show(d));
	     System.out.println(b.show(b));
	     System.out.println(b.show(c));
	     System.out.println(b.show(d));

	}    
}

 请你说出测试结果!!!!!最好用画内存的方法,去解决问题,更加清晰!!!
测试结果:

 

 


网站公告

今日签到

点亮在社区的每一天
去签到