3.1实现多态
Java面向对象还有一个重要的特性:多态
1.认识多态
多态一词的通常含义是指能够呈现多种不同的形式或形态。而在程序设计的术语中,它意味着一个特定类型的变量可以引用不同类型的对象,并且能自动地调用引用的对象的方法,也就是根据作用到的不同对象类型,响应不同的操作。方法重写是实现多态的基础。
例:
/**
* @作者:Xem626
* @date: 2022/7/13 9:17
* @TODO
*/
class Pet {
public void toHospital(){
System.out.println("宠物去看病");
}
}
class Dog extends Pet{
public void toHospital(){
System.out.println("狗去看病");
}
}
class Bird extends Pet{
public void toHospital(){
System.out.println("鸟去看病");
}
}
class Test1{
public static void main(String[] args) {
Dog dog=new Dog();
dog.toHospital();
Bird bird=new Bird();
bird.toHospital();
Pet pet;
pet=new Dog();
pet.toHospital();
pet=new Bird();
pet.toHospital();
}
}
分析:
测试1和测试2中两端Test类的代码运行效果完全一样。虽然测试2中定义的是Pet类,但实际执行时都是调用Pet子类的方法。测试2的代码就体现了多态性
多态意味着在一次方法调用中根据包含的对象的实际类型(即实际的子类对象)来决定应该调用哪个方法,而不是由用来存储对象引用的变量的类型决定的。当调用一个方法时,为了实现多态的操作,这个方法既是在父类中声明过的,也必须是在子类中重写过的方法。
以后:Pet这个类后期会定义成抽象类,因为这个类的实例化没有任何意义。toHospital()后期申明为抽象方法
注意:
1.抽象类不能被实例化
2.子类如果不是抽象类,则必须重写抽象类中的全部抽象方法
3.abstract修饰不能和final一起使用
4.abstract修饰的方法没有方法体
5.private不能修饰抽象方法
2.向上转型
子类向父类的转换向上转型
向上转型的语法:
<父类型> <引用变量名> =new <子类型>()
(1)把int类型常量或变量赋值给double类型,可以进行类型自动转换
int i=5;
double di =5;
(2)把double类型的常量或变量的值赋给int类型的变量,必须进行强制类型转换
double d2 =3.14;
int a = (int)d2;
实际上在引用数据类型的子类和父类之间也存在着类型转换问题,如示例中的代码
//当Pet为父类时,Dog为子类,Pet中包含方法toHosptial()
Pet pet =new Dog();//子类到父类的转换
//会调用Dog()类的toHospital()方法,而不是Pet类的toHospital()方法,体现多态
pet.toHospital()
注意:
Pet对象无法调用子类特有的方法
子类转换为父类时的规则:
1.将一个父类的引用指向子类对象称为向上转型,系统自动类型转换
2.此时通过父类引用变量调用方法时,子类覆盖或继承了父类的方法,不是父类的方法
3.此时无法通过父类的引用变量调用子类特有的方法
3.向下转型
当向上转型发生后,将无法调用子类特有的方法,但是如果需要调用子类特有的方法,可以通过把父类转换为子类的实现
将一个指向子类对象的父类引用给一个子类引用,即父类类型转换为子类类型,称为向下转型,此时必须要强制类型转换
向下类型转换的语法:
<子类型> <引用变量名> =(子类类型)<父类类型的引用变量>
例:
/**
* @作者:Xem626
* @date: 2022/7/13 9:17
* @TODO
*/
class Pet {
public void toHospital(){
System.out.println("宠物去看病");
}
}
class Dog extends Pet{
public void toHospital(){
System.out.println("狗去看病");
}
public void catching(){
System.out.println("玩飞盘");
}
}
class Bird extends Pet{
public void toHospital(){
System.out.println("鸟去看病");
}
}
class Test1{
public static void main(String[] args) {
// Dog dog=new Dog();
// dog.toHospital();
// Bird bird=new Bird();
// bird.toHospital();
//
//
//
Pet pet;
pet=new Dog();
pet.toHospital();
// pet=new Bird();
// pet.toHospital();
Dog dog=(Dog) pet;
dog.catching();
}
}
4.instanceof运算符
在向下转型的过程中,如果不是转换为真实的子类类型,会出现异常
Pet pet=new Dog();
pet.toHospital();
Bird bird=(Bird) pet;//代码编写不会出错运行会报错
bird.toHospital();
使用instanceof 时,对象类型必须和instanceof后面的参数所指定的类有继承关系,否则会出现编译错误,
例如:代码“pet instanceof String”。instanceof通常和强转类型转换结合使用
Pet pet=new Bird();
pet.toHospital();
if(pet instanceof Dog){
Dog dog=(Dog) pet;
dog.catching();
}else if(pet instanceof Bird){
Bird bird=new Bird();
bird.fly();
多态的应用
1.使用父类作为方法的形参
使用父类作为方法的参数,是java中实现和使用多态的主要方式
/**
* @作者:Xem626
* @date: 2022/7/13 9:50
* @TODO
*/
public class Host {
public void letCry(Pet pet){
pet.cry();//调用动物cry
}
}
/**
* @作者:Xem626
* @date: 2022/7/13 9:54
* @TODO
*/
public class Test2 {
public static void main(String[] args) {
Host host=new Host();
Pet pet;
pet=new Dog();
host.letCry(pet);
pet=new Bird();
host.letCry(pet);
}
}
本次案例中,主人控制宠物叫的方法中,并没有把宠物子类作为方法的参数,而是使用Pet父类
当调用LetCry()方法时,实际传入的参数是一个子类的宠物,最终调用了这个子类宠物cry方法
这个就是多态的应用:使用父类作为方法的形参
2.使用父类作为方法的返回值
使用父类作为方法的返回,也是java中实现和使用多态的主要方式
public Pet donatePet(String type){
Pet pet=null;
if(type=="dog"){
pet =new Dog();
}else if(type=="bird"){
pet =new Bird();
}else{
System.out.println("没有宠物类型");
}
return pet;
}
public class Test3 {
public static void main(String[] args) {
Host host=new Host();
Pet pet;
pet=host.donatePet("dog");
pet.cry();
System.out.println("-------------");
pet=host.donatePet("bird");
pet.cry();
}
}
本章总结:
1.继承是Java。Java支持单继承,即个类只能有一个直接父类。Object 所有Java的祖先。
2.在子类中可以根据实际需求对从父类继承的方法进行重新编写,称为方法的重写或覆盖。
3.在子类中重写的方法和父类中被重写的方法必须具有相同的方法名、参数列表,返回值类型必须和被重写方 法的返回值类型相同。
4.在实例化子类时,会首先执行其父类的构造方法,然后再执行子类的构造方法
5.通过super关键字可以访问父类的成员。
6.通过多态可以减少类中的代码量,可以提高代码的可扩展性和可维护性。继承是多态的基础,没有继承就没有多态
7.在多态的应用中,可以使用父类作为方法的形参,还可以作为方法的返回值。
8.把子类转换为父类称为向上转型,系统自动进行类型转换。把父类转换为子类,称为向下转型,必须进行强制类型转换。
9.向上转型后,通过父类引用变量调用的方法是子类覆盖或继承自父类的方法,通过父类引用变量无法调用子类特有的方法。
10.向下转型后可以访问子类特有的方法。向下转型必须转换为父类指向的真实子类类型,否则将出现类型转换异常ClassCastException。
11. instanceof运算符用于判断一个对象是否属于一个类。