1. 接口可以包含域,这些域隐式地是static和final的(即使你不写上),因此命名格式应为大写+下划线分隔。
2. 可以选择在接口中显式地将方法声明为public的,但是即使不这么做,它也是public的。因此在实现接口时,实现的方法必须被定义为public的。
3. 接口组合时的名字冲突问题:
eg.
interface I1{
void f();
}
interface I2{
int f(int i);
}
interface I3{
int f();
}
class C {
public int f(){
return 1;
}
}
class C2 implements I1,I2{
public void f(){}
public int f(int i){ //overloaded
return 1;
}
}
class C3 extends C implements I2{
public int f(int i){ //overloaded
return 1;
}
}
class C4 extends C implements I3{
@Override
public int f() { //This is OK. Override method f() in I3
return 1;
}
}
//methods differ only by return type:
//! class C5 extends C implements I1{}
//! interface I4 extends I1, I3{}
若取消最下面两行注释,问题就来了。方法重写、实现和重载会搅在一起,而且方法重载仅通过返回值类型是区分不开的。去掉最后两行注释,编译器会提示以下错误:
The return types are incompatible for the inherited methods I1.f(), C.f()
The return types are incompatible for the inherited methods I1.f(), I3.f()
在打算组合的不同接口中使用相同的方法名可能会造成代码可读性的混乱,尽量避免出现这种情况。
4. 接口的常见用法是一种被称作为策略的设计模式。编写一个执行某些操作的方法,该方法将接受一个指定的接口。这相当于编写者声明了:“你可以用任何你想要的对象来调用我的方法,只要你的对象遵循我的接口。”
例如,Scanner类的构造器接受一个Readable接口。Readable接口没有用作Java标准类库中其他任何方法的参数,它是专门为Scanner类设计的,目的是使得Scanner不必将其参数限制为某个特定类。如果你创建了一个类,并想让Scanner作用于它的对象,只需要让它实现Readable接口,并重写read()方法即可。如下例所示,RandomWords类的作用是生成一组随机的词:
public class RandomWords implements Readable{
private static Random rand=new Random(47);
private static final char[] capitals=
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers=
"abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels=
"aeiou".toCharArray();
private int count;
public RandomWords(int count){
this.count=count;
}
@Override
public int read(CharBuffer cb) throws IOException {
if(count--==0){
return -1; //Indicates end of input
}
cb.append(capitals[rand.nextInt(capitals.length)]);
for(int i=0;i<4;i++){
cb.append(vowels[rand.nextInt(vowels.length)]);
cb.append(lowers[rand.nextInt(lowers.length)]);
}
cb.append(" ");
return 10; //Number of characters appended
}
public static void main(String args[]){
Scanner s=new Scanner(new RandomWords(10));
while(s.hasNext()){
System.out.println(s.next());
}
}
}
Output:
Yazeruyac
Fowenucor
Goeazimom
Raeuuacio
Nuoadesiw
Hageaikux
Ruqicibui
Numasetih
Kuuuuozog
Waqizeyoy
5.
接口可以嵌套在其他接口或类中。
class A {
interface B{
void f();
}
public class BImp implements B{
public void f(){}
}
public class BImp2 implements B{
public void f(){}
}
public interface C{
void f();
}
class CImp implements C{
public void f(){}
}
private class CImp2 implements C{
public void f(){}
}
private interface D{
void f();
}
private class DImp implements D{
public void f(){}
}
public class DImp2 implements D{
public void f(){}
}
public D getD(){
return new DImp2();
}
private D dRef;
public void receiveD(D d){
dRef=d;
dRef.f();
}
}
interface E{
interface G{
void f();
}
public interface H{ //The modifier "public" is redundant
void f();
}
void g();
//Cannot be private within an interface:
//! private interface I{}
}
public class NestingInterfaces{
public class BImp implements A.B{
public void f(){}
}
class CImp implements A.C{
public void f(){}
}
//Cannot implement a private interface except within that interface's defining class:
//! class DImp implements A.D{
//! public void f(){}
//! }
class EImp implements E{
public void g(){}
class EG implements E.G{
public void f(){}
}
}
public static void main(String[] args) {
A a=new A();
//Can't access A.D:
//! A.D ad=a.getD();
//Doesn't return anything but A.D:
//! A.DImp2 di2=a.getD();
//Cannot access a member of the interface:
//! a.getD().f();
//Only another A can do anything with getD();
A a2=new A();
a2.receiveD(a.getD());
}
}
从上面例子可以看出,内部接口也可以用private修饰。第26行表明虽然A.D为private的,但它仍能被实现为public类DImp2。但是DImp2类极其特殊,它只能被其自身所用,你无法说它是实现了一个private接口D。在main()方法中,若去掉中间被注释的3条语句,则会提示:
The type A.D is not visible
Type mismatch: cannot convert from A.D to A.DImp2
The type A.D is not visible
这说明,任何尝试使用返回值的行为都失败了。只有一种方式可以成功,那就是将返回值交给有权使用它的对象(即A的对象),即调用A.getD()方法接收。
6. 使用接口创建工厂方法
工厂方法的设计模式不同于直接调用类的构造器来产生对象,而是在工厂对象上调用创建方法, 从而返回接口的某个实现对象。这种设计模式引入了额外级别的间接性,如果你想要编写一套框架,可以使用这种方法。如下例:
interface Service{
void method1();
void method2();
}
class Implementation1 implements Service{
public Implementation1() {} //Package access
public void method1(){
System.out.println("Implementation1 method1");
}
public void method2(){
System.out.println("Implementation1 method2");
}
}
class Implementation2 implements Service{
public Implementation2() {} //Package access
public void method1(){
System.out.println("Implementation2 method1");
}
public void method2(){
System.out.println("Implementation2 method2");
}
}
interface ServiceFactory{
Service getService();
}
class Implementation1Factory implements ServiceFactory{
@Override
public Service getService() {
return new Implementation1();
}
}
class Implementation2Factory implements ServiceFactory{
@Override
public Service getService() {
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s=fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
//Implementations are completely interchangeable
serviceConsumer(new Implementation2Factory());
}
}
如果不用工厂方法,必须在某处显式指定要创建的Service的确切类型,以便调用合适的构造器。