八,抽象类与接口


1.抽象类

1.1定义

包含号一个抽象方法的类称为抽象类.须要用abstract声明. java

并非全部的类都是用来描绘对象的,若是一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类每每用来表征咱们在对问题领域进行分析、 设计中得出的抽象概念,是对一系列看上去不一样,可是本质上相同的具体概念的抽象,咱们不能把它们实例化(拿不出一个具体的东西)因此称之为抽象。 编程

须要注意的是抽象类不能直接实例化,但能够声明,要想使用抽象类,必须依靠子类,抽象类是必须被子类继承的,并且被继承的子类须要实现抽象类中的所有抽象方法. 设计模式

:抽象类必须被实现,因此不能用final修饰. app

示例: 编程语言

public abstract class AbstractClass //里面至少有一个抽象方法
{
  public int t; //普通数据成员
   public abstract void method1(); //抽象方法,抽象类的子类在类中必须实现抽象类中的抽象方法
  public abstract void method2();
  public void method3(); //非抽象方法
  public int method4();
  publi int method4 (){
  …… //抽象类中能够赋予非抽象方法方法的默认行为,即方法的具体实现
  }

public void method3(){
  …… //抽象类中能够赋予非抽象方法方法的默认行为,即方法的具体实现
  }

}

1.2抽象方法

在面向对象编程语言中抽象方法指一些只有方法声明,而没有具体方法体的方法。抽象方法通常存在于抽象类或接口中。 函数

java中的抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型、方法名称和所需的参数,没有方法体,也就是说抽象方法只须要声明而不须要实现。 学习

数学中的抽象是指抽取出同类数学对象的共同的、本质的属性或特征,舍弃其余非本质的属性或特征的思惟过程。即把研究对象或问题中抽取数量关系或空间形式而舍弃其它属性对其进行考察的思惟方法。 测试


1.3抽象类中的构造方法

抽象类中容许有构造方法,但构造方法是不能直接调用的,是交给子类去调用的,子类实例化过错中,永远是先调用父类的构造方法.抽象类中的构造函数是有做用的。子类继承抽象类时,构造函数不会被覆盖。 并且,在实例化子类对象时首先调用的是抽象类中的构造函数再调用子类中的. 所以,在抽象类中可使用构造函数封装继承子类公共的东西。 ui

