问题 java,从SuperClass初始化SubClass


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
   ...
}

我成为Base对象的列表 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

我按照评论中的要求更新了我的问题: 上面的设计只是一个例子。我的QUESTIN完全是:

为什么将BaseClass转换为SubClass(s​​ence 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 应该具有Object中的Attribute Name btitle 属性为null

为什么这不是java中的情况?

对不起,我的英语不好, 谢谢


8737
2018-04-04 04:02


起源

从超类初始化子类 - 为什么?这听起来很不好,最坏的情况是危险的。 - Hovercraft Full Of Eels
哪儿是 List<Base> 字段定义?在里面 Base 班级本身?您是否可以控制其声明的位置以及初始化的方式? - Perception
我强烈建议你研究一下“喜欢写作而不是继承” - 谷歌吧。你会发现一些有趣的讨论。我只是这样说,因为看起来你正在拼命地滥用这一特权。 - Bill K
如果Base没有构造函数或初始化方法,如何避免手动初始化Base类属性?您是否尝试将Base类转换为Sub类? - Jake Greene
是的@Jake,这正是我想要做的 - Rami.Q


答案:


如果你有 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);
}

7
2018-04-04 04:05



感谢你的回答。 List只有Object类型的Base,所以这些不是列表中Subclass的实例。但为什么施放类错了?在转换之后,SubClass中的属性可以为null,我可以像上面的示例中那样手动设置它。你对此有何看法? - Rami.Q
我的意思是,在转换SubClass之后应该具有Base Class的所有属性,而SubClass中的其余属性将为null - Rami.Q
@Rami.Q - 好的,你的评论向我澄清了你想要的东西。我修改了我的答案来解决这个问题。 - Ted Hopp
感谢您的回答。我接受了,因为我是这样做的。但它仍然不是最好的解决方案。 Oracle应该为我们提供从Base Class到SubClass的自动转换。像属性UNION之类的东西。 - Rami.Q


有一种方法:各种Java Beans规范的操作。

例如:

Commons BeanUtils

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

这基于同名的get / setter。不复制内部字段。

如果您需要复制内部字段,实际上并不难实现 javax.lang.reflect


3
2018-06-23 09:48





您似乎拥有一个具有大量属性的类,并且没有简单的方法来设置它们。您现在遇到了一个问题,您需要一个具有附加属性的类,但您必须处理基类的混乱。

我建议,不要创建一个子类和转换,而是围绕丑陋的一个创建一个包装类:

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();
    }
}

否则,您可以为实例提供getter并直接访问它。

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

2
2018-04-04 04:55



仅仅因为你有一个超类的引用并不意味着你指向一个超类。 'base baseRef'可能指向SubClass1,因此'SubClass2 subRef =(SubClass2)baseRef'不是有效的强制转换。 - Jake Greene