问题
什么是Java中的"抽象类"?
#1 热门回答(296 赞)
抽象类是无法实例化的类。通过创建可以实例化的继承子类来使用抽象类。抽象类为继承子类做了一些事情:
- 定义继承子类可以使用的方法。
- 定义继承子类必须实现的抽象方法。
- 提供一个通用接口,允许子类与所有其他子类互换。
这是一个例子:
abstract public class AbstractClass
{
abstract public void abstractMethod();
public void implementedMethod() { System.out.print("implementedMethod()"); }
final public void finalMethod() { System.out.print("finalMethod()"); }
}
请注意,"abstractMethod()"没有任何方法体。因此,你无法执行以下操作:
public class ImplementingClass extends AbstractClass
{
// ERROR!
}
没有方法可以实现abstractMethod()
!因此,JVM无法知道当它获得类似new ImplementingClass().abstractMethod()
时它应该做什么。
这是一个正确的ImplementingClass
。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
}
请注意,你不必定义implementedMethod()
或finalMethod()
。它们已由AbstractClass
定义。
这是另一个correctImplementingClass
。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
public void implementedMethod() { System.out.print("Overridden!"); }
}
在这种情况下,你已覆盖implementedMethod()
。
但是,由于final
关键字,以下是不可能的。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
public void implementedMethod() { System.out.print("Overridden!"); }
public void finalMethod() { System.out.print("ERROR!"); }
}
你不能这样做是因为finalMethod()
inAbstractClass
的实现被标记为finalMethod()
的最终实现:永远不会允许其他实现。
现在你要两次实现一个抽象类:
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
public void implementedMethod() { System.out.print("Overridden!"); }
}
// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("second abstractMethod()"); }
}
现在你可以在某处编写另一种方法。
public tryItOut()
{
ImplementingClass a = new ImplementingClass();
AbstractClass b = new ImplementingClass();
a.abstractMethod(); // prints "abstractMethod()"
a.implementedMethod(); // prints "Overridden!" <-- same
a.finalMethod(); // prints "finalMethod()"
b.abstractMethod(); // prints "abstractMethod()"
b.implementedMethod(); // prints "Overridden!" <-- same
b.finalMethod(); // prints "finalMethod()"
SecondImplementingClass c = new SecondImplementingClass();
AbstractClass d = new SecondImplementingClass();
c.abstractMethod(); // prints "second abstractMethod()"
c.implementedMethod(); // prints "implementedMethod()"
c.finalMethod(); // prints "finalMethod()"
d.abstractMethod(); // prints "second abstractMethod()"
d.implementedMethod(); // prints "implementedMethod()"
d.finalMethod(); // prints "finalMethod()"
}
请注意,即使我们声明了b
anAbstractClass
type,它也显示为"Overriden!"
。这是因为我们实例化的对象实际上是一个ImplementingClass
,其当然是被覆盖的implementedMethod()
。 (你可能已经看到这被称为多态性。)
如果我们希望访问特定于某个子类的成员,我们必须首先转到该子类:
// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();
最后,你无法执行以下操作:
public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
... // implementation
}
一次只能扩展一个类。如果需要扩展多个类,则必须是接口。你可以这样做:
public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
... // implementation
}
这是一个示例界面:
interface InterfaceA
{
void interfaceMethod();
}
这基本上与以下相同:
abstract public class InterfaceA
{
abstract public void interfaceMethod();
}
唯一的区别是第二种方式不会让编译器知道它实际上是一个接口。如果你希望人们只实现你的界面而不是其他人,那么这将非常有用。但是,作为一般初学者的经验法则,如果你的抽象类只有抽象方法,那么你应该将它作为一个接口。
以下是非法的:
interface InterfaceB
{
void interfaceMethod() { System.out.print("ERROR!"); }
}
你无法在接口中实现方法。这意味着如果实现两个不同的接口,那些接口中的不同方法就不会发生冲突。由于接口中的所有方法都是抽象的,因此必须实现该方法,并且由于你的方法是继承树中的唯一实现,因此编译器知道它必须使用你的方法。
#2 热门回答(65 赞)
在以下条件下,Java类变为抽象类:
1.至少有一种方法被标记为摘要:
public abstract void myMethod()
在这种情况下,编译器会强制你将整个类标记为抽象。
2.该类标记为摘要:
abstract class MyClass
如前所述:如果你有一个抽象方法,编译器会强制你将整个类标记为抽象。但即使你没有任何抽象方法,你仍然可以将该类标记为抽象。
通用:
抽象类的一个常见用途是提供类似于接口的类的大纲。但是与接口不同,它已经可以提供功能,即类的某些部分已经实现,而某些部分只是通过方法声明来概述。 ("抽象")
抽象类无法实例化,但你可以基于抽象类创建具体类,然后可以实例化该抽象类。为此,你必须从抽象类继承并覆盖抽象方法,即实现它们。
#3 热门回答(9 赞)
使用abstractkeyword声明的类称为abstract class
。抽象是隐藏数据实现细节并仅向用户显示功能的过程。抽象让你可以专注于对象的作用而不是对象的作用。
抽象类的主要内容-抽象类可能包含也可能不包含抽象方法。可以使用非抽象方法。抽象方法是在没有实现的情况下声明的方法(没有大括号,后跟分号),如下所示:ex:abstract void moveTo(double deltaX,double deltaY);
- 如果一个类至少有一个抽象方法,那么该类必须是抽象的
- 可能无法实例化抽象类(不允许创建Abstract类的对象)
- 要使用抽象类,必须从另一个类继承它。为其中的所有抽象方法提供实现。
- 如果继承了抽象类,则必须为其中的所有抽象方法提供实现。
在声明期间将类声明为抽象之前,声明抽象类Specifyingabstract
keyword。看看下面的代码:
abstract class AbstractDemo{ }
在声明期间的方法将其抽象为抽象之前,声明抽象方法Specifyingabstract
keyword。看看下面的代码,
abstract void moveTo();//no body
为什么我们需要抽象类
在面向对象的绘图应用程序中,你可以绘制圆形,矩形,线条,贝塞尔曲线和许多其他图形对象。这些对象都有一些共同的状态(对于前 - :位置,方向,线条颜色,填充颜色)和行为(对于ex - :moveTo,旋转,调整大小,绘制)。其中一些状态和行为对于所有图形对象都是相同的(例如:填充颜色,位置和moveTo)。其他需要不同的实现(例如:调整大小或绘制)。所有图形对象必须能够自己绘制或调整大小,它们的工作方式不同。
这是抽象超类的完美情况。你可以利用相似性,并声明所有图形对象都从同一个抽象父对象继承(例如:GraphicObject
),如下图所示.
首先,声明一个抽象类GraphicObject
,以提供所有子类完全共享的成员变量和方法,例如当前位置和moveTo方法.GraphicObject
也声明抽象方法,例如draw或resize,它们需要是由所有子类实现但必须以不同方式实现。 GraphicObject
class看起来像这样:
abstract class GraphicObject {
void moveTo(int x, int y) {
// Inside this method we have to change the position of the graphic
// object according to x,y
// This is the same in every GraphicObject. Then we can implement here.
}
abstract void draw(); // But every GraphicObject drawing case is
// unique, not common. Then we have to create that
// case inside each class. Then create these
// methods as abstract
abstract void resize();
}
子类中抽象方法的用法每个非抽象子类GraphicObject
,例如Circle
和Rectangle
,必须提供draw
和resize
方法的实现。
class Circle extends GraphicObject {
void draw() {
//Add to some implementation here
}
void resize() {
//Add to some implementation here
}
}
class Rectangle extends GraphicObject {
void draw() {
//Add to some implementation here
}
void resize() {
//Add to some implementation here
}
}
在main
方法中你可以调用所有这样的方法:
public static void main(String args[]){
GraphicObject c = new Circle();
c.draw();
c.resize();
c.moveTo(4,5);
}
在Java中实现抽象的方法
有两种方法可以在java中实现抽象
- 抽象类(0到100%)
- 接口(100%)
具有构造函数,数据成员,方法等的抽象类
abstract class GraphicObject {
GraphicObject (){
System.out.println("GraphicObject is created");
}
void moveTo(int y, int x) {
System.out.println("Change position according to "+ x+ " and " + y);
}
abstract void draw();
}
class Circle extends GraphicObject {
void draw() {
System.out.println("Draw the Circle");
}
}
class TestAbstract {
public static void main(String args[]){
GraphicObject grObj = new Circle ();
grObj.draw();
grObj.moveTo(4,6);
}
}
输出:
GraphicObject is created
Draw the Circle
Change position according to 6 and 4
记住两条规则:-如果类具有很少的抽象方法和几个具体方法,则将其声明为抽象类。
- 如果类只有抽象方法,则将其声明为接口。
参考文献:
- TutorialsPoint - Java抽象
- BeginnersBook - Java抽象类方法
- Java Docs - 抽象方法和类
- JavaPoint - Java中的抽象类