ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Java面向对象进阶—多态

Java面向对象进阶—多态 目录1.认识多态2.多态中调用成员的特点3.多态的优势和弊端1.认识多态多态是面向对象的三大特征的最后一个那么我们先了解什么是多态呢实际上就是同类型的对象表现出不同形态。多态的表现形式父类类型 对象名称子类对象。多态的前提1.有继承关系2.有父类引用指向子类对象 Fu fnew Zi();3.有方法重写可以先体会一下多态当我们在IDEA中创建了四个类AdministratorPersonStudentTeacher这四个类之后Person类中有基础的show方法然后每个类中都重写一个新的show方法当我们在Test类中进行测试的时候public class Test { public static void main(String[] args) { //创建三个对象并调用register方法 Student s new Student(); s.setName(张三); s.setAge(18); Teacher t new Teacher(); t.setName(王建国); t.setAge(30); Administrator admin new Administrator(); admin.setName(管理员); admin.setAge(35); register(s); register(t); register(admin); } //这个方法既能接收老师又能接收学生还能接收管理员 //只能把参数写成这三个类型的父类 public static void register(Person p){ p.show(); } } /* 运行输出 学生的信息为张三, 18 老师的信息为王建国, 30 管理员的信息为管理员, 35 */2.多态中调用成员的特点变量调用编译看左边运行也看左边方法调用编译看左边运行看右边public class Test { public static void main(String[] args) { //创建对象多态方式 //Fu fnew Zi(); Animal a new Dog(); //调用成员变量编译看左边运行也看左边 //编译看左边Javac在编译代码的时候会先看左边的父类中有没有这个变量如果有编译成功如果没有则编译失败 //运行也看左边Java运行代码的时候实际获取的是左边父类中成员变量的值 System.out.println(a.name);//动物 //调用成员方法编译看左边运行看右边 //编译看左边同上 //运行看右边运行代码的时候是运行子类中的方法 a.show();//Dog --- show方法 } } class Animal{ String name 动物; // public void show(){ // System.out.println(Animal --- show方法); // } } class Dog extends Animal{ String name 狗; //Override public void show() { System.out.println(Dog --- show方法); } } class Cat extends Animal{ String name 猫; //Override public void show() { System.out.println(Cat --- show方法); } }对于这个该怎么理解呢Animal a new Dog();现在是用a去调用变量和方法的而a是Animal类型的所以默认都会从Animal这个类中去找。对于成员变量来说由于子类和父类是继承关系在子类的对象中会把父类的成员变量也继承下的。比如说父name子name的情况下a.name是调用的父因为在Animal类中。对于成员方法来说如果子类对方法进行了重写那么在虚方法表中会把父类的方法进行覆盖但是实际上还是调用的父方法所以是编译看右边了。我们可以再通过内存图来加深一下想法首先我们是先创建了Animal类然后又用Dog类继承了Animal。然后我们代码往下走在方法区写了Test的主函数。先利用多态创建a是Animal类的然后在方法区加载了Animal和Dog类。注意在Dog类中的show是重写过后的。然后我们会在堆中创建空间分别存父类和子类的name因为这个我们是Animal类的a嘛所以当a.name的时候就会去打印出来“动物”。如果我们是之前的方法Dog dnew Dog()这种方法那我们就是直接访问的子类的name如果子类中没有才会去看父类中的name。当利用show的时候根据调用方法的特点也是直接看重写的show。3.多态的优势和弊端优势1.在多态形势下右边对象可以实现解耦合便于扩展和维护Person pnew Student(); p.work();//当业务逻辑发生改变时后续代码无需修改当我这个不想执行student的work了我想改成teacher的就只需要把第一行后边这个new student改成teacher就可以了。2.定义方法的时候使用父类型作为参数可以接收所有子类对象体现多态的扩展性与便利。可以看在StringBuilder里sb.append就可以直接添加object类型方便了使用。那么多态有什么弊端呢多态弊端父类引用不能直接调用子类独有的方法public class Test { public static void main(String[] args) { //创建对象多态父类引用指向子类对象 Animal a new Dog(); //编译看左边运行看右边执行Dog重写后的eat() a.eat(); //多态弊端父类引用不能直接调用子类独有的方法 //a.lookHome(); //这行会编译报错Animal类中没有lookHome方法 //如果要调用子类特有方法需要向下转型 Dog d (Dog) a; d.lookHome(); //多态父类引用指向Cat子类对象 Animal c new Cat(); c.eat(); //向下转型调用猫特有方法 Cat cat (Cat) c; cat.catchMouse(); } } class Animal{ public void eat(){ System.out.println(动物在吃东西); } } class Dog extends Animal{ Override public void eat() { System.out.println(狗吃骨头); } //Dog子类特有方法 public void lookHome(){ System.out.println(狗看家); } } class Cat extends Animal{ Override public void eat() { System.out.println(猫吃小鱼干); } //Cat子类特有方法 public void catchMouse(){ System.out.println(猫抓老鼠); } }还是刚才的代码如果我想转换类型该怎么做利用instanceof这个关键字进行判断在Java17之后就可以不用再单独写转换直接在判断框内写就可以了public class Test { public static void main(String[] args) { Animal a new Dog(); a.eat(); // ---------------- 旧版本写法 ---------------- /* if(a instanceof Dog){ Dog d (Dog) a; d.lookHome(); }else if(a instanceof Cat){ Cat c (Cat) a; c.catchMouse(); }else{ System.out.println(没有这个类型无法转换); } */ // ---------------- Java17 新模式匹配写法 ---------------- if(a instanceof Dog d){ d.lookHome(); }else if(a instanceof Cat c){ c.catchMouse(); }else{ System.out.println(没有这个类型无法转换); } // 测试Cat对象 Animal b new Cat(); b.eat(); if(b instanceof Dog d){ d.lookHome(); }else if(b instanceof Cat c){ c.catchMouse(); }else{ System.out.println(没有这个类型无法转换); } } }
返回列表