织梦网站文章内容模板,如何购买已备案域名,360收录提交入口,成都住建局官网官网一、多态前言
1.为什么要使用多态
Java中使用多态的主要目的是提高代码的可重用性和扩展性#xff0c;使得代码更加灵活和易于维护。通过多态#xff0c;我们可以将不同的对象看做是同一种类型#xff0c;从而使得我们可以使用同一种接口来操作这些对象#xff0c;而不必…一、多态前言
1.为什么要使用多态
Java中使用多态的主要目的是提高代码的可重用性和扩展性使得代码更加灵活和易于维护。通过多态我们可以将不同的对象看做是同一种类型从而使得我们可以使用同一种接口来操作这些对象而不必关心具体的实现细节。
2.多态概念
当父类的引用所指向的子类对象引用指向的对象不一样时。调用重写的方法所表现出来的行为是不一样的我们把这种思想叫做多态。上面所说的可能大家会觉得有点抽象看到后面就懂了。 多态的基础是动态绑定所以要了解多态前提我们还要了解动态绑定。 要想实现动态绑定需要满足以上几个条件 1.要发生向上转型 2.要发生重写 3.使用父类对象的引用去调用重写方法 完成了这三部分就会发生动态绑定而在这里出现了重写以及向上转型这些概念。所以我们得先了解它们才能去了解动态绑定。进而了解多态。
二、重写
1.重写的概念 重写 (override) 也称为覆盖。将父类的方法重新在子类中使用。 返回值和形参都不能改变 。 即外壳不变核心重写 重写的好处在于子类可以根据需要定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。 方法重写的规则1.子类在重写父类的方法时必须与父类方法原型一致即返回值、方法名、参数列表要完全一致 2.被重写的方法的访问修饰限定符在子类中要大于等于父类的。 3.父类中被static或private或final修饰的方法以及构造方法都不能被重写。 4.在子类中重写的方法, 可以使用 Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验。
2.重写的作用 对于已经投入使用的类尽量不要进行修改。最好的方式是重新定义一个新的类来重复利用其中共性的内容并且添加或者改动新的内容。 例如若干年前的手机只能打电话发短信来电显示只能显示号码而今天的手机在来电显示的时候不仅仅可以显示号码还可以显示头像地区等。在这个过程当中我们不应该在原来老的类上进行修改因为原来的 类可能还在有用户使用 正确做法是 新建一个新手机的类对来电显示这个方法重写就好了这样就达到了我 们当今的需求了 。 三、向上转型 向上转型实际就是创建一个子类对象将其当成父类对象来使用。 语法格式父类类型 对象名 new 子类类型 () Animal animal new Cat ( ); 我们对以上代码进行实质化分析以上的代码其实是省略化了见以下代码 Dog dog new Dog); Animal animal dog;//该代码发生了向上转换将Dog对象转换为Animal类型 通过向上转型后就可以父类对象名来访问子类的方法了。使用animal.eat();这语句来访问 这个语句发生了动态绑定在编译过程中调用的其实是父类的eat但是在运行时换为调用子类的eat了故实现了 创建一个子类对象将其当成父类对象来使用。见以下代码 class Animal { void sound() { System.out.println(Animal makes a sound); } } class Dog extends Animal { void sound() { System.out.println(Dog barks); } void fetch() { System.out.println(Dog fetches a ball); } } public class Main { public static void main(String[] args) { Dog dog new Dog(); // 创建Dog对象 Animal animal dog; // 向上转型将Dog对象转换为Animal类型 animal.sound();//调用子类的覆盖方法 // animal.fetch(); // 编译错误因为Animal类中没有fetch方法 } } // 输出: Dog barks 通过以上代码发现一个问题不能调用到子类特有的方法因为编译时调用的是父类的方法我们可以通过向下转型来调用到子类特有的方法后面介绍静态绑定也称为前期绑定(早绑定)即在编译时根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。 动态绑定也称为后期绑定(晚绑定)即在编译时不能确定方法的行为需要等到程序运行时才能够确定具体调用那个类的方法。 【向上转型 使用场景 】 1. 直接赋值 2. 方法传参 3. 方法返回 见以下代码 public class TestAnimal { // 2. 方法传参形参为父类型引用可以接收任意子类的对象 public static void eatFood(Animal a){ //因为主方法的原因使用静态方法 a.eat(); //方法传参向上转型 } // 3. 作返回值返回任意子类对象的实例 public static Animal buyAnimal(String var){ return new Dog(); } public static void main(String[] args) { Animal cat new Cat(元宝,2); // 1. 直接赋值子类对象赋值给父类对象 Dog dog new Dog(小七, 1); animal.eat(); //直接赋值向上转型 eatFood(cat); eatFood(dog); Animal animal buyAnimal(狗); animal buyAnimal(猫); animal.eat();//方法返回向上转型 } } 向上转型的优点让代码实现更简单灵活。 向上转型的缺陷不能调用到子类特有的方法。 四、多态的实现
多态具体点就是去完成某个行为时当不同的对象去完成时会产生出不同的状态。代码如下 class Animal { public void eat(){ System.out.println( 吃饭); } } class Cat extends Animal{ Override //注解 public void eat(){ System.out.println(吃鱼~~~); } } class Dog extends Animal { Override public void eat(){ System.out.println(吃骨头~~~); } } public class TestAnimal { public static void eat(Animal a){ a.eat(); //两次调用该方法但是结果却不一样 } public static void main(String[] args) { Cat cat new Cat(); Dog dog new Dog(); eat(cat); eat(dog); } } //输出结果 吃鱼~~~ 吃骨头~~~ 此时在上述代码中当父类的引用所指向的子类对象引用指向的对象不一样时。调用重写的方法eat所表现出来的行为是不一样的(输出结果不一样),我们把它叫做多态。
五、向下转型 将一个子类对象经过向上转型之后当成父类方法使用再无法调用子类的方法但有时候可能需要调用子类特有的方法此时将父类引用再还原为子类对象即可即向下转换。 语法格式子类类型 对象名 强制转换父类对象名 Dog myDog (Dog) animal; 那么以上代码为什么要强制类型转换呢向上转型可以不用因为是从小范围向大范围的转换。可以类比整型里面的强制转换我们现在提出一个问题什么时候都可以向下转型吗 答案是不在Java中向下转型将父类引用转换为子类引用一般需要先进行向上转型 见以下代码 class Animal { void sound() { System.out.println(Animal的sound); } void sun() { System.out.println(Animal特有的sun); } } class Dog extends Animal { void sound() { System.out.println(Dog的sound); } void fetch() { System.out.println(Dog特有的fetches ); } } public class Mainn { public static void main(String[] args) { Animal animal new Dog(); // 向上转型 Dog myDog (Dog) animal; // 向下转型 myDog.sound(); // 输出: Dog barks调用子类的覆盖方法 myDog.fetch(); // 输出: Dog fetches a ball调用子类特有的方法 // 调用父类的方法 myDog.sound(); // 输出: Dog barks调用子类的覆盖方法 myDog.sun(); } } 如果上面的代码没有 Animal animal new Dog();向下转型将报错同时注意必须确保父类引用所指向的对象确实是子类的实例。如果父类引用所指向的对象不是子类的实例那么即使进行了向上转型向下转型也是不安全的见以下代码 class Parent {} class Child extends Parent {} class AnotherChild extends Parent {} public class Main { public static void main(String[] args) { Parent parent new AnotherChild(); // 向上转型 // 这里如果尝试向下转型为Child编译器将会报错 // Child child (Child) parent;//不安全的向下转型 } } //为了演示方便这个代码是不完整的 因此向下转型之前你需要确保父类引用所指向的对象确实是你要转型的子类的实例。这通常通过instanceof操作符来检查用来判断parent是否为Child的实例若是返回true,否则返回false if (parent instanceof Child) { Child child (Child) parent; // 安全的向下转型} else { ...... // 不能转换为Child } 我们最后思考一个问题向上转型的缺陷是不能调用到子类特有的方法那么向下转型可以调用父类特有的方法吗是可以的同时向下转型后不会影响向上转型的操作。见以下代码 class Animal { void sound() { System.out.println(Animal的sound); } void sun() { System.out.println(Animal特有的sun); } } class Dog extends Animal { void sound() { System.out.println(Dog的sound); } void fetch() { System.out.println(Dog特有的fetches ); } } public class Mainn { public static void main(String[] args) { Animal animal new Dog(); // 向上转型 Dog myDog (Dog) animal; // 向下转型 myDog.sound(); // 输出: Dog barks调用子类的覆盖方法 myDog.fetch(); // 输出: Dog fetches a ball调用子类特有的方法 myDog.sound(); // 输出: Dog barks调用子类的覆盖方法 myDog.sun(); //观察到向下转型过程中可以调用父类的特有的方法 animal.sun(); //观察到向下转型后不会影响向上转型的操作 animal.sound(); } } //输出结果 Dog的sound Dog特有的fetches Dog的sound Animal特有的sun Animal特有的sun Dog的sound 六、多态的优缺点
待更新~~~
七、避免在构造方法中调用重写的方法