Java 多态
多态的实现条件、向上转型、动态绑定与虚函数机制。
多态的实现
One parent reference pointing at different subclass objects produces different results from the same call. Polymorphism lets code depend on abstractions, so adding a subclass needs no change at the call site.
class Shape {
double area() {
return 0;
}
}
class Circle extends Shape {
double r = 2;
@Override
double area() {
return 3.14 * r * r;
}
}
class Square extends Shape {
double side = 3;
@Override
double area() {
return side * side;
}
}
public class PolyDemo {
public static void main(String[] args) {
Shape[] shapes = {new Circle(), new Square()};
for (Shape s : shapes) {
System.out.println(s.area());
}
}
}12.56
9.0向上转型
Assigning a subclass object to a parent reference is an upcast: automatic and always safe, but only parent-declared members are visible. To reach subclass-specific methods, downcast after an instanceof check.
class Animal {
void eat() {
System.out.println("eating");
}
}
class Cat extends Animal {
void meow() {
System.out.println("meow");
}
}
public class Casting {
public static void main(String[] args) {
Animal a = new Cat(); // 向上转型,自动
a.eat();
if (a instanceof Cat c) {
c.meow();
}
System.out.println(a.getClass().getSimpleName());
}
}eating
meow
Cat虚函数
Java has no virtual keyword: apart from final, static and private methods, every instance method is virtual and dispatched by the object's runtime type.
class Base {
void call() {
System.out.println("Base.call");
}
}
class Derived extends Base {
@Override
void call() {
System.out.println("Derived.call");
}
void onlyInDerived() {
System.out.println("Derived only");
}
}
public class Virtual {
public static void main(String[] args) {
Base b = new Derived();
b.call();
Base plain = new Base();
plain.call();
}
}Derived.call
Base.call字段不参与多态
Polymorphism applies to methods only. Field access is resolved from the reference type, not the object type, so a parent reference always reads the parent's copy — a common trap.
class P {
String name = "P";
}
class C extends P {
String name = "C";
}
public class FieldPoly {
public static void main(String[] args) {
P p = new C();
C c = new C();
System.out.println(p.name);
System.out.println(c.name);
System.out.println(((C) p).name);
}
}P
C
C多态的实现
同一个父类引用,指向不同子类对象,调用同一方法得到不同结果 —— 这就是多态。它让代码依赖抽象而非具体类型,新增子类时不必改调用方。
class Shape {
double area() {
return 0;
}
}
class Circle extends Shape {
double r = 2;
@Override
double area() {
return 3.14 * r * r;
}
}
class Square extends Shape {
double side = 3;
@Override
double area() {
return side * side;
}
}
public class PolyDemo {
public static void main(String[] args) {
Shape[] shapes = {new Circle(), new Square()};
for (Shape s : shapes) {
System.out.println(s.area());
}
}
}12.56
9.0向上转型
子类对象赋给父类引用叫向上转型,自动完成、永远安全,但转型后只能调用父类声明过的方法。需要子类特有方法时要向下转型,先用 instanceof 判断。
class Animal {
void eat() {
System.out.println("eating");
}
}
class Cat extends Animal {
void meow() {
System.out.println("meow");
}
}
public class Casting {
public static void main(String[] args) {
Animal a = new Cat(); // 向上转型,自动
a.eat();
if (a instanceof Cat c) {
c.meow();
}
System.out.println(a.getClass().getSimpleName());
}
}eating
meow
Cat虚函数
Java 没有 virtual 关键字 —— 除了 final、static、private 方法,所有实例方法默认都是虚函数,运行时按对象实际类型分派。
class Base {
void call() {
System.out.println("Base.call");
}
}
class Derived extends Base {
@Override
void call() {
System.out.println("Derived.call");
}
void onlyInDerived() {
System.out.println("Derived only");
}
}
public class Virtual {
public static void main(String[] args) {
Base b = new Derived();
b.call();
Base plain = new Base();
plain.call();
}
}Derived.call
Base.call字段不参与多态
多态只作用于方法。访问字段时编译器按引用类型决定,不按对象类型,所以父类引用读到的永远是父类那份字段。这是容易踩的坑。
class P {
String name = "P";
}
class C extends P {
String name = "C";
}
public class FieldPoly {
public static void main(String[] args) {
P p = new C();
C c = new C();
System.out.println(p.name);
System.out.println(c.name);
System.out.println(((C) p).name);
}
}P
C
C