您的位置:首页 > 编程语言 > Java开发

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

2014-10-05 16:07 501 查看
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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: