多态的概念
即当不同对象去完成同一件事情的时候会表现出不同的状态
比如:吃粮食这件事情对于人来说,就是吃饭,对于狗来说就是吃狗粮,对于猫来说就是吃猫粮。
总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。
多态实现的条件
public class Animal {
String name;
int age;
public void eatfood(Animal animal){
animal.eat();
}
public void eat(){
System.out.println(name + "吃东西");
}
}
class Cat extends Animal{
@Override
public void eat(){
System.out.println(name+"吃猫粮~~~");
}
}
class Dog extends Animal {
@Override
public void eat(){
System.out.println(name+"吃狗粮~~~");
}
如上述例子,猫和狗都继承了animal这个父类,并且重写的其中的方法,在运行的时候便会通过父类的引用来调用子类重写的方法
class TestAnimal {
// 编译器在编译代码时,并不知道要调用Dog 还是 Cat 中eat的方法
// 等程序运行起来后,形参a引用的具体对象确定后,才知道调用那个方法
// 注意:此处的形参类型必须时父类类型才可以
public static void eat(Animal a){
a.eat();
}
public static void main(String[] args) {
Animal cat = new Cat();
cat.name="元宝";
Animal dog = new Dog();
dog.name="小七";
cat.eat();
dog.eat();
}
}
请注意,前者的代码块是由类的实现者编写的,而后面的代码是由类的调用者实现的
所以类的调用者在使用的时候,就可以根据子类方法的需要进行重写父类的方法,不同子类有不同的方法,从而拥有多态(后面会讲多态实现的3种方法)
重写
下面是重写和重载的区别
![](https://img-blog.csdnimg.cn/direct/1d47f9405b024df2b7596bdf21b93216.png)
向上转型和向下转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
Animal animal = new Cat("元宝",2);
有以下三个使用场景:
public class Animal {
String name;
int age;
public void eatfood(Animal animal){
animal.eat();
}
public void eat(){
System.out.println(name + "吃饭");
}
}
class Cat extends Animal{
public void miao(){
System.out.println("喵喵");
}
}
public static void main(String[] args) {
Animal cat = new Cat();
cat.name ="xiaomao";
cat.age=1;
cat.eat();
//cat.miao();//编译错误
}
public class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eatfood(Animal animal){
animal.eat();
}
public void eat(){
System.out.println(name + "吃饭");
}
}
class Cat extends Animal{
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃猫粮~~~");
}
public void miao(){
System.out.println("喵喵");
}
}
如果子类重写了父类的方法:如示例里的eat,那么会发生动态绑定(只有在编译的时候才知道调用哪个方法)需要下面的条件:
1.父类引用了子类的对象{向上转型)
2.通过父类引用调用重写的对象
class TestAnimal {
public static void swim(Animal a){
System.out.println("swim");
//其他操作
}
public static void main(String[] args) {
Animal cat = new Cat("小猫",2);
swim(cat);
}
}
class TestAnimal {
public static Animal func1(){
return new Cat("小猫",2);
}
public static void main(String[] args) {
Animal cat = new Cat("小猫",2);
func1();
}
}
但是向上转型之后无法访问子类特有的方法
多态的实现
public class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eatfood(Animal animal){
animal.eat();
}
public void eat(){
System.out.println(name + "吃饭");
}
}
class Cat extends Animal{
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃猫粮~~~");
}
public void miao(){
System.out.println("喵喵");
}
}
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃狗粮~~~");
}
class TestAnimal {
public static void func(Animal animal){
animal.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("小猫",2);
Dog dog = new Dog("旺财",2);
func(cat);
func(dog);
}
}
}
输出结果时:
小猫吃猫粮
旺财吃狗粮
即,当animal引用的对象不一样的时候,导致调用eat表现的行为不一样此时就叫做多态
再举一个例子
类的实现者:
class Shape {
public void draw() {
System.out.println("画图形!");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("画一个矩形!");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("画一个圆圈!");
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("画一个三角形!");
}
}
类的调用者:
public class Test2 {
public static void drawMap(Shape shape) {
shape.draw();
}
public static void main(String[] args) {
drawMap(new Cycle());
drawMap(new Rect());
drawMap(new Triangle());
}
}
输出:
这样就大大减少了代码的量
或者如下面的代码,(因为全部继承了shape 使用可以使用shape类型的数组进行循环打印
public static void drawMaps() {
Rect rect = new Rect();
Shape shapeCycle = new Cycle();
Triangle triangle = new Triangle();
Flower flower = new Flower();
Shape[] shapes = {shapeCycle,rect,rect,
shapeCycle,triangle,flower};
for(Shape shape : shapes) {
shape.draw();
}
}
如果不用多态的话,那就只能用if else进行打印
public static void drawMaps1() {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Triangle triangle = new Triangle();
String[] shapes = {"1", "2", "2", "1", "3"};
for(String s : shapes) {
if(s.equals("1")) {
cycle.draw();
}else if(s.equals("2")) {
rect.draw();
}else if(s.equals("3")) {
triangle.draw();
}
}
}
这样会导致代码可读性低和难以扩展
所以多态的优点:
可读性强和容易扩展
但是多态的缺点:
1. 属性没有多态性
当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性
class Animal {
public String name = "动物";
public void display() {
System.out.println("这是一个" + name);
}
}
class Dog extends Animal {
public String name = "狗";
@Override
public void display() {
System.out.println("这是一只" + name);
}
}
public class TestPolymorphism {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.display(); // 使用多态调用子类重写的方法
System.out.println(myDog.name); // 访问父类的属性
}
}
会输出:
这是一只狗
动物
这是因为:
-
myDog.display()
调用了Dog
类中重写的display
方法,显示 "这是一只狗"。这是因为虽然myDog
的类型是Animal
,但实际指向的对象是Dog
类的实例,所以调用的是Dog
类的display
方法。 -
System.out.println(myDog.name);
打印的是 "动物",而不是 "狗"。这是因为属性的访问是根据引用变量的声明类型(这里是Animal
)来解析的,而不是实际对象的类型。因此,即使myDog
实际指向一个Dog
对象,它依然访问的是Animal
类中定义的name
属性。
所以在设计类的继承关系时,开发者可能需要避免在子类中重定义与父类同名的属性,以免造成混淆。
2. 构造方法没有多态性
注意点
1.避免在构造方法中调用重写的方法
在B的构造方法里面也会进行重写,调用子类的方法,但是子类的num还没有进行赋值,导致输出结果和我们想要的不一样,所以最好不用用。
2.如果父类中存在静态方法,调用该静态方法时,始终调用的是父类中的静态方法,而不是子类中的。这是因为静态方法与类的实例无关,它们在类加载时就已经存在,并且与类的特定实例无关。因此,无论你使用哪个类的引用去调用静态方法,都是调用该引用所属类的静态方法。
向下转型
现在增加一个Bird类
lass Bird extends Animal{
public Bird(String name, int age) {
super(name, age);
}
public void fly(){
System.out.println("正在飞");
}
}
public static void main(String[] args) {
Animal animal = new Bird("小fly",2);
Bird bird =(Bird) animal;
bird.fly();
}
打印结果:正在飞
但是向下转型不安全
public static void main(String[] args) {
Animal animal = new Dog("小fly",2);
Bird bird =(Bird) animal;
bird.fly();
}
如果是这样的话,那就会报错,因为Dog里面没有fly,但是这样转换编译器不会显示报错,所以不安全,一定要向下转型的时候,需要像下面这样写
感谢您耐心阅读这篇关于Java多态的文章!如果这些内容对您有所启发,或者您有更多的见解和疑问,欢迎在下方评论区留言分享您的想法。交流和讨论可以帮助我们共同进步!
如果您喜欢这篇文章,请不要吝啬您的点赞👍,您的每一个赞都是对我写作的最大鼓励。同时,您可以收藏🌟这篇博客,方便日后查阅或与朋友分享。
再次感谢您的阅读与支持!期待在评论区与您的精彩互动!💬