java反射原理aop java反射的用处_java反射原理aop

一、Java反射框架主要提供以下功能

  • 1.在运行时判断任意一个对象所属的类;
  • 2.在运行时构造任意一个类的对象;
  • 3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
  • 4.在运行时调用任意一个对象的方法

二、主要用途

反射最重要的用途就是开发各种通用框架(Spring,hibernate,mybatis)。

三、基本反射功能的实现(反射相关的类一般都在java.lang.relfect包里)

  • 1、获得Class对象
  • 2、判断是否为某个类的实例
  • 3、创建实例
  • 4、获取方法
  • 5、获取构造器信息
  • 6、获取类的成员变量(字段)信息
  • 7、调用方法
  • 8、利用反射创建数组

通过转载大佬的实例帮助了解:

四、类例

1.hero类

package pojo;
public class Hero {
	public String name; //姓名
    public float hp; //血量
    public float armor; //护甲
    public int moveSpeed; //移动速度
}

获取类对象有3种方式

1.Class.forName()
2.Hero.class
3.new Hero().getClass()

在一个JVM中,一种类,只会有一个类对象存在(此处准确是在ClassLoader下,只有一个类对象)。所以以上三种方式取出来的类对象,都是一样。
2 .用反射机制创建对象
步骤:与传统的通过new 来获取对象的方式不同反射机制,反射会先拿到Hero的“类对象”,然后通过类对象获取“构造器对象”再通过构造器对象创建一个对象。

1.获取类对象 Class class = Class.forName("pojo.Hero");
2.获取构造器对象 Constructor con = clazz.getConstructor(形参.class);
3 获取对象 Hero hero =con.newInstance(实参)
//这是最简单的获取方法,当Hero的构造方法不是无参构造方法时,获取构造器对象略有不同

给Hero类添加构造方法:

//(默认的构造方法)
	Hero(String str){
		System.out.println("(默认)的构造方法 s = " + str);
	
	//无参构造方法
	public Hero(){
		System.out.println("调用了公有、无参构造方法执行了。。。");
	}
	//有一个参数的构造方法
	public Hero(char name){
		System.out.println("姓名:" + name);
	}
	//有多个参数的构造方法
	public Hero(String name ,float hp){
		System.out.println("姓名:"+name+"血量:"+ hp);
	}
	//受保护的构造方法
	protected Hero(boolean n){
		System.out.println("受保护的构造方法 n = " + n);
	}
	//私有构造方法
	private Hero(float hp){
		System.out.println("私有的构造方法   血量:"+ hp);
	}

3.通过反射机制获取对象:

package test;
public class ConstructorTest {
	/*
	 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
	 * 1.获取构造方法:
	 * 		1).批量的方法:
	 * 			public Constructor[] getConstructors():所有"公有的"构造方法
	            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
	 * 		2).获取单个的方法,并调用:
	 * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
	 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
	 * 2.创建对象
	 * 		Constructor对象调用newInstance(Object... initargs)
	 */
	public static void main(String[] args) throws Exception {
		//1.加载Class对象
		Class clazz = Class.forName("pojo.Hero");
		//2.获取所有公有构造方法
		System.out.println("**********************所有公有构造方法*********************************");
		Constructor[] conArray = clazz.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
		conArray = clazz.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		System.out.println("*****************获取公有、无参的构造方法*******************************");
		Constructor con = clazz.getConstructor(null);
		//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
		//2>、返回的是描述这个无参构造函数的类对象。
		System.out.println("con = " + con);
		//调用构造方法
		Object obj = con.newInstance();
		System.out.println("******************获取私有构造方法,并调用*******************************");
		con = clazz.getDeclaredConstructor(float.class);
		System.out.println(con);
		//调用构造方法
		con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
		obj = con.newInstance(100);
	}
}


//总结获取构造器对象方法:
  1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
  2).获取单个的方法:
public Constructor getConstructor(Class… parameterTypes): 获取单个的"公有的"构造方法
public Constructor getDeclaredConstructor(Class…parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;

4.获取成员变量并使用
步骤;

1. 获取Hero类的对象
2. 获取属性 Field f1 = h.getDeclaredField("属性名")
3. 修改属性 f1.set(hero,实参),注意这里的hero是对象,不是类对象
Hero hero=new Hero();
        hero.setName("hero1");
        try {
            //获取类HeroPlus的名字叫做name的字段
            System.out.println("修改前的name:"+hero.name);
            Field f1= hero.getClass().getDeclaredField("name");
            //修改这个字段的值
            f1.set(hero, "hero2");
            //打印被修改后的值
            System.out.println("修改后的name:"+hero.name);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
//修改前的name:hero1
//修改后的name:hero2
//补充:getField和getDeclaredField的区别
//getField只能获取public的,包括从父类继承来的字段。
//getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 
(注:这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))

5.获取成员方法并使用

1.获取Hero类的对象
2.获取成员方法:
public Method getMethod(String name ,Class<?>… parameterTypes):
获取"公有方法";(包含了父类的方法也包含Object类)
public Method getDeclaredMethods(String name ,Class<?>… parameterTypes) :
获取成员方法,包括私有的(不包括继承的)
3.参数解释:
  name : 方法名;
  Class … : 形参的Class类型对象
4.调用方法(invoke)
Method --> public Object invoke(Object obj,Object… args):
5.参数说明:
  obj : 要调用方法的对象;
  args:调用方式时所传递的实参;
Hero hero = new Hero("hero1");
        try {
            // 获取这个名字叫做setName,参数类型是String的方法
            Method m = hero.getClass().getMethod("setName", String.class);
            System.out.println("修改前"+hero.getName());
            // 对hero对象,调用这个方法
            m.invoke(hero, "hero2");
            // 使用传统的方式,调用getName方法
            System.out.println("修改后"+hero.getName());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
//修改前hero1
//修改后hero2

五、Class类方法总结

java反射原理aop java反射的用处_spring_02

六、关于反射的用法举例

反射非常强大,但是从上面的记录来看,反而觉得还不如直接调用方法来的直接和方便。
通常来说,需要在学习了Spring 的依赖注入,反转控制之后,才会对反射有更好的理解

本文参考