基本概念
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。反射可以使我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码链接。反射允许我们在编写和执行时,使我们的代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。
reflection 的工作机制
程序运行时,java系统会一直对所有对象进行所谓的运行时类型识别,这项信息记录了每个对象所属的类。通过Class类可以访问这些信息。
构造Class对象的三种方式
1 Class.forName()
Class clazz = Class.forName("java.lang.String")
Tips:
我们还记得JDBC加载数据库驱动时要使用:Class.forName(“com.mysql.jdbc.Driver”)
我们知道Class.forName( )静态方法的目的是为了动态加载类,但是一般来说,一个类forName只是要求JVM查找并加载指定的类,最终的目的是要newInstance()去把它实例化对象的,但是这里并没有,那它的作用是什么?
其实在JVM加载指定类的过程中,如果类中有静态初始化内容的话,JVM就会执行该部分代码,与此同时JDBC规范要求任何一个driver类必须向DriverManger类去注册自己,也就是说此例中加载的com.mysql.jdbcDriver中一定是有一段代码类似。
static {
try {
DriverManager.registerDriver(new ***Driver());
} catch (SQLException e) {
System.out.println(e.toString());
}
}
所以在这里只需要forName就行了并不需要newInstance,因为我们真正需要的其实就是上述向DriverManager注册自己的过程。破案。
2.类.class
Class clazz = String.Class
3.Object.getClass()
String str = "a";
Class clazz = str.getClass()
Tips
构造Class对象时的常见错误
ClaaNotFoundException 指定的类不存在
java.lang.IllegalAccessException 没有访问权限
Java反射中主要的类和方法
获取构造函数信息
Constructor getConstructor(Class[] params) 获得使用特殊的参数类型的公共构造函数
Constructor[] getConstructors() 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params)获得使用特定参数类型的构造函数(与接入级别无关)
Constructor[] getDeclaredConstructors() 获得类的所有构造函数(与接入级别无关)
获取字段
Field getField(String name) – 获得命名的公共字段
Field[] getFields() – 获得类的所有公共字段
Field getDeclaredField(String name) – 获得类声明的命名的字段
Field[] getDeclaredFields() – 获得类声明的所有字段
获取方法
Method getMethod(String name, Class[] params) – 使用特定的参数类型,获得命名的公共方法
Method[] getMethods() – 获得类的所有公共方法
Method getDeclaredMethod(String name, Class[] params) – 使用特写的参数类型,获得类声明的命名的方法
Method[] getDeclaredMethods() – 获得类声明的所有方法
Reflection的使用
获取类的基本信息
Constructor对象的常用方法
String getName() 获取构造方法名称
int getModifiers() 获取构造方法的修饰符(获取之后可以使用Modifier.toString()来打印具体的修饰符)
Class[] getParameterTypes() 获取参数类型
Method对象的常用方法
String getName() 获取方法的名称
int getModifiers() 获取方法的修饰符
Class[] getParameterTypes() 获取参数类型
boolean isVarArgs 方法是否带有可变参数
Class getReturnType 获取方法的返回值类型
Filed对象的常用方法
String getName()
Class<?> getType()
Object get(Object obj) Returns the value of the field represented by this {@code Field}, on the specified object. The value is automatically wrapped in an object if it has a primitive type.
Class对象常用方法
public Class<?>[] getInterfaces() 获取接口的名称
public Class<? super T> getSuperclass
pulibc Package getPackage() 获取类对象的包对象
public native boolean isInterface() 是否为接口
public String getName() 获取类名
public String getSimpleName() 获取类的简称
Modifier对象的常用方法
String toString(): Return a string describing the access modifier flags in the specified modifier;
toString方法的实现;
public static String toString(int mod) {
StringBuilder sb = new StringBuilder();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
if ((mod & PROTECTED) != 0) sb.append("protected ");
if ((mod & PRIVATE) != 0) sb.append("private ");
/* Canonical order */
if ((mod & ABSTRACT) != 0) sb.append("abstract ");
if ((mod & STATIC) != 0) sb.append("static ");
if ((mod & FINAL) != 0) sb.append("final ");
if ((mod & TRANSIENT) != 0) sb.append("transient ");
if ((mod & VOLATILE) != 0) sb.append("volatile ");
if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized ");
if ((mod & NATIVE) != 0) sb.append("native ");
if ((mod & STRICT) != 0) sb.append("strictfp ");
if ((mod & INTERFACE) != 0) sb.append("interface ");
if ((len = sb.length()) > 0) /* trim trailing space */
return sb.toString().substring(0, len-1);
return "";
}
构造对象
Class<Test> c = Test.class();
//构造方式1: 使用Class类中的newInstance方法
Test t1 = c.newInstance();//当类没有无参构造方法时,使用此方法构造对象失败
//构造方式2: 使用Constructor对象的newInstance方法
Constructor con = c.getConstructor(String.class)
Test t = con.newInstance("abc")
对象方法的反射调用
Method中的invoke方法
Invokes the underlying method represented by this {@code Method}object, on the specified object with the specified parameters.
Individual parameters are automatically unwrapped to match
primitive formal parameters, and both primitive and reference
parameters are subject to method invocation conversions as
necessary.
Class studentClass = Student.class;
try {
Constructor con = studentClass.getConstructor(String.class);
Student jack = (Student) con.newInstance("jack");
Method hello = studentClass.getMethod("hello");
Method hi = studentClass.getMethod("hi");
//使用反射静态类中的调用hello
hello.invoke(jack);
//使用反射,调用jack中的hello
hi.invoke(null);
}catch (NoSuchMethodException e){
e.printStackTrace();
}catch (InstantiationException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}catch (InvocationTargetException e){//当被调用的方法的内部抛出了异常而没有被捕获时,将由此异常接收。
e.printStackTrace();
}
使用反射获取和修改成员变量
Class studentClass = Student.class;
try {
Constructor con = studentClass.getConstructor(String.class);
Student student = (Student) con.newInstance("tom");
Field filedName = studentClass.getField("name");
Object tmpName1 = filedName.get(student);
System.out.println(tmpName1.toString());//tom
filedName.set(student,"sam");
Object tmpName2 = filedName.get(student);
System.out.println(tmpName2.toString());//sam
}catch (NoSuchMethodException e){
e.printStackTrace();
}catch (InstantiationException e){
e.printStackTrace();;
}catch (IllegalAccessException e){
e.printStackTrace();
}catch (InvocationTargetException e){
e.printStackTrace();
}catch (NoSuchFieldException e){
e.printStackTrace();
}