java 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
java 反射类加载的生命周期:
在程序执行中JVM通过装载,链接,初始化这3个步骤完成。
类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。
但是同一个类只会被类装载器装载以前
链接:就是把二进制数据组装为可以运行的状态。
链接分为:校验,准备,解析这3个阶段
校验:一般用来确认此二进制文件是否适合当前的JVM(版本),
准备:就是为静态成员分配内存空间,。并设置默认值
解析:指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)
完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收,释放空间。
当没有任何引用指向Class对象时就会被卸载,结束类的生命周期
package com.bjhy.platform.criminal.search.report.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import com.bjhy.platform.criminal.search.core.annotation.ColumnConfig;
/**
* java反射
* @author wbw
*
*/
public class MyReflect {
/**
*获取一个领域对象的完整包名和类名
* @param className 领域对象
* @return 领域对象完整包名和类名
*/
public static String getClassName(Class<?> clzz){
return clzz.getName();
}
/**
* jvm运行时期获取指定实体类的属性,属性类型
* @param clzz 类名
* @return 类属性、属性类型
*/
public static String getClassField(Class<?> clzz){
Field[] fields = clzz.getFields();
StringBuffer sb = new StringBuffer();
for(Field field :fields){
//属性名称
sb.append(field.getName());
// 属性类型
sb.append(field.getType().getName());
sb.append(",");
}
String str = sb.substring(0, sb.length() - 1);
return str;
}
/**
* 获取指定实体类的父类
* @param clzz 指定的实体类
* @return 实体类的父类
*/
public static String getSuperClassName(Class<?> clzz){
return clzz.getSuperclass().getName();
}
/**
* 反射调用静态方法
* @param className 实体类的完整包名和类名
*/
public static void getStaticMethod(String className){
Class cls = null;
try {
cls = Class.forName(className);
Method sm = cls.getDeclaredMethod("hello", int.class,String.class);
sm.invoke(cls, 20,"xw");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 反射为实体类private的属性赋值
* @param className
*/
public static void setFieldValue(String className){
Class cls = null;
try {
cls = Class.forName(className);
Object user = cls.newInstance();
Field field = cls.getDeclaredField("name");
field.setAccessible(true);//设置字段为允许访问
field.set(user, "xw");
System.out.println(field.get(user));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* 获取实体类的类加载器
* java 有三种类加载器
* 1.Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2.Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3.AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
* @param clzz
* @return
*/
public static String getClassLoader(Class<?> clzz){
return clzz.getClassLoader().getClass().getName();
}
/**
* 工厂内部类,一般的工厂模式都是通过判断传入的对象类型而不做不同的操作,但是在增加多个子类的时候,就需要频繁的修改工厂类,
* 但是如果使用反射机制将会在不改变工厂类的情况下操作子类
* @author wbw
*
*/
class Factory{
/**
* 一般情况下的工厂模式
* @param className
* @return
*/
@SuppressWarnings("unused")
public User demo1(String className){
User user = null;
if(className.equals("normal")){
return user = new User();
}else if(className.equals("ammin")){
return user = new ManageUser();
}
return null;
}
/**
* 反射工厂模式
* @param className
* @return
*/
public User demo(String className) throws Exception{
return (User) Class.forName(className).newInstance();
}
}
/**
* 根据实体类名获取属性名称和使用自定义注解设置的属性中文名称
* @param clzz 实体类名
* @return List<Map<String,Object>>
*/
public static List<LinkedHashMap<String,Object>> initAnnoFieldDic(Class<?> clzz){
//使用List<LinkedHashMap<String,Object>>用于存储字段和中文值的集合
//LinkedHashMap<String,Object> key为类.属性,value为属性的中文名称
List<LinkedHashMap<String,Object>> fieldList = new ArrayList<>();
LinkedHashMap<String,Object> valueMap = new LinkedHashMap<>();
//获取对象中所有的Fields
Field[] fields = clzz.getDeclaredFields();
//循环实体类字段集合,获取标注自定义注解@ColumnConfig的属性
for (Field field : fields) {
if(field.isAnnotationPresent(ColumnConfig.class)){
//获取字段名
String fieldNames = clzz.getSimpleName()+"."+field.getName();
//获取字段注解
ColumnConfig columnConfig = field.getAnnotation(ColumnConfig.class);
//判断是否已经获取过该code的字典数据 避免重复获取
if(valueMap.get(columnConfig.description())==null){
valueMap.put(fieldNames, columnConfig.description());
}
}
}
fieldList.add(valueMap);
return fieldList;
}
}
Class文件只是一种静态格式的二进制流,它只有被虚拟机加载进内存解析之后才会生成真正的运行时的结构,因此,搞清楚类加载机制不但有助于我们加深理解Class文件中各个字段的含义,同时也有利于我们更深入的了解JAVA。
最后附上java反射类加载图,便于更好的理解