JAVA多态(polymorphism)
多态是指同一个方法可作用于不同的对象,从而执行不同的方法代码并获得不同的结果。
1.多态是继封装、继承之后,面向对象的第三大特性。
2.多态现实意义理解:
现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两态。 Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。
3.多态体现为父类引用变量可以指向子类对象。
4.前提条件:必须有子父类关系。
注意:在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
5.多态的定义与使用格式 定义格式:
父类类型 变量名=new 子类类型();
复制
多态中成员的特点
1.多态成员变量:编译运行看左边
Fu f=new Zi();System.out.println(f.num);//f是Fu中的值,只能取到父中的值
复制
2.多态成员方法:编译看左边,运行看右边
Fu f1=new Zi();System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi,所以调用的是重写后的方法。
复制
java支持两种多态:动态多态和静态多态。
- 静态多态性:在编译时,就可以被系统识别,也称为编译时多态、静态联编、静绑定。 方法重载(overload)采用的是静态联编的方法实现。
- 动态多态性:在编译时不能被系统识别,而是在运行时才能被系统识别,也称为运行时多态,也称动态联编,也称动绑定。 方法覆盖(override)[也叫方法重写]、抽象方法和接口采用动态联编的方法实现。
方法重载:
在同一个类中,方法名相同,参数列表不同,与返回值无关。
public class MethodOverload {
public static void main(String args[]) {
int a = 51, b = -98, c = 8, d = 191;
double u = 25.1, v = -29.8, x = 3.1, y = 89.98;
System.out.println("51、-98、8、191四数的最大值是:" + max(a, b, c, d));
System.out.println("25.1、-29.8、3.1、89.98四数的最大值是:" + max(u, v, x, y));
}
static int max(int a, int b, int c, int d) {
int x, y;
x = a > b ? a : b;
y = c > d ? c : d;
return x > y ? x : y;
}
static double max(double a, double b, double c, double d) {
double x, y;
x = a > b ? a : b;
y = c > d ? c : d;
return x > y ? x : y;
}
/*
* 如果一个类中有两个同名方法,其参数列表完全一样,仅仅返回值类型不同,则编译时会产生错误
*/
/*
static double max(int a, int b, int c, int d) {
int x, y;
x = a > b ? a : b;
y = c > d ? c : d;
return x > y ? x : y;
}
*/
}
复制
####### 方法重写(方法覆盖):
在子类继承父类的关系中,子类的方法名和父类的方法名相同,参数列表相同,返回值类型相同。
class Sup {
public int x, y;
Sup(int a, int b) {
x = a;
y = b;
}
public void display() {
int z;
z = x + y;
System.out.println("add=" + z);
}
}
class Sub extends Sup {
Sub(int a, int b) {
super(a, b);
}
public void display() {
int z;
z = x * y;
System.out.println("product=" + z);
}
}
//diaplay()在编译时不能被系统识别,而是在运行时才被系统识别,也称为运行时多态,也称为动态联编,也称为动绑定。
public class ResultDemo extends Sub
{ ResultDemo(int x,int y)
{ super(x,y);
}
public static void main(String args[ ])
{ Sup num1=new Sup(7,14);
Sub num2=new Sub(7,14);
ResultDemo num3=new ResultDemo(7,14);
num1.display( );
num2.display( );
num3.display( );
num1=num2;
num1.display();
num1=num3;
num1.display();
}
}
复制
多态有三个条件:
1.有继承关系 2.方法重写 3.父类的声明指向子类的引用
例1:
class Animal{
int age = 10;
public void shout(){
System.out.println("叫了一声");
}
}
class Dog extends Animal{
int age = 28;
public void shout(){
System.out.println("汪汪汪");
}
public void gnawBone(){
System.out.println("我在啃骨头");
}
}
class Cat extends Animal{
int age = 18;
public void shout(){
System.out.println("喵喵喵");
}
}
复制
public class TestPolym{
public static void main(String[] args){
Animal animal = new Dog();//向上可以自动转型
System.out.println(animal.age);//属性调用时,仍然是基类的属性,属性没有多态!
animalCry(new Dog());
//传的具体是哪一个类就调用哪一个类的方法,大大提高了程序的可扩展性。
//如果没有多态,这里需要写很多的重载方法,如果增加一种动物,就需要重载一种动物的喊叫方法,非常麻烦。
//有了多态,只需要增加这个类继承Animal基类就可以了。
animalCry(new Cat());
Dog dog = (Dog) animal;//编写程序时,如果想要调用运行时类型的方法,只能进行类型转换,不然通不过编译器的检查。
dog.gnawBone();
}
}
复制
多态的转型:
分为向上转型和向下转型。
- 向上转型: 多态本身就是向上转型的过程。
格式:
父类类型 变量名 = new 子类类型
复制
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void run(){
System.out.println("我会跑");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();//向上转型
animal.eat();
}
}
输出:狗吃骨头
复制
上面的就是向上转型, Animal animal = new Dog();就是将子类对象Dog转化为父类对象Animal。这时animal这个引用调用的方法是子类方法。
向上转型注意点:
1.向上转型时,子类单独定义的方法会丢失,比如上面的Dog类中定义的run方法,当animal引用指向Dog类实例是访问不到run方法的,animal.run();会报错。 2.子类不能指向父类对象。Dog d = (Dog) new Animal这样是不行的。
向上转型好处: 1.减少重复代码 2.提高系统扩展性
- 向下转型: 一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类对象转为子类对象。
格式:
子类类型 变量名=(子类类型) 父类类型的变量;
复制
适用场景:当要使用子类特有功能时。
以上面的例子来说:
//还是上面的animal和cat dog
Animal a = new Cat();
Cat c = ((Cat) a);
c.eat();
//输出 我吃鱼
Dog d = ((Dog) a);
d.eat();
// 报错 :java.lang.ClassCastException:com.wr.animal.Cat cannot be cast to com.wr.animal.Dog
Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();
// 报错 :java.lang.ClassCastException:com.wr.animal.Animal cannot be cast to com.wr.animal.Cat
复制
为什么第一段代码不报错呢,因为a本身就是Cat对象,所以当然可以转型为Cat,因为是Cat所以不能转为Dog。 而a1是Anmail对象,它不能向下转型Wie任何子类对象。比如发现一个古生物化石,知道它是一种动物,但你不能直接说他是猫或者他是狗。
向下转型注意点:
1.向下转型的前提是父类对象指向的是子类对象(也就是说,在向下转型之前,它得先向上转型) 2.向下转型只能转型为本类对象(猫是不能变成狗的)。
instanceof关键字
有一个场景:江苏人包含:淮安人、盐城人、扬州人…. 淮安人、盐城人、扬州人一定都是江苏人; 反过来,江苏人不一定都是淮安人。
父类和子类的对象之间转换:
- java允许在父类和子类的对象之间进行转换: 1.自动转换 2.强制类型转换
子类和父类之间存在着“is a”的关系,所以子类转换为父类对象时,是自动转换。 当父类对象转换为子类对象时,必须要强制类型转换。
强制类型转换的格式:
if(父类对象名 instanceof 子类名){ 子类对象名 = (子类名)父类对象名;}else{}
复制
Fu f1=new Zi();Fu f2=new Son();if(f1 instanceof Zi){ System.out.println("f1是Zi的类型");}else{ System.out.println("f1是Son的类型");}
复制
final关键字
用来修饰变量、方法、类。
- 修饰变量:变量一旦初始化就不能改变,相当于定义了常量 final int x = 3;
- 修饰方法:final方法在子类不能被重写(覆盖) final void eat(){}
- 修饰类:final类不能被任何类继承(最终类) final class Person{}