第9章 接口
9.3 完全解耦
import java.util.Arrays;
class Processor{
public String getName(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class Upcase extends Processor{
String process(Object input){
return ((String)input).toUpperCase();
}
}
class Downcase extends Processor{
String process(Object input){
return ((String)input).toLowerCase();
}
}
class Spliter extends Processor{
String process(Object input){
return Arrays.toString(((String)input).split(" "));
}
}
public class Apply {
public static void process(Processor p, String s){
System.out.println("Using processor " + p.getName());
System.out.println(p.process(s));
}
public static String s = "Disagreement with beliefs is by definition incorrect";
public static void main(String[] args){
process(new Upcase(), s);
process(new Downcase(), s);
process(new Spliter(), s);
}
}
Apply.process()方法可以接受任何類型的Processor,並將其應用到一個Object對象上。本例這樣,創建一個能夠根據所傳遞的參數對象的不同而具有不同行爲的方法,被稱爲策略設計模式。
在實現的時候一般不創建基類,只是創建一個接口,這樣別人在使用時只需implements接口,而非繼承基類。
10.5 在方法和作用域內的內部類
public interface Destination {
String readLabel();
public interface Contents {
int value();
}
public class Pracel {
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PDestination(String whereTo){
label = whereTo;
}
@Override
public String readLabel() {
// TODO Auto-generated method stub
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Pracel p = new Pracel();
Destination d = p.destination("Tasmania");
}
}
10.6 匿名內部類
public class Pracel {
public Contents contents(){
return new Contents(){
private int i = 11;
public int value(){return i;}
};
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Pracel p = new Pracel();
Contents c = p.contents();
}
}
public class Pracel {
public Destination destination(<span style="color:#ff0000;">final </span>String s) {
return new Destination() {
private String label = s;
@Override
public String readLabel() {
// TODO Auto-generated method stub
return label;
}
};
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Pracel p = new Pracel();
Destination d = p.destination("Tasmania");
}
}
如果定義一個匿名內部類,並且希望它使用一個在其外部定義的對象,則這個參數引用必須是final的。因爲方法結束,變量消失,而內部類不會消失,只有final,內部類會拷貝一份進行存儲及訪問。
當方法destination被調用,從而在它的調用棧中生成了變量s,此時產生了一個局部內部類對象Destination,它訪問了該局部變量s .當方法destination()運行結束後,局部變量i就已死亡了,不存在了.但:局部內部類對象Destination還可能 一直存在(只能沒有人再引用該對象時,它纔會死亡),它不會隨着方法destination()運行結束死亡.這時:出現了一個"荒唐"結果:局部內部類對象Destination要訪問一個已不存在的局部變量i!
如何才能實現?當變量是final時,通過將final局部變量"複製"一份,複製品直接作爲局部內部中的數據成員.這樣:當局部內部類訪問局部變量 時,其實真正訪問的是這個局部變量的"複製品"(即:這個複製品就代表了那個局部變量).因此:當運行棧中的真正的局部變量死亡時,局部內部類對象仍可以 訪問局部變量(其實訪問的是"複製品"),給人的感覺:好像是局部變量的"生命期"延長了.
舉例:要實現在一個方法中匿名調用ABSClass的例子
public static void test(final String s){
//或final String s = "axman";
ABSClass c = new ABSClass(){
public void m(){
int x = s.hashCode();
System.out.println(x);
}
};
//其它代碼.
}
編譯的時候,其實是這樣的:
public static void test(final String s){
//或final String s = "axman";
class OuterClass$1 extends ABSClass{
private final String s;
public OuterClass$1(String s){
this.s = s;
}
public void m(){
int x = s.hashCode();
System.out.println(x);
}
};
ABSClass c = new OuterClass$1(s);
//其它代碼.
}
即外部類的變量被作爲構造方法的參數傳給了內部類的私有成員. abstract class Base{
public Base(int i){
System.out.println("Base constructor,i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i){
return new Base(i){
@Override
public void f() {
// TODO Auto-generated method stub
System.out.println("In anonymous f()");
}
};
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Base base = getBase(47);
base.f();
}
}
注意:
接口是一種協定,抽象類則相當於類模板。
使用抽象類,而不要使用接口來分離協定與實現。
如果需要提供多態層次結構的值類型,使用接口。
如果一個類型必須實現多個協定,或者協定適用於多種類型,使用接口。
雖然抽象類和接口都支持將協定與實現分離開來,但接口不能指定以後版本中的新成員,而抽象類可以根據需要添加成員以支持更多功能。
優先考慮定義類,而不是接口。
10.12 內部類標示符
由於每個類都會生成一個.class的文件,其中共包含了如何創建該類型的對象的全部信息(此信息產生一個"meta-class",叫做class對象),內部類也必鬚生成一個.class文件以包含它們的class對象信息。這些類名有嚴格的命名規則:外圍類名字+"$"+內部類名字,如:
interface Counter{
int next();
}
public class LocalInnerClass{
private int count = 0;
Counter getCounter(final String name){
class LocalCounter implements Counter{
public LocalCounter(){
System.out.println("LocalCounter()");
}
public int next(){
System.out.print(name);
return count++;
}
}
return new LocalCounter();
}
Counter getCounter2(final String name){
return new Counter(){
{
System.out.println("Counter()");
}
@Override
public int next() {
// TODO Auto-generated method stub
System.out.print(name);
return count++;
}
};
}
public static void main(String[] args){
LocalInnerClass lic = new LocalInnerClass();
Counter
c1 = lic.getCounter("Local inner"),
c2 = lic.getCounter2("Anonymous inner");
for(int i = 0; i < 5; ++i){
System.out.println(c1.next());
}
for(int i = 0; i < 5; ++i){
System.out.println(c2.next());
}
}
}
輸出結果爲:
Counter()
Local inner0
Local inner1
Local inner2
Local inner3
Local inner4
Anonymous inner5
Anonymous inner6
Anonymous inner7
Anonymous inner8
Anonymous inner9
生成的.class文件包括:
Counter.class, LocalInnerClass$1.class, LocalInnerClass$1LocalCounter.class,LocalInnerClass.class