≈佐

—— 有恒则成。

统计

最新评论

接口

接 口

接口在java中尤其是面向对象语言中是一个很重要的概念.
java中使用接口概念的原因:java不支持多继承性,即一个类只能有一个父类.单继承性使得java简单,易于管理程序.为了克服单继承的缺点,java使用了接口.

一个类可以实现多个接口.使用关键字interface来定义一个接口.接口的定义和类的定义很相似,分为接口的声明和接口体.

1.接口声明及接口体

前面曾使用class关键字来声明类,接口通过使用关键字interface来声明.格式

interface 接口的名字

接口体中包含常量的定义和方法定义两部分.接口体中只进行方法的声明,不允许提供方法的实现,所以,方法的定义没有方法体,且

用";"结尾.如


 

interface Printable
{
    
final int max=100;
    
void add();
    
float sum(float x,float y);
}

 

2.接口的使用
一个类通过使用关键字implements声明自己使用一个或多个接口.如果使用多个接口,用逗号隔开接口名.如:
class A implements Printable,Addable

类A使用接口Printable 和接口Addable

子类使用接口格式也一样,如:
class B extends A implements Printable,Addable
子类B使用接口Printable 和接口Addable

如果一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体.需要注意的是:在类中实现接口的方法时,方法的名字,返回值类型,参数个数及类型,必须与接口中的完全一致.特别要注意的是:接口中的方法默认是public abstract方法,所以类在实现接口方法时必须给出方法体,并且一定要用public来修饰,而且接口中的常量默认是public static常量.

由于接口体中只有常量定义和public的abstract方法定义,程序在编写接口时,允许省略常量前面的public,final和static修饰,也允许省略方法前的public和abstract修饰.另外,如果接口方法的返回类型不是void型,那么在类中实现接口方法时,方法体至少要有一个return语句;如果是void型,类体除了两个大括号外,也可以没有任何语句.


java提供的接口都在相应的包中,通过引入包可以使用java提供的接口.也可以自己定义接口,一个java源文件就是由类和接口组成的.

虽然"使用接口"的描述的很罗嗦,看看下面的例子就容易掌握了

 

interface Computable//定义接口
{
        
int MAX=100;
        
int f(int x);//声明方法(是public abstract型的,只是省略了关键字)
}
class China implements Computable
{
        
int number;
        
public int f(int x) //不要忘记public关键字
        {
                
int sum=0;
                
for(int i=1;i<=x;i++)
                    {sum
=sum+i;}
        
return sum;
        }
}
class Japan implements Computable
{
        
int number;
        
public int f(int x)//不要忘记public关键字
        {
                
return 44+x; 
        }
}
public class E
{
        
public static void main(String args[])
        {
                China zhang;
                Japan henlu;
                zhang
=new China();
                henlu
=new Japan();
                zhang.number
=991898+Computable.MAX; 
                henlu.number
=941448+Computable.MAX;
                System.out.println(
"number:"+zhang.number+"求和"+zhang.f(100));
                System.out.println(
"number:"+henlu.number+"求和"+henlu.f(100));
        }
}

 

还要注意的就是如果一个类声明实现一个接口,但没有实现接口中的所有方法,那么这个类必须是abstract类,如

