类型信息:
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
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
*/
通配符:
由上图中代码,我们可以看到,数组支持了协变性,而泛型List并不支持,会编译出错,而使用通配符的时候,虽然能够通过编译,但是这个list实际上并不知道自己持有的是什么类型,所以只能够添加null。
数组的协变性(covariant)是指如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。而泛型是不可变的(invariant),List
通配符extends和super的区别:
List extends Fruit> 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 extends Frut> 表示 “具有任何从Fruit继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List
List super Fruit> flist = new ArrayList
flist.add(new Fruit());
flist.add(new Apple());
flist.add(new RedApple());
// compile error:
List super Fruit> flist = new ArrayList
List super Fruit> 表示“具有任何Fruit超类型的列表”,列表的类型至少是一个 Fruit 类型,因此可以安全的向其中添加Fruit 及其子类型。由于List super Fruit>中的类型可能是任何Fruit 的超类型,无法赋值为Fruit的子类型Apple的List
public class GenericTest1 {
public static void main(String[] args) {
//List l = new ArrayList(); // compile error
// List extends Fruit> flist = new ArrayList();
// 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();
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 delegateByMethod;
public MixinProxy(TwoTuple
Proxy.newProxyInstance方法第二个参数传递的是一个接口的数组,可以传入多个,最后根据类型强转确定具体的接口类型。