• java 反射解析


    本文主要针对java反射进行学习,以java.lang.reflect包中的接口和类进行学习和理解。文章目录如下:

    1. java反射概念
    2. java反射包接口详解
    3. java发射包中类详解
    4. java反射的应用例子

    一:java反射概念

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    java反射能起到的作用:

    • 在运行中分析类的能力,即动态获取类的基本情况;
    • 通过反射机制访问java对象的属性,方法,构造方法等;
    • 主要是为工具构造者提供的便利机制。

    二:java反射包中的接口

    1:AnnotatedElement
    java.lang.reflect.AnnotatedElement接口是所有程序元素(例如java.lang.Class、java.lang.reflect.Method、java.lang.reflect.Constructor等)的父接口。该接口主要是功能是是获取指定元素上所有类型注解、判断指定元素上是否有指定的注解。下边举例:本文定义一个MyTag注解,然后使用AnnotatedElement接口提供的isAnnotationPresent(Class<? extends Annotation> annotationClass)方法来判断指定方法上是否有该注解。

    定义公共实体类Person

    public class Person {
    	private String name;
    	private Integer age;
    	private String address;
    	public Person() {
    		// TODO Auto-generated constructor stub
    		setName("peter");
    	}
    	public Person(String name,Integer age,String address) {
    		this.address=address;
    		this.age=age;
    		this.name=name;
    		
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    	public String getAddress() {
    		return address;
    	}
    	public void setAddress(String address) {
    		this.address = address;
    	}
        @MyTag(name="peter")
    	public void getInfo()
    	{
    		System.out.println("I am student!");
    	}
    	@Override
    	public String toString() {
    		// TODO Auto-generated method stub
    		return "Person:"+name+";"+address+";"+age;
    	} 
    }
    
    

    自定义注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyTag {
         String name() default "test";
    }
    

    测试端

    public class AnnotatedElementTest {
    	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
    		// TODO Auto-generated method stub
            Class<?> person=Class.forName("com.csu.reflect.Person");
            boolean result=person.getMethod("getInfo", null).isAnnotationPresent( MyTag.class);      
            System.out.println(result);
    	}
    }
    

    运行结果:

    true
    
       通过上述例子发现,该接口为java反射获取类元素注解信息提供方法,通过该接口可以方便的获取类、方法、变量等上边的注解类型、名称等。
    

    2:InvocationHandler接口
    InvocationHandler接口主要为用户创建动态代理,即每一个代理都需要实现该接口,它只有一个方法:invoke(Object proxy, Method method, Object[] args)

    • proxy:在其上调用方法的代理实例;
    • method:对应于在代理实例上调用的接口方法的 Method 实例;
    • args:包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null
      下面创建一个动态代理,来说明该接口的使用过程:
      创建日志处理接口及实现
    public interface LogInfo {	
    	public void recordLog ();
    	public void getLength();
    
    }
    
    public class RealLogInfo implements LogInfo{
    
    	@Override
    	public void recordLog() {
    		// TODO Auto-generated method stub
    		System.out.println("记录系统运行的日志!");
    	}
    
    	@Override
    	public void getLength() {
    		// TODO Auto-generated method stub
    		System.out.println("获取日志长度!");
    	}
    
    }
    
    import java.lang.reflect.Method;
    public class DynamicLogProxy implements InvocationHandler{
        
    	private Object infoObject;
    	public DynamicLogProxy(Object object) {
    		// TODO Auto-generated constructor stub
    		this.infoObject=object;
    	}
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		// TODO Auto-generated method stub
    		//对象方法执行前调用一些方法,如spring的AOP
    		System.out.println("Before happen something!");
    		method.invoke(infoObject, args);
    		System.out.println("After happen something!");
    		return null;
    	}
    }
    

    测试端:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    public class InvocationHandlerDemo {
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		//真实对象
           LogInfo realInfo=new RealLogInfo();
           InvocationHandler handler=new DynamicLogProxy(realInfo);
           //通过Proxy的newProxyInstance方法来创建我们的代理对象
           LogInfo info=(LogInfo)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realInfo.getClass().getInterfaces(), handler);
           System.out.println(info.getClass().getName());
           info.recordLog();
           info.getLength();
    	}
    }
    

    运行结果:

    com.sun.proxy.$Proxy0
    Before happen something!
    记录系统运行的日志!
    After happen something!
    --------------------
    Before happen something!
    获取日志长度!
    After happen something!
    
       从运行结果中发现:info实例获取的类名称竟然是$Proxy0,是的这就是代理的独特之处,在jvm中对代理类进行了统一的命名管理。同时我们发现,通过代理我们可以在方法运行前后进行一些特殊逻辑处理,Spring AOP正式使用这种思想。
    

    三:java反射包中的类

    1. AccessibleObject:设置反射过程元素是否通过java安全检查,默认未false,它是类Field, Method, Constructor, ReflectPermission 父类;
    2. Array:主要用于动态的创建数字,当反射方法参数是数组时,可以使用Array来赋值。
    3. Field:主要获取类中字段信息
    4. Method:主要获取类中方法信息
    5. Constructor:获取类中所有构造器函数信息
    6. Modifier:获取类元素的权限访问标识
      通过上述类中方法的调用,通过反射动态的获取类中所有信息,下面通过三个实例来说明java反射包中类的使用方法。

    实例一:获取某个类的所有信息

    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    
    /**
     *通过反射方法获取类中详细信息
     */
    public class GetClassInfoByReflect {
    	/**
    	 * 获取类中所有构造函数
    	 */
    	@SuppressWarnings("rawtypes")
    	public static void getAllConstructors(Class clazz)
    	{
    		Constructor[] constructors=clazz.getConstructors();
    		for(Constructor c:constructors)
    		{
    			String name=c.getName();
    			System.out.print("  ");
    			String modifiers=Modifier.toString(clazz.getModifiers());
    			if(modifiers.length()>0)
    				System.out.print(modifiers+" ");
    			System.out.print(name+"(");
    			Class []paramTypes=c.getParameterTypes();
    			for(int i=0;i<paramTypes.length;i++)
    			{
    				if(i>0)
    					System.out.print(", ");
    				System.out.print(paramTypes[i].getName());
    			}
    			System.out.println(");");
    		}
    	}
    	/**
    	 * 获取类中所用方法
    	 * @param clazz
    	 */
    	@SuppressWarnings("rawtypes")
    	public static void getAllMethods(Class clazz)
    	{
    		Method[] methods=clazz.getMethods();
    		for(Method m:methods)
    		{
    			Class returntype=m.getReturnType();
    			String name=m.getName();
    			System.out.print("  ");
    			String modifiers=Modifier.toString(m.getModifiers());
    			if(modifiers.length()>0)
    				System.out.print(modifiers+" ");
    			System.out.print(returntype.getName()+" "+name+"(");
    			Class [] paramTypes=m.getParameterTypes();
    			for(int i=0;i<paramTypes.length;i++)
    			{
    				if(i>0)
    					System.out.print(",");
    				System.out.print(paramTypes[i].getName());
    			}
    			System.out.println(");");
    		}
    	}
        /**
         *  获取类中所有字段信息
         * @param clazz
         */
    	@SuppressWarnings("rawtypes")
    	public static void getAllFields(Class clazz)
    	{
    		Field [] fields=clazz.getDeclaredFields();
    		for(Field f:fields)
    		{
    			Class type=f.getType();
    			String name=f.getName();
    			System.out.print(" ");
    			String modifier=Modifier.toString(f.getModifiers());
    			if(modifier.length()>0)
    				System.out.print(modifier+" ");
    			System.out.println(type.getName()+" "+name+";");			
    		}
    	}
    }
    

    测试端实例:

    public class ReflectTest {
    	public static void main(String[] args) throws ClassNotFoundException {
    		// TODO Auto-generated method stub
            Class clazz=Class.forName("com.csu.reflect.Person");
            System.out.println("构造函数");
            GetClassInfoByReflect.getAllConstructors(clazz);
            System.out.println("类函数");
            GetClassInfoByReflect.getAllMethods(clazz);
            System.out.println("成员变量");
            GetClassInfoByReflect.getAllFields(clazz);
    	}
    }
    

    运行结果:

    构造函数
      public com.csu.reflect.Person();
      public com.csu.reflect.Person(java.lang.String, java.lang.Integer, java.lang.String);
    类函数
      public java.lang.String toString();
      public java.lang.String getAddress();
      public java.lang.String getName();
      public void setName(java.lang.String);
      public java.lang.Integer getAge();
      public void getInfo();
      public void setAge(java.lang.Integer);
      public void setAddress(java.lang.String);
      public final void wait(long,int);
      public final native void wait(long);
      public final void wait();
      public boolean equals(java.lang.Object);
      public native int hashCode();
      public final native java.lang.Class getClass();
      public final native void notify();
      public final native void notifyAll();
    成员变量
     private java.lang.String name;
     private java.lang.Integer age;
     private java.lang.String address;
    
    
    

    实例二:使用反射类Array实现所有数组拷贝

    public class GenericCopyArray {
    	/**
    	 * 通用数组拷贝方法
    	 * @param array
    	 * @param length
    	 * @return
    	 */
    	@SuppressWarnings("rawtypes")
    	public static Object copyArray(Object array,int newlength)
    	{
    		Class clazz=array.getClass();
    		if(!clazz.isArray())
    			return null;
    		Class type=clazz.getComponentType();
    		int length=Array.getLength(array);
    		Object newArray=Array.newInstance(type, newlength);
    		System.arraycopy(array, 0, newArray, 0, Math.min(length, newlength));
    		return newArray;
    	}
    }
    

    测试端实例:

    import java.util.Arrays;
    
    public class Arraytest {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		/**
    		 * GenericCopyArray.copyArray不仅可以对象数组,还可以扩展任意类型的数组
    		 */
         int[] a={1,2,3};
         a=(int[])GenericCopyArray.copyArray(a, 2);
         System.out.println(Arrays.toString(a));
         
         Person person1=new Person("zp", 28, "changsha");
         Person person2=new Person("wang", 29, "shandong");
         Person person3=new Person("liu", 29, "wuhan");
         Person [] persons={person1,person2};
         Person []personCopy=(Person[])GenericCopyArray.copyArray(persons,2);
         System.out.println("拷贝结果:"+Arrays.toString(personCopy));
         //改变拷贝数字的值
         personCopy[0]=person3;
         System.out.println("改变拷贝结果"+Arrays.toString(personCopy));
         System.out.println("原始结果未发生变化:"+Arrays.toString(persons));
    	}
    	}
    

    运行结果:

    [1, 2]
    拷贝结果:[Person:zp;address;28, Person:wang;address;29]
    改变拷贝结果[Person:liu;address;29, Person:wang;address;29]
    原始结果未发生变化:[Person:zp;address;28, Person:wang;address;29]
    

    通过运行实例发现:通过这种方式不仅能够拷贝对象数组,而且可以扩展为任意类型数组。

    实例三:通过Array给反射调用方法赋值

    public class Target {
    	
    	public void printValue(String[] values)
    	{
    		for(String value:values)
    		{
    			System.out.println(value);
    		}
    	}
    
    }
    

    测试端:

    public static void main(String[] args) {
    		// TODO Auto-generated method stub
           Class<Target> clazz =Target.class;
           try {
    		Object object=clazz.newInstance();
    		Method printValue=clazz.getMethod("printValue", String[].class);
    		Object array=Array.newInstance(String.class, 2);
    		Array.set(array, 0, "blue");
    		Array.set(array, 1, "green");
    		printValue.invoke(object, array);
    	} catch (Exception e) {
    		// TODO: handle exception
    		e.printStackTrace();
    	}
    	}
    

    运行结果:

    blue
    green
    

    引用块内容
    [1]java核心技术 卷I

  • 相关阅读:
    【网络公开课总结】砸蛋中奖效果
    【网络收集】如何修改vs tfs的登录名和密码 .
    在rdlc 中 显示成 yyyy年MM月dd日
    sql 将某一列的值拼接成字符串
    【网络收集】获取JavaScript 的时间使用内置的Date函数完成
    处理传递过来的拼接的值,中间用逗号相隔
    行列转换 pivot
    【网络收集】存储过程中自动生成主键
    Java多线程基础知识整理二
    Java多线程基础知识整理
  • 原文地址:https://www.cnblogs.com/csuwater/p/5396027.html
Copyright © 2020-2023  润新知