java定义抽象类abarea_抽象类  关键字   abstract extends  implements

本文探讨了Java中抽象类和接口的区别,包括它们的实现方式和使用场景。抽象类可以有实现的方法,而接口则没有。一个类可以实现多个接口,但不能同时继承多个类。抽象类常用于部分实现,接口则强制实现所有方法。在设计软件时,选择抽象类还是接口取决于具体问题。文章还提供了抽象类和接口的示例,强调了抽象类在初始化代码中的作用,以及接口在确保多实现一致性中的价值。
摘要由CSDN通过智能技术生成

Abstraction and interfaces are two very different

tools. The are as close as hammers and drills. Abstract classes may

have implemented methods, whereas interfaces have no implementation

in themselves.

Abstract classes that declare all their methods as abstract are not

interfaces with different names. One can implement multiple

interfaces, but not extend multiple classes (or abstract

classes).

The use of abstraction vs interfaces is problem specific and the

choice is made during the design of software, not its

implementation. In the same project you may as well offer an

interface and a base (probably abstract) class as a reference that

implements the interface. Why would you do that?

Let us assume that we want to build a system that calls different

services, which in turn have actions. Normally, we could offer a

method called execute that accepts the name of the action as a

parameter and executes the action.

We want to make sure that classes can actually define their own

ways of executing actions. So we create an interface IService that

has the execute method. Well, in most of your cases, you will be

copying and pasting the exact same code for execute.

We can create a reference implemention for a class named Service

and implement the execute method. So, no more copying and pasting

for your other classes! But what if you want to extend MySLLi?? You

can implement the interface (copy-paste probably), and there you

are, again with a service. Abstraction can be included in the class

for initialisation code, which cannot be predefined for every class

that you will write.

具有关键字abstract ,在实现内容上没有完全定义的类就叫抽象类。

抽象类和接口的区别如下:

① 在类来继承抽象类时,只需实现部分具体方法和全部抽象方法,而实现接口则要实现里面的全部方法。

② 在接口中无成员变量,而抽象类中可有成员变量。

在Java中引进接口主要是为了解决多继承的问题。

abstract

修饰类:不能用new 实列化一个对象

但可以声明成一个抽象类的变量

修饰方法: 没有方法体,以分号结束

子类如果是抽象类,可以不实现;如果子类不是抽象类,一定要实现抽象方法

如果一个类里有一个抽象方法,此类必为抽象类

如果一个类是抽象类,里面的方法可以不为抽象方法

Interface

用interface来定义一个接口

里面的方法都没有方法体

所有的方法和属性的修饰符只能是 public或不写(默认public)

接口里能定义属性

用implements来实现一个接口

一个类可以实现多个接口

实现类“继承”接口的属性

实现类里要实现接口中的所有方法

接口不能用new 来实例化

但可以声明一个接口变量。

抽象类不是好的最佳实践。接口才是最好的最佳实践。

现在用抽象类做项目的越来越少了。

在C#中使用关键字 abstract 来定义抽象类和抽象方法。

不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们

的实例。

"一个包含一个或多个纯虚函数的类叫抽象类,抽象类不能被实例化,进一步

一个抽象类只能通过接口和作为其它类的基类使用."- C++ Programming Language by Stroustrup Chapter13.2

抽象类能够被用于类,方法,属性,索引器和事件,使用abstract 在一个类声明中表示该类倾向要作为其它类的基类

成员被标示成abstract,或被包含进一个抽象类,必须被其派生类实现。

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pngabstractclassShapesClass

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngabstractpublicintArea();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassSquare : ShapesClass

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngintx, y;

a4c26d1e5885305701be709a3d33442f.png//Not providing an Area method results

a4c26d1e5885305701be709a3d33442f.png//in a compile-time error.a4c26d1e5885305701be709a3d33442f.pngpublicoverrideintArea()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngreturnx*y;

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }

a4c26d1e5885305701be709a3d33442f.png

例如,一个包含非抽象方法的抽象类:

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pnga4c26d1e5885305701be709a3d33442f.pngabstractclassMyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicvoidNonAbMethod()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Non-Abstract Method");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClass : MyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClient

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicstaticvoidMain()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png//MyAbs mb = new MyAbs();//not possible to create an instancea4c26d1e5885305701be709a3d33442f.pngMyClass mc=newMyClass();

a4c26d1e5885305701be709a3d33442f.png mc.NonAbMethod();//Displays 'Non-Abstract Method'a4c26d1e5885305701be709a3d33442f.png}a4c26d1e5885305701be709a3d33442f.png }

