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,或被包含进一个抽象类,必须被其派生类实现。
abstractclassShapesClass
{
abstractpublicintArea();
}classSquare : ShapesClass
{
intx, y;
//Not providing an Area method results
//in a compile-time error.publicoverrideintArea()
{
returnx*y;
} }
例如,一个包含非抽象方法的抽象类:
abstractclassMyAbs
{
publicvoidNonAbMethod()
{
Console.WriteLine("Non-Abstract Method");
} }classMyClass : MyAbs
{
}classMyClient
{
publicstaticvoidMain()
{
//MyAbs mb = new MyAbs();//not possible to create an instanceMyClass mc=newMyClass();
mc.NonAbMethod();//Displays 'Non-Abstract Method'} }
一个抽象类可以包含抽象和非抽象方法,当一个类继承于抽象类,那么这个派生类必须实现所有的
的基类抽象方法。
一个抽象方法是一个没有方法体的方法。
abstractclassMyAbs
{
publicvoidNonAbMethod()
{
Console.WriteLine("Non-Abstract Method");
}publicabstractvoidAbMethod();//An abstract method}classMyClass : MyAbs//must implement base class abstract methods{
publicoverridevoidAbMethod()
{
Console.WriteLine("Abstarct method");
} }classMyClient
{
publicstaticvoidMain()
{
MyClass mc=newMyClass();
mc.NonAbMethod();
mc.AbMethod();
} }
但是通过声明派生类也为抽象,我们可以避免所有或特定的虚方法的实现,
这就是抽象类的部分实现。
abstractclassMyAbs
{
publicabstractvoidAbMethod1();
publicabstractvoidAbMethod2();
}//not necessary to implement all abstract methods
//partial implementation is possibleabstractclassMyClass1 : MyAbs
{
publicoverridevoidAbMethod1()
{
Console.WriteLine("Abstarct method #1");
} }classMyClass : MyClass1
{
publicoverridevoidAbMethod2()
{
Console.WriteLine("Abstarct method #2");
} }classMyClient
{
publicstaticvoidMain()
{
MyClass mc=newMyClass();
mc.AbMethod1();
mc.AbMethod2();
} }
在C#中,一个抽象类能够继承另一个非抽象类,另外,继承了基类的方法,添加新的
抽象和非抽象方法是可行的。
classMyClass1//Non-Abstract class{
publicvoidMethod1()
{
Console.WriteLine("Method of a non-abstract class");
} }abstractclassMyAbs : MyClass1//Inherits from an non-abstract class{
publicabstractvoidAbMethod1();
}classMyClass : MyAbs//must implement base class abstract methods{
publicoverridevoidAbMethod1()
{
Console.WriteLine("Abstarct method #1 of MyClass");
} }classMyClient
{
publicstaticvoidMain()
{
MyClass mc=newMyClass();
mc.Method1();
mc.AbMethod1();
} }
一个抽象类也能从一个接口来实现,这种情况,我们必须为所有的方法提供方法体,这些方法是来自接口
interfaceIInterface
{
voidMethod1();
}abstractclassMyAbs : IInterface
{
publicvoidMethod1()
{
Console.WriteLine("Method implemented from the IInterface");
} }classMyClass : MyAbs//must implement base class abstract method{
}classMyClient
{
publicstaticvoidMain()
{
MyClass mc=newMyClass();
mc.Method1();
} }
我们不能把关键字abstract 和 sealed
一起用在C#中,因为一个密封类不能够被抽象。
abstractclassMyAbs
{
publicabstractvoidAbMethod1();
publicabstractvoidAbMethod2();
}classMyClass1 : MyAbs
{
publicoverridevoidAbMethod1()
{
Console.WriteLine("Abstarct method #1 of MyClass1");
}publicoverridevoidAbMethod2()
{
Console.WriteLine("Abstarct method #2 of MyClass1");
} }classMyClient
{
publicstaticvoidMain()
{
MyAbs ma1=newMyClass1();//Polymorphismma1.AbMethod1();
ma1.AbMethod2();
} }
抽象方法有以下特征:
1.一个抽象方法可以看作是一个虚函数。
2.抽象方法的声明只能在抽象类中。
3.因为抽象方法声明只提供一个无实现的方式,没有方法体
4.方法体的实现被覆写方法提供,覆写方法是一个非抽象类的成员。
5.抽象属性的行为和抽象方法相像,除了不同的声明形式。
6.在一个静态属性中使用abstract 是一个错误。
*一个抽象属性能够通过派生类使用
override 实现.
对于抽象类:
一个抽象类必须为所有的接口成员提供实现
一个用于实现接口的抽象类可能把接口方法安排到抽象方法上。例如
interfaceI {
voidM();
}abstractclassC: I {
publicabstractvoidM();
}
抽象类具有以下特征:
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)。