反射之详解

反射

一、什么是反射
反射就是对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称之为JAVA语言的反射机制。

我们创建的每一个类都是对象,类本身是Class类的实例对象,这个实例对象称之为类对象,也就是Class对象
二、Class对象的特点
	1Class类的实例对象表示正在运行的java应用程序中的类和接口。jvm中有很多的实例,每一个类都有唯一的Class对象
	2Class类没有公共的构造方法。Class类是在加载类时由Java 虚拟机自动构造的
	3Class 对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法
三、获取类对象
Class.forName()(常用)
Hero.class
new Hero().getClass()
一个类只会有一个类对,以上三种取出来的类对象都是一个样的
四、利用反射机制创建对象
1.获取类对象 Class class = Class.forName("pojo.Hero");
2.获取构造器对象 Constructor con = clazz.getConstructor(形参.class);
3 获取对象 Hero hero =con.newInstance(实参);

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {        
         /**
         * 获取类对象
         */
        Class clazz = Class.forName("com.zgq.entity.dto.Employee");
        
        /**
         * 获取构造器对象
         */
		//无参构造方法
        Constructor constructor = clazz.getConstructor(null);
        //所有的公有构造方法
        Constructor[] constructors = clazz.getConstructors();
        //所有的构造方法(包括:私有、受保护、默认、公有)
        Constructor[] declaredAnnotations = clazz.getDeclaredConstructors();
         //有参构造方法
        Constructor constructor1 = clazz.getConstructor(String.class,Integer.class,Double.class);
        
        System.out.println(constructor1.toString());
        System.out.println(declaredAnnotations.toString());
        System.out.println("所有"+constructors.toString());
        System.out.println(constructor.toString());
        
        /**
         * 调用
         */
        Employee e = (Employee) constructor.newInstance();
        e.setAge(20);
        e.setUserName("tom");
        e.setSalary(30000D);
        Employee employee = (Employee) constructor1.newInstance("jack",10,1000D);
        System.out.println(e);
        System.out.println(employee);
    }

Run:
public com.zgq.entity.dto.Employee(java.lang.String,java.lang.Integer,java.lang.Double)
[Ljava.lang.reflect.Constructor;@38af3868
所有[Ljava.lang.reflect.Constructor;@77459877
public com.zgq.entity.dto.Employee()
Employee{userName='tom', age=20, salary=30000.0}
Employee{userName='jack', age=10, salary=1000.0}
五、获取成员变量、方法并使用
基本步骤:
1、获取类对象h
2、获取属性(方法)Field f1 = h.getDeclaredField("属性名")/h.getDeclaredMethods(String name ,Class<?>… parameterTypes)
3、修改属性 f1.set(h,实参),注意这里的h是对象,不是类对象/调用方法method.invoke

获取HeroPlus类的对象 h
获取成员方法:
public Method getMethod(String name ,Class<?>… parameterTypes):获取"公有方法";(包含了父类的方法也包含Object类)
public Method getDeclaredMethods(String name ,Class<?>… parameterTypes) :获取成员方法,包括私有的(不包括继承的)
参数解释:
  name : 方法名;
  Class: 形参的Class类型对象
调用方法
Method --> public Object invoke(Object obj,Object… args):
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        //此代码会报exception,;只是为了方便看方法
        Class<?> aClass = Class.forName("com.zgq.entity.dto.Employee");
        //获取"公有方法"(包含了父类的方法也包含Object类)
        Method login = aClass.getMethod("sayHello", Integer.class);
        //获取成员方法,包括私有的(不包括继承的)
        Method say = aClass.getDeclaredMethod("say", String.class);
        login.invoke(123);//调用方法

        //获取类Employee的名字叫做userName的字段
        //可以获取本类所有的字段,包括private的,但是 不能获取继承来的字段。
        Field userName = aClass.getDeclaredField("userName");
        //只能获取public的,包括从父类继承来的字段。
        Field hhh = aClass.getField("hhh");
        userName.setAccessible(true);
        userName.set("wjj",String.class);
        System.out.println(aClass.getMethod("login", String.class, String.class).invoke("jack","1314520wjj"));
        
        Method main = aClass.getMethod("main", String[].class);
        //第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
        //这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。所以需要将它强转。
        main.invoke(null,(Object) new String[]{"q","e","r"});
        System.out.println(main);
    }
六、通过反射运行配置文件内容
当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件spring.txt,再运行即可。

泛型是在编译期间起作用的。在编译后的.class文件中是没有泛型的。所有比如T或者E类型啊,本质都是通过Object处理的。所以可以通过使用反射来越过泛型。

spring.txt
class=com.zgq.service.impl.UserService1
method=doService1

public class UserService2 {
    public void doService2(){
        System.out.println("service2=========");
    }
}
public class UserService1 {
    public void doService1(){
        System.out.println("service1=========");
    }
}
class ReflexDemo3{
    public static void main(String[] args) throws Exception {

        Properties springConfig = new Properties();
        //加载配置文件
        springConfig.load(new FileInputStream(new File("E:\\WORK_SPACE\\newWorkSpace\\demo\\src\\spring.txt")));
        //获取方法名和类名
        String className = (String)springConfig.get("class");
        String method = (String)springConfig.get("method");

        //获取类对象和方法
        Class<?> aClass = Class.forName(className);
        Method m = aClass.getMethod(method);
        //根据构造器,实例化对象
        Object o = aClass.getConstructor(null).newInstance();
        m.invoke(o);
    }
    
public class GenericityTest {
	public static void main(String[] args) throws Exception{
		
	ArrayList<String> list = new ArrayList<>();
	list.add("this");
	list.add("is");
	
	//	strList.add(5);报错
	
	/********** 越过泛型检查    **************/
	
	//获取ArrayList的Class对象,反向的调用add()方法,添加数据
	Class listClass = list.getClass(); 
	//获取add()方法
	Method m = listClass.getMethod("add", Object.class);
	//调用add()方法
	m.invoke(list, 5);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值