java学习笔记8--接口总结
接着前面的学习:
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note8.html,转载请注明源地址。
生活中的接口:

什么是接口?
一个Java接口是一些方法特征的集合,但没有方法的实现。
在类中实现接口可以使用关键字implements,其基本格式如下:
[修饰符] class <类名> [extends 父类名] [implements 接口列表]{
}
修饰符:可选参数,用于指定类的访问权限,可选值为public、abstract和final。
类名:必选参数,用于指定类的名称,类名必须是合法的Java标识符。一般情况下,要求首字母大写。
extends 父类名:可选参数,用于指定要定义的类继承于哪个父类。当使用extends关键字时,父类名为必选参数。
implements 接口列表:可选参数,用于指定该类实现的是哪些接口。当使用implements关键字时,接口列表为必选参数。当接口列表中存在多个接口名时,各个接口名之间使用逗号分隔。
实现上面例子中的接口:
public interface PCI {  //java接口,相当于主板上的PCI插槽的规范
    public void start();
    public void stop();
}
Java接口中定义的方法在不同的地方被实现,可以具有完全不同的行为:
//声卡、网卡都实现了PCI插槽的规范,但行为完全不同
class SoundCard implements PCI {
public void start() {
System.out.println("SoundCard start...");
}
public void stop() {
System.out.println("Sound stop!");
}
}
class NetworkCard implements PCI {
public void start() {
System.out.println("NetworkCard send...");
}
public void stop() {
System.out.println("Send stop!");
}
}
可以使用Java接口标识类型。运行时,根据实际创建的对象类型调用相应的方法实现:
public class javatest {
    public static void main(String[] args) {
        PCI nc = new NetworkCard();
        PCI sc = new SoundCard();
        nc.start();
        sc.start();
    }
}
运行结果:
NetworkCard send...
SoundCard start...
为什么需要Java接口?
例子:为学校各中心开发这样一个小系统,包含类型:教员、中心、打印机,具体要求如下:
1、教员、以及中心都具有方法:输出详细信息
2、中心具有属性:打印机,能够通过中心的打印机打印教员或中心的详细信息
3、系统要具备良好的可扩展性与可维护性

先看方案1:
public class Teacher {
    //输出教员的详细信息
    public String detail() {
        return “I am a teacher!";
    }
}
public class Printer {
    public void print(String content) {
          System.out.println("start printing:");
          System.out.println(content);
    }
}
public class ggSchool {
    private Printer printer = new Printer();
    //输出学校的详细信息
    public String detail() {
        return “this is ggSchool";
    }
    //使用打印机打印教员信息
    public void print(Teacher t){
        printer.print(t.detail());
    }
    //使用打印机打印学院信息
    public void print(ggSchool s){
        printer.print(s.detail());
    }
}
那么,问题来了:
每增加一种新类型,都需要增加相应的print方法,程序的可扩展性及可维护性极差,这不符合系统的要求
先看方案2(使用接口):
教师、中心都存在一个共同的方法特征:detail,它们对detail方法有各自不同的实现——这完全符合Java接口的定义

代码如下:
public interface Introduceable {
    public String detail();
}
public class Teacher implements Introduceable {
    //输出教员的详细信息
    public String detail() {
        return “I am a teacher!";
    }
}
public class ggSchool implements Introduceable {
    private Printer printer = new Printer();
    //输出学校的详细信息
    public String detail() {
        return “this is ggSchool";
    }
    public void print(Introduceable intro) {    //使用print方法时,参数可以是任何Introduceable接口的实现类的对象,
                                                //不必再为不同的类型建立不同的print方法了
        printer.print(intro.detail());
    }
}
public class Printer {
    public void print(String content) {
          System.out.println("start printing:");
          System.out.println(content);
    }
}
通过Java接口,我们同样可以享受到多态性的好处,大大提高了程序的可扩展性及可维护性
什么是面向接口编程?
开发系统时,主体构架使用接口,接口构成系统的骨架,这样就可以通过更换接口的实现类来更换系统的实现
打印机有多种类型,比如:黑白打印机、彩色打印机等
学院可能配备其中任意一款打印机,负责打印教员、或者学院的详细信息
系统要具备良好的可扩展性与可维护性

