2016-01-25 3 views
-2
class Monster { 
    boolean frighten(int x) { 
     System.out.println("Monster"); 
     return true; 
    } 
} 

class Vampire extends Monster { 
    boolean frighten(byte x) { 
     System.out.println("Vampire"); 
     return true; 
    } 
} 

class Dragon extends Monster { 
    boolean frighten(int x) { 
     System.out.println("Dragon"); 
     return true; 
    } 
} 


class Sample { 
    public static void main(String s[]) { 
     Monster[] inst = new Monster[3]; 
     inst[0] = new Monster(); 
     inst[1] = new Vampire(); 
     inst[2] = new Dragon(); 

     for (int i = 0; i < 3; i++) { 
      inst[i].frighten(i); 
     } 
    } 
} 

Когда я запускаю приведенный выше код с x как int в Monster или Dragon класса, код прекрасно работает так, как я ожидал. Тем не менее, когда я запускаю код путем изменения типа x от int к long либо в Monster или Dragon классов, он печатает следующее:выход в случае цепочки наследования

Monster       
Monster         
Monster         

Может кто-нибудь объяснить логику вывода?

+0

'Vampire' не переопределяет' bighten (int) ', он определяет перегрузку. И вы меняете его на 'long' в классе' Monster', 'Dragon' тоже не переопределяет этот метод. Вот почему вы должны аннотировать метод '@ Override', если вы ожидаете, что метод будет переопределен. –

+0

Я бы даже не назвал это наследование. Вы неправильно используете ключевое слово 'extends'. Чтобы уточнить, «Монстр» должен быть формой или планом для разных типов монстров. Этого не добиться. –

ответ

0

Когда вы пишете

inst[i].frighten(i); 

Поскольку inst[i] имеет тип Monster, компилятор должен найти способ frighten на Monster класса, который соответствует параметру - в случае вашего фактического кода здесь, это frighten(int).

Он вызывает этот метод во всех экземплярах Monster, которые вы передаете - это не имеет значения, что класс находится во время выполнения, метод выбирается во время компиляции.

Что это означает, что метод Vampire.frighten(byte) никогда не вызывается - это перегрузка, а не переопределения, потому что подписи frighten(int) и frighten(byte) не совпадают.

Если изменить параметр frighten метода к long на Monster, компилятор может выбрать только из методов, определенных на Monster, так что единственный способ его знает, что он может безопасно вызывать на всех случаях является frighten(long): ни из подклассов переопределяет этот метод - так поведение по сравнению с базовым классом.не

Если изменить параметр метода frighten к long на Dragon, он больше не переопределяет метод в базовом классе - поэтому поведение является то, что из базового класса.

Способ остановить это «неожиданное» поведение - всегда добавлять @Override к методам, которые, по вашему мнению, переопределяют методы в базовом классе. Компилятор будет жаловаться, если методы с этой аннотацией фактически не переопределяют метод в базовом классе.

8

Вы не передадите byte вашему примеру Vampire; вы проходите мимо int. Потому что Monster принимает int, это то, что называется.

Эффективно, вы перегрузки вашего метода, а не первостепенной это - у вас есть метод с тем же именем и двух одинаковых подписями.

Вы должны использовать однородные типы при переопределении метода, чтобы вы не сталкивались с такими проблемами. Эффективно: изменить подпись frighten в Vampire, чтобы принять int вместо byte.

Аннотирование вашего метода с помощью @Override позволит компилятору помочь в таких вещах.

// Would cause a compilation error since the method isn't overridden 
@Override 
public boolean frighten(byte x) { 
    return true; 
} 
+0

Проблема не в классе вампиров. если тип x в классе Monster или drangon является int, тогда он отлично работает и печатает следующее: Monster Monster Dragon – Nain

+2

@Nain: Я бы не назвал это «работающим нормально», учитывая, что намерение кода назовите 'испугать' какого-то класса, который является« монстром ». Это самая очевидная проблема, которую я вижу в том, что вы не видите «Vampire», потому что вы перегрузили свой метод, а не перегрузили его. – Makoto

2

Если вы намерены переопределить, вы можете использовать аннотации. Тогда компилятор поможет вам обнаружить такие ошибки. Например, компилятор увидит, что здесь есть ошибка.

class Vampire extends Monster 
    { 
     @Override 
     boolean frighten(byte x) 
     { 
     System.out.println("Vampire"); 
     return true; 
     } 
    } 
+0

Переместите аннотацию на слой ниже. Вы не можете использовать его в классе. – Makoto

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