java反射机制&动态代理

本文深入讲解Java反射机制的基本概念及应用场景,包括如何通过反射获取类信息、实例化对象、调用方法、修改属性等。此外,还介绍了如何利用反射机制进行动态代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

综合各个博客主的帖子而来,感谢以下博主!

java反射机制详解:http://www.cnblogs.com/lzq198754/p/5780331.html

java中的反射机制:http://blog.youkuaiyun.com/liujiahan629629/article/details/18013523

java中的动态代理详解:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

反射机制

1.反射机制的定义

反射机制是在运行状态中,对于任意一个类,都能够获得这个类的状态,能够访问,检测和修改它本身状态或者行为的一种能力。并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。简单来讲,就是对于任意一个类,都能在运行状态下,获得这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意一个方法和属性。

2.反射机制能做什么?

  • 反编译 .class->.java
  • 通过反射机制访问对象的方法,属性等;
  • 运行时判断任意一个对象所属的类;
  • 运行时构造任意一个类的对象;
  • 运行时调用任意一个对象的方法;
  • 生成动态代理等;
反射机制非常强大,几乎可以不创建对象而调用另外一个对象所有东西,对应的也就有了下面的例子。可以调用的功能如下:
  • 获得一个对象的类Class
  • 获得这个Class之后可以获得这个类的所有的属性(返回Field数组,getDeclaredFields())以及属性相关的名字等,并设置相关的属性
  • 获得这个Class之后可以获得这个类的单个属性(返回Field对象,getDeclareField(String name))
  • 获得这个Class之后可以获得这个类的所有的f方法(返回Method数组,getMethods())
  • 获得这个Class之后可以获得这个类的单个方法(返回Method对象,getMethod(String methodNAME,Parameter.class)如果有参数,Parameter.class)
  • 获得方法的参数情况(返回Parameter[]数组,或者返回单个Paratmeter),类似于上面的情况
  • 获得这个Class之后可以获得这个类的所有的构造函数(返回Constructor数组,getContructors())
  • 获得这个Class之后可以获得这个类的单个构造函数,不写了,自己看api去吧,反正很多。
  • 反射机制对数组进行操作Array类的很多静态方法
  • 反射机制进行动态代理

3.反射机制的类以及API

java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflec.Method;
java.lang.reflect.Modifier;
API我们通过一些例子来看

获得一个对象的完整的包名和类名以及类加载器

public class TestReflectGetClassName {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TestReflectGetClassName t = new TestReflectGetClassName();
		System.out.println(t.getClass().getName()+" "+t.getClass().getClassLoader());
	}

}

获取类,注意是类

public class TestReflectGetClass {
	public void getClasses() throws ClassNotFoundException{
		//第一种方式,使用注册的方式
		Class c1 = Class.forName("TestReflectGetClass");
		
		//第二种方式,使用每个类里面自带的class属性
		Class c2 = TestReflectGetClassName.class;
		
		//第三种方式,每个对象的getClass方法
		TestReflectGetClassName t = new TestReflectGetClassName();
		Class c3 = t.getClass();
	}

}

实例化Class类对象

		//先使用任意一种方式获得类,比如使用注册的方式
		Class c1 = Class.forName("TestReflectGetClass");
		//然后调用newInstance()方法
		Object trg = c1.newInstance();

获取属性,其实第一个后去class名和加载器的方式也算是获得属性的方式;

包括获得父类,获得接口(getInterfaces()),获得所有的方法,获得所有的参数等
public class TestReflectGetClassName {
	int a=0;
	int b=2;
	String s = "1";

	public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
		// TODO Auto-generated method stub
		//获得当前类的名字和类加载器
		TestReflectGetClassName t = new TestReflectGetClassName();
		System.out.println(t.getClass().getName()+" "+t.getClass().getClassLoader());
		
		Class<?> c = Class.forName("javaReflection.TestReflectGetClassName");
		//获得父类
		Class<?> parent = c.getSuperclass();
		System.out.println("parent's name"+parent.getName());
		//获得所有属性的名字
		Field[] fs = c.getDeclaredFields();
		
		for(Field f:fs){
			//获得当前域的类型
			System.out.print("type:"+f.getType().getName()+" ");
			//获得当前这个域的名字,a/b/s
			System.out.print("name:"+f.getName()+" ");
			//获得对象t的当前这个域的值,也可以是其他同类型对象
			System.out.println("value:"+f.get(t));
			//修改当前对象的值t,由于不是同一类型,所以只能修改为原来的值
			f.set(t, f.get(t));
		}
		System.out.println("--------------");
		//获得所有的方法
		Method[] ms = c.getMethods();
		for(Method m:ms){
			//获得方法名
			System.out.print("name:"+m.getName()+" ");
			//获得返回类型
			System.out.print("returType:"+m.getReturnType()+" ");
			//获得参数个数
			System.out.println("parameters number:"+m.getParameterCount());
		}
	}

	public int getA() {
		return a;
	}

	public void setA(int a) {
		this.a = a;
	}

	public int getB() {
		return b;
	}

	public void setB(int b) {
		this.b = b;
	}

	public String getS() {
		return s;
	}

	public void setS(String s) {
		this.s = s;
	}
}

通过反射机制获取全部的构造函数并使用构造函数初始化对象

