Java进阶之路_重温《java编程思想》篇(七)

类型信息:

RTTI:在运行时,识别一个对象的类型。

类加载器(原生类加载器,加载可信类:java API):

所有的类都是在对其第一次使用时,动态加载到JVM的。当程序创建第一个对类的静态成员引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。因此,使用new操作符创建类的新对象也会被当作对类的静态成员的引用。

类字面常量:

建议使用".class"获取生成Class对象的引用。

注意:当使用".class"来创建对Class对象的引用时,不会自动地初始化该Class对象。为了使用类而做的准备工作实际包含三个步骤:

1.加载,这是由类加载器执行的。该步骤将查找字节码(通常在classpath所在的指定路径中查找,但这并非是必须的),并从这些字节码中创建一个Class对象。

2.链接,在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。

3.初始化,如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。

初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。

package com.rtti;

import java.util.Random;

public class ClassInitialization {

	public static Random rand = new Random(47);
	public static void main(String[] args) throws Exception{

		Class initable = Initable.class;
		System.out.println("After creating Initable ref");
		//没有触发初始化
		System.out.println(Initable.staticFinal);
		//触发初始化
		System.out.println(Initable.staticFinal2);
		//触发初始化
		System.out.println(Initable2.staticNonFinal);
		Class initable3 = Class.forName("com.rtti.Initable3");
		System.out.println("After creating Initable3 ref");
		System.out.println(Initable3.staticNonFinal);
	}/*Output
	After creating Initable ref
	47
	Initializing Initable
	258
	Initializing Initable2
	147
	Initializing Initable3
	After creating Initable3 ref
	74
	*///!:
}
class Initable{
	static final int staticFinal = 47;
	static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);
	static{
		System.out.println("Initializing Initable");
	}
}
class Initable2{
	static int staticNonFinal = 147;
	static{
		System.out.println("Initializing Initable2");
	}
}
class Initable3{
	static int staticNonFinal = 74;
	static{
		System.out.println("Initializing Initable3");
	}
}
初始化有效地实现了尽可能地“惰性”。不是必需的时候就不进行初始化。

如果一个static final值是一个“编译期常量”,它不需要类初始化就可以被读取。程序中Initable.staticFinal是“编译期常量”;而Initable.staticFinal2则不是,因此在访问它的时候会初始化类。


擦除的神秘之处:

ArrayList()和ArrayList()实际上是一样的类型:

package generic;

import java.util.ArrayList;

public class ErasedTypeEquivalence {

	public static void main(String[] args) {

		Class c1 = new ArrayList().getClass();
		Class c2 = new ArrayList().getClass();
		System.out.println(c1 == c2);
	}

}/*Output: true*/

类型的丢失:

package generic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LostInformation {

	public static void main(String[] args) {
		List list = new ArrayList();
		Map map = new HashMap();
		Quark quark = new Quark();
		Particle p = new Particle();
		System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(quark.getClass().getTypeParameters()));
		System.out.println(Arrays.toString(p.getClass().getTypeParameters()));
	}/* Output:
	[E]
	[K, V]
	[Q]
	[POSITION, MOMENTUM]
	*///:~
}
class Frob{}
class Fnorkle{}
class Quark{}
class Particle{}
由运行结果可以看出,在运行过程中的类型都不是具体的类型,而是泛化的类型。

根据JDK文档的描述就,Class.getTypeParameters()将返回一个TypeVariable对象数组,表示有泛型声明所声明的类型参数。。。,所以你通过这种方式得到的只是用作参数占位符的标识符,这并非有用的信息。

残酷的现实是:

在泛型代码内部,无法获得任何有关泛型参数类型的信息。
泛型类边界:

package generic;

public class Test20 {

	public static void main(String[] args) {
		InterTestTwty obj = new ClsTwty();
		UseGeneric use = new UseGeneric(obj);
		use.runFincs();
	}
}
interface InterTestTwty{
	public void func1();
	public void func2();
}
class ClsTwty implements InterTestTwty{

	@Override
	public void func1() {
		System.out.println("ClasTwty.func1()");
	}

	@Override
	public void func2() {
		System.out.println("ClasTwty.func2()");
	}
}
class UseGeneric{
	private T obj;
	public UseGeneric(T x){
		obj = x;
	}
	public void runFincs(){
		obj.func1();
		obj.func2();
	}
}
使用泛型与不使用泛型的比较:

不使用泛型:

package generic;

public class SimpleHolder {
	private Object obj;
	public void set(Object obj){this.obj = obj;}
	public Object get(){return obj;}
	public static void main(String[] args) {
		SimpleHolder holder = new SimpleHolder();
		holder.set("Item");
		String s = (String)holder.get();
	}
}
/*
 *字节码:
 *public class generic.SimpleHolder extends java.lang.Object{
public generic.SimpleHolder();
  Code:
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."":()V
   4:   return

public void set(java.lang.Object);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #18; //Field obj:Ljava/lang/Object;
   5:   return

public java.lang.Object get();
  Code:
   0:   aload_0
   1:   getfield        #18; //Field obj:Ljava/lang/Object;
   4:   areturn

public static void main(java.lang.String[]);
  Code:
   0:   new     #1; //class generic/SimpleHolder
   3:   dup
   4:   invokespecial   #24; //Method "":()V
   7:   astore_1
   8:   aload_1
   9:   ldc     #25; //String Item
   11:  invokevirtual   #27; //Method set:(Ljava/lang/Object;)V
   14:  aload_1
   15:  invokevirtual   #29; //Method get:()Ljava/lang/Object;
   18:  checkcast       #31; //class java/lang/String
   21:  astore_2
   22:  return 
 **/

