Почему компилятор не жалуется, когда я пытаюсь переопределить статический метод?
Я знаю, что мы не можем переопределить статические методы в Java, но кто-то может объяснить следующий код?
class A {
public static void a() {
System.out.println("A.a()");
}
}
class B extends A {
public static void a() {
System.out.println("B.a()");
}
}
Как мне удалось переопределить метод a()
в классе B
?
9 ответов
Вы ничего не переопределили здесь. Чтобы убедиться в этом, попробуйте положить @Override
аннотация перед public static void a()
в классе B
и Java выдаст ошибку.
Вы только что определили функцию в классе B
называется a()
, который отличается (не имеет никакого отношения) от функции a()
в классе A
,
Но потому что B.a()
имеет то же имя, что и функция в родительском классе, скрывает A.a()
[Как указано англ. Фуад]. Во время выполнения компилятор использует фактический класс объявленной ссылки, чтобы определить, какой метод запустить. Например,
B b = new B();
b.a() //prints B.a()
A a = (A)b;
a.a() //print A.a(). Uses the declared reference's class to find the method.
Вы не можете переопределить статические методы в Java. Помните static
методы и поля связаны с классом, а не с объектами. (Хотя в некоторых языках, таких как Smalltalk, это возможно).
Я нашел несколько хороших ответов: почему Java не позволяет переопределять статические методы?
Это называется hiding a method
, как указано в методах переопределения и сокрытия учебника Java:
Если подкласс определяет метод класса с той же сигнатурой, что и у метода класса в суперклассе, метод в подклассе скрывает метод в суперклассе.
static
методы не наследуются, поэтому его B
Отдельная копия метода
static
связаны с class
не состояние Object
Вы не переопределили метод a()
, так как static
методы не наследуются. Если бы вы положили @Override
Вы бы увидели ошибку.
A.java:10: error: method does not override or implement a method from a supertype
@Override
^
1 error
Но это не мешает вам определять статические методы с одинаковой сигнатурой в обоих классах.
Кроме того, выбор метода для вызова зависит от объявленного типа переменной.
B b = null;
b.a(); // (1) prints B.a()
A a = new B();
a.a(); // (2) prints a.a()
В (1), если система заботится об идентичности b
было бы бросить NPE
, и в (2) значение a
игнорируется поскольку a
объявлен как A
, A.a()
называется.
Хотя ответ goblinjuice был принят, я подумал, что пример кода может улучшиться:
public class StaticTest {
public static void main(String[] args) {
A.print();
B.print();
System.out.println("-");
A a = new A();
B b = new B();
a.print();
b.print();
System.out.println("-");
A c = b;
c.print();
}
}
class A {
public static void print() {
System.out.println("A");
}
}
class B extends A {
public static void print() {
System.out.println("B");
}
}
Производит:
A
B
-
A
B
-
A
Если B был переопределен print()
было бы написать B в последней строке.
Ваш метод не переопределен. вы просто пытаетесь поместить аннотацию @Override перед вашим методом в производном классе. это даст вам ошибку времени компиляции. поэтому java не позволит вам переопределить статический метод.
Статические методы будут вызываться по имени класса, поэтому нам не нужно создавать объект класса, мы просто называем его именем класса, чтобы мы не могли переопределить статический
например
class AClass{
public static void test(){
}
}
class BClass extends AClass{
public static void test(){}
}
class CClass extends BClass{
public static void main(String args[]){
AClass aclass=new AClass();
aclass.test(); // its wrong because static method is called
// by its class name it can't accept object
}
}
мы просто называем это
AClass.test();
означает, что статический класс не может быть переопределен, если он переопределен, то как это сделать.
Статические члены принадлежат классу, а не каким-либо объектам. Следовательно, статические методы нельзя переопределить. Также переопределение происходит во время выполнения, поэтому компилятор не будет жаловаться.
Однако вы можете добавить аннотацию @Override к методу. Это отметит ошибку компилятора.