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

你可能感兴趣的:(java编程思想读书笔记-4)