使用泛型:

package generic;

public class GenericHolder {
	private T obj;
	public void set(T obj){this.obj = obj;}
	public T get(){return obj;}
	public static void main(String[] args) {
		GenericHolder holder = new GenericHolder();
		holder.set("Item");
		String s = holder.get();
	}
}
/**
 * public class generic.GenericHolder extends java.lang.Object{
public generic.GenericHolder();
  Code:
   0:   aload_0
   1:   invokespecial   #12; //Method java/lang/Object."":()V
   4:   return

public void set(java.lang.Object);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #23; //Field obj:Ljava/lang/Object;
   5:   return

public java.lang.Object get();
  Code:
   0:   aload_0
   1:   getfield        #23; //Field obj:Ljava/lang/Object;
   4:   areturn

public static void main(java.lang.String[]);
  Code:
   0:   new     #1; //class generic/GenericHolder
   3:   dup
   4:   invokespecial   #30; //Method "":()V
   7:   astore_1
   8:   aload_1
   9:   ldc     #31; //String Item
   11:  invokevirtual   #33; //Method set:(Ljava/lang/Object;)V
   14:  aload_1
   15:  invokevirtual   #35; //Method get:()Ljava/lang/Object;
   18:  checkcast       #37; //class java/lang/String
   21:  astore_2
   22:  return
 */

字节码是相同的,而使用泛型的代码会在编译期间做检查,使得set和get的类型与类型参数一致,并且,在调用get的时候,实际上代码自动插入了类型转换,与不使用泛型时自己进行类型转换是一样的。


通配符:

Java进阶之路_重温《java编程思想》篇(七)_第1张图片

由上图中代码,我们可以看到,数组支持了协变性,而泛型List并不支持,会编译出错,而使用通配符的时候,虽然能够通过编译,但是这个list实际上并不知道自己持有的是什么类型,所以只能够添加null。

数组的协变性(covariant)是指如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。而泛型是不可变的(invariant),List不会是List的基类,更不会是它的子类。


通配符extends和super的区别:

List flist = new ArrayList();
// complie error:
// flist.add(new Apple());
// flist.add(new Fruit());
// flist.add(new Object());
flist.add(null); // only work for null

List 表示 “具有任何从Fruit继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List 赋值。

List flist = new ArrayList();

flist.add(new Fruit());

flist.add(new Apple());

flist.add(new RedApple());

// compile error:

List flist = new ArrayList();

List 表示“具有任何Fruit超类型的列表”,列表的类型至少是一个 Fruit 类型因此可以安全的向其中添加Fruit 及其子类型。由于List中的类型可能是任何Fruit 的超类型,无法赋值为Fruit的子类型Apple的List.

public class GenericTest1 {

	public static void main(String[] args) {

		//List l = new ArrayList(); // compile error
//		List flist = new ArrayList();
//		flist.add
//		Number[] numbers = new Integer[100];
		
//		List flist = Arrays.asList(new Apple());
//		Apple a = (Apple) flist.get(0);
//		flist.contains(new Apple());
//		flist.indexOf(new Apple());
		
		List flist = new ArrayList();
		flist.add(new Apple());
		flist.add(new Jonathan());
	}

}
class Fruit{}
class Apple extends Fruit{}
class Jonathan extends Apple{}

extends 可用于的返回类型限定,不能用于参数类型限定。List list1 = getSeasonList();//getSeasonList方法会返回一个Season的子类的list

super 可用于参数类型限定,不能用于返回类型限定。

带有super超类型限定的通配符可以向泛型对易用写入,带有extends子类型限定的通配符可以向泛型对象读取。

参考资料: http://www.hollischuang.com/archives/255

自动包装机制不能应用于数组:

Integer[] a = new int[10]; int[] a = new Integer[10];

这种用法是错误的。


使用接口来实现混型效果:

package decorator;
import java.util.Date;
public class Decoration {
	public static void main(String[] args) {
		TimeStamped t = new TimeStamped(new Basic());
		TimeStamped t2 = new TimeStamped(new SerialNumber(new Basic()));
		SerialNumber s = new SerialNumber(new Basic());
		SerialNumber s2 = new SerialNumber(new TimeStamped(new Basic()));
	}
}
class Basic{
	private String value;
	public void set(String val){value = val;}
	public String get(){return value;}
}
class Decorator extends Basic{
	protected Basic basic;
	public Decorator(Basic basic){this.basic = basic;}
	public void set(String val){basic.set(val);}
	public String get(){return basic.get();}
}
class TimeStamped extends Decorator{
	private final long timeStamp;
	public TimeStamped(Basic basic){
		super(basic);
		timeStamp = new Date().getTime();
	}
	public long getTimeStamp(){return timeStamp;}
}
class SerialNumber extends Decorator{
	private static long counter = 1;
	private final long serialNumber = counter++;
	public SerialNumber(Basic basic) {
		super(basic);
	}
	public long getSerialNumber(){return serialNumber;}
}

