用类似访问文件系统路径的方式访问Java类的内部成员

比如有类如下:

class NotifySettings
{
   public NotifySettings()
   {
      notifyParams = new NotifyParams();
   }

   public String notifierClassName;
   NotifyParams notifyParams;
}

class NotifyParams
{
   public NotifyParams()
   {
   }

   public String address;
   private int port;
   protected boolean enabled;
}

现有NotifySettings类的对象settings,若想访问 settings.notifyParams.port,由于port是私有成员,所以无法用直接引用port的方式来访问port成员。利用java的反射机制就可以做到这一点。下面的程序可以用类似文件系统路径的方式指定访问类中的成员,例如,用“notifyParams\port”指定访问settings对象的notifyParams成员的port成员。

import java.lang.reflect.Field;

public class LearnRefelct
{
   public LearnRefelct()
   {
   }

   /**
    * 从指定的对象中获取由path指定的成员的值。
    * 
    * @param obj 需要获取成员值的对象
    * @param path 指定成员在对象中的路径。例如需要获取对象中a成员的b成员的c成员的值,则path应该设置为"a\b\c"
    * @return 指定成员的值。若取值失败或成员值为空,则返回null。
    */
   public Object getValue(Object obj, String path)
   {
      Object value;
      Field field = getField(obj, path, false);     // 获取由path指定的字段对象
      if (field != null)
      {
         Field ownerField = getField(obj, path, true);     // 获取path指定的字段的上级字段
         try
         {
            Object ownerObject;
            if (ownerField == null)      // 若无上级字段,则该字段为顶层字段,因此上级对象即是obj
            {
               ownerObject = obj;
            }
            else
            {
               ownerObject = ownerField.get(obj);
            }

            field.setAccessible(true); // 用于获取私有成员的访问权
            value = field.get(ownerObject);
         } catch (IllegalArgumentException | IllegalAccessException e)
         {
            value = null;
            e.printStackTrace();
         }
      }
      else
      {
         value = null;
      }

      return value;
   }

   /**
    * 设置对象的由path指定的成员的值
    * 
    * @param obj 待设定值的对象
    * @param path 成员的路径字符串。例如需要获取对象中a成员的b成员的c成员的值,则path应该设置为"a\b\c"
    * @param value 成员的设定值
    * @return 若设定成功,则返回真;否则返回假。
    */
   public boolean setValue(Object obj, String path, Object value)
   {
      boolean success;
      Field field = getField(obj, path, false);     // 获取由path指定的字段对象

      if (field != null)
      {
         Field ownerField = getField(obj, path, true);     // 获取path指定的字段的上级字段
         try
         {
            Object ownerObject;
            if (ownerField == null)      // 若无上级字段,则该字段为顶层字段,因此上级对象即是obj
            {
               ownerObject = obj;
            }
            else
            {
               ownerObject = ownerField.get(obj);
            }
            field.setAccessible(true); // 用于获取私有成员的访问权
            field.set(ownerObject, value);      // 设置字段的值
            success = true;
         } catch (IllegalArgumentException | IllegalAccessException e)
         {
            success = false;
            e.printStackTrace();
         }
      }
      else
      {
         success = false;
      }

      return success;
   }

   /**
    * 获取类的指定的成员对象或其上级对象的字段定义。
    * 
    * @param obj 待获取成员的类对象
    * @param path 成员在类中的路径
    * @param getOwner 是否获取path指定的对象的上级对象
    * @return 指定的对象成员的定义
    */
   Field getField(Object obj, String path, boolean getOwner)
   {
      String[] fieldNames = path.split(splitter);  // 分割字段
      int deep = fieldNames.length;
      if (getOwner)
      {
         deep --;
      }

      Field field = null;
      Object subObj = obj;
      for(int index = 0; index < deep; index ++)
      {
         try
         {
            if (subObj != null)
            {
               field = subObj.getClass().getDeclaredField(fieldNames[index]);
               field.setAccessible(true);
               subObj = field.get(subObj);
            }
         } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e)
         {
            field = null;
            e.printStackTrace();
         }
      }

      return field;
   }

   /**
    * 获得指定对象的成员定义
    * 
    * @param obj 待获取成员的类对象
    * @param path 成员在类中的路径
    * @return 指定的对象成员的定义
    */
   Field getField(Object obj, String path)
   {
      Field field = getField(obj, path, false);
      return field;
   }

   /**
    * 获取指定对象的上级对象的定义
    * 
    * @param obj 待获取成员的类对象
    * @param path 成员在类中的路径
    * @return 指定的对象成员的上级成员对象的定义
    */
   Field getOwnerField(Object obj, String path)
   {
      Field field = getField(obj, path, true);
      return field;
   }

   public void run()
   {
      NotifySettings settings = new NotifySettings();

      setValue(settings, "notifierClassName", "org.opensource.loader");
      String className = (String)getValue(settings, "notifierClassName");
      System.out.println("class: " + className);

      setValue(settings, "notifyParams\\address", "192.168.0.1");
      String address = (String)getValue(settings, "notifyParams\\address");
      System.out.println("address: " + address);

      setValue(settings, "notifyParams\\port", 8080);
      int port = ((Integer)getValue(settings, "notifyParams\\port")).intValue();
      System.out.println("port: " + port);

      setValue(settings, "notifyParams\\enabled", true);
      boolean enabled = ((Boolean)getValue(settings, "notifyParams\\enabled")).booleanValue();
      System.out.println("enabled: " + enabled);
   }

   public static void main(String[] args)
   {
      LearnRefelct lr = new LearnRefelct();
      lr.run();
   }

   private static String splitter = "\\\\";
}

上面的代码中,splitter的值可以任意指定,例如可以设定成“:”,那么访问方式为notifyParams:port;若splitter为“.”,则访问方式为"notifyParams.port"。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值