类型信息:
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<String>()和ArrayList<Integer>()实际上是一样的类型:
package generic;
import java.util.ArrayList;
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().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<Frob> list = new ArrayList<Frob>();
Map<Frob, Fnorkle> map = new HashMap<Frob, Fnorkle>();
Quark<Fnorkle> quark = new Quark<Fnorkle>();
Particle<Long, Double> p = new Particle<Long, Double>();
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<Q>{}
class Particle<POSITION, MOMENTUM>{}
由运行结果可以看出,在运行过程中的类型都不是具体的类型,而是泛化的类型。
根据JDK文档的描述就,Class.getTypeParameters()将返回一个TypeVariable对象数组,表示有泛型声明所声明的类型参数。。。,所以你通过这种方式得到的只是用作参数占位符的标识符,这并非有用的信息。
残酷的现实是:
在泛型代码内部,无法获得任何有关泛型参数类型的信息。
泛型类边界:
package generic;
public class Test20 {
public static void main(String[] args) {
InterTestTwty obj = new ClsTwty();
UseGeneric<InterTestTwty> use = new UseGeneric<InterTestTwty>(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<T extends InterTestTwty>{
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."<init>":()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 "<init>":()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<T> {
private T obj;
public void set(T obj){this.obj = obj;}
public T get(){return obj;}
public static void main(String[] args) {
GenericHolder<String> holder = new GenericHolder<String>();
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."<init>":()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 "<init>":()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的时候,实际上代码自动插入了类型转换,与不使用泛型时自己进行类型转换是一样的。
通配符:
由上图中代码,我们可以看到,数组支持了协变性,而泛型List并不支持,会编译出错,而使用通配符的时候,虽然能够通过编译,但是这个list实际上并不知道自己持有的是什么类型,所以只能够添加null。
数组的协变性(covariant)是指如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。而泛型是不可变的(invariant),List<Base>不会是List<Sub>的基类,更不会是它的子类。
通配符extends和super的区别:
List<? extends Fruit> flist = new ArrayList<Apple>();
// complie error:
// flist.add(new Apple());
// flist.add(new Fruit());
// flist.add(new Object());
flist.add(null); // only work for null
List<? extends Frut> 表示 “具有任何从Fruit继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List<Apple> 赋值。
List<? super Fruit> flist = new ArrayList<Fruit>();
flist.add(new Fruit());
flist.add(new Apple());
flist.add(new RedApple());
// compile error:
List<? super Fruit> flist = new ArrayList<Apple>();
List<? super Fruit> 表示“具有任何Fruit超类型的列表”,列表的类型至少是一个 Fruit 类型,因此可以安全的向其中添加Fruit 及其子类型。由于List<? super Fruit>中的类型可能是任何Fruit 的超类型,无法赋值为Fruit的子类型Apple的List<Apple>.
public class GenericTest1 {
public static void main(String[] args) {
//List<Fruit> l = new ArrayList<Apple>(); // compile error
// List<? extends Fruit> flist = new ArrayList<Apple>();
// flist.add
// Number[] numbers = new Integer[100];
// List<? extends Fruit> flist = Arrays.asList(new Apple());
// Apple a = (Apple) flist.get(0);
// flist.contains(new Apple());
// flist.indexOf(new Apple());
List<? super Fruit> flist = new ArrayList<Fruit>();
flist.add(new Apple());
flist.add(new Jonathan());
}
}
class Fruit{}
class Apple extends Fruit{}
class Jonathan extends Apple{}
extends 可用于的返回类型限定,不能用于参数类型限定。List<? extends Season> list1 = getSeasonList();//getSeasonList方法会返回一个Season的子类的list
super 可用于参数类型限定,不能用于返回类型限定。
带有super超类型限定的通配符可以向泛型对易用写入,带有extends子类型限定的通配符可以向泛型对象读取。
自动包装机制不能应用于数组:
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<String, Object> delegateByMethod;
public MixinProxy(TwoTuple<Object, Class<?>>... pairs) {
delegateByMethod = new HashMap<String, Object>();
for(TwoTuple<Object, Class<?>> 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<A, B>{
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 <A, B> TwoTuple<A,B> tuple(A a, B b){
return new TwoTuple<A, B>(a, b);
}
}
Proxy.newProxyInstance方法第二个参数传递的是一个接口的数组,可以传入多个,最后根据类型强转确定具体的接口类型。