静音版 电台版
发新话题
打印

[Java] Notes of "Thinking in Java 3rd Edition" (五)

Notes of "Thinking in Java 3rd Edition" (五)

第8章 接口与内隐类    一. 接口
   1. 如果实现接口的class未实现接口中的所有函数,则这个class必须被声明为abstractclass,而接口中未被实现的函数在这个class中为abstractclass。
   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) devricedclass可以同时继承多个interface和一个abstract或concretebaseclass。如果同时继承了baseclass和interface,那么要先写下具象类的名称,然后才是interfaces的名称。
   2) 如果derivedclass所继承的具象类具有与interfaces相同的函数,则可在derivedclass不实现那个函数。
   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);
   }
   }
   因为在ActionCharacterclass中有与接口CanFight完全相同的函数fight(),所以在Heroclass可以不实现fight()方法。当要调用x.fight()时,会调用ActionCharacterclass中的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中的函数看成是覆写classC中的函数,而不是象你想象中的作为实现接口中的函数的函数。
   (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());
   }
   }
   虽然Aclass含有接口,但它仍可被实例化,如(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-staticinnerclass,在外围class的non-static函数可以通过new产生一个inner class对象,如上面的(1)处。但要在非non-static函数产生一个inner class对象,则一定要关联到其enclosingclass的某个对象。
   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,但我们把一个Pcontentsclass对象向上转型为Contents,就可对之进行调用。
   4) innerclass的作用域为定义该innerclass的scope内。但innerclass可在它的作用域之外被继承(见4)。
   interface Contents{
   int value();
   }
   class Parcel3{
   //PContents1class的作用域为Parcel3class内
   private class PContents1 implements Contents{
   private int i = 11;
   public int value() { return i; }
   }
   public Contents cont1(){
   return new PContents1();
   }
   public Contents cont2(){
   //PContents2class的作用域为函数cont2内
   class PContents2 implements Contents{
   private int i = 11;
   public int value() { return i; }
   }
   return new PContents2();
   }
   //不能在函数cont2外使用PContents2class
   /*
   public Contents cont22(){
   return new PContents2();
   }
   */
   public Contents cont3(boolean b){
   if(b){
   //PContents3class的作用域为当前if内
   class PContents3 implements Contents{
   private int i = 11;
   public int value() { return i; }
   }
   return new PContents3();
   }
   //不能在if外使用PContents3class
   //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.1non-staticinnerclass
   1) innerclass可以访问enclosingclass的所有成员(包括private成员),就像innerclass自己拥有这些成员一样。即innerclass天生具有对enclosingclass的所有成员的访问权力。
   2) Innerclass对象被产生时,一定要关联到其enclosingclass的某个对象(这个enclosingclass对象就是Innerclass对象的制造者)。建构innerclass对象的同时,得有其enclosingclass对象的reference才行。
   原因:因为innerclass可以访问enclosingclass的所有成员,那么当产生一个innerclass时,编译器会自动为innerclass对象添加一个指向enclosingclass对象的reference(这个reference是隐藏的)。所以Innerclass被产生时,一定要关联到其enclosingclass的某个对象。
   3) 同一个enclosingclass对象产生出来的innerclass对象访问的是同一个enclosingclass对象中的成员。
   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{
   //可调用enclosingclass的成员(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)在innerclass调用了enclosingclass的成员。结果表明,同一个enclosingclass对象p1产生的innerclass对象调用的是同一个enclosingclass对象中的成员,如结果中的1、2、4。
   2.2 Static inner classes(静态内隐类)
   1) 产生Static inner classes对象时,不需要同时存在一个enclosingclass对象
   2) 只能在Static inner classes对象中访问enclosingclass中的静态成员。
   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)
   }
   }
   因为内隐类Pcontentsclass是静态的,所以在(1)处不通过enclosingclass对象而是通过静态函数来直接产生其对象。
   2.3 无论innerclass被嵌套置放的层次有多深,且所有outerclass的成员都可
   被它访问。
   class MNA{
   private void f() {}
   class A{
   private void g() {}
   class B{
   void h(){
   g();
   f();
   }
   }
   }
   }
   3. 如何产生innerclass对象的总结
   3.1non-static内隐类
   1) 在enclosingclass的non-static函数中可以直接通过new来产生
   2) 在enclosingclass的static函数或其它的class中,必须同时存在一个enclosingclass对象(原因在上面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.2static内隐类
   1) 除了可用产生non-static内隐类对象的方法来产生之外,也可以不通过已存在一个enclosingclass对象来产生。
   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)中的代码只有在Pcontentsclass为static时才能通过。(1)不能通过的原因见2.1。
   4. innerclass的继承
   1) innerclass可被继承。innerclass的drivedclass的drfault构造函数必须传入一个reference指向outerobject,并在构造函数中调用outerclass的构造函数。
   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) 覆写innerclass不具备多态特性。
   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)尝试覆写innerclass
   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)中我们尝试覆写innerclass。当通过(3)产生一个BigEgg时,会调用Egg的构造函数。在Egg的构造函数的(1)处产生的是Egg.Yolkclass对象,而不是子类BigEgg.Yolkclass对象。
   **:如上所示,上述两个innerclass是完全独立的个体,各有其专属的命名空间。
(--待续--)
小时候我以为自己长大后可以拯救整个世界,等长大后才发现整个世界都拯救不了我.......http://hi.baidu.com/kelven1986

TOP

发新话题