文档章节

java反射机制

不最醉不龟归
 不最醉不龟归
发布于 2016/11/17 17:23
字数 3107
阅读 12
收藏 0
  1. 类加载器的loadClass()方法,如果父类加载器为Null,则使用根类加载器
  2. 调用findClass(String)方法查找该类

我们可以看到前面两步是实现父类的一些逻辑,其实这里两步实现了父类委托和缓冲机制策略,而我们只需要重新findClass(String)方法来实现我们自己的逻辑即可,这样使自定义类加载器就简单多了

四、java反射机制

 前面说了类的加载器,下面开始真正学习java反射机制,java反射机制可以时我们在运行时刻获取类的信息,如:类的成员变量类型,值,方法的信息及调用方法,获取泛型类型,获取注解等等。

java反射的相关api都在java.lang.reflect包下:学习api最好的方法还是看官网文档,因为官方文档最权威。下面我们通过一个测试类来学习反射的最常用的知识。

// 通过Class的静态方法forName加载类,该方法会初始化类
Class clazz = Class.forName("Common");
// 通过反射生成该类的实例,调用public的无参构造方法,反射生成类的实例,该类必须得有一个public的无参方法
Object newInstance = clazz.newInstance();
  • 获取类的构造方法
public static void testConstructor(Class clazz){
        System.out.println("-----------构造方法测试-----------");
        // 获取所以的构造方法
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for(int i=0;i<declaredConstructors.length;i++){
            int index = i+1; // 因为i从0开始
            String str = "第"+index+"个构造方法权限修饰符为";
            if(declaredConstructors[i].getModifiers() == 1){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
                str+="public";
            }
            if(declaredConstructors[i].getModifiers() == 2){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
                str+="private";
            }
            if(declaredConstructors[i].getModifiers() == 4){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
                str+="protected";
            }
            str+="名称为:"+declaredConstructors[i].getName();
            System.out.println(str);
        }
    }
  • 获取类方法的相关信息
    ```java
    /**
    • 这个方法通过反射获取了方法的相关信息,可以看到我们得到了方法
    • 的全部信息
    • 这里字符串拼接比较多,由于是测试,所以就没用StringBuffer拼接
    • @param clazz
      */
      public static void testCommonMethodInfo(Class clazz){
      System.out.println("-----------普通方法测试-----------");
      Method[] methods = clazz.getMethods();
      System.out.println(methods.length);
      for(int i=0;i<methods.length;i++){
      int dexI = i+1;
      String str = "第"+dexI+"个方法形式为:";

      // 获取方法权限修饰符
      int modifiers = methods[i].getModifiers();
      if(modifiers == 1){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
          str+="public";
      }
      if(modifiers == 2){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
          str+="private";
      }
      if(modifiers == 4){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
          str+="protected";
      }
      
      String returnType = methods[i].getReturnType().getSimpleName(); // 获取方法返回类型
      str+=" "+returnType+" "; 
      
      String name = methods[i].getName(); // 获取方法名称
      str+= name;
      str+="(";
      
      // 获取方法参数的类型
      Class[] parameterTypes = methods[i].getParameterTypes();
      for(int j=0;i<parameterTypes.length;i++){
          str+=parameterTypes[j]+" ";
      }
      str+=")";
      System.out.println(str);

      }
      }

```

  • 调用类的方法
/**
     * 通过反射调用方法
     * @param clazz
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     */
    public static void testMethodInvoke(Class clazz,Object newInstance) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        System.out.println("-----------测试方法的调用-----------");
        /**
         * 由于我们知道类中有这种类型的方法,所以我们直接指定要获取的方法类型
         * 如果不知道我们要调用的 方法的类型,我们可以获取方法的参数类型等等所有信息
         * 然后匹配到我们需要调用的方法,这里做个说明,我们要调用的方法名是知道的
         */
        Method sum = clazz.getMethod("sum",int.class,int.class);
        System.out.println(sum);
        sum.invoke(newInstance, 1,1);
        Method setS = clazz.getMethod("setS",String.class);
        System.out.println(setS);
        setS.invoke(newInstance, "赋值啦");
    }
  • 测试类的属性Field
