tij读书笔记2

第8章    接口与内隐类


一.    接口

1.    如果实现接口的class未实现接口中的所有函数,则这个class必须被声明为abstract class,而接口中未被实现的函数在这个class中为abstract class。
  1. interface Interface{
  2.     public void f();
  3.     public void g();
  4. }
  5. abstract class First implements Interface{
  6.     public void f(){}    
  7. }
  8. class Second extends First{
  9.     public void g(){}
  10. }
  11. public class ExplicitStatic{
  12.     public static void main(String[] args){
  13.         Interface f = new Second();
  14.         f.f();
  15.         f.g();
  16.     }
  17. }

2.    接口中的所有函数自动具有public访问权限,所以实现某个接口时,必须将承袭自该接口的所有函数都定义为public
  1. interface MyInterface {
  2.     public void f();
  3.     void g();
  4. }
  5. class First implements MyInterface {
  6.     public void f(){}
  7.     //!void g(){}出错,应定义为public
  8. }

3.    接口中的数据成员自动成为static和final
  1. interface MyInterface{
  2.     int i = 5;
  3.     void f();
  4.     void g();
  5. }
  6. class First implements MyInterface {
  7.     public void f(){}
  8.     public void g(){}
  9. }
  10. public class ExplicitStatic{
  11.     public static void main(String[] args){
  12.         MyInterface x = new First();
  13.         // MyInterface的数据成员I为static,可直接调用
  14.         System.out.println("MyInterface.i = " + MyInterface.i + " , x.i = " + x.i);
  15.         // MyInterface的数据成员I为final,不能修改
  16.         //x.i++;
  17.         // MyInterface.i++;
  18.     }
  19. }

4.    多重继承
1)    devriced class可以同时继承多个interface和一个abstract或 concrete base class。如果同时继承了base class和interface,那么要先写下具象类的名称,然后才是 interfaces的名称。
2)    如果derived class所继承的具象类具有与interfaces相同的函数,则可在derived class不实现那个函数。
  1. interface CanFight{
  2.     void fight();
  3. }
  4. interface CanSwim{
  5.     void swim();
  6. }
  7. class ActionCharacter{
  8.     public void fight(){}    
  9. }
  10. class Hero extends ActionCharacter
  11.     implements CanFight, CanSwim{
  12.     public void swim(){};
  13. }
  14. public class ExplicitStatic{
  15.     static void f(CanFight x) { x.fight(); }
  16.     static void s(CanSwim x) { x.swim(); }
  17.     static void a(ActionCharacter x) { x.fight(); }
  18.     static void h(Hero x){
  19.         x.fight();  x.swim();  
  20.     }
  21.     public static void main(String[] args){
  22.         Hero h = new Hero();
  23.         f(h); s(h); a(h); h(h);
  24.     }
  25. }

因为在ActionCharacter class中有与接口CanFight完全相同的函数fight(),所以在Hero class可以不实现fight()方法。当要调用x.fight()时,会调用ActionCharacter class中的 fight()函数。
3)    接口的合并时的名称冲突问题
  1. interface I1 { void f(); }
  2. interface I2 { int f(int i); }
  3. interface I3 { int f(); }
  4. class C { public int f() { return 1; } }

  5. class C2 implements I1, I2{
  6.     public void f() {}
  7.     public int f(int i) { return 1; }
  8. }
  9. class C3 extends C implements I2{
  10.     public int f(int i) { return 1; }
  11. }
  12. class C4 extends C implements I3{
  13.     public int f() { return 1; }
  14. }
  15. //class C5 extends C implements I1{} (a)
  16. //class C6 extends C implements I1{ public void f(){} } (b)
  17. interface I4 extends I1, I3{} //(c)
  18. class C7 implements I4{
  19.     public void f() {}
  20.     public int f() { return 1; }
  21. }

