2013-05-17 3 views
33

Я знаю, что мы не можем переопределять статические методы в 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 я был?

+12

Потому что вы этого не сделали. 'B.a()' доступен только через класс 'B'. Если у вас есть что-то вроде 'A a = new B(); a.a(); ', он напечатает« A.a() », хотя это тип B. Если бы это было действительно переопределено, тогда оно напечатало бы« B.a() ». Обратите внимание, что это нечетная функция Java, которая позволяет вам вызывать статические методы из экземпляра объекта, что помогает вызывать путаницу здесь. – dlev

+1

Что заставляет вас думать, что вы переопределяете 'a' внутри' B'? Вы можете легко проверить это, добавив аннотацию '@ Override' до этого метода. – Pshemo

+0

Вы можете проверить, если 'a()' наследуется 'B', если вы удаляете функцию' a() 'из' B'. Он наследует, но не отменяет. Вместо этого он скрывает 'a()', если вы объявляете другую функцию 'a()' в 'B'. – Dorus

ответ

53

Вы здесь ничего не отменяли. Чтобы убедиться в этом, попробуйте ввести @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, это возможно).

Я нашел несколько хороших ответов здесь: Why doesn't Java allow overriding of static methods?

+6

Вы утверждаете, что статические методы не наследуются, но если я удалю 'a()' из 'B', тогда' B.a(); 'внезапно печатает" A.a() ". Вы наследуете статические методы, но вы не переопределяете их. Вместо этого вы скрываете их, как упоминал в своем ответе Eng.Fouad. – Dorus

+0

@ goblinjuice приятно объяснил. Спасибо. –

+1

@Dorus не вижу, чтобы наследование упоминалось где угодно! –

6

static методы не наследуются, так его B «s отдельный экземпляр метода

static связаны с class не состояние Object

+6

Это неправильно, вы наследуете статические методы, но механизм объявления другого метода с той же сигнатурой в подклассе называется скрытием и работает немного иначе, чем переопределение. – Dorus

+0

Как вы наследуете статические методы @Dorus? –

+1

+1 для @Dorus ... статические методы НЕ наследуются, как он показал в предыдущем комментарии. –

3

Вы не переопределить метод a(), потому что static методы не являются по наследству. Если вы положили @Override, вы бы увидели ошибку.

A.java:10: error: method does not override or implement a method from a supertype 
    @Override 
    ^
1 error 

Но это не мешает вам определять статические методы с одной и той же сигнатурой в обоих классах.

9

Это называется hiding a method, как указано в руководстве по Java Overriding and Hiding Methods:

Если подкласс определяет метод класса с той же сигнатурой как метод класса в суперклассе метод в подклассе скрывает один в суперклассе.

+1

hmmm ... не совсем уверен, если это метод скрывается. Оба 'A' ​​и' B' имеют 'static a()' и в зависимости от объявленного ссылочного типа компилятор найдет и вызовет нужную функцию. Например. 'A a = новый B(); a.a(); // печатает A.a(), поскольку компилятор просматривает объявленную ссылку a, которая является A' – goblinjuice

+1

@goblinjuice Объявление 'a()' в 'B' спрячет' A' '(a)' от 'B'. –

+2

@goblinjuice Это * буквальное определение скрытия * в Java. – dlev

2

Кроме того, выбор метода для вызова зависит от типа переменной объявлен.

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().

+0

Однако вы не должны вызывать статические методы в экземплярах класса. –

+0

Правда. Но это был способ продемонстрировать своеобразное поведение. «Вы можете вызвать метод« null »? Действительно? –

1

Ваш метод не является переопределенным. вы просто пытаетесь поставить аннотацию @Override перед вашим методом в производном классе. это даст вам ошибку времени компиляции. поэтому java не позволит вам переопределить статический метод.

0

Статические методы будут называться своим именем класса, поэтому мы не должны создавать объект класса, мы просто кал его с именем класса, поэтому мы не можем переопределить статический

, например

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();

означает статический класс не может быть отменен, если это переопределяется й ru, как это сделать.

1

Хотя 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 на последней строке.