大家好,我是个编程新手,自信但理智,写个比较吸引人的题目,主要希望能吸引到高手指导一下:)我对java不是很了解,但是这样一个面向对象的语言应该可以实现聚合吧,将一个已有的对象在新定义的对象中不通过继承重复使用,在PHP4中似乎可以这样实现:class A{
...
 function func_a(){
  ...
 }
}class B{
 var $a;
 function B(&$a){
  $this->a=$a;
 }
 ...
}$b=new B(new A());
$b->a->func_a()
我想Java中应该也有这样类似的方法吧,如果的确是这样,我就很纳闷接口这个东西是不是有点多余,据我了解,很多人认为接口能和抽象类同时存在的原因是因为调用接口的类可能已经继承了其他的类而java中又不允许多重继承,可是,这个问题完全可以通过在类中直接调用由抽象类生成的具体类来实现啊,而且,在我看来,把接口的具体实现放在其他的类中不如先把它实现了,在放入需要它的类中好,那样不是违反了最少知识原理了吗?因为刚学这些,有很多地方不懂,这些仅仅是我从目前掌握的知识产生出的疑问,接口可能有比我理解的更深的含义,如果是这样,能不能麻烦高手点拨一下,指出我理解上的错误,或是没有了解需要了解的东西? 在这谢谢大家了~!!

