java編程思想讀書筆記-4

第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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章