package mixins;

import java.util.Date;

public class Mixins {
	public static void main(String[] args) {
		Mixin mixin1 = new Mixin(), mixin2 = new Mixin();
		mixin1.set("test string 1");
		mixin2.set("test string 2");
		System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber());
		System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber());
	}
}
class Mixin extends BasicImpl implements TimeStamped, SerialNumbered{
	private TimeStamped timeStamp = new TimeStampedImpl();
	private SerialNumbered serialNumber = new SerialNumberedImpl();
	@Override
	public long getSerialNumber() {return serialNumber.getSerialNumber();}
	@Override
	public long getStamp() {return timeStamp.getStamp();}
}
interface TimeStamped{long getStamp();}
class TimeStampedImpl implements TimeStamped{
	private final long timeStamped;
	public TimeStampedImpl() {
		timeStamped = new Date().getTime();
	}
	@Override
	public long getStamp() {return timeStamped;}
}
interface SerialNumbered{long getSerialNumber();}
class SerialNumberedImpl implements SerialNumbered{
	private static long counter = 1;
	private final long serialNumber = counter++;
	@Override
	public long getSerialNumber() {return serialNumber;}
}
interface Basic{
	public void set(String val);
	public String get();
}
class BasicImpl implements Basic{
	private String value;
	@Override
	public void set(String val) {value = val;}
	@Override
	public String get() {return value;}
}

装饰器模式:


package decorator;
import java.util.Date;
public class Decoration {
	public static void main(String[] args) {
		TimeStamped t = new TimeStamped(new Basic());
		TimeStamped t2 = new TimeStamped(new SerialNumber(new Basic()));
		SerialNumber s = new SerialNumber(new Basic());
		SerialNumber s2 = new SerialNumber(new TimeStamped(new Basic()));
	}
}
class Basic{
	private String value;
	public void set(String val){value = val;}
	public String get(){return value;}
}
class Decorator extends Basic{
	protected Basic basic;
	public Decorator(Basic basic){this.basic = basic;}
	public void set(String val){basic.set(val);}
	public String get(){return basic.get();}
}
class TimeStamped extends Decorator{
	private final long timeStamp;
	public TimeStamped(Basic basic){
		super(basic);
		timeStamp = new Date().getTime();
	}
	public long getTimeStamp(){return timeStamp;}
}
class SerialNumber extends Decorator{
	private static long counter = 1;
	private final long serialNumber = counter++;
	public SerialNumber(Basic basic) {
		super(basic);
	}
	public long getSerialNumber(){return serialNumber;}
}


使用动态代理实现方式:

package delegate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class DynamicProxyMixin {
	public static void main(String[] args) {
		Object mixin = MixinProxy.newInstance(Tuple.tuple(new SerialNumbered(), SerialInter.class));
		SerialInter s = (SerialInter)mixin;
		System.out.println(s.get());
	}
}
class SerialNumbered implements SerialInter{
	private final int serialNumber = 1;
	public int get(){
		return serialNumber;
	}
}
interface SerialInter{public int get();}
class MixinProxy implements InvocationHandler{
	Map delegateByMethod;
	public MixinProxy(TwoTuple>... pairs) {
		delegateByMethod = new HashMap();
		for(TwoTuple> pair : pairs){
			for(Method method : pair.second.getMethods()){
				String methodName = method.getName();
				if(!delegateByMethod.containsKey(methodName)){
					delegateByMethod.put(methodName, pair.first);
				}
			}
		}
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		String methodName = method.getName();
		Object delegate = delegateByMethod.get(methodName);
		System.out.println(delegate.getClass().getName() + "." + methodName);
		return method.invoke(delegate, args);
	}
	public static Object newInstance(TwoTuple... pairs){
		Class[] interfaces = new Class[pairs.length];
		for(int i = 0; i < pairs.length; i++){
			interfaces[i] = (Class) pairs[i].second;
		}
		ClassLoader cl = pairs[0].first.getClass().getClassLoader();
		return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));
	}
}
class TwoTuple{
	public final A first;
	public final B second;
	public TwoTuple(A a, B b){
		first = a;
		second = b;
	}
	public String toString(){
		return "(" + ", " + second + ")";
	}
}
class Tuple{
	public static  TwoTuple tuple(A a, B b){
		return new TwoTuple(a, b);
	} 
}

Proxy.newProxyInstance方法第二个参数传递的是一个接口的数组,可以传入多个,最后根据类型强转确定具体的接口类型。





你可能感兴趣的:(Java进阶之路_重温《java编程思想》篇(七))