(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来实现多重继承的,但除了通过多重继承来扩充接口除外。
  1. interface I1{
  2.     void f1();
  3. }
  4. interface I2{
  5.     void f2();
  6. }
  7. interface Ie1 extends I2{
  8.     void fe1();
  9. }
  10. class Ce1 implements Ie1{
  11.     public void f2() {}
  12.     public void fe1() {}
  13. }
  14. interface Ie2 extends Ie1, I1{
  15.     void fe2();
  16. }
  17. class Ce2 implements Ie2{
  18.     public void fe2() {}
  19.     public void f2() {}
  20.     public void fe1() {}
  21.     public void f1() {}
  22. }

接口Ie2继承了两个接口。            
5.    嵌套的interfaces
嵌套的interfaces可以在定义该内部接口的外部类(接口)之外被使用(但内隐类不行)。
1)    当接口嵌套于class中
a)    不论接口为public、friendly或private,都可被实现为public、friendly、private三种嵌套类。
b)    被声明为private的接口不能在class外被使用。
  1. class A{
  2.     private interface B{
  3.         void f();
  4.     }
  5.     public class BImp implements B{
  6.         public void f() {}
  7.     }
  8.     private class BImp2 implements B{
  9.         public void f() {}
  10.     }
  11.     public B getB() { return new BImp(); }
  12.     private B dRef;
  13.     public void recivedD(B d){
  14.         dRef = d;
  15.         dRef.f();;
  16.     }
  17. }
  18. public class ExplicitStatic{
  19.     public static void main(String[] args){
  20.         A a = new A(); //(a)
  21.         //A.B ab = a.getB(); (b)
  22.         //A.BImp = a.getB(); (c)
  23.         a.recivedD(a.getB());
  24.     }
  25. }

虽然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函数内则不用。
  1. public class ExplicitStatic{
  2.     class Contents{
  3.         private int i = 11;
  4.         public int value() { return i; }
  5.     }
  6.     class Destination{
  7.         private String label;
  8.         Destination(String whereTo){
  9.             label = whereTo;
  10.         }
  11.         String readLabel() { return label; }
  12.     }
  13.     public Destination to(String s){
  14.     //在outer class的non-static函数中可直接产生inner class对象
  15.         return new Destination(s); //(1)
  16.     }
  17.     public Contents cont(){
  18.         return new Contents(); //(1)
  19.     }
  20.     public void ship(String dest){
  21. //在outer class的non-static函数中可直接通过InnerClassName
  22. //来指定对象型别
  23.         Contents c = cont();
  24.         Destination d = to(dest);
  25.         System.out.println(d.readLabel());
  26.     }
  27.     public static void main(String[] args){
  28.         ExplicitStatic p = new ExplicitStatic();
  29.         p.ship("Tanzania");
  30.         ExplicitStatic q = new ExplicitStatic();
  31.    //在outer class的非non-static函数内产生inner class对象
  32.         ExplicitStatic.Contents c = q.cont();
  33.         ExplicitStatic.Destination d = q.to("Borneo");
  34.   //不能在static函数直接生成inner class对象
  35.         // new Contents();
  36.     }
  37. }

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。
  1. interface Destination{
  2.     String readLabel();
  3. }
  4. interface Contents{
  5.     int value();
  6. }
  7. class Parcel3{
  8.     private class PContents implements Contents{
  9.         private int i = 11;
  10.         public int value() { return i; }
  11.     }
  12.     protected class PDestination implements Destination{
  13.         private String label;
  14.         PDestination(String whereTo){
  15.             label = whereTo;
  16.         }
  17.         public String readLabel() { return label; }
  18.     }
  19.     public Destination to(String s){
  20.         return new PDestination(s);
  21.     }
  22.     public Contents cont(){
  23.         return new PContents();
  24.     }
  25. }
  26. public class ExplicitStatic{    
  27.     public static void main(String[] args){
  28.         Parcel3 p = new Parcel3();
  29.         //把inner class对象向上转型
  30.         Contents c = p.cont();
  31.         Destination d = p.to("Borneo");        
  32.     }
  33. }

