长春维鸿东光电子器材有限公司
您的位置:网站首页 > 招贤纳士 > 正文

Java反射教程

作者:大海 来源: 日期:2019-6-4 10:20:06 人气: 标签:
今天小编为年夜家带来的 是java反射教程,对于java反射,年夜家都有很多疑问,今天小编就来为年夜家一一解答。

 反射真的 存在机能问题吗

  照样应用上篇文章的 demo,为了放年夜问题,找到共性,采取逐渐扩年夜测试次数、每次测试多次取平均值的 方法,针对同一个办法分别就直接调用该办法、反射调用该办法、直接调用该办法对应的 实例、反射调用该办法对应的 实例分别从1-1000000,每隔一个数量级测试一次

测试代码如下(Person、ICompany、ProgramMonkey这三个类已在之前的 文章中贴出)

public class ReflectionPerformanceActivity extends Activity{

private TextView mExecuteResultTxtView = null;

private EditText mExecuteCountEditTxt = null;

private Executor mPerformanceExecutor = Executors.newSingleThreadExecutor();

private static final int AVERAGE_COUNT = 10;

@Override

protected void onCreate(Bundle savedInstanceState){



super.onCreate(savedInstanceState);



setContentView(R.layout.activity_reflection_performance_layout);



mExecuteResultTxtView = (TextView)findViewById(R.id.executeResultTxtId);



mExecuteCountEditTxt = (EditText)findViewById(R.id.executeCountEditTxtId);

}

public void onClick(View v){



switch(v.getId()){





case R.id.executeBtnId:{







execute();





}





break;





default:{





}





break;



}

}

private void execute(){



mExecuteResultTxtView.setText("");



mPerformanceExecutor.execute(new Runnable(){





@Override





public void run(){







long costTime = 0;







int executeCount = Integer.parseInt(mExecuteCountEditTxt.getText().toString());







long reflectMethodCostTime=0,normalMethodCostTime=0,reflectFieldCostTime=0,normalFieldCostTime=0;







updateResultTextView(executeCount + "毫秒耗时情况测试");







for(int index = 0; index < AVERAGE_COUNT; index++){









updateResultTextView("第 " + (index+1) + " 次");









costTime = getNormalCallCostTime(executeCount);









reflectMethodCostTime += costTime;









updateResultTextView("履行直接调用办法耗时" + costTime + " 毫秒");









costTime = getReflectCallMethodCostTime(executeCount);









normalMethodCostTime += costTime;









updateResultTextView("履行反射调用办法耗时" + costTime + " 毫秒");









costTime = getNormalFieldCostTime(executeCount);









reflectFieldCostTime += costTime;









updateResultTextView("履行通俗调用实例耗时" + costTime + " 毫秒");









costTime = getReflectCallFieldCostTime(executeCount);









normalFieldCostTime += costTime;









updateResultTextView("履行反射调用实例耗时" + costTime + " 毫秒");







}







updateResultTextView("履行直接调用办法平均耗时" + reflectMethodCostTime/AVERAGE_COUNT + " 毫秒");







updateResultTextView("履行反射调用办法平均耗时" + normalMethodCostTime/AVERAGE_COUNT + " 毫秒");







updateResultTextView("履行通俗调用实例平均耗时" + reflectFieldCostTime/AVERAGE_COUNT + " 毫秒");







updateResultTextView("履行反射调用实例平均耗时" + normalFieldCostTime/AVERAGE_COUNT + " 毫秒");





}



});

}

private long getReflectCallMethodCostTime(int count){



long startTime = System.currentTimeMillis();



for(int index = 0 ; index < count; index++){





ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);





try{







Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);







setmLanguageMethod.setAccessible(true);







setmLanguageMethod.invoke(programMonkey, "Java");





}catch(IllegalAccessException e){







e.printStackTrace();





}catch(InvocationTargetException e){







e.printStackTrace();





}catch(NoSuchMethodException e){







e.printStackTrace();





}



}



return System.currentTimeMillis()-startTime;

}

private long getReflectCallFieldCostTime(int count){



long startTime = System.currentTimeMillis();



for(int index = 0 ; index < count; index++){





ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);





try{







Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");







ageField.set(programMonkey, "Java");





}catch(NoSuchFieldException e){







e.printStackTrace();





}catch(IllegalAccessException e){







e.printStackTrace();





}



}



return System.currentTimeMillis()-startTime;

}

private long getNormalCallCostTime(int count){



long startTime = System.currentTimeMillis();



for(int index = 0 ; index < count; index++){





ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);





programMonkey.setmLanguage("Java");



}



return System.currentTimeMillis()-startTime;

}

private long getNormalFieldCostTime(int count){



long startTime = System.currentTimeMillis();



for(int index = 0 ; index < count; index++){





ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);





programMonkey.mLanguage = "Java";



}



return System.currentTimeMillis()-startTime;

}

private void updateResultTextView(final String content){



ReflectionPerformanceActivity.this.runOnUiThread(new Runnable(){





@Override





public void run(){







mExecuteResultTxtView.append(content);







mExecuteResultTxtView.append("\n");





}



});

}}

