:Java多态理解多态实现重写转型和抽象类
Posted 快乐江湖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:Java多态理解多态实现重写转型和抽象类相关的知识,希望对你有一定的参考价值。
文章目录
一:对于多态的理解
多态:面向对象方法学中多态是指子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。即在类等级的不同层次中可以共享一个方法的名字, 不同层次中的每个类各自按自己的需要来实现这个行为。通俗点理解就是指完成某个行为时,不同对象有着不同的完成方法
比如买票行为,学生和普通人都属于人,但是学生买票可以半价,而普通人是全票
二:Java多态实现
Java多态实现:和C++类似,在Java中要实现多态,必须满足以下条件
- 继承是多态的前提,没有继承就没有多态
- 子类要对父类的方法完成重写
- 需要通过父类的引用调用重写的方法
(1)重写(override)
重写(override):也即覆盖,是子类对父类的非静态、非private修饰、非final修饰和非构造方法等的实现过程进行重新编写,返回值和形参都不能改变
A:重写规则
重写规则:
- 子类重写父类时与父类方法原型保持一致,也即
修饰符
返回值类型
方法名(参数列表)
需要完全一致(注意:JDK7以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系的,这称之为协变) - 访问权限不能比父类中被重写的方法的访问权限更低:例如,如果父类方法被
public
修饰,那么子类中重写该方法时不可以被声明为protected
- 父类被
static
、private
、final
所修饰以及构造方法都不能被重写 - 重写的方法可以使用
@Override
注解来显式指定。此注解可以帮助我们进行一些合法性检验
class Animal
String name;
int age;
public Animal(String name, int age)
this.name = name;
this.age = age;
public void eating()
System.out.println(name + "吃饭");
class Dog extends Animal
public Dog(String name, int age)
super(name, age);
@Override //重写父类
public void eating()
System.out.println(name + "吃鱼");
class Cat extends Animal
public Cat(String name, int age)
super(name, age);
@Override//重写父类
public void eating()
System.out.println(name + "啃骨头");
B:重写和重载的区别
- 方法重载:是类的多态性表现
- 方法重写:是子类与父类的一种多态性表现
(2)向上转型和向下转型
A:向上转型
向上转型:使用父类的引用指向子类对象,语法格式为:父类类型 对象名 = new 子类类型()
- 向上转型是合理、安全的,因为大范围可以囊括小范围
- 优点:让代码实现更为简单、灵活
- 缺点:不能调用子类特有的方法
class Animal
String name;
int age;
public Animal(String name, int age)
this.name = name;
this.age = age;
public void eating()
System.out.println(name + "吃饭");
class Dog extends Animal
public Dog(String name, int age)
super(name, age);
@Override //重写父类
public void eating()
System.out.println(name + "啃骨头");
class Cat extends Animal
public Cat(String name, int age)
super(name, age);
@Override//重写父类
public void eating()
System.out.println(name + "吃小鱼");
public class TestDemo
public static void main(String[] args)
Animal animal = new Dog("旺财", 3);//向上转型
向上转型一般会有用于以下场景
- 直接赋值:上面代码已经说过
- 方法传参:形参为父类引用,可以接受任意子类对象
- 方法返回:返回值为父类引用,此时可以返回任意子类对象
class Animal
String name;
int age;
public Animal(String name, int age)
this.name = name;
this.age = age;
public void eating()
System.out.println(name + "吃饭");
class Dog extends Animal
public Dog(String name, int age)
super(name, age);
@Override //重写父类
public void eating()
System.out.println(name + "啃骨头");
class Cat extends Animal
public Cat(String name, int age)
super(name, age);
@Override//重写父类
public void eating()
System.out.println(name + "吃小鱼");
public class TestDemo
//形参为父类引用,可以接受任意子类对象
public static void eatFood(Animal animal)
animal.eating();
public static void main(String[] args)
Cat cat = new Cat("喵喵", 3);
eatFood(cat);
class Animal
String name;
int age;
public Animal(String name, int age)
this.name = name;
this.age = age;
public void eating()
System.out.println(name + "吃饭");
class Dog extends Animal
public Dog(String name, int age)
super(name, age);
@Override //重写父类
public void eating()
System.out.println(name + "啃骨头");
class Cat extends Animal
public Cat(String name, int age)
super(name, age);
@Override//重写父类
public void eating()
System.out.println(name + "吃小鱼");
public class TestDemo
//方法返回值为父类引用,此时可以返回任意子类对象
public static Animal buyAnAnimal(String animal_name)
if(animal_name.equals("狗"))
return new Dog("旺财", 2);
else if(animal_name.equals("猫"))
return new Cat("喵喵", 3);
else
return null;
public static void main(String[] args)
System.out.println("进入宠物店:请问你需要什么动物");
Scanner sc = new Scanner(System.in);
String animal_name = sc.nextLine();
Animal animal = buyAnAnimal(animal_name);
System.out.println("你得到了:" + animal.name);
sc.close();
B:向下转型(基本不用)
向下转型:使用子类的引用指向父类对象,但是向下转型很不安全,所以基本不会使用
如下是向上转型,Animal animal = new Dog("旺财", 2)
,所以animal
是无法调用Dog
的特有方法dog_method()
的
class Animal
String name;
int age;
public Animal(String name, int age)
this.name = name;
this.age = age;
public void eating()
System.out.println(name + "吃饭");
class Dog extends Animal
public Dog(String name, int age)
super(name, age);
@Override //重写父类
public void eating()
System.out.println(name + "啃骨头");
public void dog_method()
System.out.println(name + "的特有方法");
class Cat extends Animal
public Cat(String name, int age)
super(name, age);
@Override//重写父类
public void eating()
System.out.println(name + "吃小鱼");
public class TestDemo
public static void function(Animal animal)
animal.eating();
public static void main(String[] args)
Animal animal = new Dog("旺财", 2);
animal.dog_mehtod();
但是我们可以向下转型,也即让一个子类的引用指向强转后的父类对象,此时便可以调用Dog
的特有方法dog_method()
了
public class TestDemo
public static void function(Animal animal)
animal.eating();
public static void main(String[] args)
Animal animal = new Dog("旺财", 2);
Dog dog = (Dog)animal;//向下转型
dog.dog_method();
向下转型很不安全,而且有时会有严重的歧义。 Java中为 了提高向下转型的安全性,引入了instanceof
,如果该表达式为true
,则可以安全转换
(3)实现多态
讲到这里,其实已经完成了多态,所以日后我们就可以利用继承和转型来完成传哪个对象就调用哪个对象的方法的目的
class Animal
String name;
int age;
public Animal(String name, int age)
this.name = name;
this.age = age;
public void eating()
System.out.println(name + "吃饭");
class Dog extends Animal
public Dog(String name, int age)
super(name, age);
@Override //重写父类
public void eating()
System.out.println(name + "啃骨头");
class Cat extends Animal
public Cat(String name, int age)
super(name, age);
@Override//重写父类
public void eating()
System.out.println(name + "吃小鱼");
public class TestDemo
public static void function(Animal animal)
animal.eating();
public static void main(String[] args)
Dog dog = new Dog("旺财", 2);
Cat cat = new Cat("喵喵", 3);
function(dog);
function(cat);
三:静态绑定与动态绑定
- 静态绑定:也称为早绑定,是指在编译时根据用户所传递实参类型确定所调用的方法,最典型的例子就是方法重载
- 动态绑定:也称为晚绑定,是指在编译时不能确定该调用的方法,需要在程序运行确定,最典型的例子就是多态,在程序运行时才能拿到具体的类型
四:不要在构造方法中调用重写的方法
下面的代码中,B继承自A,func
方法被重写。在构造B对象时会调用A的构造方法,在A的构造方法中调用了func
方法,但此时是B对象,所以会调用到B的func
,而B对象而没有完成构造,所以num
处于未被初始化状态,为0
class A
public A()
func();
public void func()
System.out.println("A的func()方法");
class B extends A
private int num = 1;
@Override
public void func()
System.out.println("B的func()方法,num="+num);
public class TestDemo
public static void main(String[] args)
B b = new B();
b.func();
五:抽象类
(1)一个例子
如下一个类Shape
,其中有一个方法draw
,作用是向屏幕打印某个具体的图形(没有具体实现),图形有很多种,这里给出了Rectangle
、Triangle
和Circle
三个类,分别用于描述矩形、三角形和圆形,它们各自内部也有一个方法draw
,重写了父类的方法,形成多态
class Shape
public void draw()
System.out.println("画一个图形");
class Rectangle extends Shape
@Override
public void draw()
System.out.println("画一个矩形");
class Triangle extends Shape
@Override
public void draw()
System.out.println("画一个三角形");
class Circle extends Shape
@Override
public void draw()
System.out.println("画一个三角形");
public class TestDemo
public static void drawing(Shape input)
input.draw();
public static void main(String[] args)
Circle circle 以上是关于:Java多态理解多态实现重写转型和抽象类的主要内容,如果未能解决你的问题,请参考以下文章
Java 基础语法爆肝两万字解析 Java 的多态抽象类和接口