/**
     * 测试类的Field
     * @param clazz
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     */
    public static void testField(Class clazz,Object obj) throws IllegalArgumentException{
        System.out.println("-----------测试类的Field-----------");
        // 获取所以的Field,包括private修饰的,但不能直接获取和直接改变private修饰的值
        Field[] fields = clazz.getDeclaredFields();
        for(int i=0;i<fields.length;i++){
            int dexI = i+1;
            System.out.print("第"+dexI+"个name:"+fields[i].getName()+"  ");
            Class type = fields[i].getType();
            String typeStr = type.getName();
            try{
                if(typeStr.equals("int")){
                    System.out.println("value:"+fields[i].getInt(obj));
                }else if(typeStr.equals("java.lang.String")){
                    // 字符串形式通过get(Object obj)方法取得,如果该Field的权限为private,则 获取值的时候会报java.lang.IllegalAccessException
                    System.out.println("value:"+fields[i].get(obj));
                }
            }catch(IllegalAccessException ex){
                System.out.println("不能获取private修饰的属性值");
            }
        }
    }
  • 测试注解
/**
     * 测试注解(类上的注解),属性方法上的注解分别通过
     * Field对象和Method对象的getAnnotations()方法可以得到
     * 和这里是一样的
     * @param clazz
     */
    public static void testAnnotation(Class clazz){
        System.out.println("-----------测试注解-----------");
        Annotation[] annotations = clazz.getAnnotations();
        for(int i=0;i<annotations.length;i++){
            System.out.println(annotations[i]);
        }
    }
  • 测试泛型
/**
     * 泛型测试
     * @throws NoSuchFieldException
     */
    private static void genericTest() throws NoSuchFieldException {
        System.out.println("-----------获泛型测试-----------");
        Class<ReflectTest> clazz  = ReflectTest.class;
        Field f = clazz.getDeclaredField("map");
        // 直接使用getType()只对普通类型有效,并不能得到有泛型的类型
        
        Class<?> type = f.getType(); 
        // 下面的代码可以看到只输出了java.util.Map
        System.out.println(" map 的类型为:"+type);
        // 获取Field实例f的泛型类型
        Type genericType = f.getGenericType();
        // 如果genericType是ParameterizedType对象
        if(genericType instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            // 获取原始类型
            Type rawType = parameterizedType.getRawType();
            System.out.println("原始类型是:"+rawType);
            // 取得泛型类型的泛型参数
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for(int i=0;i<actualTypeArguments.length;i++){
                System.out.println("第"+i+"个泛型类型为:"+actualTypeArguments[i]);
            }
        }else{
            System.out.println("泛型类型获取出错");
        }
    }
  • 获取泛型的实际类型
/**
     * 获取泛型T的实际类型
     */
    public static void getTType(){
        System.out.println("-----------获取泛型T的实际类型-----------");
        Dog dog = new DogImpl();
        // 注意,下面这种写法不能获取到T的实际类型,因为范式要在编译的时候就指定类型,在运行时候指定类型是获取不到真实类型的
//      Dog<Cat> dog = new Dog<Cat>();
    }

修饰符常量对应的值:

这里写图片描述

 由于注释说了很清楚了,所以这里就不过多介绍了,以上这些方法都是参考了api提供的一些方法自己写的一些测试,其实都只是一个简单方法的使用,但这些方法是反射中最基本最常用的方法,api方法很多,所以我们学习api的时候最好时刻查询文档,查看文档是个好习惯。

 总结,java反射机制是java的一个非常重要的一个知识点,其实向spring,struts等等一些知名的框架没有一个没有使用反射,所以学好java反射是提升我们技术必不可少的,我们应该掌握java反射机制。这篇文章与其说是java反射机制的讲解,其实是我自己学习java反射的学习总结,因为学习java也好久了,回顾总结一下所写的知识点,所以文章内容有说错的部分,欢迎指出。

测试代码:http://download.csdn.net/detail/ydxlt/9310157

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import javax.xml.ws.soap.Addressing;


/**
 * 测试反射
 * @author lt
 *
 */
public class ReflectTest {
	
	private Map<String,Integer> map;
	public static void main(String[] args) throws Exception {
		// 通过Class的静态方法forName加载类,该方法会初始化类
		Class clazz = Class.forName("Common");
		// 通过反射生成该类的实例,调用public的无参构造方法,反射生成类的实例,该类必须得有一个public的无参方法
		Object newInstance = clazz.newInstance();
		
		testConstructor(clazz);
		testCommonMethodInfo(clazz);
		testMethodInvoke(clazz,newInstance);
		testField(clazz,newInstance);
		testAnnotation(clazz);
		genericTest();
		getTType();
	}
	
