JAVA 复习(Think In Java, 4th) -- Inner Classes - Part2

来源:互联网 发布:网络小贷牌照 人人贷 编辑:程序博客网 时间:2024/05/06 13:43

Anonymous Inner Class

一般耒说,我们先实现接口,实现了以後,我们再从事相关的数据运算,如:

public class AInner {    public interface Inner {        public String getMsg();    }    public class MyInner implements Inner {        private String msg;        public MyInner() {            msg = "I am anonymous innner class!";        }        public String getMsg() {return msg;}    }    public Inner inner() {        return new MyInner();    }    public static void main(String[] args) {        AInner ai = new AInner();        Inner c = ai.inner();        System.out.println(c.getMsg());    }}
但是 AnonyMous Inner Class 可以让我们直接返回一个匿名类的对象,而不用宣告一个类,并实现该接口,它的意思也就是说

「创建一个继承该 Interface的对象」,代码如下,它的意义其实和上面的代码是一样的:

public class AInner {    public interface Inner {        public String getMsg();    }    public Inner inner() {        return new Inner() {            private String msg = "I am anonymous innner class!";            public String getMsg(){return msg;}        };    }    public static void main(String[] args) {        AInner ai = new AInner();        Inner c = ai.inner();        System.out.println(c.getMsg());    }}

其实这就像是 Android 的 View.OnClickListener() 的实现

// 看看 OnClickListener, 其实是个 interface    /**     * Interface definition for a callback to be invoked when a view is clicked.     */    public interface OnClickListener {        /**         * Called when a view has been clicked.         *         * @param v The view that was clicked.         */        void onClick(View v);    }// 而我们有时也就这麽用:...blablabla...mView.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {        ....blablabla....    }});... blablabla...

而我们工作时一般尽量不用这种匿名类方式实现,拿个例子耒说:

...mViewA.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {        処理方式A();    }});mViewB.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {        処理方式B();    }});mViewC.setOnClickListener(new OnClickListener() {    @Override    public void onClick(View v) {        処理方式C();    }});... 依此类推...
按上面这种实现方式的话,如果有 N 个可被点击的 View,那可能最多会有 N 个匿名类对象,而这些对象在程序运行时,都是占系统资源的,因此我们一般尽量这麽做
public class xxx extends ooo implements View.OnClickListener {...    @Override    public void onClick(View v) {        final int vid = v.getId();        switch(vid) {            case R.id.buttona:                処理事件A();                break;            case R.id.buttonb:                処理事件B();                break;            ....            default:break;        }    }...}
或是宣告一个 View.OnClickListener 的对象,然後让多个 View 引用。不同的処发事件,则使用覆写不同的 OnClick() 方法,以解决不同的需求,这便是典型的 Template Design Pattern。 


回到 Inner Classes的复习~我在练习的过程中,想试著放一些参数给 Anonymous Inner Class,但是就如下面看到的,Anonymous Class 的实现接口是不能放参数的(因为 Inner这个接口本身的Constructor就没有能放参数的),因为它是使用类的缺省(default) Constructor。

//: innerclasses/Parcel7.java// Returning an instance of an anonymous inner class.public class Parcel7 {  public Contents contents(final String name) {    return new Contents(name) { // Insert a class definition      private String mName = name;      private int i = 11;      public int value() { return i; }      public String getName(){ return mName;}    }; // Semicolon required in this case  }  public static void main(String[] args) {    Parcel7 p = new Parcel7();    Contents c = p.contents();    System.out.println(""+c.getName());  }} ///:~

我们如果要放参数的话,也是可以的,就直接另外定义一个实现该接口的类,同时让它的建构子

能放我们需要的参数就行了,如下:

public class AInner {    public interface Inner {        public String getMsg();    }    public class MyInner implements Inner {        private String mMsg;        public MyInner(String msg) {            mMsg = msg;        }        public String getMsg(){            return mMsg;        }    }    public Inner inner(final String msg) {        return new MyInner(msg);    }    public static void main(String[] args) {        AInner ai = new AInner();        Inner c = ai.inner("hi");        System.out.println(c.getMsg());    }}


虽然实现了,但这样就不是匿名类的做法了(有了 MyInner类),匿名类的做法,是在宣告一个 abstract class,

并且在该 abstract class实现构造函数,达到初始化的目的,如下:

public class AInnerPrac {    public abstract class People {        public People(String name) { // 把 Constructor 该做的事实现在这里            System.out.println("new fighter: " + name);        }        public abstract void run();     }    public People getPeople(final String name) {        return new People(name) {            @Override            public void run() {                System.out.println(name + " is running and fighting!");            }        };     }      public static void main(String[] args) {        AInnerPrac ap = new AInnerPrac();        People p = ap.getPeople("Shanwu");        p.run();        }}


public class AInnerPrac {    public abstract class People {        private String mName;        // 多了这个就不用 getPeople(final String name) 了        public People(String name) {                mName = name;            System.out.println("new fighter: " + mName);        }        public abstract void run();         public String getName() { return mName; }  // 直接把参数传进这个类    }    public People getPeople(String name) {        return new People(name) {          @Override            public void run() {                System.out.println(getName() + " is running and fighting!");            }        };     }      public static void main(String[] args) {        AInnerPrac ap = new AInnerPrac();        People p = ap.getPeople("Shanwu");        p.run();        }}

有了以上匿名类的基础知识後,我们可以改写一下JAVA 复习(Think In Java, 4th) -- Interface文中工厂方法

(Factory Method)模式的代码:

