Почему эти два примера кода дают разные результаты? - PullRequest
7 голосов
/ 09 сентября 2010

Образец 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 нестатичен, второй вызов saySomething вызывает версию Cow вместо версии Animal.Насколько я понимаю, Gurrr! Moo! Moo! будет выходом в любом случае.

Ответы [ 5 ]

7 голосов
/ 09 сентября 2010

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

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

совпадает с

Animal.saySomething();

Пример JLS:

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

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 не выдается.


Ресурсы:

На ту же тему:

3 голосов
/ 09 сентября 2010

Некоторые из известных переопределений "PITFALLS"

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

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

3 голосов
/ 09 сентября 2010

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

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

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

1 голос
/ 09 сентября 2010

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

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

Вот почему вы так никогда не сможете:

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

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

1 голос
/ 09 сентября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...