有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java从包外部获取对字段的packagelevel访问权限?

我使用的API有一个抽象类,我希望扩展它(在我的具体类中),以便利用父类中的一些方法。不幸的是,该API类的程序员决定只使用一个字段,而不使用公共setter为其提供包级访问。而是在方法中设置字段值。是否有一个通用的“桥接模式”,以便我可以适当地获取/设置该字段?这不仅对我的功能很重要,对测试也很重要(因为我需要模拟测试中在该字段中设置的值)。谢谢


共 (4) 个答案

  1. # 1 楼答案

    如果您对SecurityManager有控制权,或者没有适当的位置,则可以使用反射使字段可访问,然后更改其值

    示例代码:

    import java.lang.reflect.Field;
    
    public class ModifyProtectedFieldSample {
    
        public static void setProtectedField(final Object targetClass,
                                         final String fieldName,
                                         final Object value) {
        try {
            final Field field = targetClass.getClass().getDeclaredField(fieldName);
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
    
            field.set(targetClass, value);
        } catch (NoSuchFieldException e) {
            System.out.println("NoSuchFieldException " + e);
        } catch (SecurityException e) {
            System.out.println("SecurityException"+ e);
        } catch (IllegalAccessException e) {
            System.out.println("IllegalAccessException"+ e);
        }
      }
    
      public static void main(final String[] args) {
        setProtectedField(String.class, "someFieldName", Boolean.FALSE);
      }
    }
    
  2. # 2 楼答案

    一些可能性:

    • 获取并修改“API”的源代码

    • 在同一个包中编写一个类来偷偷访问并公开所需的字段

    • 围绕API的类编写一个包装器,提供对该字段的访问,并提供您喜欢的任何更改的语义

    • 使用反射来破坏API类的访问保护

  3. # 3 楼答案

    如果可以,可以在原始包中创建API类的子类,并公开该字段。如果您无法做到这一点,那么您可能会使用反射来修改字段的值,假设您的SecurityManager配置为允许这样做,但这感觉有点像代码的味道

  4. # 4 楼答案

    您必须使用反射来设置字段。为了设置该字段,您需要对其调用setAccessible。我尚未对此进行测试,但类似于以下内容的内容应该可以工作:

    ClassWithProtectedField o = new ClassWithProtectedField();
    Class c = o.getClass();
    java.lang.reflect.Field protectedField = c.getField("protectedField");
    protectedField.setAccessible(true);
    protectedField.set(o, someValue);
    

    http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Field.html