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

我正在学习JAVA并继续阅读JAVA:Herbert Shildt的完整参考书 。

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

抽象类不能使用new运算符直接实例化。

我搜索了web和stackoverflow并跟着这些问题: 为什么我们不能在JAVA中实例化一个抽象类? 为什么我们不能在没有匿名类方法的情况下在java中实例化接口或抽象类?

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

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

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

抽象类应该是一个没有意义的东西,如果它完全存在于它自己。

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

你的报价:

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

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

当然,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概念进行了具体扩展,那么我就可以拥有一辆车

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

 List vehicles = new ArrayList<>(); 

或者,如果您不想/不能使用菱形运算符( <> ):

 List vehicles = new ArrayList(); 

这允许我将任何类型的Vehicle放入该集合中

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

虽然这还有许多其他优点,但在这个答案中无法涵盖。

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

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

至于接口,它们只是在没有实现的情况下声明方法(除了Java8中引入的默认方法),并且没有构造函数或类变量。 如果不实现所有方法,则无法实例化它们。

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

假设我们想要设计一个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; } 

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

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

你的回答是在你的声明中:

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

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

当您需要一个类来实现inheritance和多态时,抽象类很有用, 但实例化类本身,只有它的子类是没有意义的当您想要为一组共享一些常见实现代码的子类定义模板时,通常会使用它们,但您也希望保证不能创建超类的对象。

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

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

一开始看起来令人费解,但你会习惯它

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

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

theoretically-

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

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

抽象类对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 list = new ArrayList<>(); list.add(new RedCommand()) list.add(new RedCommand()) list.add(new BlueCommand()) for(Command c : list) { c.doCommand(); } 

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

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

比喻一下,想想这四件事:动物,哺乳动物,人类,大象。 有真正的生物称为“人类”和“大象”,但没有名为“动物”或“哺乳动物”的生物。 人类和大象就是这样具体的。 动物和哺乳动物是我们创造的抽象,用于描述不同生物共有的特征。 人类和大象是各种哺乳动物。 哺乳动物是各种动物。

在OO世界中,我们可以将这四个事物建模为类。 类Mammal是一个扩展抽象类Animal的抽象类。 人类和大象是延伸哺乳动物的具体课程。 宣布动物和哺乳动物作为抽象类告诉其他人,在树林里没有“动物”或“哺乳动物”这样的东西。 动物和哺乳动物只是我们发明的想法,用来描述人类,大象和其他生物的共同点。