interface Computable
{
        
final int max=100;
        
void speak(String s);
        
int f(int x);
        
abstract class A implements Computable//类A使用的接口但类体中并没有实现接口中speak()的方法,所以此类必须是抽象类
        {
                
public int f(int x)//只是实现了接口中的一个方法
                {
                        
int sum=0;
                        
for(int i=1;i<=x;i++)
                        sum
+=i;
                        
return
                  }
            }

 


类实现的接口方法以及接口中的常量可以被类的对象调用,而且常量也可以用类名或接口名直接调用.这理解不难,因为前面讲过final修饰的常量,在内存程序加载字节码时,内存就给常量分配了一个固定空间,不可以改变(直到程序结束),所以这个地址是固定了,并且这个常量是来自一个接口,所以此接口名或者使用这个接口的类的对象可以直接调用这个常量喽.方法也是一样的.

接口声明时,如果关键字interface前面加public关键字,就称这样的接口是一个public接口.public接口可以被任何一个类使用.如果一个接口不加public修饰,就称为友好接口类,友好接口可以被同一包中的类使用.

如果父类使用了某个接口,那么子类也就自然使用了该接口,子类不必再使用关键字implements声明自己使用这个接口了.

接口也可以被继承,即可以通过关键字extends声明一个接口是另一个接口的子接口.由于接口中的方法和常量都是public的,子接口将继承父接口中的全部方法和常量.

3.理解接口

讲了半天,你已经知道如何定义和使用接口了,但你会疑问,使用接口的好处在哪里?其实接口的思想就在于它可以增加很多类都需要实现的功能,使用相同的接口类不一定由继承的关系,就是象各种各样的商品,他们可能隶属不同的公司,工商部门要求不管哪里的商品必须具有显示商标的功能(即实现同一接口),但商标的具体制作由各个公司自己去实现,这就是接口的灵活所在.再比如,你

是一个项目的主管,你需要管理许多部门,这些部门要开发一些软件所需要的类,你可能要求某个类实现一个接口,也就是说你对一些类是否具有这个功能非常关心,但不关心功能的具体实现.比如,这个功能是speaklove,但你不关心是用汉语实现功能还是用英语实现speaklove.还是用个例子来理解一下接口,如:

interface 收费 //定义接口收费功能
{
        
public void 收取费用();
}
interface 调节温度 //定义接口调节温度功能
{
        
public void controlTemperature();
}
class 公共汽车 implements 收费 //一般的公共汽车只具有收费功能,空调车少
{
        
public void 收取费用()
        {
                System.out.println(
"公共汽车:一元/张,不计算公里数");
        }
}
class 出租车 implements 收费, 调节温度//出租车比较高级当然除了收费功能还有空调喽
{
        
public void 收取费用()
        {
                System.out.println(
"出租车:1.60元/公里,起价3公里");
        }
        
public void controlTemperature()
        {
                System.out.println(
"安装了Hair空调");
        }
}
class 电影院 implements 收费,调节温度//电影院有收费和调节温度功能
{
        
public void 收取费用()
        {
                System.out.println(
"电影院:门票,十元/张");
        }
        
public void controlTemperature()
        {
                System.out.println(
"安装了中央空调");
        }
}
class E
{
        
public static void main(String args[])
        {
                公共汽车 七路
=new 公共汽车();
                出租车 天宇
=new 出租车();
                电影院 红星
=new 电影院();
                七路.收取费用();
                天宇.收取费用();
                红星.收取费用();
                天宇.controlTemperature();
                红星.controlTemperature();
        }
}

从这个例子可以看出来定义了多个接口,不同类根据自己的需要可以灵活使用想要的接口.建议接口里实现的方法越少越好,可以定义多个接口来实现多种功能.


4.接口回调
接口回调是指:可以把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量中.那么该接口变量就可以调用被类实现的接口中的方法.实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法.通过例子掌握接口回调的意义,如

interface ShowMessage//接口
{
        
void 显示商标(String s);
}
class TV implements ShowMessage//使用接口
{
        
public void 显示商标(String s)
        {
                System.out.println(s);
        }
}
class PC implements ShowMessage//使用接口
{
        
public void 显示商标(String s)
        {
                System.out.println(s);
        }
}
public class E
{
        
public static void main(String args[])
        {
                ShowMessage sm;
//声明了一个接口变量
                sm=new TV();//把使用该接口的类的对象赋给接口变量
                sm.显示商标("长城牌电视机");//此时接口变量就可以使用被该类实现的接口中的方法了
                sm=new PC(); //另一个对象赋给接口变量
                sm.显示商标("联想奔月5008PC机");
        }
}

 

体会一下,如果你理解上节课讲的上转型对象,就可以很轻松理解接口回调的过程
回顾下上节课中讲抽象类时给的例子,计算面积的那个,下面用接口l来实现,比较不同点

 

interface Computerable
{
        
public double 求面积();
}
class 梯形 implements Computerable
{
        
double a,b,h;
        梯形(
double a,double b,double h)
        {
                
this.a=a;
                
this.b=b;
                
this.h=h;
          }
        
public double 求面积()
        {
                
return((1/2.0)*(a+b)*h);
        }
}
class 圆形 implements Computerable
{
        
double r;
         圆形(
double r)
        {
                
this.r=r;
        }
        
public double 求面积()
        {
                
return(3.14*r*r);
         }
}
class 堆
{
        Computerable 底;
        
double 高;
        堆(Computerable 底,
double 高)
        {
                
this.底=底;
                
this.高=高;
        }
        
void 换底(Computerable 底)
        {
                
this.底=底;
        }
        
public double 求体积()
        {
                
return (底.求面积()*高)/3.0;
        }
}
public class E
{
        
public static void main(String args[])
        {
                堆 zui;
                Computerable bottom;
//声明接口变量
                bottom=new 梯形(2.0,7.0,10.7); //回调
                System.out.println("梯形的面积"+bottom.求面积());
                zui
=new 堆(bottom,30);
                System.out.println(
"梯形底的堆的体积"+zui.求体积());
                bottom
=new 圆形(10);
                System.out.println(
"半径是10的圆的面积"+bottom.求面积());
                zui.换底(bottom);
                System.out.println(
"圆形底的堆的体积"+zui.求体积());
        }
}

上面的例子明白后或者理解了什么时接口回调,再讨论下"接口做参数"的概念

如果准备给一个方法的参数传递一个值,可能希望该方法的参数的类型时都不了类型,这样就可以想该参数传递byte int long float double类型的数据.

如果一个方法的参数是接口类型,就可以将任何实现该接口类的实例传递给该接口参数,那么接口参数就可以回调类实现的接口方法.

比如上面的例子中堆那个类,

class 堆
{
        Computerable 底;
//声明接口类型变量
        double 高;
        堆(Computerable 底,
double 高) //方法的参数类型是接口
        {
                    
this.底=底;
                    
this.高=高;
        }
        
void 换底(Computerable 底)
        {
                
this.底=底;
        }
        
public double 求体积()
        {
                 
return (底.求面积()*高)/3.0;//"底"是接口类型的变量怎么能使用求面积的方法呢,说明了肯定是接口回调,即传进来的参数是一个被对象赋过值的接口变量,才使得此接口变量可以使用被类实现的方法
        }
}

 

如果还是不太明白过程,把下面的程序理解就行了

 

interface SpeakHello //接口
{
        
void speakHello();
}
class Chinese implements SpeakHello//使用接口
{
        
public void speakHello()
        {
                System.out.println(
"中国人习惯问候语:你好,吃饭了吗? ");
        }
}
class English implements SpeakHello//使用接口
{
        
public void speakHello()
        {
                System.out.println(
"英国人习惯问候语:你好,天气不错 ");
        }
}
class KindHello
{
        
public void lookHello(SpeakHello hello)//接口做参数
        {
                hello.speakHello();
//被赋值了的接口(回调后的接口)就可以使用被类实现了的方法speakHello();
        }
}
public class E
{
        
public static void main(String args[])
        {
                KindHello kindHello
=new KindHello();
                kindHello.lookHello(
new Chinese());//可以把它分解为SpeakHello hello; 和hello=new Chinese();
                 kindHello.lookHello(new English());
        }
}

 


总结:花了一个篇幅讲接口,就证明它的重要性,灵活使用接口对以后编写java程序再性能上会有质的提高的.

posted on 2008-09-25 00:02 ≈佐 阅读(207) 评论(0)  编辑  收藏 所属分类: J2SE 知识