为什么要声明一个接口,然后在 Java 中用它实例化一个对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7716435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why would you declare an Interface and then instantiate an object with it in Java?
提问by bot_bot
A friend and I are studying Java. We were looking at interfaces today and we got into a bit of an discussion about how interfaces are used.
我和一个朋友正在学习 Java。我们今天正在研究接口,我们就如何使用接口进行了一些讨论。
The example code my friend showed me contained this:
我朋友给我看的示例代码包含以下内容:
IVehicle modeOfTransport1 = new Car();
IVehicle modeOfTransport2 = new Bike();
Where IVehicleis an interface that's implemented in both the car and bike classes. When defining a method that accepts IVehicleas a parameter you can use the interface methods, and when you run the code the above objects work as normal. However, this works perfectly fine when declaring the car and bike as you normally would like this:
其中IVehicle是在汽车和自行车类中实现的接口。当定义一个接受IVehicle作为参数的方法时,你可以使用接口方法,当你运行代码时,上述对象正常工作。但是,这在声明汽车和自行车时非常有效,就像您通常希望的那样:
Car modeOfTransport1 = new Car();
Bike modeOfTransport2 = new Bike();
So, my question is - why would you use the former method over the latter when declaring and instantiating the modeOfTransportobjects? Does it matter?
所以,我的问题是 - 在声明和实例化modeOfTransport对象时,为什么要使用前一种方法而不是后一种方法?有关系吗?
采纳答案by Larry Watanabe
It doesn't matter there.
在那里没关系。
Where it really matters is in other interfaces that need to operate on IVehicle. If they accept parameters and return values as IVehicle, then the code will be more easily extendible.
真正重要的是需要在 IVehicle 上运行的其他接口。如果他们接受参数并返回值作为 IVehicle,那么代码将更容易扩展。
As you noted, either of these objects can be passed to a method that accepts IVehicle as a parameter.
正如您所指出的,这些对象中的任何一个都可以传递给接受 IVehicle 作为参数的方法。
If you had subsequent code that used Car or Bike specific operations that were used, then it would be advantageous to declare them as Car or Bike. The Car and Bike specific operations would be available for each of the relevant objects, and both would be usable (i.e. could be passed) as IVehicle.
如果您有使用 Car 或 Bike 特定操作的后续代码,那么将它们声明为 Car 或 Bike 将是有利的。Car 和 Bike 特定操作可用于每个相关对象,并且两者都可用作(即可以传递)为 IVehicle。
回答by Oscar Gomez
There is a big plus on declaring them using the interface, which is what is known as "coding to an interface"instead of "coding to an implementation"which is a big Object Oriented Design (OOD
)principle, this way you can declare a method like this:
使用接口声明它们有一个很大的好处,这就是所谓的“编码到接口”而不是“编码到实现”,这是一个很大的面向对象设计(OOD
)原则,这样你就可以声明一个方法像这样:
public void (IVehicle myVehicle)
and this will accept any object that implements that interface, then at runtime it will call the implementation like this:
这将接受实现该接口的任何对象,然后在运行时它将像这样调用实现:
public void (IVehicle myVehicle)
{
myVehicle.run() //This calls the implementation for that particular vehicle.
}
To answer the original question, why would you use one over the other there are several reasons:
要回答最初的问题,为什么要使用一个而不是另一个,原因有几个:
1) Declaring them using an interface, means you can later substitute that value with any other concrete class that implements that interface, instead of being locked into that particular concrete class
1) 使用接口声明它们,意味着您可以稍后用实现该接口的任何其他具体类替换该值,而不是被锁定在该特定具体类中
2) You can take full advantage of polymorphism by declaring them using an interface, because each implementation can call the correct method at runtime.
2) 您可以通过使用接口声明它们来充分利用多态性,因为每个实现都可以在运行时调用正确的方法。
3) You follow the OOD principle of code to an interface
3)你遵循代码到接口的OOD原则
回答by jtoberon
You're really asking: what reference type should I use?
你真的在问:我应该使用什么引用类型?
Generally you want to use as general a reference type as possible that still gives you access to the behavior that you need. This means any of the interfaces or parent classes of your concrete type, rather than the concrete type itself. Of course, don't take this point too far -- for example, you certainly don't want to declare everything as an Object
!
通常,您希望尽可能使用通用的引用类型,这样您仍然可以访问所需的行为。这意味着您的具体类型的任何接口或父类,而不是具体类型本身。当然,不要把这点讲得太远——例如,您当然不想将所有内容都声明为Object
!
Consider these options:
考虑以下选项:
Set<String> values1 = new TreeSet<String>();
TreeSet<String> values2 = new TreeSet<String>();
SortedSet<String> values3 = new TreeSet<String>();
All three are valid, but generally the first option of values1
is better because you will only be able to access the behavior of the Set
interface, so later you can swap in another implementation quite easily:
这三个都是有效的,但通常第一个选项values1
更好,因为您将只能访问Set
接口的行为,因此稍后您可以很容易地交换另一个实现:
Set<String> values1 = new HashSet<String>();
Beware of using the second option values2
. It allows you to use specific behavior of the TreeSet
implementation in such a way that swapping in a different implementation of Set
becomes more difficult. This is fine as long as that's your goal. So, in your example, use a Car
or Bike
reference only when you need access to something that's not in the IVehicle
interface. Be aware though that the following would not work:
当心使用第二个选项values2
。它允许您以TreeSet
这样一种方式使用实现的特定行为,从而使交换不同的实现Set
变得更加困难。只要这是您的目标,这很好。因此,在您的示例中,仅当您需要访问界面中没有的内容时才使用Car
orBike
引用IVehicle
。请注意,以下操作不起作用:
TreeSet<String> values2 = new HashSet<String>(); // does not compile!
Still there are times when you need access to the methods that are not in the most general type. This is illustrated in the third option values3
-- the reference is more specific than Set
, which allows you to rely on the behavior of SortedSet
later.
仍然有时您需要访问不是最通用类型的方法。这在第三个选项中进行values3
了说明——参考比 更具体Set
,这使您可以依赖SortedSet
后面的行为。
TreeSet<String> values3 = new ConcurrentSkipListSet<String>();
The question about reference types applies not only where variables are declared, but also in methods where you have to specify the type of each parameter. Fortunately the "use as general a reference type as possible" rule of thumb applies to method parameters, too.
关于引用类型的问题不仅适用于声明变量的地方,还适用于必须指定每个参数类型的方法。幸运的是,“尽可能通用的引用类型”的经验法则也适用于方法参数。
回答by Vincent Ramdhanie
Program to an interface rather than an implementation.
编程到接口而不是实现。
When you program to an interface you will write code that can handle any kind of Vehicle. So in the future your code, without modification, should work with Trains and Planes.
当您对接口进行编程时,您将编写可以处理任何类型 Vehicle 的代码。因此,将来您的代码无需修改,应该可以与火车和飞机一起使用。
If you ignore the interface then you are stuck with CArs and Bikes, and any new Vehicles will require additional code modifications.
如果您忽略该界面,那么您将被困在汽车和自行车上,任何新的载具都需要额外的代码修改。
The principle behind this is:
这背后的原理是:
Open to Extension, Closed to Modification.
对扩展开放,对修改关闭。
回答by corsiKa
Because you don't really care what the implementation is... only what it's behavior is.
因为你并不真正关心实现是什么......只关心它的行为是什么。
Say you have an animal
说你有一只动物
interface Animal {
String speak();
}
class Cat implements Animal {
void claw(Furniture f) { /* code here */ }
public String speak() { return "Meow!" }
}
class Dog implements Animal {
void water(FireHydrant fh) { /* code here */ }
public String speak() { return "Woof!"; }
}
Now you want to give your kid a pet.
现在你想给你的孩子一个宠物。
Animal pet = new ...?
kid.give(pet);
And you get it back later
然后你再拿回来
Animal pet = kid.getAnimal();
You wouldn't want to go
你不想去
pet.claw(favorateChair);
Because you don't know if the kid had a dog or not. And you don't care. You only know that --Animals-- are allowed to speak. You know nothing about their interactions with furniture or fire hydrants. You know animals are for speaking. And it makes your daughter giggle (or not!)
因为你不知道这个孩子是否养过狗。而你不在乎。你只知道——动物——是可以说话的。你对它们与家具或消防栓的相互作用一无所知。你知道动物是会说话的。它让你的女儿咯咯笑(或不笑!)
kid.react(pet.speak());
With this, when you make a goldfish, the kid's reaction is pretty lame (turns out goldfishes don't speak!) But when you put in a bear, the reaction is pretty scary!
有了这个,当你制作一条金鱼时,孩子的反应很蹩脚(结果金鱼不会说话!)但是当你放入一只熊时,反应非常可怕!
And you couldn't do this if you said
如果你说你不能这样做
Cat cat = new Cat();
because you're limiting yourself to the abilities of a Cat.
因为你把自己限制在猫的能力上。
回答by Chris Eberle
Honestly your argument is rather moot. What's happening here is an implicit conversion to an IVehicle
. You and your friend seem to be arguing about whether it's better to do it immediately (as per the first code listing), or later on (when you call the method, as per the second code listing). Either way, it's going to be implicitly converted to an IVehicle
, so the real question is -- do you need to deal with a Car, or just a Vehicle? If all you need is an IVehicle, the first way is perfectly fine (and preferable if at a later point you want to transparently swap out a car for a bike). If you need to treat it like a car at other points in your code, then just leave it as a car.
老实说,你的论点是没有实际意义的。这里发生的是隐式转换为IVehicle
. 您和您的朋友似乎在争论是立即执行(根据第一个代码清单)还是稍后执行(根据第二个代码清单调用该方法时)更好。无论哪种方式,它都会被隐式转换为 an IVehicle
,所以真正的问题是——您需要处理 Car 还是只需要处理 Vehicle ?如果您只需要一辆 IVehicle,则第一种方式非常好(如果以后您想透明地将汽车换成自行车,则更可取)。如果您需要在代码中的其他地方将其视为汽车,那么只需将其保留为汽车即可。
回答by Ali Raza
well interfaces are behaviors and classes are their implementation so there will be several occasions later when you will program where you will only know the behaviors(interface). and to make use of it you will implement them to get benefit out of it. it is basically used to hiding implementation details from user by only telling them the behavior(interface).
接口是行为,类是它们的实现,所以以后有几次你将编程时,你只知道行为(接口)。并利用它,您将实施它们以从中受益。它基本上用于通过仅告诉用户行为(界面)来向用户隐藏实现细节。
回答by Platinum Azure
Declaring interfaces and instantiating them with objects allows for a powerful concept called polymorphism.
声明接口并使用对象实例化它们允许使用称为多态性的强大概念。
List<IVehicle> list = new ArrayList<IVehicle>();
list.add(new Car());
list.add(new Bike());
for (int i = 0; i < list.size(); ++i)
list.get(i).doSomeVehicleAction(); // declared in IVehicle and implemented differently in Car and Bike
To explicitly answer the question: You would use an interface declaration (even when you know the concrete type) so that you can pass multiple types (that implement the same interface) to a method or collection; then the behavior common to each implementing type can be invoked no matter what the actual type is.
明确回答这个问题:您将使用接口声明(即使您知道具体类型),以便您可以将多个类型(实现相同接口)传递给方法或集合;那么无论实际类型是什么,每个实现类型的共同行为都可以被调用。
回答by irreputable
Your intuition is correct; the type of a variable should be as specific as possible.
你的直觉是正确的;变量的类型应尽可能具体。
This is unlike method return types and parameter types; there API designers want to be a little abstract so the API can be more flexible.
这与方法返回类型和参数类型不同;API 设计者想要抽象一点,这样 API 就可以更灵活。
Variables are not part of APIs. They are implementation details. Abstraction usually doesn't apply.
变量不是 API 的一部分。它们是实现细节。抽象通常不适用。
回答by RobinSun
With "IVehicle modeOfTransport1 = new Car();", methods owned only by Car are not accessible to modeOfTransport1. I don't know the reason anyway.
使用“IVehicle modeOfTransport1 = new Car();”,modeOfTransport1 无法访问仅由 Car 拥有的方法。反正我也不知道原因。