在Java中向上转换子类引用

在Java中向上转换子类引用,java,upcasting,Java,Upcasting,我正在做Bruce Eckel的《Java第四版思考》中的以下练习: 练习16:(2)创建一个名为两栖动物的类。由此继承一个名为Frog的类。在基类中放置适当的方法。在main()中,创建一只青蛙并将其向上投射到两栖动物,并演示所有方法仍然有效 Frog f=new Frog()之间的区别是什么和两栖动物f=新青蛙()在: class Amphibian { void go() { System.out.println("go"); } void stop() { System.

我正在做Bruce Eckel的《Java第四版思考》中的以下练习:

练习16:(2)创建一个名为两栖动物的类。由此继承一个名为Frog的类。在基类中放置适当的方法。在main()中,创建一只青蛙并将其向上投射到两栖动物,并演示所有方法仍然有效

Frog f=new Frog()之间的区别是什么
两栖动物f=新青蛙()在:

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();
    }
}

在这个简单的程序中,实际上没有区别。但是如果你有一个
两栖动物f
,它可以指任何两栖动物,而不仅仅是
青蛙
。您仍然使用
两栖动物
提供的所有方法,即使它是
青蛙

有关多态性的描述,请参阅。

这就是我们所知道的多态性。那是许多形状。同一物体的许多形状。正如你所了解的,同一个物体可以被称为青蛙,也可以被称为两栖动物。当引用为两栖类时,原始对象仍然是Frog,因此调用重写的方法

但是我不明白青蛙f=新青蛙()之间的区别是什么;两栖动物f=新蛙()

为了理解差异,让我们在
Frog
中添加另一个方法,该方法不在
两栖动物中

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
    }
}
底线<代码>青蛙
是一种
两栖动物
因此
青蛙
可以做
两栖动物
能做的任何事情<代码>两栖动物
不是
青蛙
所以
两栖动物
不能做
青蛙
能做的一切

当您说
两栖动物a=new Frog()
时,您正在编程一个接口(不是java接口,而是接口的一般含义)。当您说
Frog f=new Frog()
时,您正在编程实现

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

在main()中,创建一只青蛙并将其向上投射到两栖动物并演示 所有的方法仍然有效


我不认为你想问上溯有什么用,但既然标题已经被其他人编辑过,为什么不回答这个问题呢?向上转换在某些情况下很有用,例如显式调用重载方法的特殊形式。有关更多详细信息,请参见答案。

也请参见区别,您可以向Frog添加一个方法jump()(但不能将其添加到基类两栖动物:

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!
    }
}
这个很简单 如果你像下面这样使用

Frog f=new Frog();

然后,您不能将其强制转换为任何其他类型。但是,您可以调用所有
Frog
方法

但是如果你像下面这样使用

两栖动物f=新青蛙();

通过这样做,您仍然可以将对象更改为其他两栖动物,而无需更改其引用

f=newsomeother两栖动物();

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

青蛙f=新青蛙();
和两栖动物f=新青蛙();

从您的示例中,我们可以看到,
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视为类型
两栖动物
,并且在
两栖动物
类中没有方法
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.
Amphibian f = new Frog();
((Frog)f).croak(); //This will work.