2009-07-28 2 views
1

У меня есть что-то похожее на эту установку:Java Наследование Вопрос

public class Base { 
    public String getApple() {return "base apple"}; 
} 

public class Extended extends Base{ 
    public String getApple() {return "extended apple"}; 
} 

где-то в коде у меня есть это:

{ 
    Base b = info.getForm(); 

    if (b instanceof Extended){ 
     b = (Extended) b; 
    } 

    System.out.println(b.getApple()); // returns "base apple" even when if clause is true why?? 

} 

Как добиться этого?

+0

Вы хотите возвратить базовое яблоко каждый раз или он возвращает базовое яблоко каждый раз, и вы не знаете почему> – Janusz

+0

Вы должны опубликовать минимальный пример кода, который компилирует и воспроизводит проблему при ее выполнении. Если вы это сделаете, вы, вероятно, уже сами заметите, в чем проблема. –

+0

Thx за ответы ребята, это место действительно потрясающее! Мой Java-код был на самом деле прекрасен ... один выше был просто для иллюстрации, но в следующий раз я приложу усилие, чтобы опубликовать код, который действительно компилируется. Проблема была на самом деле в javascript, который делал запрос ajax, я не смог сериализовать форму перед отправкой запроса ... в любом случае я действительно многому научился из всех ответов! :) – hdx

ответ

6

Первое:

if (b instanceof Extended){ 
    b = (Extended) b; 
} 

абсолютно ничего не делает. Вы в основном говорите b = b, который ничего не говорит. Вы даже не меняете ссылку.

Во-вторых, getApple() всегда будет динамически привязан, а «расширенное яблоко» должно всегда вызываться - учитывая, что подкласс действительно расширяет базовый класс, и метод действительно переопределен.

В основном то, что вам нужно сделать для того, чтобы добиться правильного поведения getApple():

  • удалить, если положение. он ничего не делает.
  • убедитесь, что ваш класс действительно расширяет базовый класс
  • убедитесь, что метод getApple() переопределяет метод базового класса. (используйте аннотацию @override, если вы не уверены)
+0

Я предполагаю, что он использует его, чтобы полностью определить, что его b действительно является расширенным. –

+3

Но он все равно ничего не меняет ... Предложение if не имеет никакого эффекта. –

+0

Предложение if ничего не делает, в java «casts» просто убедитесь, что бросок разрешен, на самом деле они не делают «cast», в отличие от C. –

0

Единственный способ получить это поведение - вернуть super.getApple() в ваш расширенный класс, что фактически совпадает с тем, что не отменяет его в первую очередь. Единственный способ, которым это могло бы помочь, - это передать аргумент, чтобы решить, что вернуть. Не сказать, что хороший дизайн ...

Забыл упомянуть, что, как сказал Ювал, актер ничего не делает для объекта.

4

Как написано, ваш код не будет компилироваться, что заставляет меня думать, что ваша проблема в другом месте. У ваших операторов возврата нет точек с запятой в конце их. Скорее, они появляются после }. Возможно, у вас была другая проблема (возможно, ваш подкласс с ошибкой getApple()), но вы все еще используете старые файлы классов, потому что ваш новый материал не компилируется.

Этот код работает:

class Base { 
    public String getApple() { return "base apple"; } 
} 
class Extended extends Base { 
    public String getApple() { return "extended apple"; } 
} 
public class Test { 
    public static void main(String[] args) { 
    Base b = new Extended(); 
    System.out.println(b.getApple()); 
    } 
} 

консоли:

#javac Test.java 
#java Test 
extended apple 
+0

В качестве побочного примечания это работает, потому что все методы в Java являются виртуальными. – Powerlord

+0

С точки зрения C++, это правильно. Точнее, все вызовы методов в Java динамически связаны во время выполнения. –

1

Прежде всего, что если блок не должен быть необходимым. Это в основном не-op.

Во-вторых, это не ваш настоящий код, потому что он даже не компилируется. После операторов возврата вы пропускаете точки с запятой.

Я подозреваю, что ваша проблема в том, что ваш реальный код имеет опечатку, которая делает подписи двух методов getApple разными. Это означает, что Extended имеет два метода: тот, который унаследован от Base, и тот, у которого есть другая подпись. Поскольку вы звоните с сигнатурой метода Base.getApple, вы всегда получаете такое поведение. Это только предположение, поскольку ваш опубликованный код не показывает проблему, которую вы описываете.

1

Yuval Правильно, что ваш литой в блоке if не действует. Вы можете попробовать совмещая последнее заявление с if:

if (b instanceof Extended) 
{ 
    // Prints "extended apple" if reached. 
    System.out.println(((Extended)b).getApple()); 
} 
+0

совершенно не нужно. «Расширенное яблоко» будет напечатано, даже если вы не добавили (Extended). –

+0

Я предполагаю, что поведение, о котором он сообщал в своем комментарии к коду, является результатом чего-то еще? –

0

Вы должны выяснить, что строит свой экземпляр, который возвращается из info.getForm(). Возможно, вы захотите сделать аннотацию базы, чтобы она не была создана, и вы быстро увидите, где происходит строительство.

1

Добавить @Override в метод вашего подкласса и перекомпилировать. Это поможет вам выяснить, действительно ли вы не переопределяете метод, который, как вы думаете.

т.е.

public class Base { 
    public String getApple() {return "base apple";} 
} 

public class Extended extends Base{ 
    @Override 
    public String getApple() {return "extended apple";} 
} 
0

Вы уверены, что ваш пример кода, предоставленные в вашем вопросе ТОЧНО соответствует коду вашим использует? Причина, по которой я спрашиваю, заключается в том, что поведение, которое вы описываете, происходит, когда вы обращаетесь к публичному FIELD вместо публичного МЕТОД с указателем на объект.

Например:

public class BaseClass { 
    public String baseField; 

    public BaseClass() { 
     baseField = "base"; 
    } 

    public String getBaseField() { 
     return baseField; 
    } 
} 

public class SubClass extends BaseClass { 
    public String baseField; 

    public SubClass() { 
     baseField = "sub"; 
    } 

    public String getBaseField() { 
     return baseField; 
    } 
} 

public class MainClass { 
    public static void main(String[] args) { 
     BaseClass baseObject = new BaseClass(); 
     SubClass subObject = new SubClass(); 
     System.out.println(baseObject.getBaseField()); 
     System.out.println(subObject.getBaseField()); 
     System.out.println(baseObject.baseField); 
     System.out.println(subObject.baseField); 
     System.out.println(((BaseClass)subObect).getBaseField()); 
     System.out.println(((BaseClass)subObect).baseField); 
    } 
} 

напечатает:

base 
sub 
base 
sub 
sub 
base 

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