在接口和类之间进行转换 [英] Casting between Interfaces and Classes

查看:99
本文介绍了在接口和类之间进行转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

昨天我刚刚开始学习接口并且做了一些简单的例子,我注意到我在理解类和接口之间的转换时遇到了很多麻烦所以我读了 Java Cast Interface to Class 以及接口Oracle Java教程

Yesterday I just started learning interfaces and have been doing some simple examples, I noticed that I have had lots of trouble understanding casting between classes and interfaces so I read Java Cast Interface to Class as well as Interfaces Oracle Java Tutorials

然而当我的书在底部给出一个小的评论问题时,我注意到我仍然并没有完全理解,我买的那本书有解决方案。以下是问题(我给出了我的尝试和推理,这对某些人来说可能是错误的,所以任何帮助都是好的!)

However when my book gave a small review question at the bottom, I noticed that I still didn't really understand completely, and the book I bought doesent have solutions. The following is the question ( I gave my attempt and reasoning which is probably wrong for some, so any help is good!)


假设class Sandwich实现了Edible接口,你给
赋予变量声明

Suppose the class Sandwich implements the Edible interface, and you are given the variable declarations



Sandwich sub = new Sandwich();

Rectangle cerealBox = new Rectangle(5, 10, 20, 30); 

Edible e = null;




以下哪项赋值语句合法?

Which of the following assignment statements are legal?




  1. e = sub;

由于Sandwich类实现了接口 Edible ,这没问题。我们可以说 e = sub 没有问题。 有效

Since the Sandwich class implements the interface Edible, this is no problem. We can say e = sub with no issues. It Works

sub = e;

因为我们试图将 Sandwitch 类中的对象 sub 更改为接口类型,如果没有强制转换,我们无法做到这一点。 无法使用

Since we are trying to change our object sub in the Sandwitch class to an interface type, we can't do this without casting. It won't work

sub =(三明治)e

作品!这解决了我们的旧问题

Works! This fixes our old problem

sub =(三明治)cerealBox;

我不知道..但它应该工作? cerealBox 是一个 Rectangle 所以使用(三明治)我们将其转换为 sub ,这是<$ c的一部分$ c>三明治

I have no clue.. but it should work? cerealBox is a Rectangle so with (Sandwich) we convert it to sub, which is part of Sandwich

e = cerealBox;

不要这么认为。 Rectangle 未实现 Edible 界面,因此不能工作

Don't think so. Rectangle isn't implemented the Edible interface so it shouldnt work

e =(Edible)cerealBox;

应<强大>工作现在。 (可食用)就像它实现了接口一样。

Should work now. (Edible) acts as if it implements the interface.

e =(Rectangle)cerealBox;

不确定。我不认为这会起作用,我的意思是 cerealBox 的类型为Rectangle,为什么我们将它设为矩形再次?

Not sure. I don't think this will work, I mean cerealBox is of type Rectangle, why are we making it a rectangle again?

e =(Rectangle)null;

根本不确定


推荐答案

您需要了解的是每个对象都有一个具体的类。它是该类的一个实例,它是类继承的每个类的实例,所有同时。不仅如此,它是每个接口的实例这些类中的任何一个继承,所有同时

What you need to understand is that every object has one concrete class. It "is" an instance of that class, and it "is" an instance of every class that class inherits, all at the same time. Not only that but it "is" an instance of every interface any of those classes inherit, all at the same time.

所以,假设:

 class Animal
 class Mammal extends Animal implements Suckler
 class Dog extends Mammal implements Woofer

...如果我创建新狗() 然后该对象是对象(因为所有对象都继承 Object ), Animal Mammal Suckler 低音单元同时

... if I create a new Dog() then that object "is" an Object (because all objects inherit Object), an Animal, a Mammal, a Suckler, a Dog and a Woofer, all at the same time.

但是,变量与对象不同。变量指向对象,变量具有类型。该类型必须与指定的对象兼容,但这就是全部。

However, a variable is not the same thing as an object. A variable points at an object, and a variable has a type. The type must be compatible with the object assigned, but that's all.

所以:

Suckler s = new Dog();

有效,但从那一刻开始,所有编译器都知道对象通过 s 变量 Suckler 。它不知道它是一只狗;它不知道它是哺乳动物。所以我们不能再去了:

works, but from that moment on, all the compiler knows about the object via the s variable is that it's a Suckler. It doesn't know it's a dog; it doesn't know it's a mammal. So we cannot then go:

Dog d = s;

...因为编译器无法保证 s 是 Dog

... because the compiler can't guarantee that the variable pointed to by s is a Dog.

变量的类型永远无法改变。无论如何, s 的整个生命周期都有 Suckler 。我们可以将 Sheep Pig 分配给 s ,但除了属于 Suckler 定义的操作外,我们将无法做任何。

The type of the variable cannot ever be changed. s has type Suckler for the whole of its lifetime, no matter what. We could assign a Sheep or a Pig to s, but we won't be able to do anything to those objects except operations that are part of the Suckler definition.

我将假设各种类和接口的定义如下:

I'm going to assume that the various classes and interfaces are defined like this:

 public interface Edible {
     ...
 }

 public class Sandwich implements Edible {
     ...
 }

 public class Rectangle {  // note, does not implement or extend anything
                           // (except Object)
     ...
 }

