英文:
What are the benefits of declaring a different type than the initialization object due to polymorphism?
问题
将给定的代码翻译如下:
给定以下代码:
class Vehicle{
public void operate(){
System.out.println("The vehicle is being operated.");
}
}
class Car extends Vehicle{
public void operate(){
System.out.println("The car is being operated.");
}
}
public class Simulation{
public static void main(String[] args){
Vehicle vehicle1 = new Car();
Vehicle vehicle2 = new Vehicle();
vehicle1.operate();
vehicle2.operate();
}
}
在我们最终将vehicle1初始化为Car时,将vehicle1声明为Vehicle的好处是什么?我们不应该将其声明为Car吗?
英文:
Given the following code:
class Vehicle{
public void operate(){
System.out.println("The vehicle is being operated.");
}
}
class Car extends Vehicle{
public void operate(){
System.out.println("The car is being operated.");
}
}
public class Simulation{
public static void main(String[] args){
Vehicle vehicle1 = new Car();
Vehicle vehicle2 = new Vehicle();
vehicle1.operate();
vehicle2.operate();
}
}
What is the benefit of declaring vehicle1 as a Vehicle when we end up initializing it as Car? Shouldn't we just declare it as a Car?
答案1
得分: 1
在这个示例中,很难看出其中的好处。然而,这样做有以下好处:
-
通常你会使用对象调用方法。因此我们有两个选项
...myFunction(Vehicle vehicle)
或者myFunction(Car car)
。如果你选择使用 Car,那么你就限制了可以传递给该方法的类型。这非常重要。请记住,软件会经常变化,需求会变化,会进行增强。假设现在你有一个继承自 Vehicle 的全新对象,比如一辆法拉利,你不能调用myFunction(Car car)
,但你可以通过传递法拉利来调用myFunction(Vehicle vehicle)
。所以为了使用 myFunction 进行调用,你将不得不改变函数的签名。有时你无法改变函数的签名,因为它可能是一个库,你没有源代码。或者也许你可以改变它,但如果这么做,你会破坏使用你代码的人。在较大的软件开发中,团队被分割成不同部分,你必须创建一些其他人将用来完成整个项目的类。或者你将创建库并交付给客户。这就是多态存在的主要原因:为了使许多团队能够轻松协同工作,而不会破坏彼此的代码,并且通过使用子类来改进代码而不会破坏现有功能。
当你只编写一小部分不打算与任何人共享并且不打算扩展该代码库的代码时,好处不多。然而,养成这样的习惯是很有好处的。 -
意图:通过将其声明为 Vehicle,你在代码中表明你只关心具有 Vehicle 行为的东西,即你可以调用 operate()。当你扩展一个类时,可以为其添加附加的行为/方法。通过将其声明为 Vehicle,你将无法调用 Car 中的任何新方法。请记住,你的代码很可能会被他人阅读(如果不是你独有的),因此使用 Vehicle 可以清楚地表明你只关心能够 operate() 的东西。
-
集合:很常见需要创建对象并将它们作为集合使用。假设你有一组车辆参加比赛。要使所有车辆启动,如果你使用 Vehicle,你可以轻松使用
Vehicle[]
将它们全部装入其中。如果你使用 Car、Ferrari、Van 等,你只能使用Object[]
来装它们,然后你将不得不将其强制转换为((Vehicle)arrayElement).operate()
,而不仅仅是arrayElement.operate()
。我提供了一个简化的示例,但我认为你会明白。
因此,从你的代码来看,表面上没有直接的好处,但基于上述原因,如果你使用 Vehicle,将会有好处,并且现在使用它也会有好处,因为你将养成良好的习惯,更加思考面向对象编程和更大的整体架构。
英文:
In this example it's not obvious to see the benefit. However, doing so has these benefits:
-
Usually you'll be calling methods with your object. So we have two options
...myFunction(Vehicle vehicle)
ormyFunction(Car car)
. If you choose to use Car, you are restricting the type that can be passed to that method. This is very important. Keep in mind software changes a lot, requirements change, enhancements are made. Let's suppose now you have a shiny new object a Ferrari which extends Vehicle, you cannot callmyFunction(Car car)
but you will be able to callmyFunction(Vehicle vehicle)
by passing Ferrari. So in order to make your call using myFunction you will have to change the function signature. Sometimes you cannot change the function signature because, well, it is a library and you don't have the source code. Or maybe you can change it but if you do you will break people using your code. In larger software development, teams are split and you have to create some classes that others will use to complete the whole project. Or you will create libraries and ship to clients. That's the main reason there is polymorphism: to make it easy for many teams to work together without breaking each others code and also improve on the code by using subclasses without breaking things.
When you are writing only a small piece of code that you are not going to share with anyone and don't plan on expanding that code base, there is not much of a benefit. However it is a good habit to have. -
Intent: by declaring it as Vehicle, you are showing in your code that you only care about something that has the behavior of a Vehicle .i.e you can call operate(). When you extend a class you can add additional behaviors/methods to it. By declaring it as Vehicle you won't be able to call any of new methods in Car. Remember that your code will most likely be read by others (if it's not your sole property), so using Vehicle makes it obvious that you only care about something that can operate().
-
Collections: Very often you need to create objects and use them as a collection. Let's imagine you have a race of Vehicles. To make all the Vehicles start, you can easily use
Vehicle[]
and stuff all of them in there if you use Vehicle. If you were using the Car, Ferrari, Van... you could only stuff them if you useObject[]
and then you will have to cast to((Vehicle)arrayElement).operate()
instead of justarrayElement.operate()
. I'm giving a simplistic example but I think you'll get the idea.
So to conclude, from only your code there is on the surface no direct benefit but from the reasons above there will be a benefit if you use Vehicle and there is benefit to do so now because you will build good habits and think more OOP and about the bigger picture.
答案2
得分: 0
在方法中像这样局部声明它并没有太大的区别。一般来说,通过使用可能起作用的最抽象类型的引用,您可以获得更多的灵活性。您可能会在代码中看到类似于 List<String> foo = new ArrayList<>();
的代码,因为 List 就足够了。
例如,看看 Collections.sort()。它接受一个 List
,因为列表元素是有序的。它不能只接受 Collection
,因为集合的顺序不是保证的,比如 Set
。但它可以使用任何 List
的实现,比如 ArrayList
、LinkedList
等,因为排序是 sort() 关心的唯一属性。
英文:
Declaring it locally in a method like that there isn't much difference. Generally speaking you get more flexibility by working on references of the most abstract type that can possibly work. You might see that in code like List<String> foo = new ArrayList<>();
because List is enough.
For example look at Collections.sort(). It takes a List
because list elements are ordered. It can't just take Collection
because collections aren't guaranteed to be ordered, like Set
. But it can use any implementation of List
, like ArrayList
, LinkedList
, etc because ordering is the only property sort() cares about.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论