1.多态的定义
通俗来说,当同一种行为或者事情发生在不同的对象上,这些行为或者事情最终得到的结果不同。
注意:多态要发生在继承的基础上。
例如:彩色打印机和黑白打印机。
彩色打印机和黑白打印机是不同的对象,但打印(行为)这件事分别发生在它们身上的时候,彩色打印机打印的是彩色的,而黑白打印机最终打印的结果却是黑白色的。
对应到Java中就是相同的方法对应到不同的对象中有不同的结果。
2.多态的使用
2.1 向上转型
向上转型发生在继承的基础上,所谓向上转型,就是由子类类型向父类类型转换。向上转型的方式由3中,分别为:直接赋值、方法的传参和方法的返回值形式。
1.直接传参
class Animal{}
class Dog extends Animal{}
public class Test {public static void main(String[] args) {//直接赋值,发生向上转型Animal animal=new Dog();}
}
2. 方法的传参
class Animal{}
class Dog extends Animal{}
public class Test {public static void func(Animal animal){}public static void main(String[] args) {Dog dog=new Dog();//方法的传参实现向上转型func(dog);}
}
3.方法的返回值
class Animal{}
class Dog extends Animal{}
public class Test {public static Animal func(){Dog dog=new Dog();return dog;}public static void main(String[] args) {Animal animal=func(); }
}
4 向上转型的缺点
当我们进行了向上转型,我们就不能通过父类的引用(转型之后的引用)去访问子类特有的属性或者方法。
class Dog extends Animal{public Dog(String name,int age){super(name, age);}public void bark(){System.out.println(this.name+"在汪汪叫");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺财",18);animal.bark();}
}
运行以上代码会报错
2.2 动态绑定
动态绑定是理解多态的基础。
1.方法的重写
当子类和父类中有一个方法名字一样,参数列表一样和返回值类型一样,但是方法内不得具体实现不一样,则子类对应的方法构成了方法的重写。
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //编译器中方法重写的默认注释public void eat() {System.out.println(this.name+"在吃狗粮");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃饭");}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺财",18);}
}
如上图,红框框里面就是构成重写的部分。
2.方法重写的注意事项
1.重写的方法不能是一个静态的方法(被static修饰的方法)。
2.被final修饰的方法无法被重写
3.如果子类重写父类的方法时,子类重写方法时的访问权限要大于等于父类方法的权限。
访问权限大小比较 |
public>protected>default>private |
如图,因为父类要被重写的方法得访问权限为public,而子类中重写的方法的访问权限为private,所以运行代码时,编译器会报错。
4.父类中被private修饰的方法无法被重写
5.重写的方法的返回值类型可以不相同,但是返回值类型必须构成父子类的关系。
3. 方法的重写和重载的区别
重载 | 重写 |
参数列表中的数据类型,顺序和个priv数可以不一样 | 参数列表中的数据类型,顺序和个数必须一样 |
返回值的类型不一样 | 返回值类型必须一样 |
方法名必须一样 | 方法名必须一样 |
4.动态绑定
当运行代码时,我们通过父类的引用去调用在子类和父类中重写的方法,结果实际调用了子类的方法,这种情况就被称为动态绑定。
代码演示
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //编译器中方法重写的默认注释public void eat() {System.out.println(this.name+"在吃狗粮");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃饭");}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺财",18);animal.eat();}
}
运行代码
通过上面代码,我们发现,当我们完成了向上转型之后,我们通过父类的引用去调用重写的方法时,程序在编译时,调用的确实是父类的eat( )方法。但是由于动态绑定,最终我们看到的是Dog类中的eat( )方法。
2.3 向下转型
向下转型也是发生在继承的继承的基础上,向下转型就是父类向子类转换。
1.向下转型的优点
通过向下转型,我们就可以访问子类中特有的属性和方法。
代码演示
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //编译器中方法重写的默认注释public void eat() {System.out.println(this.name+"在吃狗粮");}public void run(){System.out.println(this.name+"会跑");}
}
class Bird extends Animal{public Bird(String name, int age) {super(name, age);}public void eat(){System.out.println(this.name+"在吃鸟粮");}public void fly(){System.out.println(this.name+"会飞");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃饭");}
}
public class Test {public static void main(String[] args) {Animal animal=new Dog("旺财",18);Dog dog=(Dog)animal;//要强转类型dog.run();//Dog类中特有的方法System.out.println("=======");Animal animal2=new Bird("小鸟",12);Bird bird=(Bird) animal2;//要强转类型bird.fly();//Bird类中特有的方法}
}
运行代码
2.向下转型的缺点
并不是所有的向下转型都是成功的。
3.多态的使用
了解了向上转型和多态之后,我们接着来在Java中来体验多态。
代码演示
class Dog extends Animal{public Dog(String name,int age){super(name, age);}@Override //编译器中方法重写的默认注释public void eat() {System.out.println(this.name+"在吃狗粮");}
}
class Bird extends Animal{public Bird(String name, int age) {super(name, age);}public void eat(){System.out.println(this.name+"在吃鸟粮");}
}
class Animal{public String name;public int age;public Animal(String name,int age){this.name=name;this.age=age;}public void eat(){System.out.println(this.name+"在吃饭");}
}
public class Test {public static void func(Animal animal){animal.eat();}public static void main(String[] args) {Dog dog=new Dog("旺财",18);func(dog);System.out.println("=======");Bird bird=new Bird("小鸟",12);func(bird);}
}
我们都是通过animal这个引用去调用父类中的eat( )方法,但是由于eat( )对应的对象不同,就调用了各对应子类中的eat( ) 方法,最终导致了结果的不同。这就是多态在Java语言中的体现。