Java, инициализировать SubClass от SuperClass

public class Base {
  //long list of attributes
  // no Constructor using fields
  // no init methode 
  // i cannot change this class
}

теперь я расширил базовый класс следующим образом:

public class subClass extends Base{
   private boolean selected;

   ...
   getter und setter
   ...
}

i ставьте список базового объекта List<Base>

но мне нужен тот же список, но как List<SubClass> есть ли способ инициализировать подкласс из базового класса?

Пример:

for(Base b: list){
   SubClass sub = (SubClass)b; // Thats wrong i know
   if(...){
       sub.setSelected(true);
   }
   newList.add(sub);
}

Я пытаюсь избежать ручной инициализации каждого атрибута базы Class в SubClass

i обновляю свой вопрос по запросу в комментариях: Дизайн, приведенный выше, является лишь примером. мой QUESTIN ТОЧНО:

Почему преобразование BaseClass в SubClass (sence Subclass extends BaseClass) невозможно? почему Java не разрешает мне делать следующее:

Пример:

Class Base{
   private String name;
.....
}
Class SubClass extends Base{
   private String title;
}

затем

Base b = DBController.getById(...);
SubClass sub = (SubClass)b; 

после этого объект sub должен иметь имя атрибута из объекта b и атрибут title имеет значение null

почему это не так в java?

Извините за мой плохой английский, спасибо

Ответ 1

Если у вас есть List<Base>, вы не можете преобразовать его в List<SubClass>. Это происходит главным образом потому, что список не может содержать экземпляры SubClass. Лучшее, что вы можете сделать, это:

List<SubClass> newList = new List<SubClass>();
for(Base b: list){
    if (b instanceof SubClass) {
        SubClass sub = (SubClass)b;
        . . .
        newList.add(sub);
    }
}

Как правило, однако, когда вы обнаруживаете, что занимаетесь подобным делом, что-то не так с вашим дизайном. Возможно, вы захотите избежать подклассификации Base и вместо .

РЕДАКТИРОВАТЬ. На основе ваших комментариев кажется, что вы хотите создать список экземпляров SubClass, используя список экземпляров Base в качестве запуска. Один из подходов заключается в определении конструктора для SubClass, который принимает Base в качестве аргумента.

public class SubClass extends Base{
    private boolean selected;

    public SubClass() {
        // default constructor
    }

    public SubClass(Base original) {
        // copy constructor -- initialize some fields from
        // values in original, others with default values
    }
    ...
    getter und setter
    ...
}

Затем вы можете создать свой новый список:

List<SubClass> newList = new List<SubClass>();
for(Base b: list){
    SubClass sub = new SubClass(b);
    . . .
    newList.add(sub);
}

Ответ 2

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

Я предлагаю, чтобы вместо создания подкласса и кастинга вы создавали класс оболочки вокруг уродливого:

public class BigDumbClass {
    // A lot of attributes
    // No Constructor
    // No init method
}

public class Wrapper {
    private BigDumbClass base;
    private boolean selected;

    public Wrapper(BigDumbClass base) {
        this.base = base;
        this.selected = false;
    }

    //getters and setters
}

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

List<BigDumbClass> oldList = someData();
List<Wrapper> wraps = aNewList();
for (BigDumbClass bigDumb : oldList) {
    Wrapper wrap = new Wrapper(bigDumb);
    if (someCondition()) {
        wrap.setSelected(true);
    }
    wraps.add(wrap);
}

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

public class BigDumbClass implements SharedInterface {
    // All the stuff outlined above
}

public class Wrapper implements SharedInterface {
    // All the stuff outlined above

    // Methods defined in SharedInterface
    public void doSomething() {
        base.doSomething();
    }
}

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

BigDumbClass base = wrapper.getBase();
base.doSomething();

Ответ 3

Существует один способ: различные манипуляции на основе Java Beans.

Например:

Commons BeanUtils

for( Base base: list ){
   SubClass sub = new SubClass();
   PropertyUtilsBean.copyProperties( sub, base );
   if(...){
       sub.setSelected(true);
   }
   newList.add(sub);
}

Это работает на основе get/seters с тем же именем. Не копирует внутренние поля.

Если вам нужно скопировать внутренние поля, на самом деле это не так сложно реализовать с помощью javax.lang.reflect.