不能。在子类中可以定义和父类同名的变量,也可以定义和父类方法签名相同的静态方法,但这不叫重写。属性和静态方法不具有多态性。
我们先来看一下属性:
class A {
int i = 1;
}
class B extends A {
int i = 2;
}
public class Test {
public static void main(String[] args) {
A a = new B();
System.out.println("a.i=" + a.i); // 结果为 1
B b1 = new B();
System.out.println("b1.i=" + b1.i); // 结果为 2
B b2 = (B) a;
System.out.println("b2.i=" + b2.i); // 结果为 2
}
}
输出结果为:
可见,访问的属性取决于变量的声明类型。
但值得注意的是,当在类的内部访问时,会访问当前所在类的属性,如:
class A {
int i = 1;
int fun() {
return i;
}
}
class B extends A {
int i = 2;
}
public class Test {
public static void main(String[] args) {
A a = new B();
B b1 = new B();
B b2 = (B) a;
System.out.println(a.fun()); // 结果为 1
System.out.println(b1.fun()); // 结果为 1
System.out.println(b2.fun()); // 结果为 1
}
}
输出结果均为1,在构造方法中访问也会得到同样的结果。
静态方法的情况和属性非常类似:
class A {
static void fun() {
System.out.println("A.fun");
}
}
class B extends A {
static void fun() {
System.out.println("B.fun");
}
}
public class Test {
public static void main(String[] args) {
A a = new B();
B b1 = new B();
B b2 = (B) a;
a.fun(); // 编译器提示改为A.fun()
b1.fun(); // 编译器提示改为B.fun()
b2.fun(); // 编译器提示改为B.fun()
}
}
(静态方法应直接通过类名调用,这里通过对象调用仅仅是为了测试)
可见,静态方法的调用也取决于变量的声明类型。
在类的内部调用静态/私有方法时,也会调用当前所在类的方法。
另外,在子类中定义和父类方法签名相同的非私有静态方法时,需要遵守和方法重写一样的规则(尽管这不是重写),即:父类方法不能加 final、返回值兼容、不能缩小访问权限、不能扩大异常范围。违反了规则就编译不通过。子类与父类方法签名相同的方法要么都是静态,要么都是非静态,否则会报错。当父类方法为私有时,子类定义相同签名的方法(同样不叫重写,私有方法不能被重写)没有这些规则限制。