(1)RTTI
RTTI是Run-Time Type Information的缩写,指运行时类型信息可以在程序运行时发现和使用。
要理解RTTI在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的。这项工作是由称为Class对象的特殊对象完成的,它包含了与类有关的信息。类是程序的一部分,每个类都有一个Class对象。每当编写并且编译了一个新类,就会产生一个Class对象。为了生成这个类的对象,运行这个程序的JAVA虚拟机(JVM)将使用被称为类加载器的子系统。
类加载器子系统实际上可以包含一条类加载器链,但是只有一个原生类加载器,它 是JVM实现的一部分。原生类加载器加载的是所谓的可信类,包括Java API类。
Java程序在它开始运行之前并非被完全加载,其各个部分是在必需时才加载的。这一点与许多传统语言都不同。
import java.util.*;
class Initable{
static final int staticFinal=47;
static final int staticFinal2=ClassInitialization.rand.nextInt(1000);
static {
System.out.println("Initializing Initable1");
}
}
class Initable2{
static int staticNonfinal=147;
static {
System.out.println("Initializing Initable2");
}
}
class Initable3{
static int staticNonfinal=74;
static{
System.out.println("Initialzing Initable3");
}
}
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 creation Initable ref");
//Does not trigger initialization;
System.out.println(Initable.staticFinal);
//Does trigger initialization;
System.out.println(Initable.staticFinal2);
//Does trigger initialization;
System.out.println(Initable2.staticNonfinal);
Class initable3=Class.forName("typeinfo.Initable3");
//Class initable3=Class.forName("Initable");//书中该处forName的参数仅有类名,但直接运行报异常,实际该处参数应在类名前添加包名。
System.out.println("After creation Initable3 ref");
System.out.println(Initable3.staticNonfinal);
}
}
运行结果:
After creation Initable ref
47
Initializing Initable1
258
Initializing Initable2
147
Initialzing Initable3
After creation Initable3 ref
74
47
Initializing Initable1
258
Initializing Initable2
147
Initialzing Initable3
After creation Initable3 ref
74
初始化有效地实现了尽可能的惰性。从对initable引用的创建中可以看到,仅使用.class语法来获得对类的引用不会引发初始化。但是,为了产生Class引用,Class.forName()立即就进行了初始化。
Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。可以将类型变得更具体一些,这是通过允许对Class引用所指向的Class对象的类型进行限定而实现的。
public class GenericClassReferences {
public static void main(String[] args){
Class intClass=int.class;
Class<Integer>genericIntClass=int.class;
genericIntClass=Integer.class;//Same thing
intClass=double.class;
//genericIntClass=double.class;//Illegal
//Class<Number> genericNumberClass=int.class;//Illegal
Class<?> intClass2=int.class;
intClass2 =double.class;
Class<? extends Number> bounded=int.class;
bounded=double.class;
bounded=Number.class;
// or anything else derived from Number.
}
}
普通的类引用不会产生警告信息,你可以看到,尽管泛型类引用只能赋值为指向其声明的类型,但是普通的类引用可以被重新赋值为指向任何其他的class对象。通过使用泛型语法,可以让编译器强制执行额外的类型检查。
当将泛型语法用于Class对象会发生一件很有趣的事情:newInstance()将返回该对象的确切类型,而不仅仅只是在ToyTest.java中看到的基本的Object。
interface HasBatteries{}
interface Waterproof{}
interface Shoots{}
class Toy{
//Comment out the following default constructor
//to see NoSuchMethodErroe from(*1*)
Toy(){}
Toy(int i){}
}
class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{
FancyToy(){super(1);}
}
public class GenericToyTest {
public static void main(String[] args)throws Exception{
Class<FancyToy> ftClass=FancyToy.class;
//Produces exact type;
FancyToy fancyToy=ftClass.newInstance();
Class<? super FancyToy> up=ftClass.getSuperclass();
//this Won't compile;
// Class<toy> up2=ftClass.getSuperclass();
// Only produces Object;
Object obj=up.newInstance();
}
}
如果手头的是超类,那编译器只允许声明超类引用是某个类,它是FancyToy超类。正是由于这种含糊性,up.newInstance()的返回值不是精确类型,而只是Object。
(2)类型转换
1)传统的类型转换,利用()进行强制类型转换。
2)代表对象类型的Class对象。
3)关键字instanceof。
实现了书中P323-329的代码,因为代码过长,不再粘贴。
(3)又一个工厂方法实例
import java.util.*;
interface Factory<T>{T create();}
class Part{
public String toString(){
return getClass().getSimpleName();
}
static List<Factory<? extends Part>> partFactories=new ArrayList<Factory<? extends Part>>();
static{
//Collections.addAll() gives an "unchecked generic"
//array creation... for varargs parameter" warning;
partFactories.add(new FuelFilter.Factory());
partFactories.add(new AirFilter.Factory());
partFactories.add(new CabinAirFilter.Factory());
partFactories.add(new OilFilter.Factory());
partFactories.add(new FanBelt.Factory());
partFactories.add(new PowerSteeringBelt.Factory());
partFactories.add(new GeneratorBelt.Factory());
}
private static Random rand=new Random(47);
public static Part createRandom(){
int n= rand.nextInt(partFactories.size());
return partFactories.get(n).create();
}
}
class Filter extends Part{}
class FuelFilter extends Filter{
// Create a Class Factory for each specific type;
public static class Factory implements typeinfo.Factory<FuelFilter>{
public FuelFilter create() {return new FuelFilter();}
}
}
class AirFilter extends Filter{
public static class Factory implements typeinfo.Factory<AirFilter>{
public AirFilter create(){return new AirFilter();}
}
}
class GeneratorBelt extends Belt{
public static class Factory implements typeinfo.Factory<GeneratorBelt>{
public GeneratorBelt create(){return new GeneratorBelt();}
}
}
class PowerSteeringBelt extends Belt{
public static class Factory implements typeinfo.Factory<PowerSteeringBelt>{
public PowerSteeringBelt create(){return new PowerSteeringBelt();}
}
}
class FanBelt extends Belt{
public static class Factory implements typeinfo.Factory<FanBelt>{
public FanBelt create(){return new FanBelt();}
}
}
class Belt extends Part{};
class OilFilter extends Filter{
public static class Factory implements typeinfo.Factory<OilFilter>{
public OilFilter create(){return new OilFilter();}
}
}
class CabinAirFilter extends Filter{
public static class Factory implements typeinfo.Factory<CabinAirFilter>{
public CabinAirFilter create(){return new CabinAirFilter();}
}
}
public class RegisteredFactories {
public static void main(String[] args){
for(int i=0;i<10;i++)
System.out.println(Part.createRandom());
}
}
(4)反射
反射是JAVA中用来解决某一些特殊问题的方法。可以下个阶段再做详细了解。
代理是基本设计模式之一,它是你为了提供额外的或者不同的操作,而插入的用来代替实际对象的对象。这些操作通常涉及与实际对象的通信,因此代理通常弃当着中间人的角色。
import java.lang.reflect.*;
interface Interface{
void doSomething();
void somethingElse(String arg);
}
class RealObject implements Interface{
public void doSomething(){System.out.println("doSomething");}
public void somethingElse(String arg){
System.out.println("SomegthingElse "+arg);
}
}
class DynamicProxyHandler implements InvocationHandler{
private Object proxied;
public DynamicProxyHandler(Object proxied){
this.proxied=proxied;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
System.out.println("**** proxy: "+ proxy.getClass()+",method: "+ method +",args : "+ args);
if(args!=null)
for(Object arg:args) System.out.println(" " +arg);
return method.invoke(proxied, args);
}
}
public class SimpleDynamicProxy {
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args){
RealObject real=new RealObject();
consumer(real);
//Insert a proxy and call again;
Interface proxy=(Interface)Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{Interface.class},
new DynamicProxyHandler(real));
consumer(proxy);
}
}