java 反射机制详解

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反射类加载图,便于更好的理解


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值