大家好,我是个编程新手,自信但理智,写个比较吸引人的题目,主要希望能吸引到高手指导一下:)我对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中又不允许多重继承,可是,这个问题完全可以通过在类中直接调用由抽象类生成的具体类来实现啊,而且,在我看来,把接口的具体实现放在其他的类中不如先把它实现了,在放入需要它的类中好,那样不是违反了最少知识原理了吗?因为刚学这些,有很多地方不懂,这些仅仅是我从目前掌握的知识产生出的疑问,接口可能有比我理解的更深的含义,如果是这样,能不能麻烦高手点拨一下,指出我理解上的错误,或是没有了解需要了解的东西? 在这谢谢大家了~!!
...
function func_a(){
...
}
}class B{
var $a;
function B(&$a){
$this->a=$a;
}
...
}$b=new B(new A());
$b->a->func_a()
我想Java中应该也有这样类似的方法吧,如果的确是这样,我就很纳闷接口这个东西是不是有点多余,据我了解,很多人认为接口能和抽象类同时存在的原因是因为调用接口的类可能已经继承了其他的类而java中又不允许多重继承,可是,这个问题完全可以通过在类中直接调用由抽象类生成的具体类来实现啊,而且,在我看来,把接口的具体实现放在其他的类中不如先把它实现了,在放入需要它的类中好,那样不是违反了最少知识原理了吗?因为刚学这些,有很多地方不懂,这些仅仅是我从目前掌握的知识产生出的疑问,接口可能有比我理解的更深的含义,如果是这样,能不能麻烦高手点拨一下,指出我理解上的错误,或是没有了解需要了解的东西? 在这谢谢大家了~!!
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
java中接口可是最牛叉的了!
如果没有了接口,就象你做数学题时没有小九九表........
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的实现
打字好累 :)
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); 不可能
}
}
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();,全世界都知道他是一个双重间谍,他到哪里都必死无疑
我只知道接口是java实现类似于多重继承的功能,从没想那么多
我想问一下楼主,在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();
}
terry_yip(Endless Road) 你说的一点也不对。
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
好帖子,
不顶没天理啊,
老兄,本身理解深刻,再加上例子取得好。天生一副做培训师的料啊。
例如,
public class MyApplet implements Runnable,MouseListener{
.......
}
据我所知,在java GUI 这块,是经常用到的,特别是在执行事件的时候。
接口这样描述自己:“对于实现我的所有类,看起来都应该象我现在这个样子”。因此,采用了一个特定接口的所有代码都知道对于那个接口可能会调用什么方法。这便是接口的全部含义。所以我们常把接口用于建立类和类之间的一个“协议”。有些面向对象的程序设计语言采用了一个名为“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到底是个“普通”类、“抽象”类还是一个“接口”。这是做是故意的:每种方法都使程序员能对对象的创建与使用进行不同的控制。
====================================
接口可以减少类间的耦合度;比如说我表现层可以只操作业务操作的接口,而业务逻辑发生变化时,表现层的一切都不会影响;在这个地方,接口的价值就体现了;而且,现在的Spring等无不体现着Java“面向接口编程”,而不应该是“面向实现编程”