1.这一章主要讨论了运行时类型信息的获得与使用。
(1)Class对象
“在Java中,所有的类型转换都是在运行时进行正确性检查的。”“每个类都有一个Class对象(被保存在一个同名的.class文件中)”,因此可以通过Class类(所有Class对象都属于这个类)的一些方法来动态获得所需要的类的Class对象,如Class.forName()方法通过字符串形式的类名获得其class对象引用,进而获得该类的信息,或者可以通过newInstance()方法实现对象的构建;而这里对class对象的获得,使得该类被加载,同时static语句被执行,而单纯对类static final值(编译期常量)的引用不会引起static初始化,也可以说间接的说明了构造器隐式地是静态的。
类字面常量:另一种生成class对象引用,是 类名.class 的形式,这种方式不会自动地初始化该class对象。“Class引用总是指向某个Class对象,它可以制造类的实例,并包含可作用于这些实例的所有方法代码”,为了更充分的利用Class,可以通过泛化的Class引用,使用“?”通配符和extends、super等关键字来无限或有限制的使用class类引用。
(2)类型检查
关键字instanceof,形如 x instanceof Dog 它返回一个布尔值,检测该对象是不是某个特定类型;另一种方式是Class.isInstance()可以动态的检测对象类型。这里需要注意的是使用instanceof 或者 isInstance()方法对对象进行检测时,保持了类型的概念,即检查的是“是这个类或者是这个类的派生类”,而通过使用“==”与获取的class对象引用对比则只是进行确切类型的比较。
反射
没有找到比较好的概念文字,但是这样理解还是可以的,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。这里有会产生两个问题:一是运行中动态的获得类型信息,RTTI也是可以做到的,但是这个是在编译时打开和检查.class文件的,而反射机制是在运行时获得类型信息(这个还是有些不明白,mark);另一个问题是既然是获得类或者对象的所有属性和方法,那么private等修饰隐藏的私有信息也是可以获得的了,这里需要有一个前提就是知道这个类的方法或者属性名(仍然是可以通过java反编译工具获得的,因此确实是可以的,但是并不建议如此)。
Class类和java.lang.reflect类库一起支持反射机制,包括了Field、Method、Constructor类。可以看一个书上的例子(我增加了属性获取):
package com.test.myjava;
/*
* @author w7849516230
*/
import java.lang.reflect.*;
import java.util.regex.*;
/* 功能:可以查询任意类的所有public权限的方法、属性(可以查看所有),
* 当有第二个参数时,可以作为包含指定字符串的方法或属性过滤
* 注意:在eclipse中使用时,需要包含完整的包名;如果在console执行,需要注意包名
*/
public class ShowClassInformation {
private static String usage =
"usage:\n" +
"ShowMethods qualified.class.name\n" +
"To Show all methods in class or:\n" +
"ShowMethods qualified.class.name word\n" +
"To Search for methods involving 'word'";
public String str = "public string";
private static Pattern p = Pattern.compile("\\w+\\.");
//表示过滤掉前面的命名修饰,如果用下面的可以看到完整的命名
//private static Pattern p = Pattern.compile("\\W+\\.");
public static void main(String[] args){
if(args.length < 1){
System.out.print(usage);
System.exit(0);
}
int lines = 0;
try{
Class<?> c = Class.forName(args[0]);
//使用下面的类字面常量则不用try catch语句
//Class<?> c = ShowClassInformation.class
Method[] methods = c.getMethods();
Constructor[] ctors = c.getConstructors();
Field[] fields = c.getFields();
/* 如果需要设置属性值使用setXXX方法
* 调用方法可以使用Invoke方法
*/
if(args.length == 1){
System.out.println(args[0]+" Methods:");
for(Method method : methods)
System.out.println(p.matcher(method.toString()).replaceAll(""));
System.out.println();
System.out.println(args[0]+" Constructors:");
for(Constructor ctor : ctors)
System.out.println(p.matcher(ctor.toString()).replaceAll(""));
System.out.println();
System.out.println(args[0]+" Fields:");
for(Field field : fields)
System.out.println(p.matcher(field.toString()).replaceAll(""));
System.out.println();
lines = methods.length + ctors.length + fields.length;
}else {
for(Method method : methods)
if(method.toString().indexOf(args[1]) != -1){
System.out.println(p.matcher(method.toString()).replaceAll(""));
lines++;
}
for(Constructor ctor : ctors)
if(ctor.toString().indexOf(args[1]) != -1){
System.out.println(p.matcher(ctor.toString()).replaceAll(""));
lines++;
}
for(Field field : fields)
if(field.toString().indexOf(args[1]) != -1){
System.out.println(p.matcher(field.toString()).replaceAll(""));
}
}
}catch(ClassNotFoundException e){
System.out.println("No such class:" + e);
}
}
}
输入参数为:java.lang.reflect.Method
输出为:java.lang.reflect.Method Methods:
public int hashCode()
public int getModifiers()
public transient Object invoke(Object,Object[]) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException
public boolean equals(Object)
public String getName()
public String toString()
public Annotation getAnnotation(Class)
public Annotation[] getDeclaredAnnotations()
public Class getDeclaringClass()
public Class[] getParameterTypes()
public Class getReturnType()
public TypeVariable[] getTypeParameters()
public boolean isSynthetic()
public String toGenericString()
public Object getDefaultValue()
public Class[] getExceptionTypes()
public Type[] getGenericExceptionTypes()
public Type[] getGenericParameterTypes()
public Type getGenericReturnType()
public Annotation[][] getParameterAnnotations()
public boolean isBridge()
public boolean isVarArgs()
public Annotation[] getAnnotations()
public boolean isAnnotationPresent(Class)
public boolean isAccessible()
public static void setAccessible(AccessibleObject[],boolean) throws SecurityException
public void setAccessible(boolean) throws SecurityException
public final native Class getClass()
public final void wait() throws InterruptedException
public final void wait(long,int) throws InterruptedException
public final native void wait(long) throws InterruptedException
public final native void notify()
public final native void notifyAll()
java.lang.reflect.Method Constructors:
java.lang.reflect.Method Fields:
public static final int PUBLIC
public static final int DECLARED
反射机制又为动态代理创造了条件,可以在运行时,根据反射机制获得的类型信息,调用被代理对象的属性方法。用到Interface InvocationHandler和类Proxy。