Java类型信息
1、RTTI
RTTI(Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息。
多态(polymorphism)是基于RTTI实现的。RTTI的功能主要是由Class类实现的。
2、Class对象
类是程序的一部分,每个类都有一个Class对象。Class对象就是用来创建类的所有的“常规”对象的,它包含了与类有关的信息。Java使用Class对象来执行其RTTI。
1 public class Test {
2 public static void main(String[] args) {
3 Class<?> c = null;
4 try {
5 c = Class.forName("com.my.chapter14.Man");
6 } catch(ClassNotFoundException e) {
7 System.out.println("Can't find Man");
8 return;
9 }
10
11 System.out.println("Class name: " + c.getName() +
12 " is interface? [" + c.isInterface() + "]");
13 System.out.println("Simple name: " + c.getSimpleName());
14 System.out.println("Canonical name : " + c.getCanonicalName());
15 System.out.println("");
16 for(Class<?> face : c.getInterfaces())
17 System.out.println(face.getSimpleName());
18 System.out.println("");
19
20 Class<?> up = c.getSuperclass();
21 Object obj = null;
22 try {
23 // Requires default constructor:
24 obj = up.newInstance();
25 } catch(InstantiationException e) {
26 System.out.println("Cannot instantiate");
27 return;
28 } catch(IllegalAccessException e) {
29 System.out.println("Cannot access");
30 return;
31 }
32 System.out.println(obj.getClass());
33 }
34 }
35
36 interface HasHouse{}
37
38 class Human{
39 Human(){}
40 Human(int i){}
41 }
42
43 class Man extends Human implements HasHouse{
44 Man(){super(1);}
45 }
46
47 /*Output:
48 Class name: com.my.chapter14.Man is interface? [false]
49 Simple name: Man
50 Canonical name : com.my.chapter14.Man
51
52 HasHouse
53
54 class com.my.chapter14.Human
55 */
3、类字面常量
通过类字面常量可以生成对Class对象的引用。
当通过“.class”来创建对Class对象的引用时,不会自动地初始化Class对象,初始化延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时。Class.forName()立即就进行了初始化,而仅使用.class语法来获得对类的引用不会引发初始化。
如果static final值是“编译期常量”,那么不需要初始化就可以被读取0,如staticFinal。如果只是将一个域设置为static和final,访问时将强制进行类的初始化,如staticFinal2。
1 static final int staticFinal = 6;
2 static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);
泛化的Class引用。Class<?>表示任何类型;Class<? extends Number>表示Number的子类;Class<? super FancyToy>表示FancyToy的父类。
4、注册工厂
一个父类可能会派生出许多子类,当有新的子类产生时,需要将其添加进相应的列表中才便于管理和创建。因此这个列表应置于一个位于中心的、位置明显的地方,而基类就是这个最佳位置。
因此为了便于随机创建各个子类,需要运用工厂方法设计模式,将对象的创建工作交给类自己去完成。
1 interface Factory<T>{
2 T create();
3 }
4
5 class Parts{
6 @Override
7 public String toString() {
8 return getClass().getSimpleName();
9 }
10
11 static List<Factory<? extends Parts>> partFactories = new ArrayList<Factory<? extends Parts>>();
12 static {
13 partFactories.add(new FuelFilter.Factory());
14 partFactories.add(new AirFilter.Factory());
15 partFactories.add(new CabinAirFilter.Factory());
16 }
17 private static Random rand = new Random(47);
18 public static Parts createRandom(){
19 int n = rand.nextInt(partFactories.size());
20 return partFactories.get(n).create();
21 }
22 }
23
24 class Filter extends Parts{}
25
26 class FuelFilter extends Filter{
27 public static class Factory implements com.my.chapter14.Factory<FuelFilter>{
28 @Override
29 public FuelFilter create() {
30 return new FuelFilter();
31 }
32 }
33 }
34
35 class AirFilter extends Filter{
36 public static class Factory implements com.my.chapter14.Factory<AirFilter>{
37 @Override
38 public AirFilter create() {
39 return new AirFilter();
40 }
41 }
42 }
43
44 class CabinAirFilter extends Filter{
45 public static class Factory implements com.my.chapter14.Factory<CabinAirFilter>{
46 @Override
47 public CabinAirFilter create() {
48 return new CabinAirFilter();
49 }
50 }
51 }
52
53 public class Test {
54 public static void main(String[] args) {
55 Parts part;
56 for(int i = 0; i < 20; i++) {
57 part = Parts.createRandom(); System.out.print(part.getClass().getSimpleName() + " ");
58 }
59 }
60 }
5、反射:运行时的类信息
有时你从磁盘文件,或者网络连接中获取了一串字节,并且被告知这些字节代表一个类,而这个类在编译器为你的程序生成代码之后很久才出现,如何使用这样的类呢?通过反射机制可以解决该问题。对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。对RTTI来说,编译器在编译时打开和检查.class文件。
6、动态代理
代理就是将额外的操作从“实际”对象中分离到不同的地方,并且易修改。
通过Proxy.newProxyInstance()方法可以创建动态代理,这个方法需要一个类加载器,一个你希望该代理实现的接口列表,以及InvocationHandler接口的一个实现。通过Method.invoke()方法将请求转发给被代理的对象,并传入必需的参数。
1 interface Interface {
2 void doSomething();
3 void somethingElse(String arg);
4 }
5
6 class RealObject implements Interface {
7 public void doSomething() {
8 System.out.println("doSomething"); }
9 public void somethingElse(String arg) {
10 System.out.println("somethingElse " + arg);
11 }
12 }
13
14 class DynamicProxyHandler implements InvocationHandler {
15 private Object proxied;
16 public DynamicProxyHandler(Object proxied) {
17 this.proxied = proxied;
18 }
19 public Object
20 invoke(Object proxy, Method method, Object[] args)
21 throws Throwable {
22 System.out.println("**** proxy: " + proxy.getClass() +
23 ", method: " + method + ", args: " + args);
24 if(args != null)
25 for(Object arg : args)
26 System.out.println(" " + arg);
27 Object ret = method.invoke(proxied, args);
28 return ret;
29 }
30 }
31
32 public class practice22 {
33 public static void consumer(Interface iface) {
34 iface.doSomething();
35 iface.somethingElse("bonobo");
36 }
37
38 public static void main(String[] args) {
39 RealObject real = new RealObject();
40 Interface proxy = (Interface) Proxy.newProxyInstance(
41 Interface.class.getClassLoader(),
42 new Class<?>[]{ Interface.class },
43 new DynamicProxyHandler(real));
44 consumer(proxy);
45 }
46 }
7、接口与类型信息
通过反射可以调用标识为private或包访问权限的方法。
1 package package1;
2 public interface A{
3 void f();
4 }
5
6 package package1;
7 public class HiddenC{
8 public static A makeA(){
9 return new C();
10 }
11 }
12
13 class C implements A{
14
15 @Override
16 public void f() {
17 System.out.println("public void C.f()");
18 }
19 public void g(){
20 System.out.println("public void C.g()");
21 }
22 void u(){
23 System.out.println("void C.u()");
24 }
25 protected void v(){
26 System.out.println("protected void C.v()");
27 }
28 private void w(){
29 System.out.println("private void C.w()");
30 }
31 }
32
33 package package2;
34 public class Test {
35 static void callHiddenMethod(Object a, String methodName)
36 throws Exception {
37 Method g = a.getClass().getDeclaredMethod(methodName);
38 g.setAccessible(true);
39 g.invoke(a);
40 }
41
42 public static void main(String[] args) throws Exception {
43 A a = HiddenC.makeA();
44 a.f();
45 callHiddenMethod(a,"g");
46 callHiddenMethod(a,"u");
47 callHiddenMethod(a,"v");
48 callHiddenMethod(a,"w");
49 }
50 }
51
52 /*Output:
53 public void C.f()
54 public void C.g()
55 void C.u()
56 protected void C.v()
57 private void C.w()
58 */
参考于《Java编程思想》,第313~351页