什么是多态
多态是java中面向对象的四个基本特性之一,是面向对象程序设计中代码重用的一个重要机制,它表示了同一个操作作用在不同对象时,会有不同的语义,进而产生不同的结果。
多态的表现形式
- 编译时多态:方法的重载,重载指的是同一个类中有多个同名方法,当方法的参数不同时(参数的类型和个数的不同),编译时就可以确定调用哪个方法,是同一个类中多态性的表现方式。
- 运行时多态:方法的重写,java中子类可以重写父类的方法,同样的方法在父类与子类中有着不同的表现形式。父类的引用可以指向子类对象,程序调用的方法在运行期才动态绑定,运行时才可以确定调用哪个方法,因此称之为运行时多态,是父类与子类之间多态性的表现方式。(不同类实现同一个接口也属于这种情况)。
多态存在的必要性
- 要有继承
- 要有重写
- 父类引用子类对象
多态的作用
- 代码变的更加灵活,在调用方法时,根据传入参数的不同就可以执行不同的方法,从而得到想要的结果。
- 代码拓展性变得更好,并可以对所有类的对象进行通用处理。
对象的多态性
- 向上转型:父类 父类对象 = 子类实例
package test;
public class Father {
public void print() {
System.out.println("我是father");
}
public static void main(String[] args) {
Father p1 = new Father();
Father p2 = new son();//向上转型
son s = new son();
p1.print();
p2.print();
s.print();
s.play();
}
}
class son extends Father{
@Override
public void print() {
System.out.println("我是son");
}
public void play() {
System.out.println("我是son,我能够玩耍");
}
}
运行截图:
从运行结果上可以看出,在实例化子类对象时,如果父类的实例引用了子类的对象(多态),例如:父类 实例 = new 子类(),那么该引用在调用父类的方法时遵循以下原则:
- 该实例 可以调用父类中特有的方法。(该方法未被子类重写)
- 该实例如果调用父类中的方法,若该方法被子类重写,则一定调用的是在子类中重写后的该方法。
- 该实例不可以调用父类中没有的方法。(该方法子类特有),如p1不能调用子类的play()方法。
- 父类的属性 不能被子类覆盖。
此外向上转型还可以实现参数统一化:
//参数统一化
class Person{
public void print() {
System.out.println("1.Person类的print方法");
}
}
class Student extends Person{
public void print(){
System.out.println("2.Student类的print方法");
}
}
class Worker extends Person{
public void print(){
System.out.println("3.Worker类的Print方法");
}
}
public class Text6{
public static void main(String[] args){
fun(new Person());//Person per = new Person();
fun(new Student());//Person per = new Student();//向上转型 Student类 转为 Person类
fun(new Worker());//Person per = new Worker();//向上转型 Worker 类 转为 Person类
}
public static void fun(Person per){
per.print();
}
}
//运行结果:
//1.Person类的print方法
//2.Student类的print方法
//3.Worker类的Print方法
- 向下转型,强制转型 子类 子类对象 = (子类)父类实例
向下转型可以实现子类扩充方法调用(有安全隐患,一般不操作!);
//向下转型 将父类对象转为子类
class Person{
public void print(){
System.out.println("1.我是爸爸!");
}
}
class Student extends Person{
public void print(){
System.out.println("2.我是儿砸!");
}
public void fun(){
System.out.println("3.只有儿砸有!");
}
}
public class Text8{
public static void main(String[] args){
Person per = new Student();//向上转型
per.print();//能够调用的只有父类已定义好的
Student stu = (Student) per;//向下转型
stu.fun();//
}
}
父类需要子类扩充的属性或方法时需要向下转型;并不是所有父类都可以向下转型,如果想要向下转型之前,一定要首先发生向上转型过程,否则会出现ClassCastException(类型转换异常 属于运行时异常)。两个没有关系的类是不能发生转型的,一定会产生ClassCastException.
解释:就是一个父类对象能够转成子类对象一定得是new一个子类实例得到的,这样才能转成子类对象,如果是一个new一个父类实例转成子类就会报错。看下面这个例子:
package test;
public class Father {
public void print() {
System.out.println("我是father");
}
public static void main(String[] args) {
Father p1 = new Father();
Father p2 = new son();
try {
son s = (son)p1;
s.play();
System.out.println();
}catch(ClassCastException e) {
System.err.println("p1转成子类失败");
}
son s2 = (son)p2;
s2.play();
}
}
class son extends Father{
@Override
public void print() {
System.out.println("我是son");
}
public void play() {
System.out.println("我是son,我能够玩耍");
}
}
运行结果:
如何判断当前对象知否指向目标类呐?使用instanceof类,他的作用就是检查当前对象是否属于目标类。
package test;
public class Father {
public void print() {
System.out.println("我是father");
}
public static void main(String[] args) {
Father p1 = new Father();
Father p2 = new son();
System.out.println("p1是否指向Father:"+(p1 instanceof Father));
System.out.println("p1是否指向sonFather:"+(p1 instanceof son));
System.out.println("p2是否指向Father:"+(p2 instanceof Father));
System.out.println("p2是否指向son:"+(p2 instanceof son));
}
}
class son extends Father{
@Override
public void print() {
System.out.println("我是son");
}
public void play() {
System.out.println("我是son,我能够玩耍");
}
}
运行截图: