多态
多态的概念
-
多态
:指一个实体同时具有多种形态,同一个对象在不同的时刻,代表不同的对象状态,指的是对象有多种形态
例如:
妈妈叫你去买水果,西瓜、哈密瓜、苹果、香蕉、葡萄这些都是水果
在不同的季节,能吃到的水果是不一样的,水果就是多态的体现 -
多态可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准
-
多态对象只能调用父类中定义子类中重写的功能,并不能调用子类的特有功能,这样就实现了代码的统一
多态的使用
多态使用要满足三个条件:
- 多态必须在继承体下
- 子类必须要对父类的方法进行
重写
- 通过父类的调用子类重写的方法
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法
下面来练习多态的使用:
//使用多态必须使用是继承、重写
//父类
class Animal {
String name; // 名字
// 父类的方法
public void eat() {
System.out.println(name + "吃东西");
}
// 父类的构造方法
public Animal(String name) {
this.name = name;
}
}
// 狗类 子类继承父类
class Dog extends Animal {
public Dog(String name) {
super(name);//初始化父类的构造方法
}
//添加重写方法,方法名、参数列表都要一模一样
public void eat() {
this.name = "小狗";
System.out.println(name + "吃肉骨头!");
}
// Dog 子类特有的功能
public void run() {
System.out.println(name + "正在看家!");
}
}
// 猫类
class Cat extends Animal {
public Cat(String name) {
super(name);//初始化父类的构造方法
}
//添加重写方法,方法名、参数列表都要一模一样
public void eat() {
System.out.println(name + "吃猫粮!");
}
// Cat 子类特有的功能
public void pd() {
System.out.println(name + "抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
// 创建对象用于测试
Animal a = new Animal("haha");
Dog d = new Dog("小狗");
Cat c = new Cat("小猫");
a.eat(); //调用的是父类自己的功能
d.eat(); //调用的是子类重写后的功能
c.eat(); //调用的是子类重写后的功能
// 创建多态对象进行测试
//解释:使用多态是 父类引用指向子类的对象
//注解: 编译看左边,运行看右边
Animal a1 = new Dog("小狗"); // 用父类 Animal 创建变量 a1,Dog 类对象的地址值交给了 a1 保存
Animal a2 = new Cat("小猫"); // Cat类对象的地址值交给了 a2 保存
//多态对象使用的是父类的定义,子类的方法体
a1.eat();
a2.eat();
}
}
结果:
- 多态的使用要满足三点:
要在子类继承父类的继承体下
对父类的方法进行重写
最后是父类引用指向子类的对象进行调用
多态的重写
重写
也可以称为 覆盖
重写
是子类对父类的方法的实现过程重写编写,但是父类的方法
不能是静态、private修饰、final修饰、构造方法
子类对父类的方法进行重写,返回值和参数列表不能改变
,即外壳不变,对核心重写,重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法- 被重写的方法返回值类型可以不同,但是必须是具有父子关系
例如:
- 多态的子类的访问权限要
大于等于
父类的权限
例如:
- 重写可以使用
@Override
注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心
将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法
构成重写.
重写和重载的区别
重写:(重写必须是在继承层次上)
- 方法名称相同
- 返回值相同(返回值构成父子关系也可以)
- 参数列表相同(数据类型、个数、顺序)
重载:
- 方法名称相同
- 返回值没有要求
- 参数列表不同 (数据类型、个数、顺序)
方法重写:是通过引用对象,根据不同的对象输出的内容也不同
方法重载:是根据参数的不同,匹配参数相同的那个方法
静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法
典型代表函数重载
例如:
- 动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体
调用那个类的方法,下面解释
向上转型和向下转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用
语法格式:父类类型 对象名 = new 子类类型()
例如:
// 父类
class Animal{
String name = "大黑";
public void eat(){
System.out.println(name + "正在睡觉");
}
}
// 狗类 子类
class Dog extends Animal{
int s = 10;
public void eat(){
name = "小白";
System.out.println(name + "正在吃饭");
}
}
public class Test {
public static void main(String[] args) {
// 用父类 Animal 创建变量 a,Dog 类对象的地址值交给了 a 保存
// 简单来说:父类引用指向子类对象
Animal a = new Dog();
// 父类对象不可以使用子类的变量和方法
//a.s = 20; s 是 Dog 的成员,父类是不能访问的,父类没有这个属性
// 这种也叫动态绑定
a.eat();// 使用的是子类的方法
}
在方法传参的过程中,也可以发生向上转型
例如:
public class Test {
public static void fun(Animal a){
a.eat();
}
public static void main(String[] args) {
Dog d = new Dog();
fun(d);
}
- 向上转型的优点:能让代码实现更加的灵活
- 向上转型的缺点:不能使用子类的属性和方法
向下转型
将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的
方法,此时:将父类引用再还原为子类对象即可,即向下转换
例如:
class Dog extends Animal{
int s = 10;
public void eat(){
name = "小白";
System.out.println(name + "正在吃饭");
}
public void k(){
System.out.println(name + "正在看家");
}
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
Dog d = (Dog)a; // 向下转型
a.k();
- 向下转型:是通过强制转换之前向上转型过的子类对象,因为向上转型后就不能在使用子类特有的方法,
如果想使用就要重新恢复成子类对象,加需要把之前向上转型的子类,强制转换回去
这种方法有很大的缺点
,很少使用而且不安全,万一转换失败,运行时就会抛异常
Java中为了提高向下转型的安性,引入了instanceof
,如果该表达式为true
,则可以安全转换
例如:
class Dog extends Animal{
int s = 10;
public void eat(){
name = "小白";
System.out.println(name + "正在吃饭");
}
public void k(){
System.out.println(name + "正在看家");
}
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
if(a instanceof Dog){ // 判断它是不是引用了 Dog 类,如果不是就是 false
Dog d = (Dog)a; // 向下转型
d.k();
}
}
总结
多态:
多态是指一个引用对象有多种状态(多种形态),可以通过父类来调用子类重写的方法
但是使用多态的对象引用的父类不能引用子类特有的变量(属性)和方法
多态的使用要满足三个条件:必须在子类继承体下、子类里必须对父类重写方法、必须通过父类来引用子类重写的方法
多态的重写:
重写又可以称为覆盖
,重写是子类对父类的方法的核心功能
进行重新的书写,返回值和参数列表不能被改变
必须一模一样,而且父类的方法
不可以是静态
、private修饰
、final修饰
、构造方法
重写的子类的访问权限必须是 大于等于
父类的访问权限
重写可以使用 @Override
注解来帮忙检验方法名
是否拼错
重写和重载的区别:
重写是在多态里使用的,功能:通过引用对象调用不同子类重写的方法实现多态
重载是在方法名相同、参数列表不同、返回值没有要求的情况下使用
功能:是根据参数的不同,匹配参数相同的那个方法
向上转型:
实际上是创建一个子类的对象,把子类对象的地址交给父类的对象,当成父类来使用,但是使用的是子类的方法
总结:使用时是父类的定义,子类的方法,编译看左边,运行看右边
向上转型会使的代码更加的灵活,但是向上转型后不能使用
子类特有的属性和方法
向下转型:
使用条件:一个对象向上转型后
由于向上转型后就不能使用子类特有的属性和方法,这时可以把向上转型后的对象强制转型
回去
但是有缺点,有可能强制转型
回去的类不一样,运行会出现异常
Java中为了提高向下转型的安性,引入了 instanceof
,如果该表达式为true
,则可以安全转换