虽然我们不能在ExplicitStatic class无法调用Pcontents class,但我们把一个Pcontents class对象向上转型为Contents,就可对之进行调用。
4)    inner class的作用域为定义该inner class的scope内。但inner class可在它的作用域之外被继承(见4)。
  1. interface Contents{
  2.     int value();
  3. }
  4. class Parcel3{
  5.     //PContents1 class的作用域为Parcel3 class内
  6.     private class PContents1 implements Contents{
  7.         private int i = 11;
  8.         public int value() { return i; }
  9.     }
  10.     public Contents cont1(){
  11.         return new PContents1();
  12.     }
  13.     public Contents cont2(){
  14.         //PContents2 class的作用域为函数cont2内
  15.         class PContents2 implements Contents{
  16.             private int i = 11;
  17.             public int value() { return i; }
  18.         }
  19.         return new PContents2();
  20.     }
  21.     //不能在函数cont2外使用PContents2 class
  22.     /*
  23.     public Contents cont22(){
  24.         return new PContents2();
  25.     }
  26.     */
  27.     public Contents cont3(boolean b){
  28.         if(b){
  29.             //PContents3 class的作用域为当前if内
  30.             class PContents3 implements Contents{
  31.                 private int i = 11;
  32.                 public int value() { return i; }
  33.             }
  34.             return new PContents3();
  35.         }
  36.         //不能在if外使用PContents3 class
  37.         //return new PContents3();
  38.         return null;
  39.     } 
  40. }
  41. public class ExplicitStatic{    
  42.     public static void main(String[] args){
  43.         Parcel3 p = new Parcel3();
  44.         Contents c1 = p.cont1();
  45.         Contents c2 = p.cont2();
  46.         Contents c3 = p.cont3(true);
  47.     }
  48. }

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对象中的成员。
  1. interface Destination{
  2.     String readLabel();
  3. }
  4. interface Contents{
  5.     int value();    
  6. }
  7. class Parcel3{
  8.     int i1 = 10;
  9.     private String s1 = "Parcel3_";
  10.     Parcel3(String s){
  11.         s1 += s;
  12.     }
  13.     private class PContents implements Contents{
  14.         //可调用enclosing class的成员 (1)
  15.         private int i2 = i1;
  16.         private String s2 = s1;
  17.         PContents(int num){
  18.          System.out.println("" + num + ": i2 = " + i2 + ",s2 = " + s2);
  19.         }
  20.         public int value() { return 1; }
  21.     }
  22.     public Contents cont(int i){
  23.         return new PContents(i);
  24.     }
  25. }
  26. public class ExplicitStatic{    
  27.     public static void main(String[] args){
  28.         Parcel3 p1 = new Parcel3("1");
  29.         Contents c1 = p1.cont(1);        
  30.         Contents c2 = p1.cont(2);
  31.         Parcel3 p2 = new Parcel3("2");
  32.         c2 = p2.cont(3);
  33.         c2 = p1.cont(4);
  34.     }
  35. }

结果为:
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中的静态成员。
  1. interface Contents{
  2.     int value();    
  3. }
  4. class Parcel1{ 
  5. private static String s1 = "Parcel3_";
  6. private String s11 = “Parcel3_”;
  7.     Parcel1(String s){
  8.         s1 += s;
  9.     }
  10. protected static class PContents implements Contents{ 
  11.     //只能访问enclosing class中的s1
  12.         String s2 = s1;
  13.         //s11不是static成员,不能访问
  14.         //String 22 = s11;
  15.         PContents(int num){
  16.             System.out.println("" + num + ":s2 = " + s2);
  17.         }
  18.         public int value() { return 1; }
  19.     }
  20.     public static  Contents cont(int i){
  21.         return new PContents(i);
  22.     }
  23. }
  24. public class ExplicitStatic{    
  25.     public static void main(String[] args){
  26.         Parcel1 p1 = new Parcel1("1");
  27.         Contents c1 = p1.cont(1);   
  28.         c1 = Parcel1.cont(2);  //(1)
  29.         Parcel1 p2 = new Parcel1("2");
  30.         c1 = p2.cont(3);
  31.         c1 = Parcel1.cont(4); //(1)
  32.     }
  33. }

因为内隐类Pcontents class是静态的,所以在(1)处不通过enclosing class对象而是通过静态函数来直接产生其对象。
2.3    无论inner class被嵌套置放的层次有多深,且所有outer class的成员都可
被它访问。
  1. class MNA{
  2.     private void f() {}
  3.     class A{
  4.         private void g() {}
  5.         class B{
  6.             void h(){
  7.                 g();
  8.                 f();
  9.             }
  10.         }
  11.     }
  12. }
    
