将基础对象转换为派生类

时间:2015-06-01 12:24:24

标签: java

我有两个班级:

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

是否有可能以某种方式使用额外的只读方法扩展现有对象?

4 个答案:

答案 0 :(得分:3)

对于Base foo = new Base();,你说你有一只猫,但突然之间你想把它变成波斯猫,如果所有的猫都是波斯猫的话,这将成功。这不是真的,这就是为什么你得到ClassCastException

你必须这样做:

Base foo = new Derived();

答案 1 :(得分:2)

  

将基础对象转换为派生类

您无法投射对象,您只能投射参考。无论如何,对象都没有改变。

如果您创建Basenew Base),那就是您所拥有的一切。然后,您无法将引用称为Derived,因为不是 Derived,而是Base。 (这就是为什么你得到ClassCastException:在运行时,JVM检查你所指的是什么,以确保它真的可以这样引用。)

另一个方向有效:

Derived d = new Derived();
Base b = d;

...因为d引用的对象是DerivedDerived扩展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)

  1. ObjectOrientation的核心概念不是派生(或继承)而是抽象。这意味着:如果您希望所有派生类型(类)都具有操作'genName()',那么使类Base具有此功能是一个很好的核心思想。要为基于类Base的所有对象调用此方法,可以使用

    Base ref = (Base)anyDerivedObject; ref.getName();

这是一个垂头丧气。编译器检查是否可以进行向下转换。如果Base确实是基类,则永远不会抛出ClassCastException。

  1. ObjectOrientation的第二个基本属性是虚拟操作(方法)。这意味着派生类可以实现

@Override public String getValue() { return name + " foo"; }

请使用Java中的@Override批注,以提供明显且安全的编程风格。如果您调用

ref = getName(); 

如果“ ref”引用的对象是“ Derived”的实例,则调用Derived的派生操作。这是通过虚拟表分发表完成的,该表也存在于Java(通常从C ++已知)中。

  1. 上流是:

Derived ref2 = (Derived)ref;

在上面的示例之后,ref的类型为Base。 Java编译器检查'Derived'是否从'ref'的类型衍生自'Base'。如果不是这样,编译器将强制执行错误。但是,如果引用是相关的,则编译器将无法知道引用的对象是否正确。因此

Derived bar = (Derived) foo;
介绍示例中的

失败。所引用的对象不是Derived的instanceof。那只能在运行时检测,而不能在编译时检测。

  1. 请考虑Java中的所有变量都是引用,而不是对象本身(不包括7种基本类型int,short,char等)。 Java中的对象(实例)始终位于堆中,并且在操作中对其进行引用。这是Java用于安全编程的基本概念。在C ++中,可能存在难以发现的编程错误。到目前为止,此概念的计算时间开销不大。