2.接口(interface

2.1定义

接口是一个特殊的类,java中接口是由抽象方法和全局常量组成. this

接口也须要子类,不过子类再也不是继承,而是实现接口,经过implements关键字完成.接口有多继承的能力.

一个接口不能继承一个抽象类,可是一个接口却能够同时继承多个接口.

示例:

public interface Interface
{
  static final int i; //接口中不能有普通数据成员,只可以有静态的不能被修改的数据成员,
                       //static表示全局,final表示不可修改,
                       //能够不用static final 修饰,会隐式的声明为static和final
  

   public void method1(); //接口中的方法必定是抽象方法,因此不用abstract修饰
  

  public void method2(); //接口中不能赋予方法的默认行为,即不能有方法的具体实现
}
  简言之抽象类是一种功能不全的类,接口只是一个抽象方法声明和静态不能被修改的数据的集合,二者都不能被实例化。

  从某种意义上说,接口是一种特殊形式的抽象类,在java语言中抽象类表示的是一种继承关系,一个类只能继承继承一个抽象类,而一个类却能够实现多个接口。在许多状况下,接口确实能够代替抽象类,若是你不须要刻意表达属性上的继承的话。

2.2示例

interface A{
	public void fun() ;
}
class B implements A{
	public void fun(){
		System.out.println("Hello") ;
	}
};
public class InterPolDemo01{
	public static void main(String args[]){
		A a = new B() ;	// 为接口实例化
		a.fun() ;
	}
};
接口也能够像抽象类那样经过对象多态性进行对象的实例化操做.

3.引入抽象类和接口的目的

1、从类的层次结构上看,抽象类是在层次的顶端,但在实际的设计当中,通常来讲抽象类应当是后面才会出现。为何?实际上抽象类的获取有点像数学中的提取 公因式:ax+bxx就是抽象类,若是你没有前面的式子,你怎么知道x是否是公因式呢?在这点上,也符合人们认识世界的过程,先具体后抽象。所以在设计 过程当中若是你获得大量的具体概念并从当中找到其共性时,这个共性的集合就是抽象类应当是没错的。
2
interface从表面上看,和抽象类很类似,但用法彻底不一样。它的基本功能就是把一些绝不相关的类(概念)集合在一块儿造成一个新的、可集中操做的 “新类”。我给学生的一个典型例子就是“司机”。谁能够当司机?谁均可以,只要领取了驾照。因此我无论你是学生,白领、蓝领仍是老板,只要有驾照就是司 机。

interface DriverLicence {
Licence getLicence();
}

class StudentDriver extends Student implements DriverLicence {
}
class WhtieCollarEmployeeDriver extends WhtieCollarEmployee implements DriverLicence {
}
class BlueCollarEmployeeDriver extends BlueCollarEmployee implements DriverLicence {
}
class BossDriver extends Boss implements Driver {
}
当我定义了“汽车”类后,我就能够指定“司机”了。

class Car {
setDriver(DriverLicence driver);
}
这时候, Car的对象并不关心这个司机究竟是干什么的,他们的惟一共同点是领取了驾照(都实现了 DriverLicence接口)。这个,应当是接口最强大的地方也是抽象类没法比拟的。
总结:抽象类是提取具体类的公因式,而接口是为了将一些不相关的类“杂凑”成一个共同的群体。一般咱们平时养成良好的习惯就是多用接口,毕竟 java是单继承。


4.抽象类和接口的区别

4.1适配器设计模式

正常状况下,一个接口的子类要实现所有的抽象方法.但实际中多是根据须要选择性的覆写,用一个类先将接口实现,全部的抽象方法都是空覆写,而后继承此类,这个类使用抽象类,由于抽象类也不能直接使用.

interface Window{
	public void open() ;	// 打开窗口
	public void close() ;	// 关闭窗口
	public void icon() ;	// 最小化
	public void unicon() ;	// 最大化
}
abstract class WindowAdapter implements Window{
	public void open(){}
	public void close(){}
	public void icon(){}
	public void unicon(){}
};
class MyWindow extends WindowAdapter{
	public void open(){
		System.out.println("打开窗口!") ;
	}
};
public class AdpaterDemo{
	public static void main(String args[]){
		Window win = new MyWindow() ;
		win.open() ;
	}
}
这样就实现了部分覆写的目的 ,将一个类的接口转换成客户但愿的另一个接口 .Adapter模式使得本来因为接口不兼容而不能一块儿工做的那些类能够在一块儿工做 .

优势
①经过适配器,客户端能够调用同一接口,于是对客户端来讲是透明的.这样作更简单、更直接、更紧凑.
②复用了现存的类,解决了现存类和复用环境要求不一致的问题.
③将目标类和适配者类解耦,经过引入一个适配器类重用现有的适配者类,而无需修改原有代码.
④一个对象适配器能够把多个不一样的适配者类适配到同一个目标,也就是说,同一个适配器能够把适配者类和它的子类都适配到目标接口.
缺点
①对于对象适配器来讲,更换适配器的实现过程比较复杂.
适用场景: 系统须要使用现有的类,而这些类的接口不符合系统的接口. 或者旧的系统开发的类已经实现了一些功能,可是客户端却只能以另外接口的形式访问,但咱们不但愿手动更改原有类的时候. 还有使用第三方组件,组件接口定义和本身定义的不一样,不但愿修改本身的接口,可是要使用第三方组件接口的功能.
应用举例:使用过ADO.NET的开发人员应该都用过DataAdapter,它就是用做DataSet和数据源之间的适配器.DataAdapter经过映射FillUpdate来提供这一适配器.

备注:ADO.NET的名称起源于ADOActiveX Data Objects,是一个COM组件库,用于在以往的Microsoft技术中访问数据.之因此使用ADO.NET名称,是由于Microsoft但愿代表,这是在NET编程环境中优先使用的数据访问接口.
GoF的设计模式中,对适配器模式讲了两种类型,类适配器模式对象适配器模式.因为类适配器模式经过多重继承对一个接口与另外一个接口进行匹配,C#java等语言都不支持多重继承,于是这里只是介绍对象适配器.


4.2 工厂设计模式

代码示例:

interface Fruit{
	public void eat() ;
}
class Apple implements Fruit{
	public void eat(){
		System.out.println("吃苹果...") ;
	}
};
class Orange implements Fruit{
	public void eat(){
		System.out.println("吃橘子...") ;
	}
};
class Factory{	// 工厂类
	public static Fruit getFruit(String className){
		Fruit f = null ;
		if("apple".equals(className)){
			f = new Apple() ;
		}
		if("orange".equals(className)){
			f = new Orange() ;
		}
		return f ;
	}
};
public class InterDemo{
	public static void main(String args[]){
		Fruit f = Factory.getFruit(args[0]) ;
		if(f!=null){
			f.eat() ;
		}
	}
}
全部接口的实例化都经过工厂类取得 ,客户端调用的时候传入的名称不一样 ,完成的功能不一样 .

工厂模式主要用一下几种形态:简单工厂(Simple Factory,工厂方法(Factory Method,抽象工厂(Abstract Factory.(详细见设计模式的博文)


4.3 代理设计模式

示例:

interface Give{
	public void giveMoney() ;
}
class RealGive implements Give{
	public void giveMoney(){
		System.out.println("把钱还给我。。。。。") ;
	}
};
class ProxyGive implements Give{	// 代理公司
	private Give give = null ;
	public ProxyGive(Give give){
		this.give = give ;
	}
	public void before(){
		System.out.println("准备:小刀、绳索、钢筋、钢据、手枪、毒品") ;
	}
	public void giveMoney(){
		this.before() ;
		this.give.giveMoney() ;	// 表明真正的讨债者完成讨债的操做
		this.after() ;
	}
	public void after(){
		System.out.println("销毁全部罪证") ;
	}
};
public class ProxyDemo{
	public static void main(String args[]){
		Give give = new ProxyGive(new RealGive()) ;
		give.giveMoney() ;
	}
};
代理模式对外部提供统一的接口方法 ,而代理类在接口中实现对真实类的附加操做行为 ,从而不影响外部调用状况下 ,进行系统扩展 .即修改真实角色的操做的时候 ,尽可能不要修改他 ,而是在外部“包”一层进行附加行为 ,即代理类 .

例如:接口A有一个接口方法operator(),真实角色RealA实现接口A,则必须实现接口方法operator().客户端Client调用接口A的接方法operator().新需求须要修改RealA中的operator()的操做行为.但修改RealA就会影响原有系统的稳定性,还要从新测试.这是就须要代理类实现附加行为操做.建立代理ProxyA实现接口A,并将真实对象RealA注入进来.ProxyA实现接口方法operator(),另外还能够增长附加行为,而后调用真实对象的operator().从而达到了“对修改关闭,对扩展开放,保证了系统的稳定性.客户端Client调用还是接口A的接口方法operator(),只不过实例变为了ProxyA类了而已.也就是说代理模式实现了ocp原则.

备注:ocp原则即开闭原则(Open Closed Principle)是Java最基础的设计原则,有助于创建一个稳定的、灵活的系统.一个软件实体如类、模块和函数应该对扩展开放,对修改关闭.

4.4抽象类与接口的区别

经过对比可知,若是二者均可以使用的话,优先使用接口,由于它能够避免单继承的局限.

抽象类中容许包含接口:

abstract class A{
	public abstract void fun() ;
	interface B{	// 内部接口 
		public void print() ;
	}
};
class X extends A{
	public void fun(){
		System.out.println("****************") ;
	}
	class Y implements B{
		public void print(){
			System.out.println("===================") ;
		}
	};
};
public class TestDemo01{
	public static void main(String args[]){
		A a = new X() ;
		a.fun() ;
		A.B b = new X().new Y() ;
		b.print() ;
	}
};
接口中容许包含抽象类 :
interface A{
	public void fun() ;
	abstract class B{	// 内部抽象类
		public abstract void print() ;
	}
};
class X implements A{
	public void fun(){
		System.out.println("****************") ;
	}
	class Y extends B{
		public void print(){
			System.out.println("===================") ;
		}
	};
};
public class TestDemo02{
	public static void main(String args[]){
		A a = new X() ;
		a.fun() ;
		A.B b = new X().new Y() ;
		b.print() ;
	}
};



20150413


JAVA学习笔记系列

--------------------------------------------

                    联系方式

--------------------------------------------

        Weibo: ARESXIONG

        E-Mail: aresxdy@gmail.com

------------------------------------------------
相关文章
相关标签/搜索