    interface provideCoffee {          String getCoffeeType();          void makeCoffee();      }            class VanillaCoffee implements provideCoffee {          @Override          public String getCoffeeType() {              return "Vanilla--Flavor Coffee";          }          @Override          public void makeCoffee() {              String action = "make "+getCoffeeType()+" coffee";              System.out.println(action);          }      }            class ChocolateCoffee implements provideCoffee {          @Override          public String getCoffeeType() {              return "Chocolate--Flavor Coffee";          }          @Override          public void makeCoffee() {              String action = "make "+getCoffeeType()+" coffee";              System.out.println(action);          }      }                  class Customer {          void getServed(provideCoffee coffee) {              coffee.makeCoffee();              String action = "Customer drinks "+ coffee.getCoffeeType();              System.out.println(action);          }            }      public class StarBucks {          public static void main(String[] args) {             Customer a = new Customer();             a.getServed(new VanillaCoffee());             a.getServed(new ChocolateCoffee());          }                 }  

修改後:

    interface provideCoffee {          String getCoffeeType();          void makeCoffee();      }           interface CoffeeMaker {        provideCoffee readyForCoffee();     }     class VanillaCoffee implements provideCoffee {          @Override          public String getCoffeeType() {              return "Vanilla--Flavor Coffee";          }          @Override          public void makeCoffee() {              String action = "make "+getCoffeeType()+" coffee";              System.out.println(action);          }                 public static CoffeeMaker coffeeMaker = new CoffeeMaker() {            @Override            public provideCoffee readyForCoffee() {                return new VanillaCoffee();            }        };    }            class ChocolateCoffee implements provideCoffee {          @Override          public String getCoffeeType() {              return "Chocolate--Flavor Coffee";          }          @Override          public void makeCoffee() {              String action = "make "+getCoffeeType()+" coffee";              System.out.println(action);          }        public static CoffeeMaker coffeeMaker = new CoffeeMaker() {            @Override            public provideCoffee readyForCoffee() {                return new ChocolateCoffee();            }        };    }            class Customer {          void getServed(CoffeeMaker cmaker) {            provideCoffee coffee = cmaker.readyForCoffee();            coffee.makeCoffee();              String action = "Customer drinks "+ coffee.getCoffeeType();              System.out.println(action);          }      }      public class StarBucks {        public static void main(String[] args) {             Customer a = new Customer();             a.getServed(VanillaCoffee.coffeeMaker);             a.getServed(ChocolateCoffee.coffeeMaker);          }           }

Nested Classes

当你的内部类对象和其所在的外部类对象没有什麽关系的时候,可以考据把你的内部类加上 static 属性,

加上 static 後的内部类又叫 nested class, 当你这麽做的时候,代表二件事:

一、内部类对象不用再依靠创建外部类对象以後再创建内部类对象。

二、内部类对象不能再存取外部类的 non-static 类成员(因为内部类有了 static 属性)


练习的时候发现假如在nested class 里再宣告一个 nested class,用下面的方式就会出错:

public class NestedClassPrac {    public static class Nested {        public void sayHello() { System.out.println("First nested class~");}        public static class LittleNested {            public void sayHello() { System.out.println("this is why we are nested class");}        }    }    public static void main(String[] args) {        Nested a = new Nested();        a.sayHello();        LittleNested b = new Nested();        b.sayHello();        }}

其实应该用下面这种方式来做:

public class NestedClassPrac {    public static class Nested {        public void sayHello() { System.out.println("First nested class~");}        public static class LittleNested {            public void sayHello() { System.out.println("this is why we are nested class");}        }    }    public static void main(String[] args) {        Nested a = new Nested();        a.sayHello();        Nested.LittleNested b = new Nested.LittleNested();         b.sayHello();         }}


Closures & callbacks

Closure 指的是一个自产生到结束的过程都存在,并持有资讯数据的可呼叫物件。

而在这一章,我们可以发现 Inner Class 便是个物件导向的 Closure。


从下面的代码可以看到,mOnClickListener 透过 setOnClickListener()而和外界得已接触,外界可自行实现一个接口传入,从而

有不同的 Click 事件的処理。而在本例 OnClickListener 所触发的事件已被 JavaClosure 类实现,我们可以创一个内部类,

另外实现一个方法。

interface OnClickListener {    void onClick();}public class JavaClosure implements OnClickListener {    private OnClickListener mOnClickListener;    public void setOnClickListener(OnClickListener l) {        mOnClickListener = l;    }    public void click() {        System.out.println("clicked");        if(mOnClickListener!=null) {            mOnClickListener.onClick();        }    }    @Override    public void onClick() {        System.out.println("hello! I am listener!!");    }    public OnClickListener getType2ClickEvent() {        return new Type2ClickListener();    }    private static class Type2ClickListener implements OnClickListener {        @Override        public void onClick() {            System.out.println("hello! I am type 2 listener!!");        }    }    public static void main(String[] args) {        JavaClosure jcbtn = new JavaClosure();        jcbtn.setOnClickListener(jcbtn);        jcbtn.click();        jcbtn.setOnClickListener(jcbtn.getType2ClickEvent());        jcbtn.click();    }}



其它:

http://stackoverflow.com/questions/26029272/nested-class-as-testing-method-in-java










0 0