a4c26d1e5885305701be709a3d33442f.png

一个抽象类可以包含抽象和非抽象方法,当一个类继承于抽象类,那么这个派生类必须实现所有的

的基类抽象方法。

一个抽象方法是一个没有方法体的方法。

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pngabstractclassMyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicvoidNonAbMethod()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Non-Abstract Method");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidAbMethod();//An abstract methoda4c26d1e5885305701be709a3d33442f.png}a4c26d1e5885305701be709a3d33442f.pngclassMyClass : MyAbs//must implement base class abstract methodsa4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicoverridevoidAbMethod()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Abstarct method");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClient

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicstaticvoidMain()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png MyClass mc=newMyClass();

a4c26d1e5885305701be709a3d33442f.png mc.NonAbMethod();

a4c26d1e5885305701be709a3d33442f.png mc.AbMethod();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }

a4c26d1e5885305701be709a3d33442f.png

但是通过声明派生类也为抽象,我们可以避免所有或特定的虚方法的实现,

这就是抽象类的部分实现。

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pngabstractclassMyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidAbMethod1();

a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidAbMethod2();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png//not necessary to implement all abstract methods

a4c26d1e5885305701be709a3d33442f.png//partial implementation is possiblea4c26d1e5885305701be709a3d33442f.pngabstractclassMyClass1 : MyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicoverridevoidAbMethod1()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Abstarct method #1");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClass : MyClass1

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicoverridevoidAbMethod2()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Abstarct method #2");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClient

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicstaticvoidMain()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png MyClass mc=newMyClass();

a4c26d1e5885305701be709a3d33442f.png mc.AbMethod1();

a4c26d1e5885305701be709a3d33442f.png mc.AbMethod2();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }

a4c26d1e5885305701be709a3d33442f.png

在C#中,一个抽象类能够继承另一个非抽象类,另外,继承了基类的方法,添加新的

抽象和非抽象方法是可行的。

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pngclassMyClass1//Non-Abstract classa4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicvoidMethod1()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Method of a non-abstract class");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngabstractclassMyAbs : MyClass1//Inherits from an non-abstract classa4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidAbMethod1();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClass : MyAbs//must implement base class abstract methodsa4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicoverridevoidAbMethod1()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Abstarct method #1 of MyClass");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClient

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicstaticvoidMain()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png MyClass mc=newMyClass();

a4c26d1e5885305701be709a3d33442f.png mc.Method1();

a4c26d1e5885305701be709a3d33442f.png mc.AbMethod1();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }

a4c26d1e5885305701be709a3d33442f.png

一个抽象类也能从一个接口来实现,这种情况,我们必须为所有的方法提供方法体,这些方法是来自接口

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pnginterfaceIInterface

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngvoidMethod1();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngabstractclassMyAbs : IInterface

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicvoidMethod1()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Method implemented from the IInterface");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClass : MyAbs//must implement base class abstract methoda4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClient

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicstaticvoidMain()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png MyClass mc=newMyClass();

a4c26d1e5885305701be709a3d33442f.png mc.Method1();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.png

我们不能把关键字abstract 和 sealed

一起用在C#中,因为一个密封类不能够被抽象。

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pngabstractclassMyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidAbMethod1();

a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidAbMethod2();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClass1 : MyAbs

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicoverridevoidAbMethod1()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Abstarct method #1 of MyClass1");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngpublicoverridevoidAbMethod2()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png Console.WriteLine("Abstarct method #2 of MyClass1");

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.pngclassMyClient

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicstaticvoidMain()

a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.png MyAbs ma1=newMyClass1();//Polymorphisma4c26d1e5885305701be709a3d33442f.pngma1.AbMethod1();

a4c26d1e5885305701be709a3d33442f.png ma1.AbMethod2();

a4c26d1e5885305701be709a3d33442f.png }a4c26d1e5885305701be709a3d33442f.png }

a4c26d1e5885305701be709a3d33442f.png

抽象方法有以下特征:

1.一个抽象方法可以看作是一个虚函数。

2.抽象方法的声明只能在抽象类中。

3.因为抽象方法声明只提供一个无实现的方式,没有方法体

4.方法体的实现被覆写方法提供,覆写方法是一个非抽象类的成员。

5.抽象属性的行为和抽象方法相像,除了不同的声明形式。

6.在一个静态属性中使用abstract 是一个错误。

*一个抽象属性能够通过派生类使用

override 实现.

对于抽象类:

一个抽象类必须为所有的接口成员提供实现

