Java - 转换泛型类'实例到专门课程'例

时间:2015-07-05 14:34:58

标签: java oop inheritance

我正在努力克服Java中最基本的OOP概念。

class Person {}

class Parent extends Person {}

所有父母都是人,但不是所有人都是父母。

Person adam  = new Person();
adam  = new Parent(); // but this just means that the variable 'adam' is just referencing a completely new object.
adam = (Parent)adam; // java.lang.ClassCastException

你如何表达成为Java中的子类的想法?是否只需为子类编写构造函数,该子类采用超类对象,例如......

public class Person {

    private String name;

    public Person(String name){
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

}

现在父类看起来像:

public class Parent extends Person {
    public Parent(Person p) {
        super(p.getName());
    }
}

输出:

public class Run {

    public static <T> void display(T x) {
        System.out.println(x);
    }

    public static void main(String[] args) {

        Person adam  = new Person("adam");

        display(adam instanceof Person); // true
        display(adam instanceof Parent); // false

        // now lets assume that adam has had a child. 
        // adam has 'become' a parent. He is still also a person.

        adam = new Parent(adam);

        display(adam instanceof Person); // true
        display(adam instanceof Parent); // true
    }
}

这是唯一的方法吗?有更好的方法吗?如何表达在Java中成为的想法。也就是说,从对通用对象的引用开始,变得更加专业化。

**编辑澄清:

让我们假设我们有一个 T

让我们假设我们有一个 T 的变量 v v :: T

我们设置 v 以引用 T 类型的新对象。

T v = new T();

v :: T ) - &gt; ( obj-t :: T

我们有一个 S 类,它是 T 类型的子类。它可能有也可能没有其他方法。

我想创建一个 S 类型的新对象 obj-s ,它复制 obj-t中的所有信息(实例变量)

允许我使用现有变量( v :: T )来引用新对象。

v = new S(v);

v :: T ) - &gt; ( obj-s :: S

因此 obj-s S T 的实例, v 的使用是有效,因为 S T 的子类。

我的问题是我的方法是否正确?

4 个答案:

答案 0 :(得分:2)

在Java中这是不可能的。一旦将对象创建为某种类型,它将在其生命周期的剩余时间内保持该类型。因此,如果您创建Parent,则可以将其称为ObjectPersonParent,但在其下方始终Parent,在创建对象后无法更改。

答案 1 :(得分:2)

我无法理解你“成为”的想法。您创建了一个类型为派生类的对象,并通过基类类型的变量访问它。在这种情况下,没有任何东西变成任何东西 - 对象的内容没有变化。类似地,构造函数仅使用对象作为参数来指导结果对象应具有的内容。该对象可以是任何类型。

此外,演员阵容也不会改变对象内容。

您是否尝试创建复制构造函数?

答案 2 :(得分:1)

我认为你尝试做的事情就像PHP一样使用type juggling; &#39;参考类型&#39;可以在运行时更改 相反,Java使用typed variables。您定义了一个名为 something 的引用,即变量名称,在我们的示例中为Person类型。现在你可以这么说&#39;链接&#39;变量名的对象。该对象可以是任何类型,只要它是Person类型。

使用代码adam = new Parent(),您可以将变量adam(类型为Person,与您声明的完全相同)分配给新的Parent实例。请注意,之前称为adam的对象(使用new Person()创建的对象)仍在内存中,但没有引用它。一旦garbage collector到来,对象就会从内存中删除 声明类型为adam的引用Person后,您无法重新定义变量adam以使其具有Parent类型。一旦你以这种方式声明,引用adam总是具有Person类型。

如果您确定您的引用adam实际指向的对象属于Parent类型,则可以安全地进行转换:

((Parent) adam).doSomethingOnlyParentsWouldDo();
((Parent) adam).raiseChild();

或者,您可以将引用adam的对象分配给该子类型的新变量,如下所示:

Parent padam = (Parent) adam;
padam.doSomethingOnlyParentsWouldDo();
padam.raiseChild();

如果您只想将信息或任何人复制到Parent课程中,您必须创建一个复制构造函数:

public Parent(Person person) {
    // Assuming fields are protected
    this.prop = person.prop;
    this.anotherProp = person.prop;
}

或只是静态创建者方法:

public static Parent createFromPerson(Person person) {
    Parent p = new Parent();
    // Assuming fields are protected
    this.prop = person.prop;
    this.anotherProp = person.prop;
    return p;
}

答案 3 :(得分:0)

正如其他人已经指出的那样,继承不允许你这样做 让一个物体成为别的东西。你想做什么可能 最好作为属性实现。这也是非常灵活的 解决方案,因为您可以轻松添加其他属性。

class Person {
  private boolean isParent;
  // ...
}

如果你想要更灵活,你可以实现一个非常简单的 这样的属性系统:

abstract class Attribute { }
class ParentAttribute extends Attribute {
  java.utils.ArrayList<Person> children;
}
class Person {
  java.utils.ArrayList<Attribute> attributes;
  public void setAttribute(Attribute attr) {
    // If an attribute of the same type as attr already exists,
    // replace it.
    // ...
  }
  public <T> T getAttribute() {
    // Find an attribute by the class T or return null.
  }
}