Java 反射机制是 Java 语言的一个重要特性。在学习 Java 反射机制前,大家应该先了解两个概念,编译期和运行期。
编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
Java 反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法。此外,在 ORM 中间件的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。
参考地址: http://c.biancheng.net/view/6907.html
参考: https://blog.csdn.net/Hellowenpan/article/details/107560498
//第一种
Class<?> clazz1 = Class.forName("com.ramelon.reflect.entity.Child");
//第二种
Class<? extends Child> clazz2 = new Child().getClass();
//第三种
Class<?> clazz3 = Child.class;
Class<?> superclass = clazz1.getSuperclass();
Class<?>[] interramelonces = clazz1.getInterramelonces();
//取得一个类的全类名(包名 + 类名)
clazz1.getName()
//取得类的简单名称
clazz1.getSimpleName();
Class<?> clazz1 = Class.forName("xxxx");
Constructor<?>[] constructors = clazz1.getConstructors();
Constructor<?>[] constructors1 = clazz1.getDeclaredConstructors();
//取得只有一个参数且参数类型为String的构造方法
Constructor<?> constructor1 = clazz1.getDeclaredConstructor(String.class);
System.out.println(constructor1);
Object instance = clazz1.newInstance();
//取得无参构造
Constructor<?> constructor2 = clazz1.getConstructor();
//通过无参构造创建一个对象
Object child1 = constructor2.newInstance();
//取得指定参数的构造方法对象
Constructor<?> constructor3 = clazz1.getConstructor(String.class, int.class);
//通过构造方法对象创建一个对象
constructor3.newInstance("wenpan",21);
Field[] declaredFields = clazz1.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
//属性名称
String fieldName = declaredFields[i].getName();
//属性的类型
String fieldType = declaredFields[i].getType().getName();
//属性修饰符
String fieldModifier = Modifier.toString(declaredFields[i].getModifiers());
System.out.println(fieldModifier + " " + fieldType + " " + fieldName + ";");
}
Field[] fields = clazz1.getFields();
for (int i = 0; i < fields.length; i++) {
//属性名称
String fieldName = fields[i].getName();
//属性的类型
String fieldType = fields[i].getType().getName();
//属性修饰符
String fieldModifier = Modifier.toString(fields[i].getModifiers());
System.out.println(fieldModifier + " " + fieldType + " " + fieldName + ";");
}
//通过属性名取得属性
Field field = clazz1.getDeclaredField("name");
//访问私有属性需要设置Accessible为true才可以更改或读取值(get 或 set)
field.setAccessible(true);
//取得instance对象里面的属性值
System.out.println("更改前的name值:" + field.get(instance));
//更改instance对象里的name属性值
field.set(instance,"文攀啊");
System.out.println("更改后的name属性值:" + field.get(instance));
通过属性名获取属性: Field field = clazz1.getDeclaredField("name");
返回的是属性对象: Field
Method[] methods = clazz1.getMethods();
Method[] methods = clazz1.getMethods();
//输出取得的方法
for (int i = 0; i < methods.length; i++) {
StringBuffer buffer = new StringBuffer();
//方法修饰符
String modifier = Modifier.toString(methods[i].getModifiers());
//返回值类型
String returnType = methods[i].getReturnType().getSimpleName();
//方法名
String name = methods[i].getName();
//方法参数类型
Class<?>[] parameterTypes = methods[i].getParameterTypes();
buffer.append(modifier).append(" ").append(returnType).append(" ").
append(name).append("(");
for (int j = 0; j < parameterTypes.length; j++) {
buffer.append(parameterTypes[j].getSimpleName()).append(" arg").append(j);
if(j < parameterTypes.length - 1){
buffer.append(",");
}
}
buffer.append(")");
//方法抛出的异常信息
Class<?>[] exceptionTypes = methods[i].getExceptionTypes();
if(exceptionTypes.length > 0){
buffer.append(" throws");
}
for (int k = 0; k < exceptionTypes.length; k++) {
buffer.append(exceptionTypes[k].getSimpleName());
if(k < exceptionTypes.length -1){
buffer.append(",");
}
}
buffer.append("{ }");
System.out.println(buffer);
}
Method[] declaredMethods = clazz1.getDeclaredMethods();
要调用某个对象的方法,首先这个对象得存在,所以可以通过反射创建一个对象
public static void main(String[] args) throws Exception {
//使用反射将Child类的Class对象加载进来
Class<?> clazz1 = Class.forName("com.ramelon.reflect.entity.Child");
//创建一个实例对象(使用反射调用方法必须要有实例对象)
Object instance = clazz1.newInstance();
//通过方法名称和指定的参数类型获取指定方法
Method method = clazz1.getDeclaredMethod("setName", String.class);
//调用Method对象的invoke方法执行instance对象的方法
method.invoke(instance,"文攀啊");
//通过方法名称和指定的参数类型获取指定方法
Method getNameMethod = clazz1.getMethod("getName");
//调用Method对象的invoke方法执行方法
String name = (String)getNameMethod.invoke(instance);
//输出执行方法返回的结果
System.out.println(name);
}
通过方法名和方法参数类型取得对象的方法:Method method = clazz1.getDeclaredMethod(“setName”, String.class);
public static void main(String[] args) throws Exception{
User user = new User();
// 取得类上的所有注解
Annotation[] annotations = user.getClass().getAnnotations();
// 获取类上指定类型的注解
MyAnnotation annotation = user.getClass().getAnnotation(MyAnnotation.class);
// 获取类的某个属性上的所有注解
Annotation[] allAnnotations = user.getClass().getDeclaredField("name").getAnnotations();
// 获取类的某个属性上指定类型的注解
MyAnnotation annotation1 = user.getClass().getDeclaredField("name").getAnnotation(MyAnnotation.class);
// 获取注解的属性
String value = annotation1.value();
String pattern = annotation1.pattern();
}
**原理:**首先通过反射取得该List集合的add()方法,然后使用反射调用该方法向list集合里面添加一个String类型元素
//创建一个int类型的集合
ArrayList<Integer> list = new ArrayList<Integer>();
//取得集合的添加方法
Method addMethod = list.getClass().getMethod("add", Object.class);
//执行集合的add方法,向集合中添加一个String类型元素
addMethod.invoke(list, "wenpan");
System.out.println("取得元素=========================>" + list.get(0));
**原理:**其实就是通过反射中的 Array.get()
和 Array.set()
来读取和修改数组中的元素值。
int temp[] = {1,2,3,4,5};
System.out.println("数组第一个元素:" + Array.get(temp,0));
Array.set(temp,0,100);
System.out.println("修改之后数组第一个元素为:" + Array.get(temp,0));
扩展方法:
int temp[] = {1,2,3,4,5};
//取得数组的类型,该方法为动态扩展数组大小做铺垫
Class<?> componentType = temp.getClass().getComponentType();
System.out.println("数组类型:" + componentType.getName());
System.out.println("数组长度:" + Array.getLength(temp));
**原理:**其本质就是通过反射得到原数组的类型,然后通过Array.newInstance()方法根据数组类型创造出一个指定长度的新数组,最后使用System.arraycopy()方法将原数组的值拷贝到新数组中
public static Object arrayInc(Object obj, int length) {
//取得传入数组的类型,以便于创造出同类型的数组
Class<?> componentType = obj.getClass().getComponentType();
//根据传入的数组类型创建出新的指定长度的数组实例
Object newArr = Array.newInstance(componentType, length);
//原有的数组长度
int originArrLen = Array.getLength(obj);
//将原有的数组数据拷贝到新的数组中去
System.arraycopy(obj,0,newArr,0,originArrLen);
//返回修改大小后的数组
return newArr;
}
class ramelonctory {
/**
* 通过传入的全类名返回该类的对象
* 但是有一点仍然很麻烦,就是需要知道完整的包名和类名,这里可以使用properties配置文件来完成。
* java读取配置文件可实现完全解耦
* @param className
* @return
*/
public static Object getInstance(String className){
Object instance = null;
try {
//通过反射创建对象实例
instance = Class.forName(className).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}
public static void main(String[] args) {
//反射工厂
Apple apple = (Apple)ramelonctory.getInstance("com.ramelon.reflect.Apple");
apple.method();
Banana banana = (Banana)ramelonctory.getInstance("com.ramelon.reflect.Banana");
banana.method();
}