曰:“白马非马,可乎?”

曰:“可。”

曰:“何哉?”

曰:“马者,所以命形也。白者,所以命色也。命色者,非命形也,故曰白马非马。”

面向对象方法中多态指的是(面向对象基本特征多态)(1)

什么是多态

1. 本态

一个对象的本类形态就是本态.

2. 多态

一个对象的多种父类形态就是多态

态的使用

1. 多态引用

将子类对象赋值于父类类型的引用变量就是多态引用, 在这里对象其实还是子类对象, 只不过是被看作是一个父类类型的对象.

Person person = new Student();

l 多态性,是面向对象中最重要的概念,在java中有两种体现:

1. 方法的重载(overload)和重写(overwrite)。

2. 对象的多态性 ——可以直接应用在抽象类和接口上。

l Java引用变量有两个类型:编译时类型运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。

注意:若编译时类型和运行时类型不一致,就出现多态(Polymorphism)

2. 多态带来的问题

l 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

Student m = new Student();

m.school = “pku”; //合法,Student类有school成员变量

Person e = new Student();

e.school = “pku”; //非法,Person类没有school成员变量

属性是在编译时确定的,编译时e为Person类型,没有school成员变量,

因而编译错误。

虚拟方法调用(Virtual Method Invocation)

1. 什么是虚拟方法

正常的方法调用:

Person e = new Person();

e.getInfo();

Student e = new Student();

e.getInfo();

虚拟方法调用(多态情况下):

Person e = new Student();

e.getInfo(); //调用Student类的getInfo()方法

编译时类型和运行时类型:

编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。

——动态绑定

2. 多态小结

前提:

需要存在继承或者实现关系

要有覆盖操作

成员方法:

编译时:要查看引用变量所属的类中是否有所调用的方法。

(编译时检查父类类型)

运行时:调用实际对象所属的类中的重写方法。

(运行时执行子类类型)

成员变量:

不具备多态性,只看引用变量所属的类。

多态的应用场景

1. 多态数组

当创建多个不同的子类对象, 而又想统一处理这批对象时, 就可以使用多态数组.

Person[] arr = {new Student(), new Teacher()};

public class Person { private String name; private int age; private String gender; public Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } public void setGender(String gender) { this.gender = gender; } public String getGender() { return gender; } public String say() { return "姓名:" name ",年龄:" age ",性别:" gender; } public void sayHello() { System.out.println("打个招呼"); } }

public class Chinese extends Person { private String shuxiang; public Chinese(String name, int age, String gender, String shuxiang) { super(name, age, gender); this.shuxiang = shuxiang; } public void setShuxiang(String shuxiang) { this.shuxiang = shuxiang; } public String getShuxiang() { return shuxiang; } public void spring() { System.out.println("过大年"); } @Override public String say() { return super.say() ",属相:" shuxiang; } @Override public void sayHello() { System.out.println("吃了吗?"); } }

public class American extends Person { private boolean hasGun; public American() {} public American(String name, int age, String gender, boolean hasGun) { super(name, age, gender); this.hasGun = hasGun; } public void setHasGun(boolean hasGun) { this.hasGun = hasGun; } public boolean isHasGun() { return hasGun; } public void christmas() { System.out.println("Merry Christmas!!"); } @Override public void sayHello() { System.out.println("How are you?"); } }

public class PersonTest { public static void main(String[] args) { Person[] ps = new Person[5]; // 多态数组, 可以保存任意类型的子类对象 ps[0] = new Chinese("张三", 30, "男", "牛"); ps[1] = new American("Jack", 25, "male", true); ps[2] = new Person("某人", 15, "未知"); ps[3] = new American("Rose", 32, "female", false); ps[4] = new Chinese("李四", 40, "女", "羊"); for (Person p : ps) { System.out.println(p.say()); } System.out.println("-------------------------"); // 因为在同一个数组中, 并且所有对象都有age属性, 所以就可以对所有元素进行冒泡排序 for (int i = 0; i < ps.length - 1; i ) { for (int j = 0; j < ps.length - 1 - i; j ) { if (ps[j].getAge() > ps[j 1].getAge()) { Person tmp = ps[j]; ps[j] = ps[j 1]; ps[j 1] = tmp; } } } for (Person p : ps) { System.out.println(p.say()); } } }

2. 多态参数

在设计方法时, 有的方法内部需要用到另外的类的对象, 但是在设计方法时, 又不需要关心究竟是哪个对象, 只关心这些实参对象都是某个类型的, 此时, 方法的参数的类型就可以写成父类类型的参数,这样的方法的参数就是多态参数.

public void test(Person p) { // 这个方法的参数p的具体类型未知

System.out.println(p.say());

}

main() {

test(new Chinese()); // 在实际调用多态参数方法时, 可以传入任意本类或子类类型的对象

test(new American());

}

x instanceof A:检验x是否为类A的对象,返回值为boolean型。

Ø 要求x所属的类与类A必须是子类和父类的关系,否则编译错误。

Ø 如果x属于类A的子类B,x instanceof A值也为true。

public class Person extends Object {…} public class Student extends Person {…} public class Graduate extends Person {…} ------------------------------------------------------------------- public void method1(Person e) { if (e instanceof Person) // 处理Person类及其子类对象 if (e instanceof Student) //处理Student类及其子类对象 if (e instanceof Graduate) //处理Graduate类及其子类对象 }

对象类型转换 (Casting )

l 基本数据类型的Casting:

Ø 自动类型转换:小的数据类型可以自动转换成大的数据类型

如long g=20; double d=12.0f

Ø 强制类型转换:可以把大的数据类型强制转换(casting)成小的数据类型

如 float f=(float)12.0; int a=(int)1200L

l 对Java对象的强制类型转换称为造型

Ø 从子类到父类的类型可以自动进行

Ø 从父类到子类的类型转换必须通过造型(强制类型转换)实现

Ø 无继承关系的引用类型间的转换是非法的

Ø 在造型前可以使用instanceof操作符测试一个对象的类型

面向对象方法中多态指的是(面向对象基本特征多态)(2)

class PersonTest5 { public static void test(Person p) { // 多态参数, 提高了兼容性!! p.sayHello(); //方法中父类中定义,所以直接调用, //p.spring(); // 多态副作用, 子类特有成员不能访问 // 必须对对象的真实身份进行检测 if (p instanceof Chinese) { // 造型有风险, 使用须谨慎!!! Chinese ch = (Chinese)p; // 造型: 对象是什么类型还原成什么类型 ch.spring(); // 子类特有的成员的访问,必须要经过造型. } else if (p instanceof American) { ((American)p).christmas(); } else if (p instanceof Person){ System.out.println("普通人一枚"); } } public static void main(String[] args) { Person[] ps = new Person[5]; // 多态数组, 可以保存任意类型的子类对象 Chinese c1 = new Chinese("张三", 30, "男", "牛"); American a1 = new American("Jack", 25, "male", true); Person p1 = new Person("某人", 15, "未知"); American a2 = new American("Rose", 32, "female", false); Chinese c2 = new Chinese("李四", 40, "女", "羊"); ps[0] = c1; ps[1] = a1; ps[2] = p1; ps[3] = a2; ps[4] = c2; System.out.println("-------------------------"); for (Person p : ps) { test(p); // 不同的子类对象作为实参调用方法, 方法的执行也不一样. } } }


了解更多内容:

JavaSE基础之多态的应用场景

super关键字

this关键字和对象关系

volatile关键字详解

JS实现继承有几种方法

,