我一直在阅读java中的接口。总的来说,我理解了这个概念,除了一个问题。在http://goo.gl/l5r69 (docs.oracle)中,在注释中写道,我们可以对接口和实现它的类进行类型强制转换。这就是
public interface Relatable {
public int isLargerThan (Relatable other) ;
}
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
// ...
// a method for computing the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect = (RectanglePlus) other;
if (this.getArea() < otherRect.getArea()) {
return -1;
} else if (this.getArea () > otherRect.getArea()) {
return 1;
} else {
return 0;
}
}
}
如何将otherRect(它是一个接口)强制转换为RectanglePlus。混淆的是,RectanglePlus是一个具有变量的类,这些变量不存在于otherRect中,otherRect是一个接口
我不得不承认,您展示的java文档中的示例非常糟糕,令人困惑。这很糟糕,因为它在层次结构中包含一个不安全的强制转换。向上强制转换(从实现类到接口/超类)总是安全的,但应尽可能避免向下强制转换。
理想情况下,Relatable
接口也应该包含getArea()
方法:
public interface Relatable {
public int isLargerThan(Relatable other);
public int getArea();
}
现在您不需要难看的强制类型,只需:
public int isLargerThan(Relatable other) {
if (this.getArea() < other.getArea()) {
return -1;
} else if (this.getArea () > other.getArea()) {
return 1;
} else {
return 0;
}
}
就足够了。我也认为isLargerThan(Relatable other)
是一个坏名字(更大的方面?)它应该是像hasBiggerArea(Relatable other)
这样的东西,这样它就解释了我们实际比较的东西(只有"更大"是相当流行的)。
你的界面与Comparable非常相似,(你确定Comparable不是你想要的吗?)所以也许你应该添加一个泛型:
public interface Relatable<T extends Relatable> {
public int isLargerThan(T t);
}
然后你的类将开始为:
public class RectanglePlus implements Relatable<RectanglePlus> {...
所以你的RectanglePlus实例将只与其他RectanglesPlus元素进行比较。
如果这不能满足你的需要,那么你必须选择当你比较两个不同的类时会发生什么:
public class RectanglePlus implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
public int getArea() {
return width * height;
}
public int isLargerThan(Relatable other) {
if (!(other instanceof RectanglePlus)) {
return 1; // I'm bigger than any other class!
}
RectanglePlus otherRect =(RectanglePlus)other;
return this.getArea() - otherRect.getArea();
}
}
或者,第三种选择,您可以在接口中添加另一个方法来获取对象的可测量的、可实现的值。然后,如果您使用的是Java 8,则可以向isLargerThan添加默认实现:
public interface Relatable<T extends Relatable> {
public default int isLargerThan(T t) {
return this.getRelatableValue - t.getRelatableValue();
}
public int getRelatableValue();
}
在方法声明public int isLargerThan(Relatable other){...}
中,参数other
被声明为对一个对象的引用,该对象的类实现了接口Relatable
。
在方法体中,表达式(RectanglePlus)other
表示检查对象是否属于RectanglePlus
类或该类的子类(如果不是,则抛出ClassCastException)。现在,RectanglePlus
是Relatable
,但反过来不一定是正确的;这里的强制转换确保other
将是RectanglePlus
;如果不是,则不会执行进一步的指令,因为会抛出异常。
如果T2是C类或T2==C的超类或超接口,则可以将存储在T1类型变量(接口或类)中的任何C类对象类型强制转换为T2类型变量,否则将抛出ClassCastException。
所以在你的情况下,如果对象obj类Foo实现了Relatable传递给isLargerThan方法,那么它将抛出ClassCastException,因为obj的类Foo不是RectanglePlus的超类。
在其他答案中没有涉及的一个方面是,Oracle文档中的示例有一个明显的问题:如果Relatable
只意味着类似于Comparable
,那么需要对形状进行专门化,以避免isLargerThan
方法中的强制转换。例如,可能有一个名为RelatableShape
的接口,它本身扩展了Relatable
,并提供了getArea()
方法。然后,你可以有Circle
, Hexagon
, Rectangle
等实现RelatableShape
(与isLargerThan
和getArea
的接口)的类,并且isLargerThan()
方法不需要将其参数强制转换为特定的具体类(因为参数可以保证实现RelatableShape
,并且getArea()
将始终可用)。
你的方法很简单
public int isLargerThan(Relatable other)
只是请求实现Relatable的实参。它可以是实现Relatable的任何类的对象。只要有像
这样的东西public class SomeName implements Relatable { /* Implementation */ }
在类的中,可以将该类的对象视为Relatable。
但这并不意味着这些对象不是它们自己的类型。如果您有以下类
public class Square implements Relatable {
public int isLargerThan(Relatable other) {
// Implementation
}
// Square specific implementation
}
和
public class Rectangle implements Relatable {
public int isLargerThan(Relatable other) {
// implmentation
}
// Rectangle specific implemenation
}
可以这样调用接口方法:
/* ... */
public static int check(Relatable a, Relatable b) {
return a.isLargerThan(b);
}
/* ... */
Square s = new Square();
Rectangle r = new Rectangle();
System.out.println("Check: " + check(s, r));
注意:因为几个不同的类可以实现Relatable,所以必须检查isLargerThan的实参类型,否则会遇到类型强制转换异常。
也许你可以在Relatable
中指定这样的内容public int getSize();
你可以这样写你的isLargeThan方法:
public int isLargerThan(Relatable other) {
if (this.getSize() < other.getSize())
return -1;
else if (this.getSize() > other.getSize())
return 1;
else
return 0;
}