第一步:抽象出Java接口
1、分析:
黑白、彩色打印机都存在一个共同的方法特征:print
黑白、彩色打印机对print方法有各自不同的实现
2、结论:
抽象出Java接口PrinterFace,在其中定义方法print
3、具体实现:
public interface PrinterFace {
       public void print(String content);
}
1、分析:
已经抽象出Java接口PrinterFace,并在其中定义了print方法黑白、彩色打印机对print方法有各自不同的实现
2、结论:黑白、彩色打印机都实现PrinterFace接口,各自实现print方法
3、具体实现:
public class ColorPrinter implements PrinterFace {
    public void print(String content) {
        System.out.println("彩色打印:");
        System.out.println(content);
    }
}
public class BlackPrinter implements PrinterFace {
    public void print(String content) {
        System.out.println("黑白打印:");
        System.out.println(content);
    }
}
第三步:使用Java接口
1、分析:主体构架使用接口, 让接口构成系统的骨架
2、结论:更换实现接口的类就可以更换系统的实现
3、具体实现:
public class ggSchool implements Introduceable{
    private PrinterFace printer;  //打印机
    public void setPrinter(PrinterFace p) {
        this.printer = p;
    }
    public String detail() {
        return "this is ggSchool!";
    }
    public void print(Introduceable intro){
        printer.print(intro.detail());
    }
}
public class Test {
    public static void main(String[] args) {
        // 创建学院实例
        ggSchool school=new ggSchool();
        //为该学院配备黑白打印机
        school.setPrinter(new BlackPrinter());
        school.print(school);
        //为该学院配备彩色打印机
        school.setPrinter(new ColorPrinter());
        school.print(school);
    }
}
抽象类与接口
抽象类的子类必须覆盖所有的抽象方法后才能被实例化,否则这个子类还是个抽象类。
如果一个抽象类中的所有方法都是抽象的,就可以将这个类用另外一种方式来定义,也就是接口定义。
抽象方法只需声明,不需实现。
接口是抽象方法和常量值的定义的集合。
从本质上讲,接口是一种特殊的抽象类。这种抽象类中包含常量和方法的定义,而没有变量和方法的实现。例如
注意:在接口的定义中,所有的成员都是public访问类型的,而不论是否用public关键字修饰;接口里的变量都是用public static final标识的,所以,接口中定义的变量就是全局静
态常量。
我们可以定义一个新的接口,用extends关键字去继承一个已有的接口。注意:只能接口继承接口,类不能继承接口。
一个类只能用implements关键字去实现一个接口中的所有方法
一个类可以在继承一个父类的同时,实现一个或多个接口,extends关键字必须位于implements关键字之前,如我们可以这样定义:
class classA {
    //...
}
public interface Interface1{
    //...
}
public interface Interface2{
    //...
}
class classB extends classA implements Interface1 Interface2{
    //...
}
抽象类和接口的区别
1.语法层面上的区别
1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
2.设计层面上的区别
1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而接口实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。
2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。
下面看一个网上流传最广泛的例子:门和警报的例子:门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:
abstract class Door {
    public abstract void open();
    public abstract void close();
}
或者:
interface Door {
    public abstract void open();
    public abstract void close();
}
但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:
1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;
2)将这三个功能都放在接口里,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。
从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。
interface Alram {
    void alarm();
}
abstract class Door {
    void open();
    void close();
}
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}
抽象类和接口在Java中的应用
例子:假设有若干 (如1000)个Circle,Rectangle以及若干个其他形状,希望计算它们的总面积,直截了当的做法是将它们分别放到多个数组中,分别循环求出各形状的面积,然后累加,这种做法是不漂亮的。如果还有其它形状:triangle,ellipses等,上述方法显得“累赘”。希望有一种统一的表示,例如用一个数组shape[],接受所有的形状,然后用:
for (i=0; i<shape.length; i++)
area_total += shape[i].area();
用抽象类实现多种形状面积的累加:
首先看看Circle和Rectangle两个类,如何完成相关参数的计算 :
class Circle {
    public float r;
    Circle(float r) {
          this.r = r;
    }
    public float area() {
        return 3.14 * r * r;
    }
}
class Rectangle {
    public float width, height;
    Rectangle (float w, float h) {
        width = w;
        height = h;
    }
    public float area() {
        return width * height;
    }
}
现在要利用抽象类实现多种形状面积的累加,确保每种形状分别用不同的方法来计算它们的面积和周长。因此,超类Shape包含抽象方法computeArea,然后在不同的子类中实现和覆盖这个方法,同时添加toString方法来显示几何形状的一些基本属性。现在声明了1000个Shape对象的数组,然后循环1000次随机产生1000个平面图形对象,形状为圆、矩形、正方形三种之一。
abstract class Shape {
    abstract float computeArea();
}
class Circle extends Shape {
    public float r;
    public Circle(float r) {
        this.r = r;
    }
    public float computeArea() {
        return (float)3.14 * r * r;
    }
}
class Rectangle extends Shape {
    public float width, height;
    Rectangle (float w, float h) {
        width = w; //这里不需"this"
        height = h;
    }
    public float computeArea() {
        return width * height;
    }
}
用接口实现多种形状面积的累加:
用接口的方式实现多种形状面积的累加,需要将用抽象类表示的Shape类改成接口。由于接口的语法定义要求,我们要把原来抽象类中的成员变量去掉,成员方法改成抽象方法computeArea(),该方法返回一个double类型。所以,这个接口定义为:
public interface Shape2 {
     public abstract double computeArea();
}
接口实现如下:
interface Shape2
{
public double computeArea();
}
class Circle2 implements Shape2
{
protected double radius;
public Circle2(double _radius) {
radius = _radius;
}
public double computeArea() {
return Math.PI * radius * radius;
}
}
class Rect2 implements Shape2
{
protected double width, height;
public Rect2(double w, double h) {
width = w;
height = h;
}
public double computeArea() {
return width * height;
}
}
用一个object数组实现多种形状面积的累加:
定义一个数组,它可以同时存储矩形、圆和正方形,每个Java类都是由Object扩展而来的。因此,所有的类都属于Object类型,我们可以创建一个Object类型的数组来存储任何类型的对象,也就可以存储矩形、圆和正方形对象
完整代码如下:
package javatest;
import java.util.*;
import java.io.*; interface Shape2 {
public double computeArea();
}
class Circle2 implements Shape2 {
protected double radius;
public Circle2(double _radius) {
radius = _radius;
}
public double computeArea() {
return Math.PI * radius * radius;
}
}
class Rect2 implements Shape2 {
protected double width, height;
public Rect2(double w, double h) {
width = w;
height = h;
}
public double computeArea() {
return width * height;
}
}
public class javatest {
public static void main(String args[ ]) {
Shape2 s[] = { new Circle2(4), new Rect2(4, 4),
new Circle2(10), new Rect2(20, 2), new Rect2(8, 10)
};
double total = 0;
for(int i = 0; i < s.length; i++)
total = total + s[i].computeArea();
System.out.println("totalArea = " + (int)total); }
}
参考资料
《java接口讲义》--siyuan学院
《java课程讲义》--东华大学计算机学院
http://www.cnblogs.com/dolphin0520/p/3811437.html#top
java学习笔记8--接口总结的更多相关文章
- Java 学习笔记(7)——接口与多态
		
