通过抽象类类型变量还是子类类型变量引用子对象?

时间:2019-09-04 18:04:47

标签: java abstraction

抱歉,标题令人困惑,我有点困惑,所以我只使用一个示例:D假设我们有:

public abstract class Vehicle {
    public abstract void paint();
}
public class Car extends Vehicle {
    public void paint() {
        ...
    }
    public void sell() {
        ...
    }
}
  1. 类型车
Car c = new Car();
c.paint();
c.sell(); //works
  1. 类型车辆
Vehicle c = new Car();
c.paint();
c.sell(); //error

那么使用后一种格式有什么意义呢?我只能想到限制/隐私,但即使那样也不能想到一个合理的例子。哪个选项更适合作为一般做法?

5 个答案:

答案 0 :(得分:1)

我不是专家,但据我所知

以后的格式用于实现抽象,即隐藏函数的内部工作。

现在,实现取决于扩展您的function listAllUsers(nextPageToken) { // List batch of users, 1000 at a time. admin.auth().listUsers(1000, nextPageToken) .then(function(listUsersResult) { listUsersResult.users.forEach(function(userRecord) { console.log('user', userRecord.toJSON()); }); if (listUsersResult.pageToken) { // List next batch of users. listAllUsers(listUsersResult.pageToken); } }) .catch(function(error) { console.log('Error listing users:', error); }); }); // Start listing users from the beginning, 1000 at a time. listAllUsers();类的类(此处为Vehicle)。 这样您就可以自由地实现绘画功能,而不必担心哪个类正在实现它。

例如:

Car

现在您实现

Bike extends Vehicle { // body } ,根据您的配置,您可以喷涂自行车或汽车。如果使用得当,它会非常强大

使用Vehicle.paint()也很不错,因为它强制Java使用空方法。

如果您想知道为什么会出错,那是因为interface不知道函数Vechicle存在,因为该函数是由类sell而不是Car定义的,但是Vechicle的运行就像运行paint()一样。

答案 1 :(得分:0)

原因是类型安全之一。如果Car可以扩展Vehicle,则大概其他类也可以。由于sell()不是Vehicle的接口的一部分,因此不需要子类来实现它。因此,例如,如果您拥有Bicycle extends Vehicle,但由于某种原因而没有方法sell(),那么您将必须获得运行时错误:

vehicle.sell()

vehicle指的是Bicycle的实例。因此,如果方法sell()应该在Vehicle的所有子类型上都是可调用的,则is也应该是其接口的一部分。

答案 2 :(得分:0)

超级类意味着您在某些类之间有一些共同点,这些共同点可能是属性或method.abstract

类意味着您有一些概念,可能需要通过其子类来实现其某些方法。

您可能会在应用程序中的某个地方需要vehicle概念,无论它是什么车辆,都需要对其进行涂漆,因此,您只需要知道传递的参数是车辆即可。

两个概念都是正确的,但这取决于您的用法和设计。

如果您只需要车辆概念而不管其子类型如何,则必须使用第二个概念,在这种情况下,您需要使用方法sell(),因为您使该方法可用并且必须使用第一个方法属性来自定义部分,而不是实例化部分。

最后,学习OOP中的抽象,它可能会为您带来更多帮助。希望对您有所帮助:)

答案 3 :(得分:0)

接口的想法是让不同的类实现该接口,并且调用者无需知道(或关心)接口是哪个。

再举一个例子,以Java的OutputStream为例。它是一个抽象类(因此比实际接口要多一些“肉”或逻辑),但是主要思想是相同的。在您的程序中,您可以写入调用者传入的OutputStream。您只需要编写必须编写的内容即可。另一方面,调用者可以决定要处理的数据内容:通过网络发送该数据还是将其保存到filepipe到另一个程序中? Zip还是encrypt之前这样做?调用方可以通过向您传递一个不同的OutputStream来实现此目的,并且您的代码无需更改即可处理网络I / O,压缩或加密。

测试可以通过ByteArrayOutputStream来捕获程序的输出。

答案 4 :(得分:0)

Vehicle c = new Car();
c.paint(); // <- THIS is the point of the latter format.

这种格式的重点是即使您不知道正在绘制哪种类型的paint,也可以调用Vehicle

想象一下,您有ArrayListVehicle中的需要绘画。

ArrayList<Vehicles> vehicles = new ArrayList<>();

vehicles.add(new Car());
vehicles.add(new Jet());
vehicles.add(new Tank());

for(Vehicle vehicle : vehicles) {
    vehicle.paint(); // <- This is the power, right here.
}

您肯定会在该循环内调用sell方法,因为它仅适用于Car s(根据您的设计),而并非全部{ {1}}个。