	public static void testConstructor(Class clazz){
		System.out.println("-----------构造方法测试-----------");
		// 获取所以的构造方法
		Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
		for(int i=0;i<declaredConstructors.length;i++){
			int index = i+1; // 因为i从0开始
			String str = "第"+index+"个构造方法权限修饰符为";
			if(declaredConstructors[i].getModifiers() == 1){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
				str+="public";
			}
			if(declaredConstructors[i].getModifiers() == 2){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
				str+="private";
			}
			if(declaredConstructors[i].getModifiers() == 4){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
				str+="protected";
			}
			str+="名称为:"+declaredConstructors[i].getName();
			System.out.println(str);
		}
	}
	
	/**
	 * 通过反射调用方法
	 * @param clazz
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public static void testMethodInvoke(Class clazz,Object newInstance) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		System.out.println("-----------测试方法的调用-----------");
		/**
		 * 由于我们知道类中有这种类型的方法,所以我们直接指定要获取的方法类型
		 * 如果不知道我们要调用的 方法的类型,我们可以获取方法的参数类型等等所有信息
		 * 然后匹配到我们需要调用的方法,这里做个说明,我们要调用的方法名是知道的
		 */
		Method sum = clazz.getMethod("sum",int.class,int.class);
		System.out.println(sum);
		sum.invoke(newInstance, 1,1);
		Method setS = clazz.getMethod("setS",String.class);
		System.out.println(setS);
		setS.invoke(newInstance, "赋值啦");
	}
	
	
	/**
	 * 这个方法通过反射获取了方法的相关信息,可以看到我们得到了方法
	 * 的全部信息
	 * 这里字符串拼接比较多,由于是测试,所以就没用StringBuffer拼接
	 * @param clazz
	 */
	public static void testCommonMethodInfo(Class clazz){
		System.out.println("-----------普通方法测试-----------");
		Method[] methods = clazz.getMethods();
		System.out.println(methods.length);
		for(int i=0;i<methods.length;i++){
			int dexI = i+1;
			String str = "第"+dexI+"个方法形式为:";
			
			// 获取方法权限修饰符
			int modifiers = methods[i].getModifiers();
			if(modifiers == 1){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
				str+="public";
			}
			if(modifiers == 2){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
				str+="private";
			}
			if(modifiers == 4){ // 这里的常量值可以查看api文档,博客下面也会帖子各种修饰符对应的数字
				str+="protected";
			}
			
			String returnType = methods[i].getReturnType().getSimpleName(); // 获取方法返回类型
			str+=" "+returnType+" "; 
			
			String name = methods[i].getName(); // 获取方法名称
			str+= name;
			str+="(";
			
			// 获取方法参数的类型
			Class[] parameterTypes = methods[i].getParameterTypes();
			for(int j=0;i<parameterTypes.length;i++){
				str+=parameterTypes[j]+" ";
			}
			str+=")";
			System.out.println(str);
		}
	}
	
	/**
	 * 测试类的Field
	 * @param clazz
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	public static void testField(Class clazz,Object obj) throws IllegalArgumentException{
		System.out.println("-----------测试类的Field-----------");
		// 获取所以的Field,包括private修饰的,但不能直接获取和直接改变private修饰的值
		Field[] fields = clazz.getDeclaredFields();
		for(int i=0;i<fields.length;i++){
			int dexI = i+1;
			System.out.print("第"+dexI+"个name:"+fields[i].getName()+"  ");
			Class type = fields[i].getType();
			String typeStr = type.getName();
			try{
				if(typeStr.equals("int")){
					System.out.println("value:"+fields[i].getInt(obj));
				}else if(typeStr.equals("java.lang.String")){
					// 字符串形式通过get(Object obj)方法取得,如果该Field的权限为private,则 获取值的时候会报java.lang.IllegalAccessException
					System.out.println("value:"+fields[i].get(obj));
				}
			}catch(IllegalAccessException ex){
				System.out.println("不能获取private修饰的属性值");
			}
		}
	}
	
	/**
	 * 测试注解(类上的注解),属性方法上的注解分别通过
	 * Field对象和Method对象的getAnnotations()方法可以得到
	 * 和这里是一样的
	 * @param clazz
	 */
	public static void testAnnotation(Class clazz){
		System.out.println("-----------测试注解-----------");
		Annotation[] annotations = clazz.getAnnotations();
		for(int i=0;i<annotations.length;i++){
			System.out.println(annotations[i]);
		}
	}
	
	/**
	 * 获取泛型T的实际类型
	 */
	public static void getTType(){
		System.out.println("-----------获取泛型T的实际类型-----------");
		Dog dog = new DogImpl();
		// 注意,下面这种写法不能获取到T的实际类型,因为范式要在编译的时候就指定类型,在运行时候指定类型是获取不到真实类型的
//		Dog<Cat> dog = new Dog<Cat>();
	}
	
	/**
	 * 泛型测试
	 * @throws NoSuchFieldException
	 */
	private static void genericTest() throws NoSuchFieldException {
		System.out.println("-----------获泛型测试-----------");
		Class<ReflectTest> clazz  = ReflectTest.class;
		Field f = clazz.getDeclaredField("map");
		// 直接使用getType()只对普通类型有效,并不能得到有泛型的类型
		
		Class<?> type = f.getType(); 
		// 下面的代码可以看到只输出了java.util.Map
		System.out.println(" map 的类型为:"+type);
		// 获取Field实例f的泛型类型
		Type genericType = f.getGenericType();
		// 如果genericType是ParameterizedType对象
		if(genericType instanceof ParameterizedType){
			ParameterizedType parameterizedType = (ParameterizedType) genericType;
			// 获取原始类型
			Type rawType = parameterizedType.getRawType();
			System.out.println("原始类型是:"+rawType);
			// 取得泛型类型的泛型参数
			Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
			for(int i=0;i<actualTypeArguments.length;i++){
				System.out.println("第"+i+"个泛型类型为:"+actualTypeArguments[i]);
			}
		}else{
			System.out.println("泛型类型获取出错");
		}
	}
}