一个用于实现接口的抽象类可能把接口方法安排到抽象方法上。例如

a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.pnginterfaceI a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngvoidM();

a4c26d1e5885305701be709a3d33442f.png}a4c26d1e5885305701be709a3d33442f.pngabstractclassC: I a4c26d1e5885305701be709a3d33442f.png{

a4c26d1e5885305701be709a3d33442f.pngpublicabstractvoidM();

a4c26d1e5885305701be709a3d33442f.png}a4c26d1e5885305701be709a3d33442f.png

a4c26d1e5885305701be709a3d33442f.png

抽象类具有以下特征:

1.抽象类不能被实例化。

2.抽象类可以包含抽象方法和访问器

3.不能把抽象类用密封(sealed)来修饰,那就意味着类不能被继承,这违反抽象类被继承的原则。

4.一个派生于一个抽象类的非抽象类必须包括所有的继承来的抽象方法和访问器的实现

5.在方法和属性中使用abstract 关键字意味着包含它们的实现。

抽象类存在的意义,一定程度上,可以说就是继承存在的意义。因为人总是很懒的,继承这一特性能很好的满足人类懒这一特性;另一方面,继承能够将具有

相同特性的类进行逻辑上的连接,也就是继承链(Inheritance

Chain)。继承链的顶端是父类,底部是子类。顶端可以是抽象类,也可以是具体类;底部可以是抽象类,也可以是具体类。

下面来具体讨论下抽象类。所谓抽象类,可以很直接地理解为被abstract关键字修饰的类。下面还是看看一个直接的例子(引自Core

Java):

abstractclassPerson{

publicPerson(String n){

name = n;

}

publicabstractString getDescription();

publicString getName(){

returnname;

}

privateString name;

}

从这个例子中,能够得出这样的结论:抽象类中,既可以有抽象方法,也可以有具体方法或者叫非抽象方法。

进一步看下面这段代码:

abstractclassManextendsPersons{

publicMan(String n){

super(n);

this.gender ="Male";

}

publicString getGender(){

returngender;

}

privateString gender;

}

这个例子很有意思。你看到这个类是抽象类,但是它的方法“全是”非抽象方法。那么可不可以把这个abstract去掉呢?答案是:不能!因为你没有

具体实现父类,也就是Person类的所有抽象方法。好了,补充上面的结论:抽象类中,既可以全是抽象方法,也可以全是非抽象方法。一个继承于抽象类的子

类,只有实现了父类所有的抽象方法才能够是非抽象类。

再看下面的代码:

publicclassAbstractTest {

publicstaticvoidmain(String args[]){

Persons p = newPersons("Justin");//Error

}

}

当你试图去实例化一个抽象类的时候,会有编译期错误。很好理解,抽象的东西无法具体化,也就是实例化。

再看下面的代码:

classMyselfextendsMan{

publicString getDescription(){

String temp = "";

temp = "My name is"+this.getName() +", and I am a "+this.getGender() +".";

returntemp;

}

}

类Myself实现了仅有的一个抽象方法,但是这个时候编译器还是会报错。为什么?把错误贴出来:Implicit super

constructor Man() is undefined for default constructor. Must define

an explicit

constructor。意思是说类Myself的父类没有定义默认无参数的构造方法,因此Myself类必须显式地定义一个构造方法。所以,为了改正这

个错误,有两个办法。一是给Man类添加默认的无参数的构造方法,但是问题来了,Person类也需要添加。二是给Myself类显式地添加一个构造方

法,而且是带参数的构造方法。还是取捷径吧!看代码:

classMyselfextendsMan{

publicMyself(String n){

super(n);

}

publicString getDescription(){

String temp = "";

temp = "My name is "+this.getName() +", and I am a "+this.getGender() +".";

returntemp;

}

}

多提一句:一般情况下还是提倡显式地实现默认无参数的构造方法。好了,现在再来重写AbstractTest类:

publicclassAbstractTest {

publicstaticvoidmain(String args[]){

Persons p = newMyself("Justin");

Man m = newMyself("Justin");

Myself me = newMyself("Justin");

System.out.println(p.getDescription());

System.out.println(m.getDescription());

System.out.println(me.getDescription());

}

}

输出如下:

My name is Justin, and I am a Male.

My name is Justin, and I am a Male.

My name is Justin, and I am a Male.

你可以看到这下,就没有问题了。但是你可能疑惑为什么Myself的实例可以赋值给Person和Man的对象呢?你可以认为是动态绑定(Dynamic

Binding),多态(Polymorphism)甚至是转型(Casting)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值