Java: Interface



我一直在阅读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)。现在,RectanglePlusRelatable,但反过来不一定是正确的;这里的强制转换确保other将是RectanglePlus;如果不是,则不会执行进一步的指令,因为会抛出异常。

如果T2是C类或T2==C的超类或超接口,则可以将存储在T1类型变量(接口或类)中的任何C类对象类型强制转换为T2类型变量,否则将抛出ClassCastException。

所以在你的情况下,如果对象objFoo实现了Relatable传递给isLargerThan方法,那么它将抛出ClassCastException,因为obj的Foo不是RectanglePlus的超类。

在其他答案中没有涉及的一个方面是,Oracle文档中的示例有一个明显的问题:如果Relatable只意味着类似于Comparable,那么需要对形状进行专门化,以避免isLargerThan方法中的强制转换。例如,可能有一个名为RelatableShape的接口,它本身扩展了Relatable,并提供了getArea()方法。然后,你可以有Circle, Hexagon, Rectangle等实现RelatableShape(与isLargerThangetArea的接口)的类,并且isLargerThan()方法不需要将其参数强制转换为特定的具体类(因为参数可以保证实现RelatableShape,并且getArea()将始终可用)。

因此,尽管Oracle文档显示了一些有效的Java,但由于糟糕的设计,它也显示了一些必要的东西。记住这一点。在实际代码中几乎不需要强制转换。

你的方法很简单

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

最新更新