在JAVA中实例化一个抽象类?

时间:2014-07-17 14:56:11

标签: java class oop design-patterns abstract-class

我正在学习JAVA并关注本书JAVA:The Complete Reference by Herbert Shildt

我在Java中学习了抽象类,但无法理解这一行背后的原因:

  

无法使用new运算符直接实例化抽象类。

我搜索了网络和stackoverflow,并按照以下问题:Why can't we instantiate a abstract class in JAVA?Why can't we instantiate an interface or an abstract class in java without an anonymous class method?

在一个答案中,有人写道:

  

简单地说,在一个好的面向对象的程序中,你永远不应该这样做   实例化抽象类或接口。如果你这样做,设计是   可能是错的。

我不明白为什么重要的是不要为良好的OOP设计实例化一个抽象类。如果有人可以给出一个很好的解释,那么请帮助。

8 个答案:

答案 0 :(得分:2)

抽象类应该是没有意义的东西,如果它完全存在的话。

以车辆为例。您是否可以在不同时描述特定类型的车辆的情况下描述车辆?否 - 因为车辆只是描述一组相关对象的共同特征和行为的一种方式。或者,您可以将它们视为 concepts

你的引言:

  

简单地说,在一个好的面向对象的程序中,你永远不应该想要实例化一个抽象类或接口。如果你这样做,设计可能是错误的。

是现货吗?如果您编写了一个想要完全实例化的抽象类,那么它就不是一个抽象类。如果你发现自己处于这种情况,你可能需要进行另一层次的抽象,将抽象部分与实际开始将类压缩成具体事物的部分分开。你应该想要用抽象类做的唯一事情是扩展它 - 把它变成不那么模糊的东西(如果你愿意,可以更具体)。

当然,Java有时候看起来有些矛盾。实际上,为抽象类编写构造函数是完全有效

abstract class Vehicle {

    // You might have some common variables defined here

    Vehicle() { }
}

起初这看起来有点愚蠢。为什么我可以编写一个构造函数,它被设计为允许您实例化一个对象,当我不允许实例化该类时?如果你不写一个,编译器甚至会为你创建一个默认的构造函数!

答案是, 允许实例化一个抽象类 - 您不能使用new关键字直接实例化 。但抽象类最重要的部分是它们被设计为以进行扩展

当您实例化抽象类的子类时,您可以在构造函数中显式或隐式地调用super();

public class Car extends Vehicle {
    public Car() {
        super(); // If you don't put this here, the compiler will!
    }
}

当你想到它时,这实际上是有意义的 - 你不能拥有一辆车,但我坐在停车场的车肯定 车辆。一旦我对我的车辆概念进行了具体扩展,在这种情况下Car,那么我可以拥有一辆车

这使您可以做的最有用的事情是创建泛型集合。因为Vehicle是所有不同类型车辆的超类,我可以说:

List<Vehicle> vehicles = new ArrayList<>();

或者如果您不想/不能使用钻石操作符(<>):

List<Vehicle> vehicles = new ArrayList<Vehicle>();

这允许我将任何类型的车辆放入该集合

vehicles.add(new Car());
vehicles.add(new Van());
vehicles.add(new Lorry());
vehicles.add(new Motorcycle());
// and so on...

虽然这还有很多其他优点,但在这个答案中还有很多不足。

答案 1 :(得分:1)

您无法实例化一个抽象类,因为它通常包含没有实现的抽象方法。为了实例化一个类,必须实现其所有方法。子类将实现抽象方法,您将实例化这些子类。

但是,即使您实现了所有方法,如果要阻止类的用户实例化它,有时也会将该类定义为抽象。如果要将类定义为子类,则将其定义为抽象类,并且不包含创建完整功能对象所需的全部内容。

对于接口,它们只是声明没有实现的方法(Java8中引入的默认方法除外),并且没有构造函数或类变量。您无法实现所有方法,无法实例化它们。

答案 2 :(得分:1)

抽象类旨在提供骨架结构,因此它们中没有具体的实现。

子类应该填写实现,因此可以实例化它们。

答案 3 :(得分:1)

你的回答是在你的陈述中:

  

简单地说,在一个好的面向对象的程序中,你永远不应该想要实例化一个抽象类或接口。如果你这样做,设计可能是错误的。