解决方案 »

  1.   

    举个例子吧,首先,你应该知道接口是一种契约,它与实现方式无关但是类,即使是抽象类,你都能自定义成员变量,而成员变量往往就与实现方式有关。这一点的实际意义不大。但是有一点,类会暴露太多不必要,甚至不能暴露的东西,你看一下java.util中,大部分的数据结构,都被设计成了接口-抽象类-最后实际类例如Collection-List
         L-AbstractCollection
           L-AbstractList
             L-ArrayList但是有一个,由于历史原因,被设计成了类,比如Stack extends Vector,
    你应该知道Stack的数据访问模式,就只能是LIFO,但是Vector是一个List,可以随机访问,可以任意增减。结果Stack s = new Stack();不光能够pop/push/peer还能add,get,set,remove如果你用一个接口IStack 里面只有pop/push/peer方法,然后仍然通过继承Vector的方式实现,IStack s = new MyStack();此时,就无法add,get,set,remove
      

  2.   

    谢谢shine333,好像你的意思是说,接口可以隐藏不需要的方法,而抽象函数却不可以?能不能举一个简单的例子呢?那个stack和vector的描述,我看不太懂:)
      

  3.   

    同意
    java中接口可是最牛叉的了!
      

  4.   

    如果没有了接口,java就是一潭死水;
    如果没有了接口,就象你做数学题时没有小九九表........
      

  5.   

    我学过VB,delphi,asp,C,Java四种语言,接口这个概念,对JAVA这种特有的开发模式真的很有用,可能学JAVA的人不知道,相比于其它语言,JAVA是最能体现“对象化编程”的,无论哪种JAVA的框架,技术都离不开这个最基本的原则.而其他的语言,很多是“过程化编程”。举个例子,如果JAVA中要实现某个可重用的代码块,通常是把这个代码块写成一个类的形式的,其实这么类,很多时候都是一个对象,这个对象有方法,有属性的,要用到这个对象时,生成一个这个对象的新实例,然后调用这个实例中的方法的.而像VB,ASP,Dephi这些,虽然也有“对象”的概念,但如果要写一个可重用模块,通常是写成一个过程或函数的形式的,这些过程或函数,只是一个事务处理过程,而不是一个对象。   正是因为java是“对象化”的,所以在代码中管理一个工程中的众多的对象就成了一个难题,于是就出现了接口的概念,接口使众多实现了它的对象都属于一种共同的"类型",这样的话,就可以通过一个接口来实例化众多不同的对象,另一方面,由于实现了同一个接口的各个对象必须定义在接口中所声明的所有虚方法,这就使这些不同的对象有了共同的方法。JAVA中的“对象工厂”就是通过接口来实现对不同的对象的管理的。其实我也学了JAVA不久,不知我的理解有没有错,大家见笑了。
      

  6.   

    其实java还可以通过接口,把不同的对象进行“装配”,使对象间建立一种逻辑关系,或者讲形成一种新的更大的“新对象”,Spring就是这样,我也正在学习当中,不说了,免得贻笑大方。
      

  7.   

    //访问数据库的接口
    public interface IUserDao{
      public abstract User getUser(String id);
    }//实现IUserDao的类,用Hibernate实现访问数据库的相关操作
    public class UserDaoHibernateImpl implements IUserDao{
      public User getUser(String id){
        //hibernate的数据库操作,然后返回查询到的user
      }
    }//实现IUserDao的类,用基本的JDBC实现访问数据库的相关操作
    public class UserDaoJdbcImpl implements IUserDao{
      public User getUser(String id){
        //JDBC实现访问数据库,然后返回查询到的user
      }
    }//实现IUserDao的类,用Spring的JDBC实现访问数据库的相关操作
    public class UserDaoSpringImpl implements IUserDao{
      public User getUser(String id){
        //Spring的JDBC实现访问数据库,然后返回查询到的user
      }
    }public class Test{
      public void oneMethod(IUserDao userDao){
        //do Something.....
      }
    } IUserDao是个接口.
    Test是个测试类.这个类中有一个方法,参数为实现了IUserDao的对象.所以上面的三个实现了IUserDao的接口的类都可以作为参数传递给这个方法.如果oneMethod方法的参数类型改为UserDaoHibernateImpl,UserDaoJdbcImpl和UserDaoSpringImpl的任何一个,那么就只能传递某个具体的实现类了.所以接口是一个契约或者约定,还可以认为是规范.
    public void oneMethod(IUserDao userDao)方法中的IUserDao告诉调用者,只要实现了IUserDao这个接口的任何类都可以传递给我,而不管你是如何实现的,当然也不会管你是从火星还是太阳系以外获得与数据库的连接!
    也就是获得"通用性".另外一个典型的例子是java中的数据库连接的javax.sql.DataSource接口,你可以看到,无论你如何链接数据库,你最后都会返回DataSource的实现
    打字好累   :)
      

  8.   

    这个例子不懂,你需要好好看看,java.util不会的话,等于不会java举个生动一点的例子public interface BritishSpy {
      public String speak(); //英国间谍讲英语
    }public interface GermanSpy {
      public String sprechen(); //德国间谍讲德语
    }public class DoubleAgent implements BritishSpy, GermanSpy {
      public String speak() { return "Hello"; }
      public String sprechen() { return "Gutentag"; }
    }public class Agency {
      public static void toMI5(BritishSpy spy) {
        //军情5处当然只能说英语,做英国间谍
        spy.speak();
        //spy.sprechen();不可见
      }  public static void inGermany(GermanSpy spy) {
        //spy.speak();不可见
        spy.sprechen();
      }  public static void main(String[] args) {
        DoubleAgent da = new DoubleAgent();
        EnglishSpy es = (EnglishSpy) da;
        GermanSpy gs = (GermanSpy) da;
        toMI5(da); //MI5也不知道他是一个双重间谍,只知道他是BritishSpy
        toMI5(es); //更安全
        //toMI5(gs); 不可能
        inGermany(da); //在德国还是安全的,德国人不知道他的双重间谍身份,只知道他是GermanSpy
        inGermany(gs); 
        //inGermany(es); 不可能
      }
    }
      

  9.   

    假设你只用class,因为不能多重继承,所以,speak()/sprechen()比然声明在同一个class里面
    public abstract class DoubleAgent extends Spy/**(略...)*/ {
      public abstract String speak();
      public abstract String sprechen();
    }public class PoorDoubleAgent {
      public String speak() { return "Hello"; }
      public String sprechen() { return "Gutentag"; }
    }晚了,不管你PoorDoubleAgent a = new PoorDoubleAgent();还是DoubleAgent a = new PoorDoubleAgent();,全世界都知道他是一个双重间谍,他到哪里都必死无疑
      

  10.   

    生动
    我只知道接口是java实现类似于多重继承的功能,从没想那么多
      

  11.   

    shine333:其实你举这个例子,是不是想表达“接口增加了一个类的通用性”这个观点呢?
      

  12.   

    一个真实的赚钱网站http://www.chenhs.nud8.com
      

  13.   

    感谢shine333,帮我举了生动的例子,刚才在忙,我顶一下,回家再仔细看:)
      

  14.   

    shine333 对接口的理解比较深刻,例子有趣.
    我想问一下楼主,在c++里面"回调"是通过将方法的指针传给被调用者,在java里没有指针,不用接口如何实现?  比如 class C 要调用 A中的doSth()方法,然后又要在doSth()里面回调自己 里的方法.听上去是不是有点多余? 但是有时候用得着,比如有个A 类,他有个很好的copy文件的方法,
    但是我想给他加个自己的进程条显示,怎么办?//A.java
    public class A {        public A(){                System.out.println("Hello,A!");
            }        public void doSth(D d){                //这里做很多事情
                    d.sayHello();  //这里回调 调用者内部的方法        }}
    //C.java
    public class C implements D{        
            public void sayHello(){                System.out.println("Hello,I am c");
            }
            public static void main(String[] args){                A a=new A();
                    C c=new C();
                    a.doSth(c);
            }}//D.java
    public interface D{        public void sayHello();
    }
      

  15.   

    to:
     terry_yip(Endless Road) 你说的一点也不对。
      

  16.   

    还是先看看设计模式吧,,java的模式
      

  17.   

    前面举了一个关于“安全性”方面的例子接口只暴露给对方(比如Agent的军情5处方法)它所需要的足够信息,其他无关的,甚至有害的信息不会暴露给对方。因为,我传给你的是接口类型,我除了是这个接口(和这个接口的父接口,inteface A extends B, C)的实例外,你顶多知道我是一个Object(不是int:P),其他的姓甚名谁,哪里住址,父母安好,兄妹几何都与你无关,我们只需要关心我们签订的合同(接口)再举一个有关灵活性方面的例子假设某公司已经有一个更新过N代的,逻辑复杂无比
    public class A extends B /** where b extends c, c extends d and so on... */ {
      public void init() {...}
      public void release() {...}
      public String doXXX() {...}
      public String doYYY() {...}
    }而这个A又被很多类继承或使用,doXXX/doYYY 方法已经无法更改假设现在这个公司要参加某个标准化组织,而这个组织要求所有提供这样的方法String getXXX(); String getYYY();加入用接口标准化组织只要规定成员们都实现
    public interface IBusiness {
      String getXXX(); 
      String getYYY();
    }
    而这个公司只需要稍微改写一点点即可
    public class A extends B /** where b extends c, c extends d and so on... */ 
      implements IBusiness {
      public String getXXX() { return doXXX(); }
      public String getYYY() { return doYYY(); }//保留
      public void init() {...}
      public void release() {...}
      public String doXXX() {...}
      public String doYYY() {...}
    }这样既满足了标准化的要求,又满足了无需修改原来继承A或者使用A的无数个class(有些可能在用户那里,不可能更改)假如不用接口,你有两个选择:数典忘祖或者自绝于人数典忘祖:
    你的新A必须继承标准化组织的Business,原来a,b, c d...里面的代码全部得重新组织到这个新的A里面,与此同时,那些调用或者继承A的class难保不需要重写自绝于人
    原来的就让它去,谁也别再提它了,我们以后就用新的NewA,结果,你的新客户倒是满足了标准化,你的老客户可就 :< :@ :$,而且以后需要维护A和NewA
      

  18.   

    接口和抽象,继承都是OOP的精华所在
      

  19.   

    interface就是类之间的合同和契约
    好帖子,
    不顶没天理啊,
      

  20.   

    shine333(enihs) 老兄讲的相当好、而且文采也不错。在下在学习中、忍不住支持一下
      

  21.   

    JAVA是面向对象的,在JAVA里可以说"一切都是对象". 对象都会有属性和行为,一些对象的类似行为和属性可以抽象为接口.就是把一些共性的东西放在接口里. 不知道我的理解对不对.
      

  22.   

    回复人: shine333(enihs) ( ) 信誉:115 
    老兄,本身理解深刻,再加上例子取得好。天生一副做培训师的料啊。
      

  23.   

    接口作为java语言对多继承的补充,因为在java里,类与类之间只能单继承,即一个子类只有一个父类,而通过接口就可以实现继承多个类了,这里应该叫“实现”一个类可以实现几个接口
    例如,
    public class MyApplet implements Runnable,MouseListener{
    .......
    }
    据我所知,在java GUI 这块,是经常用到的,特别是在执行事件的时候。
      

  24.   

    对了,补充一句,大家都知道openGL,那个3d图形数据库,jogl,也就是openGL的java绑定,也是需要用到接口来实现的,我觉得gui应该是他的基础知识。对了,顺便问一句,谁知道哪能找到jogl的中文教程?谢谢!
      

  25.   

    “interface”(接口)关键字使抽象的概念更深入了一层。我们可将其想象为一个“纯”抽象类。它允许创建者规定一个类的基本形式:方法名、自变量列表以及返回类型,但不规定方法主体。接口也包含了基本数据类型的数据成员,但它们都默认为static和final。接口只提供一种形式,并不提供实施的细节。
    接口这样描述自己:“对于实现我的所有类,看起来都应该象我现在这个样子”。因此,采用了一个特定接口的所有代码都知道对于那个接口可能会调用什么方法。这便是接口的全部含义。所以我们常把接口用于建立类和类之间的一个“协议”。有些面向对象的程序设计语言采用了一个名为“protocol”(协议)的关键字,它做的便是与接口相同的事情。
    为创建一个接口,请使用interface关键字,而不要用class。与类相似,我们可在interface关键字的前面增加一个public关键字(但只有接口定义于同名的一个文件内);或者将其省略,营造一种“友好的”状态。
    为了生成与一个特定的接口(或一组接口)相符的类,要使用implements(实现)关键字。我们要表达的意思是“接口看起来就象那个样子,这儿是它具体的工作细节”。除这些之外,我们其他的工作都与继承极为相似。下面是乐器例子的示意图:
     
    具体实现了一个接口以后,就获得了一个普通的类,可用标准方式对其进行扩展。
    可决定将一个接口中的方法声明明确定义为“public”。但即便不明确定义,它们也会默认为public。所以在实现一个接口的时候,来自接口的方法必须定义成public。否则的话,它们会默认为“友好的”,而且会限制我们在继承过程中对一个方法的访问——Java编译器不允许我们那样做。
    在Instrument例子的修改版本中,大家可明确地看出这一点。注意接口中的每个方法都严格地是一个声明,它是编译器唯一允许的。除此以外,Instrument5中没有一个方法被声明为public,但它们都会自动获得public属性。如下所示://: Music5.java
    // Interfaces
    import java.util.*;interface Instrument5 {
      // Compile-time constant:
      int i = 5; // static & final
      // Cannot have method definitions:
      void play(); // Automatically public
      String what();
      void adjust();
    }class Wind5 implements Instrument5 {
      public void play() {
        System.out.println("Wind5.play()");
      }
      public String what() { return "Wind5"; }
      public void adjust() {}
    }class Percussion5 implements Instrument5 {
      public void play() {
        System.out.println("Percussion5.play()");
      }
      public String what() { return "Percussion5"; }
      public void adjust() {}
    }class Stringed5 implements Instrument5 {
      public void play() {
        System.out.println("Stringed5.play()");
      }
      public String what() { return "Stringed5"; }
      public void adjust() {}
    }class Brass5 extends Wind5 {
      public void play() {
        System.out.println("Brass5.play()");
      }
      public void adjust() { 
        System.out.println("Brass5.adjust()");
      }
    }class Woodwind5 extends Wind5 {
      public void play() {
        System.out.println("Woodwind5.play()");
      }
      public String what() { return "Woodwind5"; }
    }public class Music5 {
      // Doesn't care about type, so new types
      // added to the system still work right:
      static void tune(Instrument5 i) {
        // ...
        i.play();
      }
      static void tuneAll(Instrument5[] e) {
        for(int i = 0; i < e.length; i++)
          tune(e[i]);
      }
      public static void main(String[] args) {
        Instrument5[] orchestra = new Instrument5[5];
        int i = 0;
        // Upcasting during addition to the array:
        orchestra[i++] = new Wind5();
        orchestra[i++] = new Percussion5();
        orchestra[i++] = new Stringed5();
        orchestra[i++] = new Brass5();
        orchestra[i++] = new Woodwind5();
        tuneAll(orchestra);
      }
    } ///:~代码剩余的部分按相同的方式工作。我们可以自由决定上溯造型到一个名为Instrument5的“普通”类,一个名为Instrument5的“抽象”类,或者一个名为Instrument5的“接口”。所有行为都是相同的。事实上,我们在tune()方法中可以发现没有任何证据显示Instrument5到底是个“普通”类、“抽象”类还是一个“接口”。这是做是故意的:每种方法都使程序员能对对象的创建与使用进行不同的控制。
      

  26.   

    贴子太长了看着也累.但学到一点,多看看java api,especially java.util
      

  27.   

    我就很纳闷接口这个东西是不是有点多余,据我了解,很多人认为接口能和抽象类同时存在的原因
    ====================================
    接口可以减少类间的耦合度;比如说我表现层可以只操作业务操作的接口,而业务逻辑发生变化时,表现层的一切都不会影响;在这个地方,接口的价值就体现了;而且,现在的Spring等无不体现着Java“面向接口编程”,而不应该是“面向实现编程”