1.多态概述
- 多态是继封装、继承之后,面向对象的第三大特性。
- 多态*现实意义*理解:
-
现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。
-
Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。
-
3.多态体现为父类引用变量可以指向子类对象。
4.前提条件:必须有子父类关系。
*注意:在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。*
5.多态的定义与使用格式
定义格式:父类类型 变量名=new 子类类型();
2.多态中成员的特点
- 多态成员变量:编译运行看左边
Fu f=new Zi();
System.out.println(f.num);//f是Fu中的值,只能取到父中的值
2.多态成员方法:编译看左边,运行看右边
Fu f1=new Zi();
System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi,所以调用的是重写后的方法。
public class Person {
public void run(){
System.out.println("run");
}
public void eat() {
System.out.println("eat");
}
}
public class Student extends Person{
public void run(){
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student();
//new Person();
//可以指向的引用类型就不确定了:父类的引用指向子类
//Student能调用的方法都是自己或者继承父类的
Student s1 = new Student();
//可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();//Student也是Person
Object s3 = new Student();
s2.run();//子类重写了父类的方法,执行子类的方fa
s1.run();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
s2.eat();
s1.eat();
}
}
/*
输出结果
son
son
eat
eat
*/
注意事项:
- 多态是方法的多态,没有属性的多态:父可以吃,你也可以吃。但你和父的名字不一样
- 父类和子类有联系 类型转换异常!ClassCastException
- 存在的条件:继承关系,方法需要重写,父类引用指向子类对象!
static 方法:属于类,它不属于实例
final常量:无法重写
private方法:
3.多态性
java引用类型有两个:
编译时类型
编译时类型由声明该变量时使用的类型决定
运行时类型
运行时类型由实际赋给该变量的对象决定
例:
1 class Animal{
2 public int month = 2;
3 public void eat(){
4 System.out.println("动物吃东西");
5 }
6
7 }
8
9 class Dog extends Animal{
10 public int month = 3;
11
12 public void eat() {
13 System.out.println("小狗吃肉");
14 }
15
16 public void sleep() {
17 System.out.println("小狗睡午觉");
18 }
19 }
20
21 class Cat extends Animal{
22 public int month = 4;
23
24 public void eat() {
25 System.out.println("小猫吃鱼");
26 }
27 }
28
29 public class Test {
30 public static void main(String[] args){
31 Animal a = new Dog();
32 Animal b = new Cat();
33 a.eat();
34 System.out.println(a.month);
35 //下面代码编译时会出错
36 // a.sleep();
37 b.eat();
38 System.out.println(b.month);
39
40 }
41 }
a对象编译时类型是Animal,运行时类型是Dog;
b对象编译时类型是Animal,运行时类型是Cat。
当运行时调用引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就表现出:相同类型的变量调用同一个方法时表现出不同的行为特征,这就是多态。
该例中:当他们调用eat方法时,实际调用的是父类Animal中被覆盖的eat方法。
运行结果:
小狗吃肉
2
小猫吃鱼
2
上例中main方法中注释了a.sleep(),由于a的编译时类型为Animal,而Animal类中没有sleep方法,因此无法在编译时调用sleep方法。
对象的实例变量不具备多态性
上例中a,b对象分别调用了month,可以看到,其输出结果都是2
总的来说:
引用变量在编译阶段只能调用编译时类型所具有的方法,但运行时则执行他运行时类型所具有的方法。
4.多态的转型
- 多态的转型分为向上转型和向下转型两种
- 向上转型:多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
- 向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
java中向上转型的意义
首先了解多态
- 使用父类类型的引用指向子类的对象;
- 该引用只能调用父类中定义的非private方法和变量;
- 如果子类中重写了父类中的一个方法,那么调用这个方法的时候,将会调用子类中的方法(动态绑定);
- 变量不可以被重写,重写只针对方法,不重写变量;
- 重写就是相同的方法,得到的结果和表现的形式不同;
//父类
public class Father{
//父类有一个打孩子方法
public void hitChild(){
}
}
//子类1
public class Son1 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("为什么打我?我做错什么了!");
}
}
//子类2
public class Son2 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我知道错了,别打了!");
}
}
//子类3
public class Son3 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我跑,你打不着!");
}
}
//测试类
public class Test{
public static void main(String args[]){
Father father;
father = new Son1();
father.hitChild();
father = new Son2();
father.hitChild();
father = new Son3();
father.hitChild();
}
}
如果是Son1 a = new Son1();如果要改为son2那就很麻烦了,而father = new Son1();只需要改动一处。但是后面做大程序的时候,往往好几十个方法,如果你不用father,而用了son,那你一旦在写程序的时候发现这里应该用son2而不是son1,而你又没用father,那你这里一改就要改N多的地方,而且一改动很有可能会引发其他的错误,而且你这些方法很有可能又被其他的类所调用,那其他的类肯定也要跟着改啊,那这个改动量就非常大了。
向上转型的意义:程序开始的时候确定有一个father型对象,但是要根据用户的选择来决定他要被实例化成哪种类型的。但如果你要分开来声明的话,那你就因为不确定性必须要声明两个变量,分别来等待实例化。就是实例化的时候可以根据不同的需求实例化不同的对象,这也就是多态的意义。
5.多态案例:
例1:
package day0524;
public class demo04 {
public static void main(String[] args) {
People p=new Stu();
p.eat();
//调用特有的方法
Stu s=(Stu)p;
s.study();
//((Stu) p).study();
}
}
class People{
public void eat(){
System.out.println("吃饭");
}
}
class Stu extends People{
@Override
public void eat(){
System.out.println("吃水煮肉片");
}
public void study(){
System.out.println("好好学习");
}
}
class Teachers extends People{
@Override
public void eat(){
System.out.println("吃樱桃");
}
public void teach(){
System.out.println("认真授课");
}
}
例2:
请问题目运行结果是什么?
package day0524;
public class demo1 {
public static void main(String[] args) {
A a=new A();
a.show();
B b=new B();
b.show();
}
}
class A{
public void show(){
show2();
}
public void show2(){
System.out.println("A");
}
}
class B extends A{
public void show2(){
System.out.println("B");
}
}
class C extends B{
public void show(){
super.show();
}
public void show2(){
System.out.println("C");
}
}
答案:A B