3.    如何产生inner class对象的总结
3.1 non-static内隐类
1)    在enclosing class的non-static函数中可以直接通过new来产生
2)    在enclosing class的static函数或其它的class中,必须同时存在一个enclosing class对象(原因在上面2.1已说明)。
  1. interface Contents{
  2.     int value();    
  3. }
  4. class Parcel1{   
  5.     protected class PContents implements Contents{
  6.         public int value() { return 1; }
  7.     }
  8.     public Contents cont(){
  9.       //在non-static函数中直接通过new来产生PContents class对象
  10.         return new PContents();
  11.     }
  12.     public static void test(String[] args){
  13.         Parcel1 p1 = new Parcel1();
  14.         //在static函数中通过外部类Parcel1对象来产生
  15.         Contents c1 = p1.cont();  //调用函数 
  16.         c1 = p1.new PContents(); //通过new
  17.     }
  18. }
  19. public class ExplicitStatic{    
  20.     public static void main(String[] args){
  21.         //通过外部类Parcel1对象来产生
  22.         Parcel1 p1 = new Parcel1();
  23.         Contents c1 = p1.cont();  //调用函数
  24.         c1 = p1.new PContents();  //通过new
  25.     }
  26. }

3.2 static内隐类
1)    除了可用产生non-static内隐类对象的方法来产生之外,也可以不通过已存在一个enclosing class对象来产生。
  1. interface Contents{
  2.     int value();    
  3. }
  4. class Parcel1{   
  5.     protected static class PContents implements Contents{
  6.         public int value() { return 1; }
  7.     }
  8.     public Contents cont(){
  9.       //在non-static函数中直接通过new来产生PContents class对象
  10.         return new PContents();
  11.     }
  12.     public static Contents cont1(){
  13.         //在static函数中直接通过new来产生PContents class对象
  14.         return new PContents(); //(1)
  15.     }
  16.     public static void test(String[] args){
  17.         Parcel1 p1 = new Parcel1();
  18.         //在static函数中通过外部类Parcel1对象来产生
  19.         Contents c1 = p1.cont();  //调用函数
  20.         c1 = p1.new PContents();  //通过new
  21.         //在static函数中直接通过new来产生PContents class对象
  22.         c1 = new PContents();  //(1)
  23.     }
  24. }
  25. public class ExplicitStatic{    
  26.     public static void main(String[] args){
  27.         //通过外部类Parcel1对象来产生
  28.         Parcel1 p1 = new Parcel1();
  29.         Contents c1 = p1.cont();  //调用函数
  30.         c1 = p1.new PContents();  //通过new
  31.         //直接产生
  32.         c1 = Parcel1.cont1();  //(2)
  33.     }
  34. }

上面的(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的构造函数。
  1. class WithInner{
  2.             class Inner{}
  3. }
  4. class InheritInner extends WithInner.Inner
  5. {
  6.             //InheritInner(){}  编译错误
  7.             InheritInner(WithInner wi) { wi.super(); }
  8. }
  9. public class ExplicitStatic{    
  10.             public static void main(String[] args){
  11.                 WithInner wi = new WithInner();
  12.                 InheritInner ii = new InheritInner(wi);
  13.             }
  14. }

2)    覆写inner class不具备多态特性。
  1. class Egg{
  2.     class Yolk{
  3.         public Yolk(){
  4.             System.out.println("Egg.Yolk()");
  5.         }
  6.     }
  7.     private Yolk y;
  8.     public Egg(){
  9.         System.out.println("New Egg()");
  10.         y = new Yolk(); //(1)
  11.     }
  12. }
  13. class BigEgg extends Egg{
  14.     //(2)尝试覆写inner class
  15.     class Yolk{
  16.         public Yolk(){
  17.             System.out.println("BigEgg.Yolk()");
  18.         }
  19.     }
  20. }
  21. public class ExplicitStatic{    
  22.     public static void main(String[] args){
  23.         new BigEgg(); //(3)
  24.     }
  25. }

结果为:
    New Egg()
Egg.Yolk()
在(2)中我们尝试覆写inner class。当通过(3)产生一个BigEgg时,会调用Egg的构造函数。在Egg的构造函数的(1)处产生的是Egg.Yolk class对象,而不是子类BigEgg.Yolk class对象。
**:如上所示,上述两个inner class是完全独立的个体,各有其专属的命名空间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值