所以:

Sandwich sub = new Sandwich();
Edible e = null;
e = sub;

这很好。 sub 三明治三明治是一种 Edible

This is fine. sub is a Sandwich, and Sandwich is a kind of Edible.

Sandwich sub = new Sandwich();
Edible e = null;
sub = e;

这不会编译。 e 是一个 Edible ,但可能有任意数量的类实现 Edible ,以及三明治 sub 必须是三明治,因为编译器无法确定 e 是一个三明治,它将拒绝编译。

This won't compile. e is an Edible, but there could be any number of classes that implement Edible, as well as Sandwich. sub has to be a Sandwich and since the compiler can't be sure that e is a sandwich, it will refuse to compile.

Sandwich sub = new Sandwich();
Edible e = null;
sub = (Sandwich) e;

这是有效的。正如你已经正确解决的那样,演员告诉编译器好的,你不能确定 e 三明治,但作为编码员,我告诉你它是。

This works. As you've correctly worked out, the cast tells the compiler "OK, you can't be sure that e is a Sandwich, but as the coder, I'm telling you it is.

如果你这样做,并且在运行时 e 实际上是 Apple实现Edible ,而不是 Sandwich ,JRE会抛出 ClassCastException 。确保不会发生这种情况是你的工作 - 避免投射是最好的方法。

If you did this, and at runtime e was actually an Apple implements Edible, and not a Sandwich, the JRE would throw a ClassCastException. It's your job to make sure this doesn't happen -- avoiding casting is the best way to do this.

Sandwich sub = new Sandwich();
Rectangle cerealBox = new Rectangle(5, 10, 20, 30); 
sub = (Sandwich) cerealBox;

...将拒绝编译。三明治 Rectangle 彼此无关。编译器知道没有三明治也是一个 Rectangle ,所以它拒绝编译。

... will refuse to compile. Sandwich and Rectangle are not related to one another. The compiler knows that no Sandwich is also a Rectangle, so it refuses to compile.

变量 sub 必须始终指向三明治 cerealBox 必须始终指向 Rectangle Rectangle 的唯一方法是三明治,如果 Rectangle 继承三明治,反之亦然。由于这两种情况都不是这样,所以不会编译。

The variable sub must always point to a Sandwich, and cerealBox must always point to a Rectangle. The only way a Rectangle could be a Sandwich is if Rectangle inherited Sandwich, or vice versa. Since neither of these is the case, it won't compile.

这是假设上面的声明。一个类可以实现多个接口,所以如果它是公共类Sandwich实现Edible,Rectangle {...} ,这个代码就可以工作。

This is assuming the declarations above. It's possible for a class to implement multiple interfaces, so if it was public class Sandwich implements Edible, Rectangle {...}, this code would work.

Rectangle cerealBox = new Rectangle(5, 10, 20, 30); 
Edible e = null;
e = cerealBox;

...将无法编译。 矩形不是可食用

... will not compile. A Rectangle is not an Edible.

Rectangle cerealBox = new Rectangle(5, 10, 20, 30); 
Edible e = null;
e = (Edible) cerealBox;

..乍一看,你可能认为不会编译。 Rectangle 不是 Edible ,你无法告诉编译器它。但是编译器无法保证不存在这样的类:

.. at first glance, you might think will not compile. A Rectangle is not an Edible, and you can't tell the compiler it is. However the compiler can't guarantee that there isn't a class like this:

public class Flapjack extends Rectangle implements Edible { ... }

A Flapjack 将是一个一种 Rectangle ,它也是 Edible ,因为编译器不够聪明,不知道 cerealBox 不是 Flapjack ,它必须编译(它将在运行时失败)。

A Flapjack would be a kind of Rectangle that is also an Edible, and since the compiler isn't clever enough to know that cerealBox is not a Flapjack, it must compile (it will fail in runtime).

一个非常聪明的编译器可能能够分析程序逻辑,看看 cerealBox 已被初始化为 new Rectangle(),并且没有机会在运行时更改。但Java标准没有那种复杂的静态分析。

A really clever compiler might be able to analyse the program logic to see that cerealBox has been initialised as new Rectangle(), and that there has been no opportunity for that to change at runtime. But the Java standard does not have that kind of sophisticated static analysis.

Rectangle 的作者可以确保 Square 不能存在,通过将其定义为 public final class Rectangle - final keyword禁止子类。

The writer of Rectangle could ensure that Square can't exist, by defining it as public final class Rectangle -- the final keyword forbids subclasses.

Rectangle cerealBox = new Rectangle(5, 10, 20, 30); 
Edible e = null;
e = (Rectangle) cerealBox;

...将无法编译。 e 仍然是 Edible 。你不能为它指定一个 Rectangle ,因为 Edible Rectangle 不相关。

... won't compile. e is still an Edible. You can't assign a Rectangle to it, because Edible and Rectangle are not related.

Edible e = null;
e = (Rectangle) null;

将null转换为 Rectangle 很好,但是 e 是一个 Edible ,你不能分配一个 Rectangle Edible ,因为它们是不相关的类型。

Casting null to a Rectangle is fine, however e is an Edible, and you can't assign a Rectangle to an Edible, since they are unrelated types.

这篇关于在接口和类之间进行转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