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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值