上一篇说了Java面向对象中的继承关系,在继承中说到:调用对象中的成员变量时,根据引用类型来决定调用谁,而调用成员方法时由于多态的存在,具体调用谁的方法需要根据new出来的对象决定,这篇主要描述的是J ...
 - Java学习笔记 07 接口、继承与多态
		
一.类的继承 继承的好处 >>使整个程序架构具有一定的弹性,在程序中复用一些已经定义完善的类不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性 继承的基本思想 >>基 ...
 - Java学习笔记之接口
		
一.接口的概念与定义 首先考虑一个简单的接口的定义: public interface Output { int MAX_LINE = 40; void out(); void getData(Str ...
 - 1)Java学习笔记:接口和抽象类的异同
		
Java接口和抽象类很像,他们有哪些相同点和异同点呢,下面我们做一个小结 相同 ① 都不能被实例化,都位于继承树的顶端,用于被实现或者继承 ② 都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必 ...
 - Java学习笔记之——接口
		
接口(interface)和抽象类 为何要定义接口?------>实现不同的方法 Java的设计思想是单继承和多实现 类:属性和方法的集合,方法围绕着属性转,可以理解为自定义的类型 接口:与类是 ...
 - Java学习笔记_22_Set接口的实现类
		
22.Set接口的实现类: Set接口存放的元素是无序的且不包括反复元素. 1>实现类HashSet: HashSet类依据元素的哈希码进行存放,取出时也能够依据哈希码高速找到.HashSet不 ...
 - Java学习笔记之接口和抽象类
		
接口(interface)1.interface创建一个接口,implements实现接口 interface jiekou{} class lie implements jiekou{}2.接口可以 ...
 - Java学习笔记 抽象类 接口 多态
		
instanceof 对象名 instanceof 类名 该对象是否属于该类 Animal animal = new Dog(); if(animal instanceof Dog){ Dog d = ...
 - java学习笔记_接口
		
接口:interface(关键字) public interface USB {} 1. 接口中都是抽象方法,方法前面的可见度(public.private)和抽象关键字(abstract)可以不写. ...
 - Java学习笔记——Map接口
		
Map接口 Map接口 Map接口中键和值一一映射. 可以通过键来获取值. 异常 NoSuchElementException:访问的值不存在 ClassCastException:对象类型错误 Un ...
 
随机推荐
- mysql 事务回滚
			
begindeclare t_error integer default 0; //添加变量t_error并赋初始值为0declare continue handler for sqlexcepti ...
 - 【转】eval()函数用法
			
eval 功能:将字符串str当成有效的表达式来求值并返回计算结果. 语法: eval(source[, globals[, locals]]) -> value 参数: source:一个Py ...
 - NOIP2013 D1 T2火柴排队
			
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...
 - shell 从变量中切割字符串
			
1. 在shell变量中切割字符串 shell中截取字符串的方法有很多中,${expression}一共有9种使用方法.${parameter:-word}${parameter:=word}${pa ...
 - 深度学习笔记之【随机梯度下降(SGD)】
			
随机梯度下降 几乎所有的深度学习算法都用到了一个非常重要的算法:随机梯度下降(stochastic gradient descent,SGD) 随机梯度下降是梯度下降算法的一个扩展 机器学习中一个反复 ...
 - java getenv getProperties区别
			
网上很多使用的是getProperties.说获得系统变量,但是其实不正确.getProperties中所谓的"system properties"其实是指"java s ...
 - 深入理解javascript函数系列第三篇
			
前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...
 - [webpack] devtool里的7种SourceMap[转]
			
modle: development cheap-source-map debug 不太方便,不是以原来的文件的形式cheap-module-source-map 可以 debugcheap-modu ...
 - Scrapy实战篇(七)之Scrapy配合Selenium爬取京东商城信息(下)
			
之前我们使用了selenium加Firefox作为下载中间件来实现爬取京东的商品信息.但是在大规模的爬取的时候,Firefox消耗资源比较多,因此我们希望换一种资源消耗更小的方法来爬取相关的信息. 下 ...
 - 01-学前入门概念:.net与c#
			
.Net是由(.Net 平台和.Net FrameWork框架)这两部分组成. .Net FrameWork是由(CLR公共语言运行时和.Net 类库组成). .Net FrameWork框架是.Ne ...