2016-02-19 2 views
-2

В приведенном ниже коде я получаю ошибку компилятора в b.printname() ;. Насколько я понимаю, ошибка связана с тем, что компилятор эффективно работает не полиморфным образом (т. Е. Компилятор по существу только выбирает смотреть на левую часть операнда и, следовательно, b является Вопросом). Так как b имеет тип Question, и поскольку у вопроса не существует метода noN args printName, вы получаете ошибку компиляции. Это верно? Теперь, полагая, что это правильно, мой вопрос - почему? Разумеется, компилятор должен знать, что вопрос b относится к объекту, который фактически поддерживает метод no-args printName? Например. если вы посмотрите, как работает компилятор с точки зрения кастинга, есть примеры, когда компилятор, из-за отсутствия лучшего слова, действует полиморфно или, говоря иначе, компилятор знает, что происходит с точки зрения правой стороны операнд и действует на это знание. Например, если тип интерфейса относится к объекту, который реализует интерфейс, то компилятор просматривает правую часть инструкции (т. Е. Объект, реализующий интерфейс), и решает, что никакого приведения не требуется. Итак, почему компилятор не действует таким образом, почему он не выглядит и не видит, что рассматриваемый объект на самом деле является синим, а синий действительно поддерживает метод no-arg метода printName?Java Compile time non polymorphism

public class Polymorf3 { 



    public static void main(String[] args){ 
     Polymorf3 me = new Polymorf3(); 
     me.doStuff(); 
    } 

    public void doStuff() { 
     Bat a = new Bat(); 
     Question b = new Blue(); 
     //a.printName(); 
     a.printName(a.name); 
     b.printName(); // Compiler Error:Required String Found no args 
    } 
    abstract class Question { 
     String name="Question_name"; 
      public void printName(String name){ System.out.println(name);} 
    } 
    class Bat extends Question { 
     String name = "Bat_Bruce"; 
     //public void printName(){ System.out.println(name);} 

    } 
    class Blue extends Question { 
     String name = "Clark"; 
     public void printName() {System.out.println(name);} 
    } 
} 
+1

Поскольку здесь 'b' содержит ссылку класса' Question'. – Satya

ответ

1

Хотя b имеет тип Blue, так как вы объявили его в качестве Question b = new Blue();, компилятор рассматривает его как тип Question, и, таким образом, что это единственный интерфейс, доступный для него без явного приведения:

((Blue)b).printName(); 

Кроме того, вы можете объявить его как Blue b = new Blue();, а b.printName(); не будет вызывать ошибку времени компиляции.

По сути то, что здесь происходит, что вы Заявляя новую переменную b на более высоком уровне абстракции, так что единственный printName метод, доступный b является один в более высоком уровне абстракции, то один с арг.

Edit:

OP спросил, почему компилятор обрабатывает b как Question даже если он инициализируется как Blue. Рассмотрим следующий пример:

Question q = new Blue(); 
// ... some other code... 
q = new Bat(); // Valid!! 
q.printName("some string"); 

Теперь рассмотрим, что завтра какой-то другой разработчик приходит и меняет его на следующее:

Blue q = new Blue(); 
// ... some other code... 
q = new Bat(); // Invalid!! Compiler error 
q.printName("some string"); 

Объявление переменной на самом высоком уровне абстракции, необходимой для вашей работы означает, что вы могут более позднее изменить реализацию более легко и без ущерба для всего остального вашего кода. Таким образом, должно быть понятно, почему компилятор Java обрабатывает b как Question. Это потому, что b может в любое время, становится экземпляром Blue или Bat, поэтому рассматривать его как осуществление (Blue или Bat) нарушил бы контракт интерфейса Question, позволяя какой-либо другой не-Arg getName метода.

+0

Извините, я не думаю, что мой вопрос был ясен. Я понимаю логику. Я понимаю, что когда вы объявляете b как вопрос, тогда он рассматривается как вопрос, и в этом случае вопрос не поддерживает запрошенный метод. Однако мой вопрос касается компилятора Java. Почему компилятор не работает с информацией, которую он имеет? то есть он знает, что b на самом деле является синим, и он знает, что Blue поддерживает запрошенный метод. – Risteard

+0

Я попытался ответить на ваш вопрос в моем редактировании – Tgsmith61591

+0

Спасибо, что, безусловно, отвечает на мой вопрос. Я бы проголосовал за вас, если бы мог, но моя репутация была уничтожена после постановки этого вопроса. :( – Risteard

0

Вы, кажется, неправильно поняли, что означает полиморфизм. Это означает, что вы можете обрабатывать экземпляр производного класса, как если бы он был экземпляром базового класса. Это включает в себя не вызывающие на нем методы, которые базовый класс не предоставляет. Тип переменной сообщает, какие методы вы можете вызывать, а тип экземпляра определяет, какие реализации этих методов выполняются.

Помещая свой экземпляр Blue в переменную Question, вы просите обработать ее как Question. Если вы хотите вызвать методы в своей переменной Question, которые не предоставлены классом Question, то почему она должна быть переменной Question? Если вы можете вызвать методы производного класса в переменной базового класса, это не будет переменной базового класса.

+0

Спасибо за ответ, но вы можете вызвать методы производных классов в переменной базового класса. например если Question выполнил запрошенный (no-args) метод, тогда он будет разрешен. Полиморфизм заработает. Кроме того, во время выполнения будет реализована реализация класса Blue. Поэтому мой вопрос заключается в том, что было бы так плохо в компиляторе, рассматривающем b как Blue, так как это Blue, и компилятор знает, что это Blue. – Risteard

+0

Точка полиморфизма заключается в том, что наличие переменной типа «Вопрос» является способом рассмотрения экземпляра типа «Вопрос» и не нуждается в том, чтобы знать, какова конкретная реализация. Если вы не хотите рассматривать свой объект как «Вопрос», то вы не хотите использовать полиморфизм, поэтому не указывайте свою переменную типа «Вопрос». – khelwood

+0

Спасибо, я думаю, что понял. Поэтому, если сказать, что у животных есть методы спать и есть, а у ребенка у собаки есть метод лай. Тогда, если Собака рассматривается как Животное, тогда не должно быть позволено лаять? Извините за длинный вопрос. – Risteard