public class TestReflect {
    public static void main(String[] args) throws Exception {
        Class<?> class1 = null;
        class1 = Class.forName("javaReflection.User");
        // 第一种方法,实例化默认构造方法,调用set赋值
        User user = (User) class1.newInstance();
        user.setAge(20);
        user.setName("Rollen");
        System.out.println(user);
        // 结果 User [age=20, name=Rollen]
        // 第二种方法 取得全部的构造函数 使用构造函数赋值
        Constructor<?> cons[] = class1.getConstructors();
        // 查看每个构造方法需要的参数
        for (int i = 0; i < cons.length; i++) {
            Class<?> clazzs[] = cons[i].getParameterTypes();
            System.out.print("cons[" + i + "] (");
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1)
                    System.out.print(clazzs[j].getName());
                else
                    System.out.print(clazzs[j].getName() + ",");
            }
            System.out.println(")");
        }
        // 结果
        // cons[0] (int,java.lang.String)
        // cons[1] (java.lang.String)
        // cons[2] ()
        //这里必须按照前面的结果顺序来。
        user = (User) cons[0].newInstance(20,"Rollen");
        System.out.println(user);
        // 结果 User [age=0, name=Rollen]
        user = (User) cons[1].newInstance( "Rollen");
        System.out.println(user);
        // 结果 User [age=20, name=Rollen]
    }
}
class User {
    private int age;
    private String name;
    public User() {
        super();
    }
    public User(String name) {
        super();
        this.name = name;
    }
    public User(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

4.反射机制实战

在泛型Integer的ArrayList中存放一个String类型的对象

public class TestReflect {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<Integer>();
        Method method = list.getClass().getMethod("add", Object.class);
        method.invoke(list, "Java反射机制实例。");
        System.out.println(list.get(0));
    }
}

通过反射机制取得并修改数组的信息

public class TestReflect3 {
	/*执行结果
	 * 数组类型: int
	 * 数组长度  5
	 * 数组的第一个元素: 1
	 * 修改之后数组第一个元素为: 100
	 */

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] array = {1,2,3,4,5};
		Class<?> cl = array.getClass().getComponentType();
		System.out.println("数组类型: " + cl.getName());
	        System.out.println("数组长度  " + Array.getLength(array));
	        System.out.println("数组的第一个元素: " + Array.get(array, 0));
	        Array.set(array, 0, 100);
	        System.out.println("修改之后数组第一个元素为: " + Array.get(array, 0));
	}
}

通过反射机制修改数组大小

/*
 * 数组长度为: 15
 *1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 
 *数组长度为: 8
 *a b c null null null null null 
 */

public class TestReflect4 {
    public static void main(String[] args) throws Exception {
        int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        int[] newTemp = (int[]) arrayInc(temp, 15);
        print(newTemp);
        String[] atr = { "a", "b", "c" };
        String[] str1 = (String[]) arrayInc(atr, 8);
        print(str1);
    }
    // 修改数组大小
    public static Object arrayInc(Object obj, int len) {
        Class<?> arr = obj.getClass().getComponentType();
        Object newArr = Array.newInstance(arr, len);
        int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }
    // 打印
    public static void print(Object obj) {
        Class<?> c = obj.getClass();
        if (!c.isArray()) {
            return;
        }
        System.out.println("数组长度为: " + Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i) + " ");
        }
        System.out.println();
    }
}


动态代理--基于反射机制

在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

public interface Subject   
{   
  public void doSomething();   
}   
public class RealSubject implements Subject   
{   
  public void doSomething()   
  {   
    System.out.println( "call doSomething()" );   
  }   
}   
public class ProxyHandler implements InvocationHandler   
{   
  private Object proxied;   
     
  public ProxyHandler( Object proxied )   
  {   
    this.proxied = proxied;   
  }   
     
  public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable   
  {   
    //在转调具体目标对象之前,可以执行一些功能处理

    //转调具体目标对象的方法
    return method.invoke( proxied, args);  
    
    //在转调具体目标对象之后,可以执行一些功能处理
  }    
}

import java.lang.reflect.InvocationHandler;   
import java.lang.reflect.Method;   
import java.lang.reflect.Proxy;   
import sun.misc.ProxyGenerator;   
import java.io.*;   
public class DynamicProxy   
{   
  public static void main( String args[] )   
  {   
    RealSubject real = new RealSubject();   
    Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), 
     new Class[]{Subject.class}, 
     new ProxyHandler(real));
         
    proxySubject.doSomething();
   
    //write proxySubject class binary data to file   
    createProxyClassFile();   
  }   
     
  public static void createProxyClassFile()   
  {   
    String name = "ProxySubject";   
    byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject.class } );   
    try  
    {   
      FileOutputStream out = new FileOutputStream( name + ".class" );   
      out.write( data );   
      out.close();   
    }   
    catch( Exception e )   
    {   
      e.printStackTrace();   
    }   
  }   
}
总的来说,proxy生成了一个关于指定定对象(real)的代理对象(proxySubject),这个对象继承了proxy,同时实现了被代理对象(上述的RealSubject类的对象)的所有接口(Subject接口)。因此这个代理对象能够调用被代理对象的所有方法(被代理对象的非接口实现方法无法调用,也算是个缺陷吧),调用这个方法的步骤是 proxySubject调用doSomething方法,这个doSomething 方法调用InvocatoinHandler的invoke方法,invoke方法通过method参数和一开始初始化的代理对象real调用real的doSomething方法。就是这样。
具体的实现比较难理解,源代码涉及到非常复杂的情况,有空再看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值