我正在努力克服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 的子类。
我的问题是我的方法是否正确?
答案 0 :(得分:2)
在Java中这是不可能的。一旦将对象创建为某种类型,它将在其生命周期的剩余时间内保持该类型。因此,如果您创建Parent
,则可以将其称为Object
,Person
或Parent
,但在其下方始终是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.
}
}