精华内容
下载资源
问答
  • 这里不谈反射的概念和基本用法,仅仅就我遇到的ERP系统中,有哪些地方用到了反射,是如何用的。 1 操作对象的属性或方法 Get/Set property and invoke method 通过反射调用,代码中很容易形成抽象化的公共...

    反射Reflection,MFC时代叫RTTI(Runtime Type Identification) 运行时类型识别,提供一种动态创建对象的能力。

    这里不谈反射的概念和基本用法,仅仅就我遇到的ERP系统中,有哪些地方用到了反射,是如何用的。

     

    1  操作对象的属性或方法  Get/Set property and invoke method

    通过反射调用,代码中很容易形成抽象化的公共代码,比如,系统中很多地方,直接用反射对对象赋值,参考:

    ReflectionHelper.SetPropertyValue(salesOrder, "OrderAmount", 3123.54);

    这样直接给销售订单的订单金额赋值3123.54,也可以调用方法:

    ReflectionHelper.InvokeMethod(license, "VerifyExpiredDate");

    2  调用功能  Execute function

    ERP系统中的每个功能对应一个类型定义,用一个特性FunctionCodeAttribute标识出来,参考下面的代码定义。

    [FunctionCode("ICIMSR")]
    public partial class InventoryReceipt :Foundation.Forms.EntryForm
    {
            private IInventoryMovementManager _inventoryMovementManager;
            private InventoryMovementEntity _inventoryMovement;  

    运行时通过遍历程序集中类型有加FunctionCodeAttribute特性的,即可找到这个功能对应的类型,实例化类型即可。

    public void OpenFunctionForm(string functionCode)
    {
            functionCode = functionCode.ToUpper().Trim();
            Type formBaseType = null;
                
            if (!_formBaseType.TryGetValue(functionCode, out formBaseType))
            {
                    Assembly assembly = Assembly.GetExecutingAssembly();
                    foreach (Type type in assembly.GetTypes())
                    {
                        try
                        {
                            object[] attributes = type.GetCustomAttributes(typeof(FunctionCode), true);
                            foreach (object obj in attributes)
                            {
                                FunctionCode attribute = (FunctionCode)obj;
                                if (!string.IsNullOrEmpty(attribute.Value))
                                {
                                    if (!_formBaseType.ContainsKey(attribute.Value))
                                        _formBaseType.Add(attribute.Value, type);
    
                                    if (formBaseType == null && attribute.Value.Equals(functionCode,StringComparison.InvariantCultureIgnoreCase))
                                        formBaseType = type;
                                }
    
                                if (formBaseType != null)
                                {
                                    goto Found;                               
                                }
                            }
    
                        }
                        catch
                        {
    
                        }
                    }
                }
                Found:
                if (formBaseType != null)
                {
                    object entryForm = Activator.CreateInstance(formBaseType) as Form;
                    Form functionForm = (Form)entryForm;
                    OpenFunctionForm(functionForm);
                }
    
            }

    这个用法就是.NET反射实现插件化应用程序的例子。


    3  简化重复代码  Avoid duplicate code

    比如一个考勤系统中,定义8个时间点,字段名称依次是T1Begin, T2End,T2Begin,T2End,T3Begin,T3End,T4Begin,T4End。在使用这8个变量的时候,可以在系统中直接调用逐个上述字段,也可以用一个循环语句完成调用,参考下面的代码:

    ShiftEntity shift.... 
    for (int shiftIndex = 1; shiftIndex <= 4; shiftIndex++)
    {
           
         object  begin=   ReflectionHelper.GetPropertyValue(shift, string.Format("T{0}Begin", shiftIndex));
         object  end=     ReflectionHelper.GetPropertyValue(shift, string.Format("T{0}End", shiftIndex));

    如代码中所示,使用反射方法获取对象的值,节省了一部分代码,代码的可维护性也好一点。

     

    再参看下面的ERP自定义字段的例子,供应商表(Vendor)表增加20个自定义字段,SQL语句看起来是这样的:

    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_1] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_2] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_3] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_4] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_5] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_6] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_7] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_8] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_9] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_10] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_11] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_12] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_13] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_14] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_15] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_16] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_17] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_18] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_19] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
    ALTER TABLE Vendor ADD  COLUMN [USER_DEFINED_FIELD_20] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL

    我用反射调用这些属性,参考下面的代码,简洁容易理解:

    for (int i = 1; i <= 20; i++)
    {
         string fieldName = string.Format("UserDefinedField{0}", i);
         decimal fieldValue = (decimal) ReflectionHelper.GetPropertyValue(vendor, fieldName);
         amount += fieldValue;
    }

     

    再举一个数据读取的例子,先参考下面的硬编码的例子程序。

    System.DateTime start = DateTime.Now;
    System.Data.IDataReader dr = GetData(recordCount);
    while (dr.Read())
    {
          CustomTypes.Employees newEmployee =  new CustomTypes.Employees();
          newEmployee.Address = dr["Address"].ToString();
          newEmployee.BirthDate = DateTime.Parse(dr["BirthDate"].ToString());
          newEmployee.City = dr["City"].ToString();
          newEmployee.Country = dr["Country"].ToString();
          newEmployee.EmployeeID = Int32.Parse(dr["EmployeeID"].ToString());
          newEmployee.Extension = dr["Extension"].ToString();
          newEmployee.FirstName = dr["FirstName"].ToString();
          newEmployee.HireDate = DateTime.Parse(dr["HireDate"].ToString());
          newEmployee.LastName = dr["LastName"].ToString();
          newEmployee.PostalCode = dr["PostalCode"].ToString();
          newEmployee.Region = dr["Region"].ToString();
          newEmployee.ReportsTo = Int32.Parse(dr["ReportsTo"].ToString());
          newEmployee.Title = dr["Title"].ToString();
          newEmployee.TitleOfCourtesy = dr["TitleOfCourtesy"].ToString();
          pgbHardCodedConversion.Increment(1);
    }
    dr.Close();

    如果用反射,参考一下代码例子:

    List<Employees>  employee= MapDataToBusinessEntityCollection<Employees>(sqlDataReader);
    public static List<T> MapDataToBusinessEntityCollection<T>  (IDataReader dr)  where T : new()
    {
      Type businessEntityType = typeof (T);
      List<T> entitys = new List<T>();
      Hashtable hashtable = new Hashtable();
      PropertyInfo[] properties = businessEntityType.GetProperties();
      foreach (PropertyInfo info in properties)
      {
          hashtable[info.Name.ToUpper()] = info;
      }
      while (dr.Read())
      {
          T newObject = new T();
          for (int index = 0; index < dr.FieldCount; index++)
          {
              PropertyInfo info = (PropertyInfo)  hashtable[dr.GetName(index).ToUpper()];
              if ((info != null) && info.CanWrite)
              {
                  info.SetValue(newObject, dr.GetValue(index), null);
              }
          }
          entitys.Add(newObject);
      }
      dr.Close();
      return entitys;
    }
     

    一对一比较没有看出优势,但是如果有很多个数据读取器读取数据转化为实体对象集合,则只需要像上面那样一句话调用,代码可复用,开发效率相当高。

     

    4  运行时绑定 Runtime bind

    需要设计一个水晶报表查看器,它不依赖于具体的水晶报表运行库,编译时完全不知道是在引用水晶报表,运行时检测环境安装的水晶报表版本,调用相应类型的水晶报表运行库。

    object subreports = ReflectionHelper.GetPropertyValue(reportDocument, "Subreports");
    IEnumerator subreportEnumerator = (IEnumerator)ReflectionHelper.InvokeMethod(subreports, "GetEnumerator");
    while (subreportEnumerator.MoveNext())
    {
           object subreport = subreportEnumerator.Current;
           string reprotName = (string)ReflectionHelper.GetPropertyValue(subreport, "Name");
           if (string.Compare(reprotName, subreportName, true) == 0)
           {
                return subreport;
           }
    }
     

    反射中类型都是object,所以foreach操作需要变成方法调用。

    当需要延迟绑定类型时,代码可以考虑用反射编程。虽然书写代码和调试困难,但是运行时灵活,可适应性好。
     

    5  从资源文件或内存中创建类型实例  Invoke method from embeded  resouces

    当.NET程序集不是以编译时添加引用的方式引用,则可以用反射调用这些程序集中的方法。比如我将程序集编译完成后,以嵌入式资源文件的形式附加到主程序中,主程序要能调用嵌入的资源文件程序集,必须用反射调用。

    Assembly library = Assembly.Load("License");
    Type type = library.GetType("License.ErpLicense");
    object empLicense= ReflectionHelper.CreateObjectInstance(type);
    ReflectionHelper.InvokeMethod(empLicense, "VerifyLicense"); 
     

    6  检测环境 Environment detection

    这个和第4步的用意一样,凡是不能在编译时确定引用到的类型,运行时只有用反射尝试调用引用它的类型。以水晶报表环境检测的例子,需要从高版本到低版本逐个遍历,直到找到合适的版本。

    以下是水晶报表运行库检测代码片段。

    CrystalReportVersion? nullable = null;
    ArrayList list = null;
    if (supportedVersions == null)
    {
        list = new ArrayList(Enum.GetValues(typeof(CrystalReportVersion)));
    }
    else
    {
        list = new ArrayList(supportedVersions);
    }
    list.Sort();
    for (int i = list.Count - 1; i >= 0; i--)
    {
         CrystalReportVersion crystalReportVersion = (CrystalReportVersion) list[i];
         try
         {
              if (IsCrystalReportInstalled(crystalReportVersion, false))
              {
                    nullable = new CrystalReportVersion?(crystalReportVersion);
                    break;
                 }
            }
            catch
            {
            }
    }
    if (!nullable.HasValue)
    {
       throw new ApplicationException("Crystal Reports runtime is not installed");
    }

    我们要检测系统是否安装特定系统的运行库,先尝试以反射的方式创建这个类型的实例,如果返回空对象,则有可能表示未安装系统运行库。

    7  克隆对象 Clone object

    .NET中克隆/复制一个对象,能够以序列化的方式做深拷贝(Deep copy)实现,参考下面的代码例子。

    EntityCollection collection = ...
    byte[] bytes = Serialize(collection);
    EntityCollection receiptCollection = (EntityCollection)Deserialize(bytes);
    
    public static object Deserialize(byte[] buffer)
    {
            BinaryFormatter binaryF = new BinaryFormatter();
            MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length, false);
            object obj = binaryF.Deserialize(ms);
            ms.Close();
            return obj;
    }
    
    public static byte[] Serialize(object obj)
    {
            BinaryFormatter binaryF = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            binaryF.Serialize(ms, obj);
            ms.Seek(0, SeekOrigin.Begin);
            byte[] buffer = new byte[(int)ms.Length];
            ms.Read(buffer, 0, buffer.Length);
            ms.Close();
            return buffer;
    }

    代码中的receiptCollection和collection是指向两块不同的内存地址,也就是改变一个对象的值不会影响另一个对象。

    这种复制对象的方法要求原对象的类型与新的对象的类型完全一样,否则会抛出类型异常。

    有时候我们需要另外一种复制,将一个对象中的属性值,复制到另一个对象中去,举例子说明:

    销售订单SalesOrder有OrderNo, OrderDate, CustomerNo三个属性,销售订单修改SalesOrderAmendment也有

    OrderNo, OrderDate, CustomerNo三个属性,当我们想做销售订单的修改业务,需要根据销售订单创建销售订单修改单,可以用下面的方法:

    SalesOrder  salesOrder...
    SalesOrderAmendment  orderAmendment=new  SalesOrderAmendment();
    orderAmendment.OrderNo=salesOrder.OrderNo;
    orderAmendment.OrderDate=salesOrder.OrderDate;
    orderAmendment.CustomerNo=salesOrder.CustomerNo;

    标准的销售订单实体可能有50个以上的属性,则上面的赋值代码需要重复很多次。借助于反射,用一句话完成相同属性的赋值,参考下面的代码:

    SalesOrder  salesOrder...
    SalesOrderAmendment  orderAmendment=new  SalesOrderAmendment();
    CopyObjectFieldValue(salesOrder,orderAmendment);
    
    public static void CopyObjectFieldValue(IEntity2 sourceEntity, IEntity2 targetEntity)
    {
          BindingFlags flags = (BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Static |
                    BindingFlags.NonPublic | BindingFlags.Public);
    
           CopyObjectFieldValue(sourceEntity, targetEntity, flags);
    }

    也就是说反射可以将两个对象的公共属性的值,从一个对象复制到另一个对象,这在ERP的单据复制,单据下推等功能中有重要的作用,节省了大量的重复性代码。

    在对象赋值的过程中,要考虑对象为可空类型或泛型的情况。比如整数类型与可空的整数类型,是可以相互赋值的,但是在反射中,我们需要取它的原生类型,参考下面的例子代码。

    Type dataType = column.DataType;
    if (ReflectionHelper.IsNullable(dataType))
          dataType = ReflectionHelper.GetUnderlyingTypeOf(dataType);

     

    对象之间的赋值操作也不复杂,参考下面的代码,无非是获取属性,设置属性值。

    public  void CopyTo(object sourceObject, object targetObject)
    {
      object[] value = new object[1];
      Type sourceType = sourceObject.GetType();
      Type targetType = targetObject.GetType();
    
      LoadProperties(sourceObject, sourceType);
      LoadProperties(targetObject, targetType);
      List<PropertyInfo> sourcePoperties =  Properties[sourceType.FullName] as List<PropertyInfo>;
      List<PropertyInfo> targetProperties = Properties[targetType.FullName] as List<PropertyInfo>;
    
      foreach (PropertyInfo sourceProperty in sourcePoperties)
      {
          PropertyInfo targetPropertyInfo = targetProperties.
              Find(delegate(PropertyInfo prop)
               { return prop.Name == sourceProperty.Name ; });
          if (sourceProperty.CanRead)
          {
              if (targetPropertyInfo.CanWrite)
              {
                  value[0] = sourceProperty.GetValue(sourceObject, BindingFlags.Public, null, null, null);
                  targetPropertyInfo.SetValue(targetObject, value, null);
              }
          }
      }
    }
     

    8 预加载类型 Preload type

    通过在系统启动时预先创建对象的实例(通常是一些控件),如果稍后执行的界面功能中用到这些控件时,界面的响应速度会快一些,参考下面的代码例子加深印象。

    public void PreloadAssemblyType()
    {
        LoadAssembly("Foundation.Component", "Foundation.WinUI.Image");
        LoadAssembly("Foundation.Component", "Foundation.WinUI.GroupBox");
        LoadAssembly("Foundation.Component", "Foundation.WinUI.Label");
        LoadAssembly("Foundation.Component", "Foundation.WinUI.Button");

    LoadAssembly的程序代码如下,仅仅是创建对象的实例:

    private static void LoadAssembly(string assemblyName, string className)
    {
         object obj2 = null;
         try
         {
             obj2 = ReflectionHelper.CreateObjectInstance(assemblyName, className);
         }
         catch
         {
         }
         finally
         {
             obj2 = null;
             GC.Collect();
          }
    }
     

    9 类型转换与赋值  Convert type and its value

    反射应用于类型转化的例子,比较合理的一个例子是将List<T>转化为DataTable,或是将DataTable转化为List<T>。

    public static DataTable ToDataTable<T>(this IEnumerable<T> varlist)
    {
       DataTable dtReturn = new DataTable();
       PropertyInfo[] oProps = null;
    
       if (varlist == null) return dtReturn;
        foreach (T rec in varlist)
        {
           if (oProps == null)
           {
               oProps = ((Type) rec.GetType()).GetProperties();
               foreach (PropertyInfo pi in oProps)
               {
                Type colType = pi.PropertyType;
                if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof (Nullable<>)))
                {
                    colType = colType.GetGenericArguments()[0];
                }
    
                 dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
             }
           }
    
            DataRow dr = dtReturn.NewRow();
            foreach (PropertyInfo pi in oProps)
            {
                dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue(rec, null);
             }
             dtReturn.Rows.Add(dr);
          }
          return dtReturn;
    }
     

    仅仅获取类型的公共属性,再复制到另一个对象中,抽象的代码通用性也高。

    10 测试 Test

    实际环境中,有些类型所依赖的环境是不容易测试的,可以考虑用反射创建一些fake值,注入到要测试的类型中。

    这样可以让难以模拟测试的类型,通过测试。

    技术水平有限,写的不对的地方请多指正。

    转载于:https://www.cnblogs.com/JamesLi2015/p/4672321.html

    展开全文
  • JAVA 反射机制是在运行状态中,对于任意一个类,能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射...

    反射机制介绍

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

    获取 Class 对象的两种方式

    如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了三种方式获取 Class 对象:

    1.知道具体类的情况下可以使用:

    Class alunbarClass = TargetObject.class;
    

    但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象

    2.通过 Class.forName()传入类的路径获取:

    Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
    

    3.通过对象实例instance.getClass()获取:

    Employee e;
    Class alunbarClass2 = e.getClass();
    

    代码实例

    简单用代码演示一下反射的一些操作!

    1.创建一个我们要使用反射操作的类 TargetObject:

    package cn.javaguide;
    
    public class TargetObject {
        private String value;
    
        public TargetObject() {
            value = "JavaGuide";
        }
    
        public void publicMethod(String s) {
            System.out.println("I love " + s);
        }
    
        private void privateMethod() {
            System.out.println("value is " + value);
        }
    }
    

    2.使用反射操作这个类的方法以及参数

    package cn.javaguide;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Main {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
            /**
             * 获取TargetObject类的Class对象并且创建TargetObject类实例
             */
            Class<?> tagetClass = Class.forName("cn.javaguide.TargetObject");
            TargetObject targetObject = (TargetObject) tagetClass.newInstance();
            /**
             * 获取所有类中所有定义的方法
             */
            Method[] methods = tagetClass.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println(method.getName());
            }
            /**
             * 获取指定方法并调用
             */
            Method publicMethod = tagetClass.getDeclaredMethod("publicMethod",
                    String.class);
    
            publicMethod.invoke(targetObject, "JavaGuide");
            /**
             * 获取指定参数并对参数进行修改
             */
            Field field = tagetClass.getDeclaredField("value");
            //为了对类中的参数进行修改我们取消安全检查
            field.setAccessible(true);
            field.set(targetObject, "JavaGuide");
            /**
             * 调用 private 方法
             */
            Method privateMethod = tagetClass.getDeclaredMethod("privateMethod");
            //为了调用private方法我们取消安全检查
            privateMethod.setAccessible(true);
            privateMethod.invoke(targetObject);
        }
    }
    

    输出内容:

    publicMethod
    privateMethod
    I love JavaGuide
    value is JavaGuide
    

    注意 : 有读者提到上面代码运行会抛出 ClassNotFoundException 异常,具体原因是你没有下面把这段代码的包名替换成自己创建的 TargetObject 所在的包 。

    Class<?> tagetClass = Class.forName("cn.javaguide.TargetObject");
    

    静态编译和动态编译

    • 静态编译: 在编译时确定类型,绑定对象
    • 动态编译: 运行时确定类型,绑定对象

    反射机制优缺点

    • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
    • 缺点: 1,性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。

    反射的应用场景

    反射是框架设计的灵魂

    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

    举例:

    1. 我们在使用 JDBC 连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;
    2. Spring 框架的 IOC(动态加载管理 Bean)创建对象以及 AOP(动态代理)功能都和反射有联系;
    3. 动态配置实例的属性;

    推荐阅读

    1. Java反射使用总结
    2. Reflection:Java 反射机制的应用场景
    3. Java 基础之—反射(非常重要)
    展开全文
  • java反射机制是在运行状态中,对于任意一个类,能够知道这个类的所有属性和方法;对于任意一个对象,能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 ...

    java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

     

    静态编译:在编译时确定类型,绑定对象。

    动态编译:在运行时确定类型,绑定对象。

     

    反射机制的优缺点:

    优点:运行期类型的判断,动态加载类,提高代码灵活度。

    缺点:性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

     

    反射的应用场景

    反射是框架设计的灵魂。

    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

    举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性。

    转载于:https://www.cnblogs.com/wylwyl/p/10244860.html

    展开全文
  • JAVA 反射机制是在运行状态中,对于任意一个类,能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射...

    反射机制介绍

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

    获取 Class 对象的四种方式

    如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了四种方式获取 Class 对象:

    1.知道具体类的情况下可以使用:

    Class alunbarClass = TargetObject.class;
    

    但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象,通过此方式获取Class对象不会进行初始化

    2.通过 Class.forName()传入类的路径获取:

    Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
    

    Class.forName(className)方法,内部实际调用的是一个native方法 forName0(className, true, ClassLoader.getClassLoader(caller), caller);

    第2个boolean参数表示类是否需要初始化,Class.forName(className)默认是需要初始化。

    一旦初始化,就会触发目标对象的 static块代码执行,static参数也会被再次初始化。

    3.通过对象实例instance.getClass()获取:

    Employee e = new Employee();
    Class alunbarClass2 = e.getClass();
    

    4.通过类加载器xxxClassLoader.loadClass()传入类路径获取

    class clazz = ClassLoader.LoadClass("cn.javaguide.TargetObject");
    

    通过类加载器获取Class对象不会进行初始化,意味着不进行包括初始化等一些列步骤,静态块和静态对象不会得到执行

    代码实例

    简单用代码演示一下反射的一些操作!

    1.创建一个我们要使用反射操作的类 TargetObject

    package cn.javaguide;
    
    public class TargetObject {
        private String value;
    
        public TargetObject() {
            value = "JavaGuide";
        }
    
        public void publicMethod(String s) {
            System.out.println("I love " + s);
        }
    
        private void privateMethod() {
            System.out.println("value is " + value);
        }
    }
    

    2.使用反射操作这个类的方法以及参数

    package cn.javaguide;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Main {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
            /**
             * 获取TargetObject类的Class对象并且创建TargetObject类实例
             */
            Class<?> tagetClass = Class.forName("cn.javaguide.TargetObject");
            TargetObject targetObject = (TargetObject) tagetClass.newInstance();
            /**
             * 获取所有类中所有定义的方法
             */
            Method[] methods = tagetClass.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println(method.getName());
            }
            /**
             * 获取指定方法并调用
             */
            Method publicMethod = tagetClass.getDeclaredMethod("publicMethod",
                    String.class);
    
            publicMethod.invoke(targetObject, "JavaGuide");
            /**
             * 获取指定参数并对参数进行修改
             */
            Field field = tagetClass.getDeclaredField("value");
            //为了对类中的参数进行修改我们取消安全检查
            field.setAccessible(true);
            field.set(targetObject, "JavaGuide");
            /**
             * 调用 private 方法
             */
            Method privateMethod = tagetClass.getDeclaredMethod("privateMethod");
            //为了调用private方法我们取消安全检查
            privateMethod.setAccessible(true);
            privateMethod.invoke(targetObject);
        }
    }
    
    

    输出内容:

    publicMethod
    privateMethod
    I love JavaGuide
    value is JavaGuide
    
    

    注意 : 有读者提到上面代码运行会抛出 ClassNotFoundException 异常,具体原因是你没有下面把这段代码的包名替换成自己创建的 TargetObject 所在的包 。

    Class<?> tagetClass = Class.forName("cn.javaguide.TargetObject");
    

    静态编译和动态编译

    • 静态编译: 在编译时确定类型,绑定对象
    • 动态编译: 运行时确定类型,绑定对象

    反射机制优缺点

    • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
    • 缺点: 1,性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。

    反射的应用场景

    反射是框架设计的灵魂。

    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

    举例:

    1. 我们在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序;
    2. Spring 框架的 IOC(动态加载管理 Bean)创建对象以及 AOP(动态代理)功能都和反射有联系;
    3. 动态配置实例的属性;

    作者:Snailclimb
    链接:什么是反射机制?反射机制的应用场景有哪些?
    来源:github

    展开全文
  • JAVA反射机制是在运行状态中,对于任意一个类,能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。...
  • 不知道多少次听说过了Java反射机制的使用,比如:Spring 框架如何实例化IoC容器中的Bean,编码...在运行状态中,对于任意一个类,能够获取到这个类的所有属性和方法,对于任意一个对象,能够调用它的任意一个方...
  • 反射机制介绍JAVA 反射机制是在运行状态中,对于任意一个类,能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java ...
  • 反射都有哪些常用API?从本文开始我们将系统的介绍Java中反射技术。Java反射学习系列教程主要内容:​本文主要内容:一:什么是反射?二:反射的特点是什么?一:Java中反射是什么反射中的反怎么理解既然有反射及反...
  • 运行时类型识别(Run-time Type Identification, RTTI)主要有两种方式,一种是我们在编译时和运行时已经知道了所有的类型,另外一种是功能...类是程序的重要组成部分,每个类都有一个Class对象,每当编写并编译了一个...
  • Java基础入门要学哪些?怎么掌握反射和枚举?Java是老牌编程语言,是一种可以撰写跨平台应用软件的面向对象的程序设计语言。...反射可以将字节码文件封装成对象,并将字节码文件中的内容封装成对象,这样...
  • 这一篇主要讲反射都有哪些方法,了解了这些基本的方法就对java中的反射有了一些基本的概念了,不至于看源码或这是别人封装的通用代码摸不着头脑,下面先贴出需要引用的类。这个是Person类 作为User的父类,用来展示...
  • 反射

    2020-12-01 08:53:48
    有哪些应用?4.什么是反射机制?5.哪里用到反射机制?6.反射机制的优缺点? 反射 概念: 反射机制是在运行状态中,对于任意一个类,能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意一个...
  • 我们在上一篇文章中给...首先我们给大家介绍一下大数据的第三阶段,第三阶段就是前端框架,这个阶段还是很简单的,需要学习的内容还是挺多的,比如Java、Jquery、注解反射一起使用,XML以及XML解析、解析dom4j、jx...
  • 可能的情况:从一个类继承,从一个或多...GetInterfaces方法来取得类实现了哪些接口。 测试代码如下: 类库代码: using System; namespace GetInterface {    public class Class1 : Class2,Ba
  • 个人的代码风格不一样,写代码的时候会条件反射般的遵守着自己的习惯,甚至是强迫症般的存在。那你要那些强迫症一样的独特习惯呢?比如:频繁Ctrl+S,方括号圆括号必须对齐,tab和空格不能混用...... ...
  • 筒灯在日常生活中极为常见,筒灯的特点有哪些?今日就由PChouse为你一一解答。筒灯一般装设在卧室、客厅、卫生间的周边天棚上。这种嵌装于天花板内部的隐置性灯具,所有光线向下投射,属于直接配光。可以用不同的...
  • 都有哪些映射形式? 第一种是使用标签,逐一定义数据库列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列的别名书写为对象属性名。 有了列名与属性名的映射关系后,Mybatis通过反射创建对象, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 616
精华内容 246
关键字:

反射都有哪些