Вопрос

Привет всем,

Интересно, есть ли какие-нибудь Java-хакеры, которые могут подсказать мне, почему следующее не работает:

public class Parent {
    public Parent copy() {
       Parent aCopy = new Parent();
       ...
       return aCopy;
    }
}

public class ChildN extends Parent {
    ...
}

public class Driver {
     public static void main(String[] args) {
         ChildN orig = new ChildN();
         ...
         ChildN copy = orig.getClass().cast(orig.copy());
     }
}

Код вполне готов к компиляции, но решает вызвать ClassCastException во время выполнения D=

Редактировать: Ого, действительно быстрые ответы.Спасибо, ребята!Так что, похоже, я не могу отказаться, используя этот метод...есть ли какой-нибудь другой способ сделать понижающую передачу в Java?Я действительно думал о том, чтобы иметь каждого ChildN перезапись класса copy(), но не был в восторге от добавления дополнительного шаблонного кода.

Это было полезно?

Решение

(Не могу добавить код в комментарий, поэтому добавлю здесь)

Относительно Клонируемого:если вы реализуете Cloneable, реализуйте его следующим образом;гораздо чище звонить...

public class Foo implements Cloneable {
    public Foo clone() {
        try {
            return (Foo) super.clone();
        } catch (CloneNotSupportedException e) {
            return null; // can never happen!
    }
}

[ПРАВИТЬ:Я также видел, как другие люди используют

throw new AssertionError("This should never happen! I'm Cloneable!");

в блоке catch.]

Другие советы

Это все равно что пытаться сделать это:

  public Object copy(){
       return new Object();
  }

А затем попытайтесь:

  String s = ( String ) copy();

Ваш Родитель класс и Ребенок класс имеет те же отношения, что и Объект и Строка

Чтобы это сработало, вам нужно будет сделать следующее:

public class ChildN extends Parent {
    public Parent copy() {
        return new ChildN();
    }
}

То есть переопределите метод "копировать" и верните нужный экземпляр.


Редактировать

Согласно вашей правке.Это действительно возможно.Это может быть одним из возможных способов:

public class Parent {
    public Parent copy() {
        Parent copy = this.getClass().newInstance();
        //...
        return copy;
    }
}

Таким образом, вам не нужно переопределять метод "копировать" в каждом подклассе.Это шаблон проектирования прототипа.

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

public class Parent {
    public Parent copy()  throws InstantiationException, IllegalAccessException  {
       Parent copy = this.getClass().newInstance();
       //...
       return copy;
    }
}
class ChildN  extends Parent {}

class Driver {
     public static void main(String[] args) throws  InstantiationException ,  IllegalAccessException  {
         ChildN orig = new ChildN();
         ChildN copy = orig.getClass().cast(orig.copy());
         System.out.println( "Greetings from : " + copy );
    }
}

Актерский состав эффективно пытается это сделать:

ChildN copy = (ChildN) orig.copy();

(Это отрабатывает приведение для выполнения во время выполнения, но так оно и будет, потому что orig.getClass() будет ChildN.class) Однако, orig.copy() не возвращает экземпляр ChildN, он возвращает экземпляр just Parent, поэтому он не может быть приведен к ChildN.

Если ChildN не переопределяет copy() для возврата экземпляра ChildN, то вы пытаетесь понизить значение объекта типа parent до типа ChildN

java.lang.Класс #cast(Object) вызывает исключение ClassCastException, если класс #isInstance() возвращает false.Из javadoc для этого метода:

Определяет, совместим ли указанный объект с назначением объекту , представленному этим классом.Этот метод является динамическим эквивалентом оператора instanceof языка Java ...В частности, если это Class объект представляет собой объявленный класс, этот метод возвращает true если указанный Object аргумент - это экземпляр представленного класса (или любого из его подклассов);он возвращается false в противном случае.

Поскольку Parent не является подклассом child, isInstance() возвращает false, поэтому cast() выдает исключение.Это может нарушать принцип наименьшего удивления, но он работает так, как это задокументировано - cast() может только повышать, а не понижать.

Может быть, вам просто нужна копия / клон вашего объекта?

В этом случае реализуйте клонируемый интерфейс и переопределяйте clone() по мере необходимости.

public class Parent implement Cloneable {
   public Object clone() throws CloneNotSupportedException {
     Parent aCopy = (Parent) super.clone();
   ...
   return aCopy;
   }
}

public class ChildN extends Parent {
    ...
}

public class Driver {
     public static void main(String[] args) {
         ChildN orig = new ChildN();
         ...
         ChildN copy = orig.getClass().cast(orig.clone());
     }
}

Это делает именно то, что ваш метод "copy ()" пытался сделать способом Java.

(Да, вы тоже могли бы создавать модные игры для самоанализа, но эти методы терпят неудачу или становятся уродливыми, как только у вас нет общедоступного конструктора по умолчанию.Клонирование работает в любом случае, независимо от того, какие конструкторы у вас есть.)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top