2013-04-28 2 views
2

Я немного смущен точно о том, как полиморфизм и расширяющиеся классы и т. Д. Работает в Java при создании объектов из этих классов.Полиморфизм в Java и создание объектов из этих классов

У меня недавно возникла проблема, которую кто-то здесь помог мне решить (см. Not able to access object sub class's variable? (Java/Android)) для фона.

Я пытался создать объект так:

Quad hero = new Hero(); 

Где герой был подкласс Quad();

У меня были переменные в классе Hero, для которых я не был выше доступа.

Решение было изменить создание объекта для:

Hero hero = new Hero(); 

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

Мой вопрос сейчас - почему это?

И с этим в виду, когда это было бы полезно использовать свой оригинальный метод:

Quad hero = new Hero(); 

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

Был бы признателен, если кто-то может объяснить это для меня - спасибо

ответ

2

Объявление переменной типа, как Quad, означает, что переменная может также ссылаться на другие типы подклассов Quad, не только Hero. И если вы передадите эту ссылку, получатель узнает только, что это «какой-то квадрат», и не может полагаться на то, что это Hero. Следовательно, он не может получить доступ к полям ссылки, которые объявляются только в подклассе.

Что касается того, когда использовать такое назначение, я обычно делаю это только при работе с типами интерфейсов. Нравится:

public List<SomeObject> doSomething() { 
    List<SomeObject> result = new ArrayList<>(); 
    // do something 
    return result; 
} 

Но это действительно просто привычка.

4

Предположим OtherHero также подкласс от Quad с различным поведением:

Это будет работать нормально:

Quad hero = new Hero(); 
// some code 
hero = new OtherHero(); 

Принимая во внимание следующее не скомпилируется:

Hero hero = new Hero(); 
// some code 
hero = new OtherHero(); 

Это Безразлично» t кажется полезным. Теперь предположим, что у вас есть метод, который имеет Quad в качестве возвращаемого типа.Я напишу это в псевдокоде:

Quad method() { 
    if (condition) 
     return new Hero(); 
    else 
     return new OtherHero(); 
} 

Так что вы на самом деле не знаю, если он будет возвращать Hero или OtherHero

Теперь вы можете написать:

Quad foo = method(); 

Теперь, вы на самом деле не знаете точный тип foo, но можете использовать его как Quad.

Известным примером является java.util.List

Вы можете написать:

List<Integer> list = Arrays.asList(1,2,3,4,5,6); 
Collections.shuffle(list); 

List представляет собой интерфейс, реализуемый ArrayList, LinkedList и многих других классов. Не зная кода, мы не знаем, какой класс точно возвращается Arrays.asList(), но мы можем использовать его как List.

+0

Хммм ... интересный @jlordo, спасибо. Так что, если бы у меня было, например, враг1, враг2, враг3 и герой, все они были созданы как квадроциклы и хотели сгруппировать их в массив, тогда я смог бы, так как все они - Квады? Но как я могу получить доступ к переменным, которые хранятся только в подклассах? (скажем, например, у подкласс класса Hero есть переменная, хранящаяся в ней, что класс Enemy не делает. Как мне получить доступ к этим переменным, поскольку они не находятся в базовом классе? Я не могу добраться до них через объект, не меняя это тип Герою, но тогда я не могу сгруппировать его с Врагами? Спасибо! – Zippy

+0

@Zippy: Это зависит от того, как вы хотите получить доступ к этим переменным и что вы хотите с ними делать.Вы можете безопасно отбрасывать, если вы сначала проверите с оператором 'instanceof'. Я бы предпочел сделать интерфейс «Quad» (или абстрактный класс) и использовать его только методы. В любом случае переменные должны быть инкапсулированы, поэтому вы можете получить к ним доступ с помощью методов в классах. – jlordo

+0

Спасибо @jlordo - могу я попросить вас отредактировать ответ, чтобы привести пример выше комментария? (о том, как получить доступ к переменным, как я описал в своих комментариях? Обычно мне легче понять, используя примеры), - тогда я прочитаю и отметю ваш ответ - еще раз спасибо, очень ценю! – Zippy

2

Если вы храните свой объект в переменной Quad, то для всего, что знает компилятор, объект, хранящийся в этой переменной, является Quad и не более того. Это может быть подтип, конечно, но компилятор понятия не имеет, что такое подтип. Насколько известно, этот подтип будет вводить абсолютно нулевые члены базовому типу. Если у компилятора нет гарантии, что объект является чем-то большим, чем Quad, он не хочет позволять вам делать что-либо большее, чем то, что он позволит вам делать с Quad.

Предоставлено Вы,, можете видеть, что этой переменной присваивается только new Hero(). И, предоставленный, вы можете знать, что определенная переменная будет содержать только объекты типа Hero. Но это информация о времени выполнения, которую вы можете вывести на практике. Компилятор не может вычислить все эти сценарии. Вот почему у вас есть. Если вы знаете, что объекты, хранящиеся в этой переменной, всегда будут иметь тип Hero, вы можете продолжить и выразить его компилятору.

Одна из причин, по которой язык позволяет отличать объект от супер-типа, заключается в том, что во многих случаях вы хотите передать этот объект методу, который не должен знать обо всех возможных подтипах базового класса (скажем, , Hero), но только то, что переданный объект является, по меньшей мере, базовым классом (скажем, Quad). Другим типичным сценарием является то, что вы хотите хранить различные объекты, которые не все одного и того же определенного типа (они не все Hero), но все они имеют общего предка (все они Quad), и вы хотите что-то с ними сделать, коллективно. В общем случае, бросание объектов в класс предков разрешено, потому что полезно сделать объекты совместимыми с их базовым типом в ситуациях, когда требуется базовый тип.

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