java反射如何优化_Java反射性能优化(上)

反射是一种很重要的技术,然而它与直接调用相比性能要慢很多,因此如何优化反射性能也就成为一个不得不面对的问题。 目前最常见的优化反射性能的方法就是采用委托:用委托的方式调用需要反射调用的方法(或者属性、字段)。

那么如何得到委托呢? 目前最常见也就是二种方法:Emit, ExpressionTree 。其中ExpressionTree可认为是Emit方法的简化版本, 所以Emit是最根本的方法,它采用在运行时动态构造一段IL代码来包装需要反射调用的代码, 这段动态生成的代码满足某个委托的签名,因此最后可以采用委托的方式代替反射调用。

用Emit方法优化反射

如果我们需要设计自己的数据访问层,那么就需要动态创建所有的数据实体对象,尤其是还要为每个数据实体对象的属性赋值, 这里就要涉及用反射的方法对属性执行写操作,为了优化这种反射场景的性能,我们可以用下面的方法来实现:

public delegate voidSetValueDelegate(objecttarget, objectarg);

public static classDynamicMethodFactory{

public staticSetValueDelegateCreatePropertySetter(PropertyInfoproperty)

{

if( property ==null)

throw newArgumentNullException("property");

if( !property.CanWrite )

return null;

MethodInfosetMethod =property.GetSetMethod(true);

DynamicMethoddm =newDynamicMethod("PropertySetter", null,

newType[] { typeof(object), typeof(object) },

property.DeclaringType, true);

ILGeneratoril =dm.GetILGenerator();

if( !setMethod.IsStatic ) {

il.Emit(OpCodes.Ldarg_0);

}

il.Emit(OpCodes.Ldarg_1);

EmitCastToReference(il, property.PropertyType);

if( !setMethod.IsStatic && !property.DeclaringType.IsValueType ) {

il.EmitCall(OpCodes.Callvirt, setMethod, null);

}

elseil.EmitCall(OpCodes.Call, setMethod, null);

il.Emit(OpCodes.Ret);

return(SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));

}

private static voidEmitCastToReference(ILGeneratoril, Typetype)

{

if( type.IsValueType )

il.Emit(OpCodes.Unbox_Any, type);

elseil.Emit(OpCodes.Castclass, type);

}

}

现在可以用下面的测试代码检验委托调用带来的性能改进:

Console.WriteLine(System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion());

intcount =1000000;

OrderInfotestObj =newOrderInfo();

PropertyInfopropInfo =typeof(OrderInfo).GetProperty("OrderID");

Console.Write("直接访问花费时间: ");

Stopwatchwatch1 =Stopwatch.StartNew();

for( inti =0; i

testObj.OrderID =123;

watch1.Stop();

Console.WriteLine(watch1.Elapsed.ToString());

SetValueDelegatesetter2 =DynamicMethodFactory.CreatePropertySetter(propInfo);

Console.Write("EmitSet花费时间: ");

Stopwatchwatch2 =Stopwatch.StartNew();

for( inti =0; i

setter2(testObj, 123);

watch2.Stop();

Console.WriteLine(watch2.Elapsed.ToString());

Console.Write("纯反射花费时间:  ");

Stopwatchwatch3 =Stopwatch.StartNew();

for( inti =0; i

propInfo.SetValue(testObj, 123, null);

watch3.Stop();

Console.WriteLine(watch3.Elapsed.ToString());

Console.WriteLine("-------------------");

Console.WriteLine("{0} / {1} = {2}",

watch3.Elapsed.ToString(),

watch1.Elapsed.ToString(),

watch3.Elapsed.TotalMilliseconds /watch1.Elapsed.TotalMilliseconds);

Console.WriteLine("{0} / {1} = {2}",

watch3.Elapsed.ToString(),

watch2.Elapsed.ToString(),

watch3.Elapsed.TotalMilliseconds /watch2.Elapsed.TotalMilliseconds);

Console.WriteLine("{0} / {1} = {2}",

watch2.Elapsed.ToString(),

watch1.Elapsed.ToString(),

watch2.Elapsed.TotalMilliseconds /watch1.Elapsed.TotalMilliseconds);

我用VS2008 (.net 3.5 , CLR 2.0) 测试可以得到以下结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值