我有两个班级:
class Base {
public String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Derived extends Base {
public String getValue() {
return name + " foo";
}
}
创建了一个对象:
Base foo = new Base();
foo.setName("John");
Derived bar = (Derived) foo;
这个简单的例子给出了ClassCastException
例外:
java.lang.ClassCastException: Base cannot be cast to Derived
是否有可能以某种方式使用额外的只读方法扩展现有对象?
答案 0 :(得分:3)
对于Base foo = new Base();
,你说你有一只猫,但突然之间你想把它变成波斯猫,如果所有的猫都是波斯猫的话,这将成功。这不是真的,这就是为什么你得到ClassCastException
。
你必须这样做:
Base foo = new Derived();
答案 1 :(得分:2)
将基础对象转换为派生类
您无法投射对象,您只能投射参考。无论如何,对象都没有改变。
如果您创建Base
(new Base
),那就是您所拥有的一切。然后,您无法将引用称为Derived
,因为不是 Derived
,而是Base
。 (这就是为什么你得到ClassCastException
:在运行时,JVM检查你所指的是什么,以确保它真的可以这样引用。)
另一个方向有效:
Derived d = new Derived();
Base b = d;
...因为d
引用的对象是Derived
,Derived
扩展Base
,意味着它有 与Base
的 关系:所有Derived
个对象也是Base
个对象。
相反的情况并非如此:所有Base
个对象都是不是 Derived
个对象。尝试将它们视为(通过投射引用)将会失败。
您可以定义接受Derived
的{{1}}构造函数,并将其状态复制为构建新对象的一部分。但是你不能改变实际对象的类型;你必须创建一个具有等效状态的 new 对象。
答案 2 :(得分:1)
只是假装:
Derived bar = (Derived) foo;
工作!
class Base
没有getValue()
方法,所以
Base foo = new Base();
foo
没有。
但由于条形码是class Derived
的引用,因此您可以拨打bar.getValue()
因此,如果您致电bar.getValue()
将会发生什么(getValue()
中没有任何bar
)。
基本概念是所有子类都可以视为父类。因为子类几乎包含了父类所拥有的所有内容。
但是你可以稍后在子类上添加任何内容,这样父类对象就不能被转换为子类对象。
扩展现有对象
从OOP
object
的基础是Class
创建的实例(真实的东西)(蓝图)。如果有办法,那么它将违反基本规则。
答案 3 :(得分:0)
ObjectOrientation的核心概念不是派生(或继承)而是抽象。这意味着:如果您希望所有派生类型(类)都具有操作'genName()',那么使类Base
具有此功能是一个很好的核心思想。要为基于类Base
的所有对象调用此方法,可以使用
Base ref = (Base)anyDerivedObject;
ref.getName();
这是一个垂头丧气。编译器检查是否可以进行向下转换。如果Base
确实是基类,则永远不会抛出ClassCastException。
@Override public String getValue() {
return name + " foo";
}
请使用Java中的@Override
批注,以提供明显且安全的编程风格。如果您调用
ref = getName();
如果“ ref”引用的对象是“ Derived”的实例,则调用Derived的派生操作。这是通过虚拟表或分发表完成的,该表也存在于Java(通常从C ++已知)中。
Derived ref2 = (Derived)ref;
在上面的示例之后,ref
的类型为Base
。 Java编译器检查'Derived'是否从'ref'的类型衍生自'Base'。如果不是这样,编译器将强制执行错误。但是,如果引用是相关的,则编译器将无法知道引用的对象是否正确。因此
Derived bar = (Derived) foo;
介绍示例中的失败。所引用的对象不是Derived的instanceof。那只能在运行时检测,而不能在编译时检测。