Java反射的一些效率分析

(如今已经看不到只用Map的项目了,可能不理解为什么会去争论这个,如果项目中不存在JavaBean,其实就可以不用反射技术)

在很长的时间里,一直以为使用反射技术效率低,使用反射创建对象,效率不如Map。
这样的认知,导致一个问题,就是程序员畏惧使用反射解决问题,尤其是片面追求程序效率的开发人员。

 

这样的认知,显然是不对的,我们应该更加深入了解,到底哪些步骤慢,是否可以通过技术,加以改进。

 

实验数据结果有点令人意外: 

创建对象耗时:Class.newInstance > new HashMap() > new Object();
填充值耗时 :map.put(key,val) > obj.setValue(val) > field.setValue(val);

 

1、Map的创建效率低于直接创建对象,看过源码,基本也能猜到原因,因为 Map 初始化做太多事情了,Map有默认的容量,每一个元素都是一个Entity对象。

2、Map值的填充最慢,填值过程中,如果已经有值,需要覆盖旧的值,包含了 “遍历字段的过程”,而遍历的效率,取决于采用的数据结构,
以树和数组为例,数据量少的情况下,数组遍历肯定是最高的,树形结构的优势,需要数据量达到一定水平之后才能体现。
(案例中,Map数据量过低,因此 Map.put() 效率直接垫底了)

3、反射的setValue()实际最快,为什么会说它慢?是因为实际业务场景中,几乎不可能直接调用Java反射代码。
思考一下业务场景:查数据库中的数据,要把它放到一个对象中,这个对象有10个字段,如果你实际编写了这段代码,就会发现,你在不断地遍历数组。
尽管反射不会太慢,但是,实际应用中,会涉及大量的数据结构遍历,而Map本身就包含了检索机制,设计上能简化很多操作。

 

Java反射并不是所有的步骤都慢,如果扩大它的优势,才是我们需要思考的问题。

比如说,可以预先处理一部分的反射,将预处理过的Class、Field等对象缓存起来,

如果有条件,可以学习asm包,从字节码直接分析对象。

 

以下以创建一百万个对象为例:

package spring;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.client.bean.Person;

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        {
            //在很长的时间里,一直以为map是快速的存储结构,实际测试下,反而是最慢的
            //(但是map支持无限制地填充数据,这一点优于bean对象,尤其是数据库结果的封装,用Map算法十分简洁)
            List<Map<String,Object>> l = new ArrayList<>();
            Map<String,Object> map;
            int cnt = 1000000;
            long start = System.nanoTime();
            while(cnt-->0){
                map= new HashMap<>();
                map.put("name", "xiaoming");
                map.put("age", cnt);
                map.put("name", "xiaoming");
                map.put("age", cnt);
                l.add(map);
            }
            long end = System.nanoTime();
            System.out.println(l.size());
            System.out.println(start);
            System.out.println(end);
            System.out.println(end-start);
        }
        {
            //阿里的JSON本质是Map,效率上稍微低于map,但是并不明显
            List<JSONObject> l = new ArrayList<>();
            JSONObject map;
            int cnt = 1000000;
            long start = System.nanoTime();
            while(cnt-->0){
                map= new JSONObject();
                map.put("name", "xiaoming");
                map.put("age", cnt);
                l.add(map);
            }
            long end = System.nanoTime();
            System.out.println(l.size());
            System.out.println(start);
            System.out.println(end);
            System.out.println(end-start);
        }
        {
            //使用bean对象
            List<Person> l = new ArrayList<>();
            Person map;
            int cnt = 1000000;
            long start = System.nanoTime();
            while(cnt-->0){
                map= new Person();
                map.setName("xiaoming");
                map.setAge(cnt);
                l.add(map);
            }
            long end = System.nanoTime();
            System.out.println(l.size());
            System.out.println(start);
            System.out.println(end);
            System.out.println(end-start);  
        }
        {   
            //对java反射进行优化,先解析一部分参数,如果用以下这种编码方式,它的效率是最快的
            //但是做map.get的时候,随着参数的增多,达到某个阶段,耗时会超过Bean的set函数
       //其中while循环下new Person()这一步,实际生产中,应该是class.newInstance(),这是极耗时的一步
List<Person> l = new ArrayList<>(); Person map; int cnt = 1000000; Field fn = Person.class.getDeclaredField("name"); fn.setAccessible(true); Field fa = Person.class.getDeclaredField("age"); fa.setAccessible(true); Map<String,Field> f = new HashMap<>(); f.put("name", fn); f.put("age", fa); long start = System.nanoTime(); while(cnt-->0){ map= new Person(); f.get("name").set(map, "xiaoming"); f.get("age").set(map, cnt); l.add(map); } long end = System.nanoTime(); System.out.println(l.size()); System.out.println(start); System.out.println(end); System.out.println(end-start); } { //所有的反射留到使用时再解析,这种方式会随着参数变多, //耗时也越来越多,超过某个阶段,效率低于Map List<Person> l = new ArrayList<>(); Person map; int cnt = 1000000; long start = System.nanoTime(); Field fa,fn; while(cnt-->0){ fn = Person.class.getDeclaredField("name"); fn.setAccessible(true); fa = Person.class.getDeclaredField("age"); fa.setAccessible(true); map= new Person(); fn.set(map, "xiaoming"); fa.set(map, cnt); l.add(map); } long end = System.nanoTime(); System.out.println(l.size()); System.out.println(start); System.out.println(end); System.out.println(end-start); } } }

 

posted on 2019-01-08 11:00  疯狂的妞妞  阅读(909)  评论(0编辑  收藏  举报

导航