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

来源:互联网 发布:机器人c语言编程 编辑:程序博客网 时间:2024/05/18 00:01

类型信息:

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);}/*OutputAfter creating Initable ref47Initializing Initable258Initializing Initable2147Initializing Initable3After creating Initable3 ref74*///!:}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{@Overridepublic void func1() {System.out.println("ClasTwty.func1()");}@Overridepublic 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:   returnpublic void set(java.lang.Object);  Code:   0:   aload_0   1:   aload_1   2:   putfield        #18; //Field obj:Ljava/lang/Object;   5:   returnpublic java.lang.Object get();  Code:   0:   aload_0   1:   getfield        #18; //Field obj:Ljava/lang/Object;   4:   areturnpublic 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:   returnpublic void set(java.lang.Object);  Code:   0:   aload_0   1:   aload_1   2:   putfield        #23; //Field obj:Ljava/lang/Object;   5:   returnpublic java.lang.Object get();  Code:   0:   aload_0   1:   getfield        #23; //Field obj:Ljava/lang/Object;   4:   areturnpublic 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子类型限定的通配符可以向泛型对象读取。

参考资料: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();@Overridepublic long getSerialNumber() {return serialNumber.getSerialNumber();}@Overridepublic long getStamp() {return timeStamp.getStamp();}}interface TimeStamped{long getStamp();}class TimeStampedImpl implements TimeStamped{private final long timeStamped;public TimeStampedImpl() {timeStamped = new Date().getTime();}@Overridepublic long getStamp() {return timeStamped;}}interface SerialNumbered{long getSerialNumber();}class SerialNumberedImpl implements SerialNumbered{private static long counter = 1;private final long serialNumber = counter++;@Overridepublic long getSerialNumber() {return serialNumber;}}interface Basic{public void set(String val);public String get();}class BasicImpl implements Basic{private String value;@Overridepublic void set(String val) {value = val;}@Overridepublic 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);}}}}@Overridepublic 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方法第二个参数传递的是一个接口的数组,可以传入多个,最后根据类型强转确定具体的接口类型。





0 0