简体   繁体   English

Java:介面

[英]Java: Interface

I have been reading about interface in java. 我一直在阅读有关Java接口的信息。 Overall I understood the concept except one problem. 总的来说,我理解这个概念,除了一个问题。 In http://goo.gl/l5r69 (docs.oracle), in the note it is written that we can type cast an interface and a class implementing it. http://goo.gl/l5r69(docs.oracle )中,在笔记中写道,我们可以类型转换接口和实现该接口的类。 That is 那是

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

How can otherRect (which is a interface) be casted to a RectanglePlus. 如何将otherRect(这是一个接口)强制转换为RectanglePlus。 The confusion is, RectanglePlus is a class having variables, which are not present in the otherRect which is an interface 令人困惑的是,RectanglePlus是具有变量的 ,该变量在作为接口的otherRect中不存在

Your interface is pretty similar to Comparable , (Are you sure Comparable isn't what your looking for?) so maybe you should add a generic to it: 您的界面非常类似于Comparable ,(您确定Comparable并不是您想要的吗?),所以也许您应该向其添加通用名称:

public interface Relatable<T extends Relatable> {

    public int isLargerThan(T t);
}

And then your class will start as: 然后您的课程将开始为:

 public class RectanglePlus implements Relatable<RectanglePlus> {...

So your RectanglePlus instance will be compared with other RectanglesPlus elements only. 因此,您的RectanglePlus实例将仅与其他RectanglesPlus元素进行比较。

If this does not suit what you need, then you have to choose what will happen when you are comparing two different classes: 如果这不符合您的需求,那么您必须选择在比较两个不同的类时将发生的情况:

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

Or, a third option, you can add another method to your interface to obtain the measureable, realatable value of an object. 或者,第三个选择是,您可以在界面中添加另一种方法以获得对象的可测量且可实现的值。 Then you could add a default implementation to isLargerThan, if you are using Java 8: 然后,如果您使用的是Java 8,则可以向isLargerThan添加默认实现:

public interface Relatable<T extends Relatable> {

    public default int isLargerThan(T t) {
        return this.getRelatableValue - t.getRelatableValue();
    }

    public int getRelatableValue();

}

I have to admit that the example in the java doc you showed is simply bad and confusing. 我必须承认,您显示的Java文档中的示例简直是糟糕且令人困惑。 It's bad because it contains an unsafe cast down the hierarchy . 这很糟糕,因为它包含不安全的层次结构 It is always safe to cast up (from implementing class to interface/superclass), but casting down should be avoided when possible. 强制转换(从实现类到接口/超类)始终是安全的,但应尽可能避免强制转换。

Ideally, the Relatable interface should also contain getArea() method: 理想情况下, Relatable接口还应该包含getArea()方法:

public interface Relatable { 
    public int isLargerThan(Relatable other);
    public int getArea();
}

Now you don't need the ugly cast, simply: 现在,您不需要丑陋的演员表,只需:

public int isLargerThan(Relatable other) { 
    if (this.getArea() < other.getArea()) { 
        return -1; 
    } else if (this.getArea () > other.getArea()) { 
        return 1; 
    } else {
        return 0;
    }
}

is enough. 足够。 I also think that isLargerThan(Relatable other) is a bad name (larger in terms of what?). 我还认为isLargerThan(Relatable other)是一个不好的名字(就什么而言更大)。 It should probably be something like hasBiggerArea(Relatable other) so that it explains what we are actually comparing (only "larger" is rather vogue). 它可能应该类似于hasBiggerArea(Relatable other)类的东西,以便它解释我们实际上正在比较的内容(只有“较大”才是比较时尚的)。

In the method declaration public int isLargerThan(Relatable other){...} the parameter other is declared to be a reference to an object whose class implements the interface Relatable . 在方法声明public int isLargerThan(Relatable other){...} ,参数other被声明为对该对象的引用,该对象的类实现了Relatable接口。

In the method body, the expression (RectanglePlus)other means to check that the object is of class RectanglePlus or a subclass of that (and throw a ClassCastException if it isn't). 在方法主体中,表达式(RectanglePlus)other表示检查对象是否为RectanglePlus类或该类的子类(如果不是,则抛出ClassCastException)。 Now, a RectanglePlus is Relatable , but the inverse isn't necessarily true; 现在,一个RectanglePlusRelatable ,但是逆不一定成立。 the cast here ensures that other will either be RectanglePlus ; 此处的转换确保other将是RectanglePlus ; if it's not further instructions will not be executed because an exception will have been thrown. 如果不是这样,将不会执行进一步的指令,因为将引发异常。

We can type cast any object(of class C) stored in a variable of type T1 (interface or class) into a variable of type T2 if T2 is a super class or super interface of class C or T2==C otherwise a ClassCastException will be thrown. 如果T2是类C的超类或T2 == C的超级接口,我们可以将类型T1的变量(接口或类)中存储的任何对象(类C)转换为类型T2的变量,否则ClassCastException被抛出。

So in your case if an object obj of class Foo implements Relatable is passed to isLargerThan method then it will throw ClassCastException , because obj's class Foo is not a super class of RectanglePlus . 因此,在您的情况下,如果将Foo实现Relatable的对象obj传递给isLargerThan方法,则它将抛出ClassCastException ,因为obj的 Foo类不是RectanglePlus的超类。

One aspect that hasn't been touched on in other answers is the fact that the example in the Oracle docs has a clear problem: if Relatable is only meant to be analogous to Comparable , then there needs to be a specialization for shapes in order to avoid the cast in the isLargerThan method. 在其他答案中没有涉及的一个方面是Oracle文档中的示例存在一个明显的问题:如果Relatable仅旨在类似于Comparable ,则需要对形状进行专门化处理,以便避免在isLargerThan方法中进行isLargerThan Perhaps, for example, an interface called RelatableShape , which itself extends Relatable , and provides for the getArea() method. 例如,也许有一个名为RelatableShape的接口,该接口本身扩展了Relatable ,并提供了getArea()方法。 Then, you could have Circle , Hexagon , Rectangle , etc. classes that implement RelatableShape (the interface with isLargerThan and getArea ), and the isLargerThan() method would not need to cast its argument to a particular concrete class (since the parameter could be guaranteed to implement RelatableShape , and getArea() would always be available). 然后,您可以具有实现RelatableShape (具有isLargerThangetArea的接口)的CircleHexagonRectangle等类,并且isLargerThan()方法无需将其参数isLargerThan()转换为特定的具体类(因为该参数可以是保证实现RelatableShape ,并且getArea()将始终可用)。

Thus, though the Oracle documentation is showing something that is valid Java , it's also showing something that's necessary because of a bad design . 因此,尽管Oracle文档显示的是Java的有效内容 ,但由于设计不良 ,它也显示了必要的内容。 Keep that in mind. 记住这一点。 Casting is almost never necessary in real code. 在实际代码中,铸造几乎从来没有必要。

It's rather simple your mehtod 你的方法很简单

public int isLargerThan(Relatable other)

just asks for an argument that implements Relatable. 只是要求一个实现Relatable的参数。 It could be an object of any class that implements Relatable. 它可以是实现Relatable的任何类的对象。 As long as there is something like 只要有类似的东西

public class SomeName implements Relatable { /* Implementation */ }

in the class, you can treat objects of that class as Relatable. 在类中,您可以将该类的对象视为可关联对象。

But that does not mean that these objects are not of their own type. 但这并不意味着这些对象不是自己的类型。 If you have the following classes 如果您有以下课程

public class Square implements Relatable {
  public int isLargerThan(Relatable other) {
    // Implementation
  }

  // Square specific implementation
}

and

public class Rectangle implements Relatable {
  public int isLargerThan(Relatable other) {
    // implmentation
  }

  // Rectangle specific implemenation
}

you can call the interface methods like this: 您可以像这样调用接口方法:

/* ... */

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

ATTENTION: Because several different classes can implement Relatable you have to check the type of the argument to isLargerThan, otherwise you run into type cast exceptions. 注意:因为几个不同的类可以实现Relatable,所以必须检查isLargerThan的参数类型,否则会遇到类型转换异常。

Maybe you can specify something like this in Relatable 也许您可以在Relatable中指定类似的内容

public int getSize();

Than you could write your isLargeThan method like this: 比您可以像这样编写isLargeThan方法:

public int isLargerThan(Relatable other) {

    if (this.getSize() < other.getSize())
        return -1;
    else if (this.getSize() > other.getSize())
        return 1;
    else
        return 0;               
}

Then there would be no need for a type cast. 这样就不需要类型转换了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM