2010-09-09 3 views
7

Пример 1:Почему эти два примера кода производят разные выходы?

class Animal { 
    public static void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public static void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

Выход:

Gurrr! Gurrr! Moo! 

Пример 2:

class Animal { 
    public void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

Выход:

Gurrr! Moo! Moo! 

Я просто не понимаю, почему делает saySomething не-стат ic вызывает второй вызов saySomething, вызывающий версию Cow вместо версии Animal. Я понимаю, что Gurrr! Moo! Moo! будет выходом в любом случае.

+0

«Спецификация языка Java говорит так» - это действительно все. Почему вам разрешено вызывать статический метод из справки экземпляра, как в первую очередь, это настоящая странность. Но по крайней мере один огромный поток вики сообщества сообщества на этом :) – Affe

ответ

1

Статические методы привязаны к их классу во время компиляции и не могут использоваться полиморфно. Когда вы объявляете «статический» метод для Animal, он всегда привязан к классу Animal и не может быть переопределен. Статические методы привязаны к объекту Class, а не к экземпляру класса.

Регулярные методы связаны во время выполнения, поэтому JVM может посмотреть ваш вызов на «saySomething» и попытаться определить, проходите ли вы через подкласс Animal, и если да, то он переопределил метод saySomething(). Регулярные методы привязаны к экземпляру объекта, а не к самому классу.

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

class Animal 
{ 
    public abstract static void saySomething(); 
} 

С «статических» означает «связаны во время компиляции», он никогда не имеет смысла для то, чтобы быть статичным и абстрактным.

7

Когда вы звоните saySomething() на животных, фактический тип животного не учитывается, потому что saySomething() является статическим.

Animal cow = new Cow(); 
cow.saySomething(); 

такое же, как

Animal.saySomething(); 

ПСБ например:

Когда цель опорного вычисляется и затем отбрасывают, поскольку режим вызова является статическим, то ссылка не проверяется, является ли оно нулевым:

class Test { 
    static void mountain() { 
     System.out.println("Monadnock"); 
    } 
    static Test favorite(){ 
     System.out.print("Mount "); 
     return null; 
    } 
    public static void main(String[] args) { 
     favorite().mountain(); 
    } 

}

который печатает:
Монаднок
Здесь любимая возвращает нуль, пока не NullPointerException не генерируется.


Ресурсы:

На эту же тему:

+1

Я никогда не понимал, почему Java разрешает вызов статического метода через ссылку на объект. Это не обязательно, и это приводит к такой путанице. – erickson

+0

Согласовано. C++ позволяет вам это делать. Я предполагаю, что это просто упростит для компилятора возможность такого доступа. –

+0

Ну, я пытался защитить это здесь: http://stackoverflow.com/questions/3610309/java-static-confusion/ –

3

Вы не можете переопределить статические методы с той же подписью в подклассах, просто шкурой их.

Для методов класса, система выполнения вызывает метод, определенный в типе время компиляции ссылки, на котором вызывается метод. Например, методы, среда выполнения вызывает метод, определенный в типе времени выполнения ссылки, на которой вызывается этот метод.

http://life.csu.edu.au/java-tut/java/javaOO/override.html

3

Некоторые из известных Переопределение "Ловушки"

  • статические методы не могут быть переопределены
  • частные методы не могут быть переопределены

Это объясняет выход.

1

Статические методы привязаны к «классу», а не к «экземпляру» объекта. Поскольку вы имеете в виду «Животное» и вызываете статический метод saySomething(). Он всегда будет звонить «Животным», если вы не обращаетесь к коровам.

Смежные вопросы