在Java中向上转换子类引用

时间:2015-06-18 11:35:23

标签: java upcasting

我正在Bruce Eckel的 Thinking in Java 4th Edition 中进行以下练习:

  

练习16:(2)创建一个名为Amphibian的类。从此,继承一个名为Frog的类。在基类中放置适当的方法。在main()中,创建一个Frog并将其向上转换为Amphibian并演示所有方法仍然有效。

Frog f = new Frog();Amphibian f = new Frog();之间有什么区别:

class Amphibian {
    void go() { System.out.println("go"); }
    void stop() { System.out.println("stop!"); }
}

class Frog extends Amphibian {
    void go() { System.out.println("not go"); }
}

public class EFrog {
    public static void main(String[] args) {
        Frog f = new Frog();
        f.go();
    }
}

6 个答案:

答案 0 :(得分:3)

  

但我不明白Frog f = new Frog()之间有什么区别;和两栖动物f =新青蛙();

为了理解差异,让我们在Frog中添加另一个不在Amphibian

的方法
class Frog extends Amphibian {
    void go() { System.out.println("not go"); }
    void come() { System.out.println("come"); }
}

现在让我们看一下有什么区别:

public class EFrog {
    public static void main(String[] args) {
        Frog f = new Frog();
        f.go();
        f.come();
        Amphibian a = f;
        a.come();//this won't compile
    }
}

底线。 FrogAmphibian,因此Frog可以执行Amphibian所能做的任何事情。 Amphibian不是Frog,因此Amphibian无法完成Frog所能做的所有事情。

当你说Amphibian a = new Frog()时,你正在编程接口(不是java接口,而是接口的一般含义)。当你说Frog f = new Frog()时,你正在为一个实现编程。

现在回答这本书要求你尝试的实际问题:

  

在main()中,创建一个Frog并将其向上播放给两栖动物并进行演示   所有方法仍然有效。

public class EFrog {
        public static void main(String[] args) {
            Frog f = new Frog();
            Amphibian g = (Amphibian)f;//this is an upcast
            g.go(); //okay since Amphibian can go
            g.come();//not okay since Amphibian can't come                
        }
    }

我认为你不打算问使用预告有什么用途,但由于标题已被其他人编辑过,为什么不回答呢?在某些情况下,向上转换非常有用,例如显式调用重载方法的特殊形式。有关其他详细信息,请参阅this答案。

答案 1 :(得分:1)

在这个简单的程序中,实际上没有区别。但是如果你有Amphibian f,它可以引用任何两栖动物,而不仅仅是Frog。您仍然使用Amphibian提供的所有方法,即使它是Frog的实例 有关多态性的描述,请参阅What is polymorphism, what is it for, and how is it used?

答案 2 :(得分:1)

  

Frog f = new Frog();Amphibian f = new Frog();

之间有何区别?

从您的示例中我们可以看到Frog继承了Amphibian。因此,任何声明类型为Amphibian的变量都可以始终存储在您的案例Amphibian中具有超级类Frog的对象的实例。至于示例代码,它没有区别。

但是在你的例子中找不到两者之间的细微差别。请考虑以下事项:

class Frog extends Amphibian {
    void go() { System.out.println("not go"); }
    void croak(){ System.out.println("croak");} //Added this extra line
}

现在,如果您将Frog实例存储为

Amphibian f = new Frog();
f.croak(); //This will not work.

这不起作用,因为JVM将f视为类型Amphibian,而Amphibian类中没有方法croak。所以会抛出一个错误。但如果你把它存储起来:

Frog f = new Frog();
f.croak(); //This will work.

这是有效的,因为JVM将f视为类型Frog,而类Frog认为方法为croak

当然,您可以通过将f转换为Frog的类型来使之前的案例工作为:

Amphibian f = new Frog();
((Frog)f).croak(); //This will work.

答案 3 :(得分:0)

这就是我们所知的多态性。那是很多形状。许多形状的同一物体。正如您所了解的那样,同一个对象可以称为Frog,它可以被称为两栖动物。当引用为两栖动物时,原始对象仍然是Frog,因此调用被覆盖的方法。

答案 4 :(得分:0)

看到差异,你可以将一个方法jump()添加到Frog(但不能添加到基类Amphibian:

class Amphibian {
    void go() { System.out.println("go"); }
    void stop() { System.out.println("stop!"); }
}

class Frog extends Amphibian {
    void go() { System.out.println("not go"); }
    void jump() { System.out.println("jump!"); }
}

public class EFrog {
    public static void main(String[] args) {
        Frog f = new Frog();
        f.go();
        f.jump(); // works
        Amphibian a = new Frog();
        a.jump(); // will not compile!
    }
}

答案 5 :(得分:0)

这个很简单 如果您使用如下

Frog f = new Frog();

然后你不能把它投射到任何其他类型。但是,您可以调用所有Frog方法。

但如果您使用如下

Amphibian f = new Frog();

你仍然可以通过简单的方式将对象更改为其他两栖动物而不改变它的参考。

f = new SomeOtherAmphibian();

这种编码方式非常流行,称为编码基类或接口