简体   繁体   English

当我们要重写方法时,为什么要使用接口?

[英]Why do we use interfaces when we are going to override the method anyway?

Here we're importing Comparator because the class SizeComparator implements Comparator... - Why not leave out the implements part of comparator if all we want is the compare method, which we are overriding anyway?在这里我们导入 Comparator 因为 class SizeComparator 实现了 Comparator... - 如果我们想要的只是比较方法,为什么不省略比较器的实现部分,无论如何我们都将覆盖它? Since we're overriding it why even type in the code that we want to implement the interface?既然我们要重写它,为什么还要输入我们想要实现接口的代码呢?

I think what you're implying is the effective difference between nominal typing and structural typing.认为你的意思是名义打字和结构打字之间的有效区别。

Structural typing is like this:结构类型是这样的:

  • If variable x is an object whose definition so happens to have a method named compare , please invoke it.如果变量x是一个 object ,其定义恰好有一个名为compare的方法,请调用它。 Otherwise throw something or fail to compile.否则抛出一些东西或编译失败。

Nominal typing is like this:标称类型是这样的:

  • Variable x has a type.变量x有一个类型。 If that type has a method named compare , invoke it.如果该类型有一个名为compare的方法,则调用它。 If x is not that type, or x is but that type does not have a method named compare , throw something, or fail to compile.如果x不是那个类型,或者 x 是,但是那个类型没有一个名为compare的方法,抛出一些东西,或者编译失败。

Java is nominally typed: You can't just go: "I want to call the compare method on this object". Java 名义上是键入:你不能只是 go:“我想在这个对象上调用compare方法”。 No, the object needs to be of a known type that has a compare method.不,object 需要是具有比较方法的已知类型。 It's a 2step process: First java checks what the type of some expression is, and then you get to write method calls to methods that this type is declared to have.这是一个两步过程:首先 java 检查某个表达式的类型是什么,然后您可以编写对声明该类型的方法的方法调用。 What the actual object's actual type is, is immaterial.实际对象的实际类型是什么,无关紧要。 Trivial example:简单的例子:

Object o = new ArrayList<String>();
o.add("Hello");

does not compile - because the compiler notices o.不编译 - 因为编译器注意到o. , checks the type of the o expression, finds that it is java.lang.Object , checks what jlObject 's API exposes, notices that there is no add(String) method in there, and fails to compile. , checks the type of the o expression, finds that it is java.lang.Object , checks what jlObject 's API exposes, notices that there is no add(String) method in there, and fails to compile. Even though at runtime it would have worked .即使在运行时它会起作用 Because o-the-variable is pointing at an object whose real type is something that does have an add method.因为 o-the-variable 指向一个 object ,其实际类型具有add方法的东西。

The reason that nominal typing is good goes deep, and certainly not all programming languages work that way.名义类型很好的原因很深,当然不是所有的编程语言都这样工作。 It has advantages and disadvantages.它有优点和缺点。 For just one simple reason why structural typing can be a bit dangerous, imagine these two classes:仅出于结构类型可能有点危险的一个简单原因,想象一下这两个类:

class Camera {
  void shoot(Person p) {}
}

class Gun {
  void shoot(Person p) {}
}

Hopefully that helps you see how structural typing could get problematic.希望这可以帮助您了解结构类型是如何出现问题的。 Names are useful.名字很有用。 Namespaced names are far more useful - they avoid 'name squatting', where somebody who wrote a camera class thought they could claim the name 'shoot' as did someone writing a gun class.命名空间名称更有用 - 它们避免了“名称抢注”,其中编写相机 class 的人认为他们可以像编写枪 class 的人一样声称他们可以使用名称“射击”。 This problem goes away if the language is fundamentally designed that all methods have a complete name, and that name is com.martinhavens.Gun.shoot .如果该语言从根本上设计为所有方法都有一个完整的名称,并且该名称是com.martinhavens.Gun.shoot ,那么这个问题就会消失。 Now there is no way to accidentally blow your face off if all you wanted to do, was make a selfie.如果你想做的只是自拍,现在没有办法不小心把你的脸吹掉。

In your specific example it is perhaps possible for the system to work without it, given that SizeComparator itself also defines it, but programming is an exercise in abstraction.在您的具体示例中,系统可能在没有它的情况下工作,因为 SizeComparator 本身也定义了它,但编程是一种抽象练习。 For example, java's built in java.util.TreeSet class builds a tree set: It can store objects, automatically promises you that it only ever contains 1 of a given value (never duplicates), and it automatically sorts itself.例如,java 内置的java.util.TreeSet class 构建了一个树集:它可以存储对象,自动向您保证它只包含给定值的 1(从不重复),并且它会自动对自身进行排序。 It does this by making a tree structure.它通过创建树结构来做到这一点。 To make such a class, you need to provide - A comparator .要制作这样的 class,您需要提供-A 比较器 Obviously, the authors of java-the-core-library cannot know that you have written your own class named SizeComparator .显然,java-the-core-library 的作者不知道您已经编写了自己的 class,名为SizeComparator Hence, only 3 options:因此,只有 3 个选项:

  • They hardcode every name of every comparison type anybody ever makes for the rest of eternity.他们对任何人为永恒的 rest 所做的每种比较类型的每个名称进行硬编码。
  • They use structural typing: It doesn't matter what you pass to the constructor of TreeSet , as long as it is something that has a compare(T a, T b) method.他们使用结构类型:传递给TreeSet的构造函数的内容并不重要,只要它具有compare(T a, T b)方法即可。 Possible, but java is not like that, and there are advantages to this - see above.可能,但 java 不是那样的,这有好处 - 见上文。
  • The authors of TreeSet also publish a type that describes what "code capable of comparing things in the way TreeSet needs to do its job", and then any code anybody else writes with the intention of feeding it to TreeSet's constructor must indicate they are an implementation of this. TreeSet的作者还发布了一种类型,该类型描述了“能够以 TreeSet 完成其工作的方式比较事物的代码”,然后任何其他人编写的意图将其提供给 TreeSet 的构造函数的任何代码都必须表明它们是一个实现这个的。 Which is exactly how java works.这正是 java 的工作原理。

暂无
暂无

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

相关问题 如果只声明方法签名,为什么我们需要接口? - Why do we need interfaces if it only declares the method signature? JPA的单元测试用例值得吗? 无论如何,只是要访问数据库,为什么我们需要它? - Are the unit test case for JPA worthy? anyway it is just going to access DB, why do we need it? 为什么我们必须覆盖 Java 中的 equals() 方法? - Why do we have to override the equals() method in Java? 为什么我们使用Java中的clone()方法? - Why do we use the clone() method in Java? 我们可以在实现接口时有一个“不覆盖具体方法......”编译时错误吗? - Can we have a “not override a concrete method …” compile time error when implementing interfaces? 为什么我们需要Java中的接口? - Why do we need interfaces in Java? 当我们重写一个方法时,我们应该使用方法签名中的所有参数吗? - When we override a method we should use all the parameters that are in the method signature? 为什么在从Interface实现方法时使用@Override? 它真的覆盖方法吗? - Why we use @Override while implementing a method from Interface ? Does it really Override the method? 当我们要使用Spring @ModelAttribute时,我们是否需要为http get和post使用类似的@RequestMapping值? - Do we need similar @RequestMapping value for both http get and post when we are going to use Spring @ModelAttribute 无论如何,我们为什么要检查哈希值呢? - Why do we check hash if we are going to check equals anyways?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM