1

以下代码:

class Base{}

class Agg extends Base{

   public String getFields(){
    String name="Agg";
    return name;
   }
}

public class Avf{
   public static void main(String args[]){
   Base a=new Agg();
   //please take a look here
   System.out.println(((Agg)a).getFields());  // why a needs cast to Agg? 

  }
}

我的问题是:为什么我们不能替换 ((Agg)a).getFields()a.getFields()?为什么我们需要 type cast on a?我提到它getFields()没有在 class 中定义Base,因此 classAgg没有从它的基类扩展这个方法。但是,如果我 getFields()在 class中定义了方法Base,例如:

class Base{
    public String getFields(){
        String name="This is from base getFields()";
        return name;
    }
}

一切都会好起来的。那么 ((Agg)a).getFields() 等价于 a.getFields()

在代码中

Base a=new Agg();    

这条线是否意味着a有引用Agg()并且可以直接调用class的方法Agg。但是,如果我不在getFields()类中定义方法,为什么会有区别Base?谁能给我解释一下?

4

5 回答 5

11

System.out.println(((Agg)a).getFields()); // why a needs cast to Agg?

因为Base没有一个名为getFields.

宣言

Base a;

...告诉编译器你在使用a. 然后分配给它并不重要,您必须分配的new Agg();接口仍然aBase. 并且由于Base没有getFields,尝试使用getFields是编译错误。

Base a=new Agg();

这条线是否意味着a有引用Agg()并且可以直接调用class的方法Agg

这意味着a 包含对对象的引用Agg,但该对象的接口由Base, not定义Agg,因此Agg如果它们不是由Base( 没有强制转换,并且强制转换是危险的,应该是尽可能避免)。

如果您的代码需要访问由 定义的方法或字段Agg,则应该声明变量(或参数,在我的示例中)Agg a,而不是Base a.

这是关于 OOP 的基本内容,尤其是 Java 中的 OOP 实现:对象的接口和对象的实现之间存在很大差异。在您的示例中,您知道Base a它确实是一个Agg,但请考虑一下:

void foo(Base a) {
    // Use `a` here...
}

// A long time later in a class far, far away...
xyz.foo(new Agg());

很明显,编译器不应该允许您使用a未定义的方法或字段Base。您的代码中的情况相同,只是不太明显。

于 2012-11-02T17:07:43.247 回答
2

我的问题是:为什么我们不能将 ((Agg)a).getFields() 替换为 a.getFields()?为什么我们需要在 a 上进行类型转换?

听起来你真的理解这一点 - 编译器不会在( )getFields的编译时类型上找到方法,因此它会引发编译时错误。aBase

这似乎是这个问题的真正胆量:

 Base a=new Agg();

这行是否意味着 a 具有 Agg() 的引用,并且 a 可以直接调用类 Agg 的方法。但是,如果我没有在 Base 类中定义方法 getFields(),为什么会有区别?谁能给我解释一下?

这意味着编译器将只允许您访问 的成员Base,因为这就是它知道可用的全部内容。如果有多个同名方法,则重载决议也适用于编译时类型。

但是,在执行时,您实际上是在类型对象上调用方法Agg- 因此,如果Agg 覆盖在 中声明的方法,则将使用Base该实现。Agg

基本上,您需要区分基于表达式的编译时类型在编译时做出的决策与基于对象的执行时类型在执行时(由 JVM)做出的决策值是指。

于 2012-11-02T17:12:25.460 回答
1

An instance of a Class has access to its methods (defined in the class definition) and methods of its superclass (ex. Object class). Therefore instance of Class Base with reference variable "a", can not access method getFields(). It's neither defined in its class structure or its super class. When you typecast like below:

((Agg)a)

You are basically changing changing the type from (Base) to type (Agg). Agg which is a subclass of Base, defines method getFields().

于 2012-11-02T17:25:05.470 回答
1

该行Base a=new Agg();表示
1 - 局部变量a属于类型 Base
2 - 有一个 Agg 类型的新对象
3 -a该对象的变量引用
对象和变量具有不同(但兼容)的类型。由于变量 a 具有 Base 类型,因此没有 a.getFields()
但是由于变量引用了 Agg 类的对象,因此您可以将其强制转换为 Agg 并访问 getFields
变量是(某种程度上类似于近似的)指向一个对象,而不是一个对象。

于 2012-11-02T17:16:53.867 回答
1

因为 typeAgg是更具体的Base. a您的声明中的类型是Base. 声明左侧的内容代表对象的类型。实际上a包含了 method getFields(),但是因为它是向上转型的,所以 method 被隐藏在了 type 中Base。我向您推荐HeadFirstJava书。它可以帮助您清除这些概念。

于 2012-11-02T17:17:20.207 回答