java的多态性

java的多态性


文章内容选自尚硅谷

java多态性的使用方法

java的多态性的用法一般是父类的引用指向子类的对象,即在创建对象的时候,假如声明了变量p为A类型的变量,但是在new对象的时候却new的是A类型子类的对象。

  • 用法为 子类的对象赋值给父类的引用,即 A类型 变量 = new A类型的子类()
  • 多态一般用于子类重写父类方法的情况,当父类.方法(重写的方法)时候,调用的其实是子类中重写的方法,但是当我们按ctrl+点击来查找方法位置的时候,找到的是父类中定义的方法。由此可见,编译和调用其实是分开的。
  • 使用多态性的时候,引用的方法必须是父类中定义过的方法。

代码如下
先创建一个Person的父类

package com.atguigu.java4;

public class Person {
	String name;
	int age;
	
	public void eat(){
		System.out.println("人吃饭");
	}
	public void walk(){
		System.out.println("人走路");
	}
}

再创建两个子类,分别为Man类和Woman类

package com.atguigu.java4;

public class Man extends Person {
	boolean isSmoking;
	
	public void earnMoney(){
		System.out.println("男人挣钱");
		
	}
	public void eat(){
		System.out.println("男人吃饭");
	}
	public void walk(){
		System.out.println("男人走路");
	}
}
package com.atguigu.java4;

public class Woman extends Person {
	boolean isBeauty;
	
	public void eat(){
		System.out.println("女人吃饭");
		
	}
	public void walk(){
		System.out.println("女人走路");
	}
	public void goShopping(){
		System.out.println("女人爱逛街");
	}
}

Man类和Woman类都重写了Person类的walk和eat方法。

最后进行测试

package com.atguigu.java4;

public class PersonTest {
	public static void main(String[] args) {
		Person p1 = new Person();
		Person p2 = new Man();
		p2.eat();
	}
}

得到的运行结果为

男人吃饭

经过以上的代码验证,采用多态,new出来的对象必须是左边声明类的子类,而且在调用方法的时候,调用方法的是一般经过子类重写后的方法,而且实际上也运行的是子类重写后的方法。

在用多态调用方法的时候,调用的方法必须是父类中声明过的方法
多态性在调用方法的时候分为三种情况

  1. 调用的方法是子类中特有的方法,即调用的方法没有对父类的方法进行重写,此时编译器会报错。
  2. 调用的方法是子类中重写后的方法,虽然用ctrl+点击方法会定位到父类中声明的方法,但实际上运行的是子类中重写过后的方法。
  3. 调用的方法是没有被子类进行重写,这样做不会报错,但是这样做不能体现多态的优越性:如果仅因为要调用父类的方法而采用多态new了一个子类的对象,还不如直接就new一个父类的对象,只有调用的方法是子类重写的方法,采用多态才有意义。

综上,多态在编译期间,要看左边父类声明过该方法没有,在实际运行期间,运行的是子类中重写后的方法,记住“编译看左边,运行看右边”口诀。

多态的使用

  • 采用多态的前提必须要有继承关系
  • 多态调用方法的时候一般调用被子类重写后的方法

创建一个AnimalTest类来测试代码

package com.atguigu.java4;

public class AnimalTest {
	public static void main(String[] args) {
		AnimalTest test = new AnimalTest();
		test.fun(new Dog());
		test.fun(new Cat());
	}
	
	public void fun(Animal animal){
		animal.eat();
		animal.shout();
	}
	
//	public void fun(Cat cat){
//		cat.eat();
//		cat.shout();
//	}
//	
//	public void fun(Dog dog){
//		dog.eat();
//		dog.shout();
//	}
}

class Animal{
	public void eat(){
		System.out.println("吃东西");
	}
	public void shout(){
		System.out.println("动物叫");
	}
}

class Dog extends Animal{
	public void shout(){
		System.out.println("wangwangwang");
	}
	
	public void eat(){
		System.out.println("eat bone");
	}
}

class Cat extends Animal{
	public void eat(){
		System.out.println("eat fish");
	}
	public void shout(){
		System.out.println("miaomiaomiao");
	}
}

运行结果为

eat bone
wangwangwang
eat fish
miaomiaomiao

分析代码,采用了匿名对象的方式来把cat和dog对象传递给animal对象

test.fun(new Dog());
test.fun(new Cat());

这两句代码实际上相当于

Animal animal = new Dog();
Animal animal = new Cat();

如果不允许采用多态性的话,就必须在代码中再重载两个fun方法

//	public void fun(Cat cat){
//		cat.eat();
//		cat.shout();
//	}
//	
//	public void fun(Dog dog){
//		dog.eat();
//		dog.shout();
//	}

要是不允许多态,就必须重载两个fun方法,用于传递不同类型的形参
因此采用多态,能够有效的避免代码的冗余。

对象的多态性不适用于属性

在Person类和Man类中分别假如属性id并进行初始化

package com.atguigu.java4;

public class Person {
	String name;
	int age;
	int id = 1001;
	public void eat(){
		System.out.println("人吃饭");
	}
	public void walk(){
		System.out.println("人走路");
	}
}
package com.atguigu.java4;

public class Man extends Person {
	boolean isSmoking;
	int id = 1002;
	public void earnMoney(){
		System.out.println("男人挣钱");
		
	}
	public void eat(){
		System.out.println("男人吃饭");
	}
	public void walk(){
		System.out.println("男人走路");
	}
}
package com.atguigu.java4;

public class PersonTest {
	public static void main(String[] args) {
		Person p1 = new Person();
		Person p2 = new Man();
		p2.eat();
		System.out.println(p2.id);
	}
}

运行结果为

男人吃饭
1001

可见,多态性的使用仅仅针对方法,不针对属性,属性的编译和运行都看左边的父类。
ps:p2对象中的堆空间中,其实有两个id属性,一个id属性是继承自父类,并且已经默认初始化为1001,另一个id属性是Man类自身属性,默认初始化为1002
java的多态性

上一篇:方法的重载与方法的重写


下一篇:英语入门学习笔记(一)