精华内容
下载资源
问答
  • 对java反射机制的一些理解

    千次阅读 2016-08-14 10:47:16
    甚至于在刚开始的时候,我还觉得java反射机制真的麻烦,还不如平常的使用类以及其实例对象还有方法等。但随着慢慢的理解以及了解,才发现其实java的反射机制还是很棒的,甚至于说这才是java的精髓所在,那么我们就一...

    1.什么是java的反射机制?

    说实话,一开始的时候我真的不知道什么是java的反射机制,反射机制又有什么用呢?甚至于在刚开始的时候,我还觉得java反射机制真的麻烦,还不如平常的使用类以及其实例对象还有方法等。但随着慢慢的理解以及了解,才发现其实java的反射机制还是很棒的,甚至于说这才是java的精髓所在,那么我们就一起来探讨一下吧:

    反射(Reflection)机制:其实就是程序在运行的时候可以获取任意一个类的内部信息,也可以说是动态获取吧。

    2.那么我们怎么利用反射(Reflection)去获取类的相关信息呢?

    首先我们必须要了解什么是静态加载类,什么是动态加载类?

    静态加载类:其实说的通俗一点的话,就是程序编译的的过程,这就是静态加载类。

    动态加载类:其实说的就是程序运行的时候,可以说动态加载。

    简单一点的说法就是:编译--------静态      运行---------动态

    我们在控制台运行java程序的时候是不是要执行一下:javac *.java(其实这个时候会生成一个该类的.class文件) 然后再java *(这个时候其实运行加载的就是这个.class文件),而所谓的动态加载,就是绕过编译,在调用的时候就运行。下面通过一个简单的例子来说明一下:

    比如我新建一个类:         

    package com.mytest01;
    
    public class showObj {
    	public void showObject(){
    		Person p = new person();
    		system.out.println(p);
    }

    还没有运行的时候在eclispe等软件是不是会提示报错?然后你在控制台中编译是不是不通过?说找不到这个Person这个类?

    那么我们稍微改一下代码看看是否还会出错:

    package com.mytest01;
    
    public class showObj {
    	public void showObject(){
    		Class p = person.class;
    		System.out.println(p);
    }
    	class person{
    		
    		}
    	}
    
    看看编译的时候还会不会出错?

    下面我们再来谈一下我们到底应该怎么去获取类的内部信息呢?

    在获取类的内部信息之前,我想说的是一点点面向对象的思想。首先什么是对象?我们常说一个实体就是一个对象,那么我们在想想java里面我们新建的类是不是一个对象呢?你可能会有疑问?对象不就还是类的实例化吗?为什么说类也是一个对象?其实也不难理解,因为我们所有新建的类其实都是java里面java.lang.Class的实例对象来的,新建一个类,其实就是实例化java.lang.Class类;

    明白了这一点,我们就可以继续的往下走了,下面我们就来谈谈怎么去获取一个类的内部信息:

    第一步:获取该类的类类型(这一步非常关键)

    那么我们怎么去获取呢:

    其实很简答,一共有三种方法:

    1.利用Class c  = Class.forName("")----------传就来要获取类的路径,会出现异常。

    2.利用Class c = A.class ---------------------A代表该类的类名

    3.利用Class c = a.getClass();---------------a代表的就是该类的实例化对象,也就是 A a = new A();这一步

    通过上面的方法我们就获取了该类的一个实例对象,那么我们怎么调用类里面的成员函数,成员变量呢?(注意都是public的)如果要访问私有的要在你要获取的变量后加上setAccessible(true);例如 Filed[] filed = c.getFields(); field.setAccessible(true);

    其实还是很简单:

    1.c.getName()-------------------获取该类的类名;返回String类型的值

    2.c.getFileds()------------------------获取该类的所有成员变量   c.getDeclaredFields()--------自己声明的类的成员变量;

    3.c.getType()---------------------------获取该类的类型

    4.c.getMethods()----------------------获取所有的方法     c.getDeclaredMethod()-----------所有声明过的方法。

    .......

    .....

    ..

    还有很多可以去查阅官方的文档。

    那么我们怎么反向的去执行方法呢?

    分为三步:

    第一:获取类的;类类型

    Class c = a.getClass();

    第二步:获取类的方法

    Method m = c.getMethod("方法的名称",参数的类类型new Class[]{...,.....});

    第三部:传入参数,利用invoke()函数

    Object  o = m.invoke(a(实例化对象),执行函数要传进来的参数);

    好了,上面就是一些java反射的浅层应用以及讲解。

    展开全文
  • 思考:在讲反射之前,先思考一个问题,java中如何创建一个对象,有哪几种方式? Java中创建对象大概有这几种方式: 1、使用new关键字:这是我们最常见的也是最简单的创建对象的方式 2、使用Clone的方法:无论何时...

    视频功能审核通过了,可以看视频啦!

    建议一定要花十几分钟时间把视频看完,然后再结合博客里的内容来理解

    看完后,相信对你了解Java中的反射一定会有所帮助!

    注意:因为网络原因,视频前一两分钟可能会比较模糊,过一会儿就好了

    记得点关注啊,视频里的wx二维码失效了,wx搜索:“聊5毛钱的java 或 扫码关注公众号,欢迎一起学习交流

    快扫码关注啦!关注可领取博主的Java学习视频+资料,保证都是干货

    用最通俗易懂的话来说一说Java中的反射机制

    思考:在讲反射之前,先思考一个问题,java中如何创建一个对象,有哪几种方式?

    Java中创建对象大概有这几种方式:

    1、使用new关键字:这是我们最常见的也是最简单的创建对象的方式

    2、使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去

    3、使用反序列化:当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象

    上边是Java中常见的创建对象的三种方式,其实除了上边的三种还有另外一种方式,就是接下来我们要讨论的 “反射”

    1、反射概述

    1.1什么是反射

    反射就是把Java类中的各个组成部分进行解剖,并映射成一个个的Java对象,拿到这些对象后可以做一些事情。

    既然说反射是解剖Java类中的各个组成部分,所以说咱们得知道一个类中有哪些部分?

    例如,一个类有:构造方法,方法,成员变量(字段),等信息,利用反射技术咱们可以把这些组成部分映射成一个个对象

    拿到映射后的构造方法,可以用它来生成对象;拿到映射后的方法,可以调用它来执行对应的方法;拿到映射后的字段,可以用它来获取或改变对应字段的值;

    1.2、反射能干什么

    说完反射的概念后,咱们说一下反射能干什么?

    一般来说反射是用来做框架的,或者说可以做一些抽象度比较高的底层代码,反射在日常的开发中用到的不多,但是咱们还必须搞懂它,因为搞懂了反射以后,可以帮助咱们理解框架的一些原理。所以说有一句很经典的话:反射是框架设计的灵魂。现在说完这个可能还不太能理解,不急,等下说完一个快速入门的例子后,应该会稍微有点感觉

    1.3、怎么得到想反射的类

    刚才已经说过,反射是对一个类进行解剖,想解剖一个东西,前提是首先你得拿到这个东西,那么怎么得到咱们想解剖的类呢?

    首先大家要明白一点,咱们写的代码是存储在后缀名是 .java的文件里的,但是它会被编译,最终真正去执行的是编译后的 .class文件。Java是面向对象的语言,一切皆对象,所以java认为 这些编译后的 class文件,这种事物也是一种对象,它也给抽象成了一种类,这个类就是Class,大家可以去AIP里看一下这个类

    所以拿到这个类后,就相当于拿到了咱们想解剖的类,那怎么拿到这个类?

    看API文档后,有一个方法forName(String className); 而且是一个静态的方法,这样咱们就可以得到想反射的类了

    到这里,看Class clazz = Class.forName("com.cj.test.Person");这个应该有点感觉了吧

    Class.forName("com.cj.test.Person");因为这个方法里接收的是个字符串,字符串的话,我们就可以写在配置文件里,然后利用反射生成我们需要的对象,这才是我们想要的。很多框架里都有类似的配置

    2、解剖类

    我们知道一个类里一般有构造函数、方法、成员变量(字段/属性)这三部分组成

    翻阅API文档,可以看到

    Class对象提供了如下常用方法:

    public Constructor getConstructor(Class<?>…parameterTypes)

    public Method getMethod(String name,Class<?>… parameterTypes)

    public Field getField(String name)

    public Constructor getDeclaredConstructor(Class<?>…parameterTypes)

    public Method getDeclaredMethod(String name,Class<?>… parameterTypes)

    public Field getDeclaredField(String name)

    这些方法分别用于帮咱们从类中解剖出构造函数、方法和成员变量(属性)。

    然后把解剖出来的部分,分别用Constructor、Method、Field对象表示。

    2.1反射构造方法

    2.1.1反射无参的构造函数

    可以看到 默认的无参构造方法执行了

    从上边的例子看出,要想反射,首先第一步就是得到类的字节码

    所以简单说一下得到类的字节码的几种方式

    (1)、Class.forName("com.cj.test.Person"); 这就是上边我们用的方式

    (2)、对象.getClass();

    (3)、类名.class;

    2.1.2反射“一个参数”的构造函数

    2.1.3反射“多个参数”的构造函数

    2.1.4反射“私有”的构造函数

    注意:在反射私有的构造函数时,用普通的clazz.getConstructor()会报错,因为它是私有的,所以提供了专门反射私有构造函数的方法 clazz.getDeclaredConstructor(int.class);//读取私有的构造函数,用这个方法读取完还需要设置一下暴力反射才可以

    c.setAccessible(true);//暴力反射

    2.1.5反射得到类中所有的构造函数

    2.2反射类中的方法

    package com.cj.test;
    
    import java.util.Date;
    
    public class Person {
    	
    	public Person(){
    		System.out.println("默认的无参构造方法执行了");
    	}
    
    	public Person(String name){
    		System.out.println("姓名:"+name);
    	}
    	
    	public Person(String name,int age){
    		System.out.println(name+"="+age);
    	}
    	
    	private Person(int age){
    		System.out.println("年龄:"+age);
    	}
    	
    	public void m1() {
    		System.out.println("m1");
    	}
    	
    	public void m2(String name) {
    		System.out.println(name);
    	}
    	
    	public String m3(String name,int age) {
    		System.out.println(name+":"+age);
    		return "aaa";
    	}
    	
    	private void m4(Date d) {
    		System.out.println(d);
    	}
    	
    	public static void m5() {
    		System.out.println("m5");
    	}
    	
    	public static void m6(String[] strs) {
    		System.out.println(strs.length);
    	}
    
            public static void main(String[] args) {
    		System.out.println("main");
    	}
    
    }
    
    
    
    
    
    package com.cj.test;
    
    import java.lang.reflect.Method;
    import java.util.Date;
    import org.junit.Test;
    
    public class Demo2 {
    
    	@Test//public void m1()
    	public void test1() throws Exception{
    		Class clazz = Class.forName("com.cj.test.Person");
    		Person p = (Person)clazz.newInstance();
    		Method m = clazz.getMethod("m1", null);
    		m.invoke(p, null);
    	}
    	@Test//public void m2(String name)
    	public void test2() throws Exception{
    		Class clazz = Person.class;
    		Person p = (Person) clazz.newInstance();
    		Method m = clazz.getMethod("m2", String.class);
    		m.invoke(p, "张三");
    	}
    	@Test//public String m3(String name,int age)
    	public void test3() throws Exception{
    		Class clazz = Person.class;
    		Person p = (Person) clazz.newInstance();
    		Method m = clazz.getMethod("m3", String.class,int.class);
    		String returnValue = (String)m.invoke(p, "张三",23);
    		System.out.println(returnValue);
    	}
    	@Test//private void m4(Date d)
    	public void test4() throws Exception{
    		Class clazz = Person.class;
    		Person p = (Person) clazz.newInstance();
    		Method m = clazz.getDeclaredMethod("m4", Date.class);
    		m.setAccessible(true);
    		m.invoke(p,new Date());
    	}
    	@Test//public static void m5()
    	public void test5() throws Exception{
    		Class clazz = Person.class;
    		Method m = clazz.getMethod("m5", null);
    		m.invoke(null,null);
    	}
    	@Test//private static void m6(String[] strs)
    	public void test6() throws Exception{
    		Class clazz = Person.class;
    		Method m = clazz.getDeclaredMethod("m6",String[].class);
    		m.setAccessible(true);
    		m.invoke(null,(Object)new String[]{"a","b"});
    	}
    	@Test
    	public void test7() throws Exception{
    		Class clazz = Person.class;
    		Method m = clazz.getMethod("main",String[].class);
    		m.invoke(null,new Object[]{new String[]{"a","b"}});
    	}
    }
    

    *****注意:看下上边代码里test6和test7的invoke方法里传的参数和其他的有点不一样

    这是因为 jdk1.4和jdk1.5处理invoke方法有区别

    1.5:public Object invoke(Object obj,Object…args)

    1.4:public Object invoke(Object obj,Object[] args)

    由于JDK1.4和1.5对invoke方法的处理有区别, 所以在反射类似于main(String[] args) 这种参数是数组的方法时需要特殊处理

    启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数个数不对的问题。

    上述问题的解决方法:

    (1)mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});

    这种方式,由于你传的是一个数组的参数,所以为了向下兼容1.4的语法,javac遇到数组会给你拆开成多个参数,但是由于咱们这个Object[ ] 数组里只有一个元素值,所以就算它拆也没关系

    (2)mainMethod.invoke(null,(Object)new String[]{"xxx"});

    这种方式相当于你传的参数是一个对象,而不是数组,所以就算是按照1.4的语法它也不会拆,所以问题搞定

    编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了

    对上边的描述进行一下总结:在反射方法时,如果方法的参数是一个数组,考虑到向下兼容问题,会按照JDK1.4的语法来对待(JVM会把传递的数组参数拆开,拆开就会报参数的个数不匹配的错误)
    解决办法:防止JVM拆开你的数组
        方式一:把数组看做是一个Object对象
        方式二:重新构建一个Object数组,那个参数数组作为唯一的元素存在。

    2.3反射类中的属性字段

    package com.cj.test;
    
    import java.util.Date;
    
    public class Person {
    	
    	public String name="李四";
    	private int age = 18;
    	public static Date time;
    	
    	public int getAge() {
    		return age;
    	}
    	
    	public Person(){
    		System.out.println("默认的无参构造方法执行了");
    	}
    
    	public Person(String name){
    		System.out.println("姓名:"+name);
    	}
    	
    	public Person(String name,int age){
    		System.out.println(name+"="+age);
    	}
    	
    	private Person(int age){
    		System.out.println("年龄:"+age);
    	}
    	
    	public void m1() {
    		System.out.println("m1");
    	}
    	
    	public void m2(String name) {
    		System.out.println(name);
    	}
    	
    	public String m3(String name,int age) {
    		System.out.println(name+":"+age);
    		return "aaa";
    	}
    	
    	private void m4(Date d) {
    		System.out.println(d);
    	}
    	
    	public static void m5() {
    		System.out.println("m5");
    	}
    	
    	public static void m6(String[] strs) {
    		System.out.println(strs.length);
    	}
    	
    	public static void main(String[] args) {
    		System.out.println("main");
    	}
    	
    }
    
    
    
    
    
    package com.cj.test;
    
    import java.lang.reflect.Field;
    import java.util.Date;
    import org.junit.Test;
    
    public class Demo3 {
    	//public String name="李四";
    	@Test
    	public void test1() throws Exception{
    		Class clazz = Person.class;
    		Person p = (Person)clazz.newInstance();
    		Field f = clazz.getField("name");
    		String s = (String)f.get(p);
    		System.out.println(s);
    		
    		//更改name的值
    		f.set(p, "王六");
    		System.out.println(p.name);
    	}
    	@Test//private int age = 18;
    	public void test2() throws Exception{
    		Class clazz = Person.class;
    		Person p = (Person)clazz.newInstance();
    		Field f = clazz.getDeclaredField("age");
    		f.setAccessible(true);
    		int age = (Integer)f.get(p);
    		System.out.println(age);
    		
    		f.set(p, 28);
    		age = (Integer)f.get(p);
    		System.out.println(age);
    	}
    	@Test//public static Date time;
    	public void test3() throws Exception{
    		Class clazz = Person.class;
    		Field f = clazz.getField("time");
    		f.set(null, new Date());
    		System.out.println(Person.time);
    	}
    }
    

    以上就是自己对Java中反射的一些学习总结,欢迎大家留言一起学习、讨论

    看完上边有关反射的东西, 对常用框架里的配置文件是不是有点思路了

    上边是Spring配置文件里的常见的bean配置,这看起来是不是可以用反射很轻易的就可以实现:解析xml然后把xml里的内容作为参数,利用反射创建对象。

    拓展:

    1、除了上述的Spring配置文件里会用到反射生成bean对象,其他常见的MVC框架,比如Struts2、SpringMVC等等一些框架里还有很多地方都会用到反射。

    前端夜页面录入的一些信息通过表单或者其他形式传入后端,后端框架就可以利用反射生成对应的对象,并利用反射操作它的set、get方法把前端传来的信息封装到对象里。

    感兴趣的话可以看下这篇:利用Java反射模拟一个Struts2框架 Struts2主要核心设计 手动实现Struts2核心代码,这篇里边包含了XML解析、反射的东西,模拟了一个Struts2的核心代码

    2、框架的代码里经常需要利用反射来操作对象的set、get方法,来把程序的数据封装到Java对象中去。

    如果每次都使用反射来操作对象的set、get方法进行设置值和取值的话,过于麻烦,所以JDK里提供了一套API,专门用于操作Java对象的属性(set/get方法),这就是内省

    关于内省相关的内容我也整理了一篇文章,感兴趣可以点击:Java反射——内省(Introspector)以及BeanUtils内省框架

    3、平常用到的框架,除了配置文件的形式,现在很多都使用了注解的形式。

    其实注解也和反射息息相关:使用反射也能轻而易举的拿到类、字段、方法上的注解,然后编写注解解析器对这些注解进行解析,做一些相关的处理

    所以说不管是配置文件还是注解的形式,它们都和反射有关。注解和自定义注解的内容,最近也抽时间大概整理了一下,感兴趣的小可爱可以点击了解:Java中的注解以及自定义注解

    写在最后:反射是框架的灵魂,具备反射知识和思想,是看懂框架的基础。希望看完文章后对你能有所帮助。

    铁子们,如果觉得文章对你有所帮助,可以点关注,点赞

    也可以关注下公众号:扫码 或 wx搜索:“聊5毛钱的java ,欢迎一起学习交流,关注公众号可领取博主的Java学习视频+资料,保证都是干货

    3Q~

    展开全文
  • 对java反射机制的理解

    千次阅读 2013-10-29 17:30:13
    一、通过反射生成对象的类,必需有一个无参构造方法; 二、可以调用类的方法; 三、可以为属性赋值或者获取属性的值,且该属性有无get,set方法都可以。 package com.csair.test; import java.lang.reflect.Field; ...

    一、通过反射生成对象的类,必需有一个无参构造方法;

    二、可以调用类的方法;

    三、可以为属性赋值或者获取属性的值,且该属性有无get,set方法都可以。

    package com.csair.test;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    public class Test {
    	public static void main(String[] args) throws Exception {
    		Class<?> clz = Class.forName("com.csair.test.A");
    		A aa = (A)clz.newInstance();
    		Field field = clz.getDeclaredField("name");
    		if(!Modifier.isPublic(field.getModifiers())) {
    			field.setAccessible(true);
    		}
    		//获取属性
    		Object obj = field.get(aa);
    		System.out.println(obj);
    		//调用方法
    		Method method = clz.getDeclaredMethod("test", new Class[] {String.class});
    		if(!Modifier.isPublic(method.getModifiers())) {
    			method.setAccessible(true);
    		}
    		method.invoke(aa, new Object[] {"ppt"});
    	}
    }
    class A{
    	private String name;
    	public A() {
    		name = "hello world";
    	}
    	private void test(String name) {
    		System.out.println(name);
    	}
    }
    

    展开全文
  • 说说你对Java反射理解

    千次阅读 2019-10-09 20:29:09
    随着调用次数的增加,每次反射都使用JNI跨越native边界会优化有阻碍作用,相对来说使用拼装出的字节码可以直接以Java调用的形式实现反射,发挥了JIT优化的作用,避免了JNI为了维护OopMap(HotSpot用来实现准确式GC...
    public class ReflectCase {
        public static void main(String[] args) throws Exception {
            Proxy target = new Proxy();
            Method method = Proxy.class.getDeclaredMethod("run");
            method.invoke(target);
        }
    
        static class Proxy {
            public void run() {
                System.out.println("run");
            }
        }
    }
    

    主要有两部分:Method的获取、Method的使用

    一、Method获取

    我们会调用getDeclaredMethod()方法

    其中privateGetDeclaredMethods方法从缓存或JVM中获取该Class中申明的方法列表,searchMethods方法将从返回的方法列表里找到一个匹配名称和参数的方法对象。

     

    1searchMethods(从方法列表中找到相应的对象)

    如果找到一个匹配的Method,则重新copy一份返回,即Method.copy()方法

    所次每次调用getDeclaredMethod方法返回的Method对象其实都是一个新的对象,且新对象的root属性都指向原来的Method对象如果需要频繁调用,最好把Method对象缓存起来

     

    2privateGetDeclaredMethods(获取该class中声明的方法列表

    从缓存或JVM中获取该Class中申明的方法列表,实现如下:

    先利用reflectionData()方法从缓存中获取该Class中声明的方法列表,如果有就直接返回,不用执行下一步骤。

    如果从缓存中找不到,则会利用getDeclaredMethods0()方法从JVM中获取该类中的所有方法,然后找出特定方法

    private native Method[]      getDeclaredMethods0(boolean publicOnly);

     

     

    1)从缓存中获取:

    先利用reflectionData()方法从缓存中获取该Class中声明的方法列表。

    其中reflectionData()方法实现如下:

    这里有个比较重要的数据结构ReflectionData,用来缓存从JVM中读取类的如下属性数据:

    reflectionData()方法实现可以看出:

    ReflectionData对象是SoftReference类型的,说明在内存紧张时可能会被回收不过也可以通过-XX:SoftRefLRUPolicyMSPerMB参数控制回收的时机,只要发生GC就会将其回收

    如果ReflectionData被回收之后,又执行了反射方法,那只能通过newReflectionData()方法重新创建一个这样的对象了。newReflectionData()方法实现如下:

    通过unsafe.compareAndSwapObject方法重新设置reflectionData字段;

    如果通过reflectionData()获得的ReflectionData对象不为空,则尝试从ReflectionData对象中获取declaredMethods属性。如果是第一次,或则被GC回收之后,重新初始化后的类属性为空,则需要重新到JVM中获取一次,并赋值给ReflectionData,下次调用就可以使用缓存数据了。

    2)从JVM中查找

    如果从缓存中找不到,则会利用getDeclaredMethods0()方法从JVM中获取该类中的所有方法

    private native Method[]      getDeclaredMethods0(boolean publicOnly);

    然后调用Reflection.filterMethods()方法找出特定方法

    res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));

     

    二、Method调用

    获取到指定的方法对象Method之后,就可以调用它的invoke方法了,invoke实现如下:

    主要是MethodAccessor对象中的invoke()方法调用

    1)获取MethodAccessor对象一开始methodAccessor为空,需要调用acquireMethodAccessor生成一个新的MethodAccessor对象。

    MethodAccessor本身就是一个接口,实现如下:

    acquireMethodAccessor()方法:

    在acquireMethodAccessor方法中,会通过ReflectionFactory类的newMethodAccessor()方法创建一个实现了MethodAccessor接口的对象,实现如下:

    (ReflectionFactory类中,有2个重要的字段:

    noInflation(默认false)inflationThreshold(默认15)

    在checkInitted方法中可以通过

    -Dsun.reflect.inflationThreshold=xxx

    和-Dsun.reflect.noInflation=true

    对这两个字段重新设置,而且只会设置一次;

     

    如果noInflation为false,方法newMethodAccessor都会返回DelegatingMethodAccessorImpl对象

    注:

    DelegatingMethodAccessorImpl的类实现:

    其实,DelegatingMethodAccessorImpl对象就是一个代理对象,负责调用被代理对象delegate的invoke方法,其中delegate参数目前是NativeMethodAccessorImpl对象。

     

    由于DelegatingMethodAccessorImpl对象内部实现是一个代理对象,被代理的对象是NativeMethodAccessorImpl对象。所以最终Method的invoke方法调用的是NativeMethodAccessorImpl对象invoke方法。

     

    NativeMethodAccessorImpl对象invoke方法实现如下:

    这里用到了ReflectionFactory类中的inflationThreshold

    创建机制采用了一种名为inflation的方式(JDK1.4之后):

    1调用次数小于等于15次:如果该方法的累计调0.用次数<=15,会创建出NativeMethodAccessorImpl,它的实现就是直接调用native方法实现反射;

    2调用次数大于15:如果该方法的累计调用次数>15,会由java代码创建出字节码组装而成的MethodAccessorImpl。(改变DelegatingMethodAccessorImpl类中的代理对象)

     

    这里需要注意的是:

    MethodAccessorGenerator#generateMethod()方法在生成MethodAccessorImpl对象时,会在内存中生成对应的字节码,并调用ClassDefiner.defineClass创建对应的class对象,实现如下:

    在ClassDefiner.defineClass方法实现中,每被调用一次都会生成一个DelegatingClassLoader类加载器对象

    这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载,从其设计来看本身就不希望这些类一直存在内存里的,在需要的时候有就行了。

     

    从变化趋势上看,第1次和第16次调用是最耗时的(初始化NativeMethodAccessorImpl和字节码拼装MethodAccessorImpl)。毕竟初始化是不可避免的,而native方式的初始化会更快,因此前几次的调用会采用native方法。

    随着调用次数的增加,每次反射都使用JNI跨越native边界会对优化有阻碍作用,相对来说使用拼装出的字节码可以直接以Java调用的形式实现反射,发挥了JIT优化的作用,避免了JNI为了维护OopMap(HotSpot用来实现准确式GC的数据结构)进行封装/解封装的性能损耗。因此在已经创建了MethodAccessor的情况下,使用Java版本的实现会比native版本更快。所以当调用次数到达一定次数(15次)后,会切换成Java实现的版本,来优化未来可能的更频繁的反射调用。

     

    2)调用MethodAccessor对象invoke()方法:

    1)调用次数小于等于15,那么MethodAccessor会是NativeMethodAccessorImpl,即调用NativeMethodAccessorImpl#invoke()方法

    2)调用次数大于15,那么MethodAccessor会是字节码组装而成的MethodAccessorImpl,即调用MethodAccessorImpl#invoke()方法

     

     

    Class对象

    虚拟机在class文件的加载阶段,把类信息保存在方法区数据结构中,并在Java堆中生成一个Class对象,作为类信息的入口。

    反射的性能问题

    1. 代码的验证防御逻辑过于复杂,本来这块验证时在链接阶段实现的,使用反射reflect时需要在运行时进行;
    2. 产生过多的临时对象,影响GC的消耗;
    3. 由于缺少上下文,导致不能进行更多的优化,如JIT;

    不过现代JVM已经运行的足够快,我们应该把主要重心放在复杂的代码逻辑上,而不是一开始就进行各种性能优化。

     

     

    展开全文
  • 且谈谈我对Java反射理解

    千次阅读 2015-05-10 20:00:12
    Java培训、Android培训、iOS培训、.Net培训、期待与您交流!  在张老师的课程当中,谈到了...JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任
  • 显然可以提高java灵活性和增加应用场景 核心 Class c=Class.forName("reflection.User"); 这里声明一个类的对象(注意Class中c是大写,class是关键字) 然后获取路径(包名+类名),这样c虽然不是User类...
  • 对Java反射机制的理解

    万次阅读 多人点赞 2018-07-29 11:10:42
    简单的说,反射机制就是在程序的运行过程中被允许程序本身进行操作,比如自我检查,进行装载,还可以获取类本身,类的所有成员变量和方法,类的对象,还可以在运行过程中动态的创建类的实例,通过实例来调用类的...
  • java反射机制的理解

    2015-09-26 15:03:42
    java反射机制:动态(运行时)获取类中的信息就是java反射,可以理解类的解剖。 反射机制主要提供的功能: 1)在运行时判断任意一个对象所属的类 2)在运行时构造任意一个类的对象 3)在运行时判断任意...
  • 深度理解JAVA 反射机制

    千次阅读 2020-04-28 11:30:35
    JAVA 反射机制是非常基础也是非常重要的板块,经过自己的总结,希望能帮到更多的朋友一起理解,大牛请绕道 首先反射有以下三种实现方式 1: Class.forName(“全类名”),将字节码文件加载进内存,返回Class对象 * ...
  • java反射简单理解

    千次阅读 2010-11-18 23:58:00
    今天又看了一次java反射的视频,为啥说是又呢,那是因为前一段时间看的时候走马观花,心浮气躁,头晕目眩……。准确的说是因为上次看的时候觉得自己虽然java不熟,但是.net中的反射还是用过的,所以看视频的...
  • 最近看了java反射,不是太理解,请各位朋友多多指点,给我一点深入理解的思路。
  • 简单理解java反射机制

    千次阅读 2017-09-10 19:03:22
    简单理解java反射技术我理解的反射技术就是在运行时从内存中获得取得指定类的对象并得到其全部内容。百度百科定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个...
  • java的封装,个人的简单理解就是将一个类的功能暴露给外部,但是将内部实现细节隐藏起来。换个说话就是类的外部只需要知道我给你提供了哪些功能即可,关于这些功能是是如何实现的你不需要知道,也不让你知道。这就...
  • 怎么理解java反射机制?或者说反射的作用和原理?简要阐述一下。
  • java反射

    千次阅读 2018-01-23 18:02:05
    java反射 ...深入理解Java反射 https://www.cnblogs.com/luoxn28/p/5686794.html java 使用BeanInfo实现bean实体与map之间的互相转换 http://blog.csdn.net/cuiyaoqiang/article/details/535823
  • 总结: 十分钟深入理解Java反射机制

    万次阅读 多人点赞 2018-03-30 13:16:52
    首先先看一下Java反射的概念JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为...
  • Java反射

    千次阅读 多人点赞 2018-11-08 07:54:15
    理解反射学习Java框架有很大的帮助,如Spring框架的核心就是使用Java反射实现的,而且做一些Java底层的操作会很有帮助。  要想理解反射的原理,首先要了解什么是类型信息。 Java让我们在运行时识别对象和类的...
  • 本文转载自:张拭心的博客 shixinzhang 的:深入理解 Java 反射:Class (反射的入口)深入理解 Java 反射系列:深入理解 Java 反射:Class (反射的入口) 深入理解 Java 反射:Field (成员变量)深入理解 Java ...
  • 深入理解java反射机制

    万次阅读 多人点赞 2016-07-24 02:32:36
    一,java的核心机制java有两种核心机制:java虚拟机(JavaVirtual Machine)与垃圾收集机制(Garbage collection): Java虚拟机:是运行所有Java程序的抽象计算机,是Java语言的运行环境,在其上面运行Java代码编译后的...
  • Java 反射机制的理解

    千次阅读 2016-07-08 11:17:22
    这两天把JAVA反射机制看了一遍,回味真的很酸爽,应该说很痴迷和很敬佩JAVA设计者的睿智,太完美了,简直是C++设计者的一种藐视(原理我的无知,我只是想表达下JAVA反射有多么强大和完美)。首先定义一下什么...
  • Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)...
  • java反射理解

    千次阅读 2018-03-01 13:23:02
    java反射机制是运行状态中,对于任意一个类,能够知道这个类的所有属性和方法、对于任意一个对象,都能够调用它的任意一个方法。这种动态获取的信息以及动态调用对象的方法的功能就是java的反射机制。在博客看到的一...
  • 深入理解Java类型信息(Class对象)与反射机制

    万次阅读 多人点赞 2017-05-01 23:19:19
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ...深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解
  • java反射机制理解及其用途归纳

    千次阅读 2018-03-01 10:27:30
    在imooc上看到关于反射的文章就留心看了看,写的挺好 作者: 陈树义  ... 来源:慕课网 ...反射之中包含了一个「反」字,所以想要解释反射就...于是我们直接这个类进行实例化,之后使用这个类对象进行操作。 Apple
  • 今天看知乎关于java反射理解

    千次阅读 2017-05-07 21:17:56
    今天看知乎关于java反射理解,看到一个答案比较明了,所以记录一下: https://www.zhihu.com/question/24304289 侵删。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 119,731
精华内容 47,892
关键字:

对java反射的理解

java 订阅