测试成果如下

 

反射机能测试成果

测试结论

反射的 确会导致机能问题;

反射导致的 机能问题是否严重跟应用的 次数有关系,假如控制在100次以内,根本上没什么差别,假如调用次数跨越了100次,机能差别会很明显;

四种拜访方法,直接拜访实例的 方法效力最高;其次是直接调用办法的 方法,耗时约为直接调用实例的 1.4倍;接着是经由过程反射拜访实例的 方法,耗时约为直接拜访实例的 3.75倍;最慢的 是经由过程反射拜访办法的 方法,耗时约为直接拜访实例的 6.2倍;

反射到底慢在哪?

  跟踪源码可以发明,四个办法中都存在实例化ProgramMonkey的 代码,所以可以清除是这句话导致的 不合调用方法产生的 机能差别;经由过程反射调用办法中调用了setAccessible办法,但该办法纯粹只是设置属性值,不会产生明显的 机能差别;所以最有可能产生机能差别的 只有getMethod和getDeclaredField、invoke和set办法了。
 

下面分别就这两组办法进行测试,找到具体慢在哪?


  起首测试invoke和set办法,修改getReflectCallMethodCostTime和getReflectCallFieldCostTime办法的 代码如下



private long getReflectCallMethodCostTime(int count){



long startTime = System.currentTimeMillis();



ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);



Method setmLanguageMethod = null;



try{





setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);





setmLanguageMethod.setAccessible(true);



}catch(NoSuchMethodException e){





e.printStackTrace();



}



for(int index = 0 ; index < count; index++){





try{







setmLanguageMethod.invoke(programMonkey, "Java");





}catch(IllegalAccessException e){







e.printStackTrace();





}catch(InvocationTargetException e){







e.printStackTrace();





}



}



return System.currentTimeMillis()-startTime;

}

private long getReflectCallFieldCostTime(int count){



long startTime = System.currentTimeMillis();



ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);



Field ageField = null;



try{





ageField = programMonkey.getClass().getDeclaredField("mLanguage");



}catch(NoSuchFieldException e){





e.printStackTrace();



}



for(int index = 0 ; index < count; index++){





try{







ageField.set(programMonkey, "Java");





}catch(IllegalAccessException e){







e.printStackTrace();





}



}



return System.currentTimeMillis()-startTime;

}

  Java反射教程沿用上面的 测试办法,测试成果如下

 

invoke和set

  修改getReflectCallMethodCostTime和getReflectCallFieldCostTime办法的 代码如下,对getMethod和getDeclaredField进行测试

private long getReflectCallMethodCostTime(int count){

long startTime = System.currentTimeMillis();

ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);

for(int index = 0 ; index < count; index++){



try{





Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);



}catch(NoSuchMethodException e){





e.printStackTrace();



}

}

return System.currentTimeMillis()-startTime;}private long getReflectCallFieldCostTime(int count){

long startTime = System.currentTimeMillis();

ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);

for(int index = 0 ; index < count; index++){



try{





Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");



}catch(NoSuchFieldException e){





e.printStackTrace();



}

}

return System.currentTimeMillis()-startTime;}

  沿用上面的 测试办法,测试成果如下
 

getMethod和getDeclaredField

测试结论

getMethod和getDeclaredField办法会比invoke和set办法耗时;

跟着测试数量级越年夜,机能差别的 比例越趋于稳定;

  因为测试的 这四个办法最终调用的 都是native办法,无法进一步跟踪。小我猜测应当是和在法度榜样运行时操作class有关,比如须要断定是否安然?是否许可如许操作?入参是否精确?是否可以或许在虚拟机中找到须要反射的 类?主如果这一系列断定前提导致了反射耗时;也有可能是因为调用natvie办法,须要应用JNI接口,导致了机能问题(参照Log.java、System.out.println,都是调用native办法,反复调用多次耗时很明显)。

假如避免反射导致的 机能问题,广州java培训Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。?

  经由过程上面的 测试可以看出,过多地应用反射,的 确会存在机能问题,但假如应用合适,所谓反射导致机能问题也就不是问题了,关于反射对机能的 影响,参照下面的 应用原则,并不会有什么明显的 问题

不要过于频繁地应用反射,年夜量地应用反射会带来机能问题;

经由过程反射直接拜访实例会比拜访办法快很多,所以应当优先采取拜访实例的 方法。

跋文

  上面的 测试并不周全,但在必定程度上可以或许反应出反射的 确会导致机能问题,也可以或许年夜概知道是哪个处所导致的 问题。假如后面有须要进一步测试,我会从下面几个方面作进一步测试

测试频繁调用native办法是否会有明显的 机能问题;

测试同一个办法内,过多的 前提断定是否会有明显的 机能问题;

测试类的 复杂程度是否会对反射的 机能有明显影响。
以上就是小编为年夜家带来的 Java反射教程,欲望对年夜家有所赞助。

读完这篇文章后,您心情如何?
0
0
0
0
0
0
0
0
本文网址:
下一篇:没有资料
技术支持:FXTCopyright @ 长春维鸿东光电子器材有限公司