java对象的多态性

来源:互联网 发布:郑凯淘宝店铺链接 编辑:程序博客网 时间:2024/05/29 07:22

1. 定义

如果B类是A类的子类或间接子类,当用B类创建对象b并将这个对象b的引用赋给A类对象a时,如:
A a;
a = new B();
OR
A a;
B b = new B();
a = b;
则称A类对象a是子类B对象b的上转型对象。


2. 性质

对象b的上转型a的实体是有子类B创建的,但是上转型对象会失去子类B的一些属性和功能。上转型对象具有以下特点:
1.上转型对象不能操作子类新增加的成员变量,不能使用子类新增的方法。即为较子类B失去一些属性和功能,这些属性和功能是新增的。
2.上转型对象可以操作子类继承或隐藏的成员变量,也可以使用子类继承的或重写的方法。即为上转型对象可以操纵父类原有的属性和功能,无论这些方法是否被重写。
3.上转型对象调用方法时,就是调用子类继承和重写过的方法。而不会是新增的方法,也不是父类原有的方法。
可以将对象的上转型对象再强制转换到一个子类对象,强制转换过的对象具有子类所有属性和功能。


3. 举例

如:
OutputStream output;
output = new FileOutputStream(filename);


并且根据Java API知
java.lang.Object
  java.io.OutputStream

     java.io.FileOutputStream

这时,output就是上转型对象啦。有什么特殊呢?就是output可以使用FileOutputStream从父类OutputStream那里继承来的方法和重写的方法,而不能使用子类FileOutputStream自己新增的方法啦。最后,这种方法是很常用的哦。。。当父类有很多子类时,就能实现方法的多态。

多态中非静态成员方法的特点

  • 在编译时,参阅引用型变量所属的类中是否有调用的方法。如果有,则编译通过,如果没有没有则编译失败。
  • 在运行时,参阅对象所属的类中是否有调用的方法。
简单总结:成员方法在多态调用的时候编译时看左边,运行时看右边。

多态中静态成员方法的特点

编译和运行都看左边。

多态中成员变量的特点

无论编译或者运行的时候都看左边(引用型变量所属的类)。
/** * 多态中成员方法和成员变量的特点 * 非静态成员方法:编译时看左边(父类),运行时看右边(子类) * 静态成员方法:编译和运行都参考左边(父类) * 成员变量:编译和运行都看左边(父类) */class Fu{static int count = 100;// 父类中的静态成员变量int num = 100;// 父类中的非静态成员变量public void fun1(){System.out.println("父类中的fun1方法");}public void fun2(){System.out.println("父类中的fun2方法");}public static void fun4(){System.out.println("父类中的fun4静态方法");}}class Zi extends Fu{static int count = 0; // 子类中的静态成员变量int num = 0; // 子类中的非静态成员变量@Overridepublic void fun1() {System.out.println("子类中的fun1方法,覆写了父类的fun1方法");}public void fun3(){System.out.println("子类中的fun3方法,此方法是子类特有的");}public static void fun4(){System.out.println("子类中的fun4静态方法");}}public class PolymorphismDemo {public static void main(String[] args) {Fu obj = new Zi();obj.fun1();// 调用子类重写的方法,输出“子类中的fun1方法,覆写了父类的fun1方法”obj.fun2();// 子类中没有重写fun2,则调用父类的fun2方法,打印“父类中的fun2方法”//obj.fun3();//编译失败,因为父类中没有fun3方法,fun3方法是子类特有的obj.fun4();// fun4是父类和子类都有的静态方法,打印“父类中的fun4静态方法”(因为Fu obj加载的是父类,静态不需要创建对象直接调用方法)System.out.println("obj.num = " + obj.num);// 非静态成员变量编译和运行都看左边即num = 100System.out.println("obj.count = " + obj.count);// 静态成员变量在类加载的是否确定值,看左边即count = 100}}


对象的多态性

在对象实例化的时候A a = new B(),中满足B is-a A的关系(因为B extends A),而A a = new A(),中同样满足A is-a A的关系。

多态数组

abstract class Animal {public abstract void eat();public void sleep() {System.out.println("动物睡觉!");}}class Dog extends Animal {@Overridepublic void eat() {System.out.println("我是狗,我吃肉!");}}class Cat extends Animal {@Overridepublic void eat() {System.out.println("我是猫,我吃鱼");}}class Bird extends Animal {@Overridepublic void eat() {System.out.println("我是鸟,我吃虫子。");}}public class Test {public static void main(String[] args) {/* 创建对象数组 */Animal[] animals = { new Dog(), new Cat(), new Bird() };for (Animal animal : animals) {animal.eat();animal.sleep();}}}
运行结果:
我是狗,我吃肉!
动物睡觉!
我是猫,我吃鱼
动物睡觉!
我是鸟,我吃虫子。
动物睡觉!

对象的多态性中调用的是被子类覆写的方法。

方法参数的多态性

public class Test {public static void main(String[] args) {/* 创建对象数组 */Animal[] animals = { new Dog(), new Cat(), new Bird() };for (Animal animal : animals) {fun(animal);}}/*方法参数的多态*/public static void fun(Animal animal){animal.eat();}}

运行结果:
我是狗,我吃肉!
我是猫,我吃鱼
我是鸟,我吃虫子。
执行各自的eat()方法。

如果程序编写的时候使用多态参数——也就是说将参数声明为父类类型,就可以在运行的时候传入子类对象。在以上的例子中如果别人写了一个Rabbit类,那么它就可以直接使用fun()方法,而不需要任何的修改。


Q1:你能够继承任何一个类么?

A1:继承中的一些限制:①存取控制(非public类)只能在同一个包中有子类;②final关键字修饰的类不能被继承;③构造方法私有化,没有子类。

方法覆写时应该遵循的规则:
①:方法的返回值和参数必须完全一样;
②:不能降低方法的访问权限。

方法的重载与多态毫无关系。(重载只是参数 不同)

一个抽象类除了被继承外没有任何其他作用。

为什么要有抽象方法?
将有方法体的方法放在父类中是一个好主意。但是有的时候就是没有办法给出对于任何子类都有意义的程序代码。抽象方法的意义就在于就算无法实现出方法的内容,但是也可以定义出一组子型共同的协议。这样做的好处就是多态。各个子类可以根据自己的需要去覆写父类中的抽象方法。
在继承树结构中的第一个具体类必须实现抽象类中的所有抽象方法。

Object类
public class Object,Object类是所有类的父类,是一个具体的类,常用的方法有:equals()、hashCode()方法、toString()方法和getClass()方法,强烈建议用自己的方法去覆盖原来的equals()、hashCode()方法和toString()方法。

Object类的两个目的:
1.作为多态让方法可以应付多种类型的机制。
2.提供java在执行期间对任何对象都有需要的方法的实现程序代码(让所有的类都会继承到)。有一部分的方法和线程有关。

0 0