有没有办法在java中用父对象实例化子类?

时间:2014-07-07 17:29:14

标签: java inheritance instantiation

我有一个基类说

class A {
   private String name;
   private String age;

   //setters and getters for same
}

和一个儿童班说

class B extends A {
 private String phone;
 private String address;

  //setters and getters for same
}

现在我有一个A的实例,除此之外我还要在B中设置字段,所以代码就像,

A instanceOfA = gotAFromSomewhere();
B instanceOfB = constructBFrom(instanceOfA);
instanceOfB.setPhone(getPhoneFromSomewhere());
instanceOfB.setAddress(getAddressFromSomewhere());

我可以用给定的A实例化B,但是我不想这样做

B constructBFrom(A instanceOfA) {
  final B instanceOfB = new B();
  instanceOfB.setName(instanceOfA.getName());
  instanceOfB.setPhone(instanceOfA.getAge());

  return B;
}

而是我喜欢拥有一些功能,它具有通用性,足以构造对象,

public class SomeUtility {

   public static <T1, T2> T2 constructFrom(T1 instanceOfT1, Class<T2> className) {

      T2 instatnceOfT2 = null;

      try {
         instatnceOfT2 = className.newInstance();
         /*
         * Identifies the fields in instanceOfT1 which has same name in T2
         * and sets only these fields and leaves the other fields as it is.
         */
      } catch (InstantiationException | IllegalAccessException e) {
         // handle exception
      }          

      return instatnceOfT2;
   }
}

所以我可以用它作为,

B constructBFrom(A instanceOfA) {
   return SomeUtility.constructFrom(instanceOfA, B.class);
}

此外,用例不仅限于父子类,而且这个实用函数可以用于适配器用例。

PS-A和B是我要使用这些类的第三方类,所以我不能做任何修改 在A和B中。

3 个答案:

答案 0 :(得分:10)

良好的做法是建立一个factory课程,以及#34;生产&#34; B

的实例
public class BFactory {
    public B createBFromA(A a) { ... }
}

必须编写工厂方法的代码,因为没有基于其父类创建子类的标准方法。它总是具体的,取决于你的课程的逻辑。

但是,请考虑它是否真的 你需要什么。 没有很多智能用例用于基于其父实例实例化类。一个很好的例子是ArrayList(Collection c) - 构造一个特定的列表(&#34; child&#34;),其中包含泛型集合的元素(&#34;基&#34;。)

实际上,对于很多情况,一种模式,以避免这种奇怪的结构。我知道它可能不适用于您的具体案例,因为您写道您的Base和Child是第三方课程。但是你的问题标题很通用,所以我认为你可能会发现以下内容很有用。

  1. 创建界面IBase
  2. 让班级Base实施界面
  3. 使用composition instead of inheritance - 让Child 使用 Base而非继承
  4. Child实施IBase并将IBase中的所有方法委托给Base
  5. 的实例

    您的代码如下所示:

    public interface IBase {
        String getName();
        int getAge();
    }
    
    public class Base implements IBase {
        private String name;
        private int age;
        // getters implementing IBase
    }
    
    public class Child implements IBase {
        // composition:
        final private IBase base;        
        public Child(IBase base) {
            this.base = base;
        }
        // delegation:
        public String getName() {
            return base.getName();
        }
        public int getAge() {
            return base.getAge();
        }
    }
    

    在你编辑了你的问题后,我更加怀疑你想要的是什么是好的。你的问题看起来更像是企图破解(或不理解)class-based面向对象概念的原则。对我来说听起来像是来自JavaScript的人,并试图保持JavaScript编程风格,只是使用不同的Java语法,而不是采用不同的语言哲学。

    Fun-fact:在prototype-based languages中可以使用父对象实例化子对象,请参阅JavaScript 1.8.5中的示例:

    var base = {one: 1, two: 2};
    var child = Object.create(base);
    child.three = 3;
    
    child.one;   // 1
    child.two;   // 2
    child.three; // 3
    

答案 1 :(得分:0)

在我看来,你想要避免的方式非常合适。某处必须有一段这样的代码。

如果您不能将该方法放在目标类中,只需将其放在其他地方(某些工厂)。您应该另外制作方法static

看看Factory method pattern

第二个选项将扩展B并将此方法作为工厂静态方法放在该新类中。但这个解决方案对我来说似乎更复杂。然后你可以打电话给NewB.fromA(A)。然后,您应该可以使用NewB而不是B。

答案 2 :(得分:0)

你可以通过反思来做到这一点:

public static void copyFields(Object source, Object target) {
        Field[] fieldsSource = source.getClass().getFields();
        Field[] fieldsTarget = target.getClass().getFields();

        for (Field fieldTarget : fieldsTarget)
        {
            for (Field fieldSource : fieldsSource)
            {
                if (fieldTarget.getName().equals(fieldSource.getName()))
                {
                    try
                    {
                        fieldTarget.set(target, fieldSource.get(source));
                    }
                    catch (SecurityException e)
                    {
                    }
                    catch (IllegalArgumentException e)
                    {
                    }
                    catch (IllegalAccessException e)
                    {
                    }
                    break;
                }
            }
        }
    }

*上面的代码是从在线教程中复制的