多态性是OOP中的重要特性,在java中,多态性主要通过重载和重写两种方式实现。
当一个父类有多个子类,通过多态可正确地调用不同子类的方法:
class Shape{ public void draw(){ System.out.println("draw a shape"); } } class Square extends Shape{ @Override public void draw() { System.out.println("draw a square"); } } class Circle extends Shape{ @Override public void draw() { System.out.println("draw a circle"); } } class PolyTest{ public static void main(String[] args) { Shape[] shapes=new Shape[10]; for (int i = 0; i < shapes.length; i++) { shapes[i]=new Random().nextInt(2)==0?new Square():new Circle(); } for (Shape shape : shapes) { shape.draw(); } } } /* output: draw a square draw a circle draw a square draw a circle draw a circle draw a square draw a square draw a circle draw a square draw a circle */
但是也有需要注意的地方,如当父类的变量和方法为私有时:
class Super { private String name = "private name"; private void func() { System.out.println("private function"); } public static void main(String[] args) { Super sup = new Sub(); sup.func(); System.out.println(sup.name); } } class Sub extends Super { public String name = "public name"; public void func() { System.out.println("public function"); } } /* * output: private function private name */
结果并不是我们所认为的“public function public name”。因为父类的私有成员对子类是屏蔽的,无法被重写,所以jvm直接调用父类的func方法,不会再检查子类,即使子类中拥有同名方法,也会被认为是新的方法。
为了避免出错,最好不要在子类中出现与父类私有成员同名的成员,以免被误导。
再来看一个例子:
class Super { public String name = "super name"; public String getName() { return name; } } class Sub extends Super { public String name = "sub name"; public String getName() { return name; } public String getSupName() { return super.name; } } class PolyTest { public static void main(String[] args) { Super sup = new Sub(); System.out.println("sup name:" + sup.name + ";sup.getName:" + sup.getName()); Sub sub = new Sub(); System.out.println( "sub name:" + sub.name + ";sub.getName:" + sub.getName() + ";sub.getSupName:" + sub.getSupName()); } } /* output: sup name:super name;sup.getName:sub name sub name:sub name;sub.getName:sub name;sub.getSupName:super name */
当子类对象向上转型为父类对象,并直接调用成员变量时,调用的是父类的成员变量;调用的成员方法还是子类的成员方法。
所以在继承过程中,如果成员变量可能要被覆盖,最好将其设置为private,并用get,set方法来对其进行操作,这种方法在很多情况下都会用到,例如在封装新的数据类型时。