第8章 接口与内隐类
一. 接口
1. 如果实现接口的class未实现接口中的所有函数,则这个class必须被声明为abstract class,而接口中未被实现的函数在这个class中为abstract class。
- interface Interface{
- public void f();
- public void g();
- }
- abstract class First implements Interface{
- public void f(){}
- }
- class Second extends First{
- public void g(){}
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- Interface f = new Second();
- f.f();
- f.g();
- }
- }
2. 接口中的所有函数自动具有public访问权限,所以实现某个接口时,必须将承袭自该接口的所有函数都定义为public
- interface MyInterface {
- public void f();
- void g();
- }
- class First implements MyInterface {
- public void f(){}
- //!void g(){}出错,应定义为public
- }
3. 接口中的数据成员自动成为static和final
- interface MyInterface{
- int i = 5;
- void f();
- void g();
- }
- class First implements MyInterface {
- public void f(){}
- public void g(){}
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- MyInterface x = new First();
- // MyInterface的数据成员I为static,可直接调用
- System.out.println("MyInterface.i = " + MyInterface.i + " , x.i = " + x.i);
- // MyInterface的数据成员I为final,不能修改
- //x.i++;
- // MyInterface.i++;
- }
- }
4. 多重继承
1) devriced class可以同时继承多个interface和一个abstract或 concrete base class。如果同时继承了base class和interface,那么要先写下具象类的名称,然后才是 interfaces的名称。
2) 如果derived class所继承的具象类具有与interfaces相同的函数,则可在derived class不实现那个函数。
- interface CanFight{
- void fight();
- }
- interface CanSwim{
- void swim();
- }
- class ActionCharacter{
- public void fight(){}
- }
- class Hero extends ActionCharacter
- implements CanFight, CanSwim{
- public void swim(){};
- }
- public class ExplicitStatic{
- static void f(CanFight x) { x.fight(); }
- static void s(CanSwim x) { x.swim(); }
- static void a(ActionCharacter x) { x.fight(); }
- static void h(Hero x){
- x.fight(); x.swim();
- }
- public static void main(String[] args){
- Hero h = new Hero();
- f(h); s(h); a(h); h(h);
- }
- }
因为在ActionCharacter class中有与接口CanFight完全相同的函数fight(),所以在Hero class可以不实现fight()方法。当要调用x.fight()时,会调用ActionCharacter class中的 fight()函数。
3) 接口的合并时的名称冲突问题
- 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) { return 1; }
- }
- class C3 extends C implements I2{
- public int f(int i) { return 1; }
- }
- class C4 extends C implements I3{
- public int f() { return 1; }
- }
- //class C5 extends C implements I1{} (a)
- //class C6 extends C implements I1{ public void f(){} } (b)
- interface I4 extends I1, I3{} //(c)
- class C7 implements I4{
- public void f() {}
- public int f() { return 1; }
- }
(a)处代码会产生以下错误: method f() in class C cannot implement method f() in interface I1 with different return type, was void。
(b)处代码也是错误的: method f() in class C6 cannot override method f() in class C with different return type, was int。由(b)处代码也可看出,虽然你试图实现接口I1中的函数,但由于extends C在前,所以编译器会把C6中的函数看成是覆写class C中的函数,而不是象你想象中的作为实现接口中的函数的函数。
(c)处代码在原书中(P253)说会出错,但我在测试时并没发生错误。但当你试图通过C7来实现接口I4时,是无论如何也不可能编译通过的。
4) Java中唯一可以使用多重继承的地方
Java是不允许通过关键字extends来实现多重继承的,但除了通过多重继承来扩充接口除外。
- interface I1{
- void f1();
- }
- interface I2{
- void f2();
- }
- interface Ie1 extends I2{
- void fe1();
- }
- class Ce1 implements Ie1{
- public void f2() {}
- public void fe1() {}
- }
- interface Ie2 extends Ie1, I1{
- void fe2();
- }
- class Ce2 implements Ie2{
- public void fe2() {}
- public void f2() {}
- public void fe1() {}
- public void f1() {}
- }
接口Ie2继承了两个接口。
5. 嵌套的interfaces
嵌套的interfaces可以在定义该内部接口的外部类(接口)之外被使用(但内隐类不行)。
1) 当接口嵌套于class中
a) 不论接口为public、friendly或private,都可被实现为public、friendly、private三种嵌套类。
b) 被声明为private的接口不能在class外被使用。
- class A{
- private interface B{
- void f();
- }
- public class BImp implements B{
- public void f() {}
- }
- private class BImp2 implements B{
- public void f() {}
- }
- public B getB() { return new BImp(); }
- private B dRef;
- public void recivedD(B d){
- dRef = d;
- dRef.f();;
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- A a = new A(); //(a)
- //A.B ab = a.getB(); (b)
- //A.BImp = a.getB(); (c)
- a.recivedD(a.getB());
- }
- }
虽然A class含有接口,但它仍可被实例化,如(a)。
由于接口B为private,所以在(b)处调用接口B时会出错。但当把接口B声明为public时,(b)将通过编译。但(c)处依然会出错,因为内隐类的作用域为定义该内隐类的外部类内(见内隐类)。
2) 当接口嵌套于接口中
1) 嵌套于接口中的接口自动为public,且只能为public。
2) 当实现某个接口时,无需实现其中嵌套的接口。
3) Private接口无法在其所定义的class之外被实现。
二. Inner classes(内隐类)
1. 内隐类的基本用法
1) 如果要在外围class的non-static函数之外产生一个inner class 对象,得以OuterClassName.InnerClassName的形式指定该对象的型别。而在non-static函数内则不用。
- public class ExplicitStatic{
- class Contents{
- private int i = 11;
- public int value() { return i; }
- }
- class Destination{
- private String label;
- Destination(String whereTo){
- label = whereTo;
- }
- String readLabel() { return label; }
- }
- public Destination to(String s){
- //在outer class的non-static函数中可直接产生inner class对象
- return new Destination(s); //(1)
- }
- public Contents cont(){
- return new Contents(); //(1)
- }
- public void ship(String dest){
- //在outer class的non-static函数中可直接通过InnerClassName
- //来指定对象型别
- Contents c = cont();
- Destination d = to(dest);
- System.out.println(d.readLabel());
- }
- public static void main(String[] args){
- ExplicitStatic p = new ExplicitStatic();
- p.ship("Tanzania");
- ExplicitStatic q = new ExplicitStatic();
- //在outer class的非non-static函数内产生inner class对象
- ExplicitStatic.Contents c = q.cont();
- ExplicitStatic.Destination d = q.to("Borneo");
- //不能在static函数直接生成inner class对象
- // new Contents();
- }
- }
2) 对于non-static inner class,在外围class的non-static函数可以通过new产生一个inner class对象,如上面的(1)处。但要在非non-static函数产生一个inner class对象,则一定要关联到其enclosing class的某个对象。
3) inner class的向上转型
当把一个inner class对象向上转型成为interface时,我们得到的只是一个reference。
- interface Destination{
- String readLabel();
- }
- interface Contents{
- int value();
- }
- class Parcel3{
- private class PContents implements Contents{
- private int i = 11;
- public int value() { return i; }
- }
- protected class PDestination implements Destination{
- private String label;
- PDestination(String whereTo){
- label = whereTo;
- }
- public String readLabel() { return label; }
- }
- public Destination to(String s){
- return new PDestination(s);
- }
- public Contents cont(){
- return new PContents();
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- Parcel3 p = new Parcel3();
- //把inner class对象向上转型
- Contents c = p.cont();
- Destination d = p.to("Borneo");
- }
- }
虽然我们不能在ExplicitStatic class无法调用Pcontents class,但我们把一个Pcontents class对象向上转型为Contents,就可对之进行调用。
4) inner class的作用域为定义该inner class的scope内。但inner class可在它的作用域之外被继承(见4)。
- interface Contents{
- int value();
- }
- class Parcel3{
- //PContents1 class的作用域为Parcel3 class内
- private class PContents1 implements Contents{
- private int i = 11;
- public int value() { return i; }
- }
- public Contents cont1(){
- return new PContents1();
- }
- public Contents cont2(){
- //PContents2 class的作用域为函数cont2内
- class PContents2 implements Contents{
- private int i = 11;
- public int value() { return i; }
- }
- return new PContents2();
- }
- //不能在函数cont2外使用PContents2 class
- /*
- public Contents cont22(){
- return new PContents2();
- }
- */
- public Contents cont3(boolean b){
- if(b){
- //PContents3 class的作用域为当前if内
- class PContents3 implements Contents{
- private int i = 11;
- public int value() { return i; }
- }
- return new PContents3();
- }
- //不能在if外使用PContents3 class
- //return new PContents3();
- return null;
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- Parcel3 p = new Parcel3();
- Contents c1 = p.cont1();
- Contents c2 = p.cont2();
- Contents c3 = p.cont3(true);
- }
- }
2. 内隐类与外围enclosing class的连接关系
2.1 non-static inner class
1) inner class可以访问enclosing class的所有成员(包括private成员),就像inner class自己拥有这些成员一样。即inner class天生具有对enclosing class的所有成员的访问权力。
2) Inner class对象被产生时,一定要关联到其enclosing class的某个对象(这个enclosing class对象就是 Inner class对象的制造者)。建构inner class对象的同时,得有其enclosing class对象的reference才行。
原因:因为inner class可以访问enclosing class的所有成员,那么当产生一个inner class时,编译器会自动为inner class对象添加一个指向enclosing class对象的reference(这个reference是隐藏的)。所以Inner class 被产生时,一定要关联到其enclosing class的某个对象。
3) 同一个enclosing class对象产生出来的inner class对象访问的是同一个enclosing class对象中的成员。
- interface Destination{
- String readLabel();
- }
- interface Contents{
- int value();
- }
- class Parcel3{
- int i1 = 10;
- private String s1 = "Parcel3_";
- Parcel3(String s){
- s1 += s;
- }
- private class PContents implements Contents{
- //可调用enclosing class的成员 (1)
- private int i2 = i1;
- private String s2 = s1;
- PContents(int num){
- System.out.println("" + num + ": i2 = " + i2 + ",s2 = " + s2);
- }
- public int value() { return 1; }
- }
- public Contents cont(int i){
- return new PContents(i);
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- Parcel3 p1 = new Parcel3("1");
- Contents c1 = p1.cont(1);
- Contents c2 = p1.cont(2);
- Parcel3 p2 = new Parcel3("2");
- c2 = p2.cont(3);
- c2 = p1.cont(4);
- }
- }
结果为:
1: i2 = 10,s2 = Parcel3_1
2: i2 = 10,s2 = Parcel3_1
3: i2 = 10,s2 = Parcel3_2
4: i2 = 10,s2 = Parcel3_1
在(1)在inner class调用了enclosing class的成员。结果表明,同一个enclosing class对象p1产生的inner class对象调用的是同一个enclosing class对象中的成员,如结果中的1、2、4。
2.2 Static inner classes(静态内隐类)
1) 产生Static inner classes对象时,不需要同时存在一个enclosing class对象
2) 只能在Static inner classes对象中访问enclosing class中的静态成员。
- interface Contents{
- int value();
- }
- class Parcel1{
- private static String s1 = "Parcel3_";
- private String s11 = “Parcel3_”;
- Parcel1(String s){
- s1 += s;
- }
- protected static class PContents implements Contents{
- //只能访问enclosing class中的s1
- String s2 = s1;
- //s11不是static成员,不能访问
- //String 22 = s11;
- PContents(int num){
- System.out.println("" + num + ":s2 = " + s2);
- }
- public int value() { return 1; }
- }
- public static Contents cont(int i){
- return new PContents(i);
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- Parcel1 p1 = new Parcel1("1");
- Contents c1 = p1.cont(1);
- c1 = Parcel1.cont(2); //(1)
- Parcel1 p2 = new Parcel1("2");
- c1 = p2.cont(3);
- c1 = Parcel1.cont(4); //(1)
- }
- }
因为内隐类Pcontents class是静态的,所以在(1)处不通过enclosing class对象而是通过静态函数来直接产生其对象。
2.3 无论inner class被嵌套置放的层次有多深,且所有outer class的成员都可
被它访问。
- class MNA{
- private void f() {}
- class A{
- private void g() {}
- class B{
- void h(){
- g();
- f();
- }
- }
- }
- }
3. 如何产生inner class对象的总结
3.1 non-static内隐类
1) 在enclosing class的non-static函数中可以直接通过new来产生
2) 在enclosing class的static函数或其它的class中,必须同时存在一个enclosing class对象(原因在上面2.1已说明)。
- interface Contents{
- int value();
- }
- class Parcel1{
- protected class PContents implements Contents{
- public int value() { return 1; }
- }
- public Contents cont(){
- //在non-static函数中直接通过new来产生PContents class对象
- return new PContents();
- }
- public static void test(String[] args){
- Parcel1 p1 = new Parcel1();
- //在static函数中通过外部类Parcel1对象来产生
- Contents c1 = p1.cont(); //调用函数
- c1 = p1.new PContents(); //通过new
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- //通过外部类Parcel1对象来产生
- Parcel1 p1 = new Parcel1();
- Contents c1 = p1.cont(); //调用函数
- c1 = p1.new PContents(); //通过new
- }
- }
3.2 static内隐类
1) 除了可用产生non-static内隐类对象的方法来产生之外,也可以不通过已存在一个enclosing class对象来产生。
- interface Contents{
- int value();
- }
- class Parcel1{
- protected static class PContents implements Contents{
- public int value() { return 1; }
- }
- public Contents cont(){
- //在non-static函数中直接通过new来产生PContents class对象
- return new PContents();
- }
- public static Contents cont1(){
- //在static函数中直接通过new来产生PContents class对象
- return new PContents(); //(1)
- }
- public static void test(String[] args){
- Parcel1 p1 = new Parcel1();
- //在static函数中通过外部类Parcel1对象来产生
- Contents c1 = p1.cont(); //调用函数
- c1 = p1.new PContents(); //通过new
- //在static函数中直接通过new来产生PContents class对象
- c1 = new PContents(); //(1)
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- //通过外部类Parcel1对象来产生
- Parcel1 p1 = new Parcel1();
- Contents c1 = p1.cont(); //调用函数
- c1 = p1.new PContents(); //通过new
- //直接产生
- c1 = Parcel1.cont1(); //(2)
- }
- }
上面的(1)和9(2)中的代码只有在Pcontents class为static时才能通过。(1)不能通过的原因见2.1。
4. inner class的继承
1) inner class可被继承。inner class的drived class的 drfault构造函数必须传入一个reference指向outer object,并在构造函数中调用outer class的构造函数。
- class WithInner{
- class Inner{}
- }
- class InheritInner extends WithInner.Inner
- {
- //InheritInner(){} 编译错误
- InheritInner(WithInner wi) { wi.super(); }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- WithInner wi = new WithInner();
- InheritInner ii = new InheritInner(wi);
- }
- }
2) 覆写inner class不具备多态特性。
- class Egg{
- class Yolk{
- public Yolk(){
- System.out.println("Egg.Yolk()");
- }
- }
- private Yolk y;
- public Egg(){
- System.out.println("New Egg()");
- y = new Yolk(); //(1)
- }
- }
- class BigEgg extends Egg{
- //(2)尝试覆写inner class
- class Yolk{
- public Yolk(){
- System.out.println("BigEgg.Yolk()");
- }
- }
- }
- public class ExplicitStatic{
- public static void main(String[] args){
- new BigEgg(); //(3)
- }
- }
结果为:
New Egg()
Egg.Yolk()
在(2)中我们尝试覆写inner class。当通过(3)产生一个BigEgg时,会调用Egg的构造函数。在Egg的构造函数的(1)处产生的是Egg.Yolk class对象,而不是子类BigEgg.Yolk class对象。
**:如上所示,上述两个inner class是完全独立的个体,各有其专属的命名空间。