@SuppressWarnings(value="unchecked")
@Deprecated
@Addressing
class Common{
	public int a = 3;
	private String s = "dfdff";
	protected int b = 4;
	int c = 5;
	
	public Common(){
		System.out.println("public Constructor invoked");
	}
	
	private Common(String s){
		System.out.println("private Constructor invoked");
	}
	
	protected Common(int i){
		System.out.println("protected Constructor invoked");
	}
	
	
	public void method1(){
		System.out.println("method1 invoked");
	}
	
	public void sum(int x,int y){
		int z = x+y;
		System.out.println("sum="+z);
	}
	
	public void setS(String s){
		System.out.println("s 的之前的值为:"+this.s);
		this.s = s;
		System.out.println("s 赋值之后的值为:"+this.s);
	}
}

class Dog<T>{
	public Class<T> clazz;
	public Dog(){
		getTType();
	}

	private void getTType() {
		// getGenericSuperclass获得带有泛型的父类
		ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass(); 
		clazz = (Class) parameterizedType.getActualTypeArguments()[0];
		System.out.println("clazz的实际类型为:"+clazz.getSimpleName());
	}
}

class Cat{}

class DogImpl extends Dog<Cat>{}

 

本文转载自:http://www.cnblogs.com/ydxlt/p/5031755.html

共有 人打赏支持
不最醉不龟归
粉丝 17
博文 425
码字总数 446167
作品 0
深圳
程序员
私信 提问

暂无文章

node.js学习笔记之koa框架和简单爬虫练习

Koa -- 基于 Node.js 平台的下一代 web 开发框架 koa是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,可以免除重复繁琐的回调...

前端小攻略
32分钟前
3
0
JavaScript中的继承及实现代码

JS虽然不像是JAVA那种强类型的语言,但也有着与JAVA类型的继承属性,那么JS中的继承是如何实现的呢? 一、构造函数继承 在构造函数中,同样属于两个新创建的函数,也是不相等的 function Fn...

peakedness丶
54分钟前
3
0
记一次面试最常见的10个Redis"刁难"问题

导读:在程序员面试过程中Redis相关的知识是常被问到的话题。作为一名在互联网技术行业打击过成百上千名的资深技术面试官,本文作者总结了面试过程中经常问到的问题。十分值得一读。 Redis在...

小刀爱编程
今天
18
0
TiDB Lab 诞生记 | TiDB Hackathon 优秀项目分享

本文由红凤凰粉凤凰粉红凤凰队的成员主笔,他们的项目 TiDB Lab 在本届 TiDB Hackathon 2018 中获得了二等奖。TiDB Lab 为 TiDB 培训体系增加了一个可以动态观测 TiDB / TiKV / PD 细节的动画...

TiDB
今天
5
0
当区块链遇到零知识证明

本文由云+社区发表 当区块链遇到零知识证明 什么是零知识证明 零知识证明的官方定义是能够在不向验证者任何有用的信息的情况下,使验证者相信某个论断是正确的。这个定义有点抽象,下面笔者举...

腾讯云加社区
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部