你永远不应该想要实例化一个抽象类。因为抽象类是一个不完整的类,它的intstantiation没有任何意义。你定义了一个类的行为,它将扩展你的abstact类。它更多的是关于一个人说'#34;这些类应该看起来像这样,他们有共同点,所以填补空白!&#34;。

  

当您需要一个类时,抽象类很有用   继承和多态,但实例化它是没有意义的   class本身,只有它的子类。 它们通常在您使用时使用   想要为一组共享一些的子类定义模板   常见的实施代码,,但你也要保证   无法创建超类的对象。

因此,根据正确的设计,不要实例化抽象类 是很重要的,抽象类的目的是不同的,你在使用时使用它如果要为一组子类定义模板,并且实例化类本身没有意义,

例如:让我们说你需要创建Dog,Cat,Hamster和Fish对象。它们具有类似的属性,如颜色,大小和腿数以及行为,因此您可以创建一个Animal超类。但是,什么颜色的动物? Animal对象有多少条腿?在这种情况下,实例化Animal类型的对象而不仅仅是它的子类没有多大意义。

答案 4 :(得分:1)

好吧,让我们举一个例子,这样你就可以理解为什么在面向对象的范例中抽象类不是用于实例化,而是用于扩展:

假设我们想要设计一个Zoo应用程序,我们通过一组信息呈现每个动物,但是每个类型都会由它的类提供,如果我们想要遵循一个好的实践,那么我们创建一个名为Animal的类,我们在其中提供有关所有动物的公共信息(id,price,entryDate ......)。

public abstract class Animal {
    private long id;
    private Date entryDate;
    private double price;
    private String name;
    // other common info
}

这有助于从结构的角度设计其他类

public Lion extend Animal {
    private boolean isFromAfrica;
}

答案 5 :(得分:0)

一开始看起来好笑不过,但你会习惯它

从技术上讲,它无法实例化,因为 -

它不包含方法定义。因此在实例化时浪费空间!

理论上 -

如果你可以实例化它,它就会破坏抽象类的整个目的..当它与普通类没有什么不同时,你会遇到创造概念的所有麻烦

答案 6 :(得分:0)

抽象类的唯一目的是扩展。抽象类将包含其所有子类的公共代码,子类将仅实现与其相关的那些部分。

抽象类对Command模式非常有用。例如,假设您有一个需要执行一组操作的任务,那么您可以定义一个Command抽象类:

public abstract class Command
  public void doCommand() {
    // Actual code here doing stuff...
    runInternal();
    // more code;
  }

  public abstract void runInternal();
}

现在的想法是你可以实现一系列命令,例如:

public void RedCommand extends Command {
   public void runInternal() {
     // Real code that does red things
   }
}

......还有

public void BlueCommand extends Command {
   public void runInternal() {
     // Real code that does blue things
   }
}

现在,你可以这样:

List<Command> list = new ArrayList<>();
list.add(new RedCommand())
list.add(new RedCommand())
list.add(new BlueCommand())

for(Command c : list) {
  c.doCommand();
}

现在通过简单地扩展Command抽象类并实现runInternal()方法,可以轻松添加更多命令。与所有事情一样,这种模式可能会被严重滥用,但在适当的环境中会使代码变得容易/可读。

答案 7 :(得分:0)

原因是有时几个具体的类(可以实例化的类)都共享共同的功能。可以通过继承共享通用功能。常用方法放在抽象类中。具体的子类可以使用那些在抽象类中定义的方法,或者具体的子类可以覆盖实现特殊行为的方法。

作为类比,想一想这四件事:动物,哺乳动物,人类,大象。有真正的生物被称为&#34;人类&#34;和&#34; elephant&#34;,但没有名为&#34; animal&#34;或者&#34;哺乳动物&#34;。人类和大象就是这样具体的。动物和哺乳动物是我们创造的抽象,用于描述不同生物共有的特征。人类和大象是哺乳动物的。哺乳动物是动物的

在OO世界中,我们可以将这四个事物建模为类。类Mammal是一个扩展抽象类Animal的抽象类。人类和大象是延伸哺乳动物的具体课程。将动物和哺乳动物类声明为 abstract 告诉其他人没有动物和#34;或者&#34;哺乳动物&#34;在树林里跑来跑去。动物和哺乳动物只是我们发明的想法,用来描述人类,大象和其他生物的共同点。