【问题标题】:How do you access protected Java method in thirdparty library?如何访问第三方库中受保护的 Java 方法?
【发布时间】:2011-09-18 18:58:04
【问题描述】:

假设您必须访问您在代码中某处收到的 Java 对象的受保护方法。你的解决方案是什么?

我知道一种方法:您可以使用反射并在 Method 对象上调用 setAccessible(true)。

还有什么想法吗?

【问题讨论】:

  • 您是否在使用具有已发布 API 的库?如果是这样,请将该信息添加到问题中;你会得到更好的帮助。
  • 这不是我第一次遇到这个问题,但如果你好奇的话:Eclipse Debug Plugin、JDILocalVariable、getStackFrame。网址:docjar.com/docs/api/org/eclipse/jdt/internal/debug/core/model/…

标签: java methods protected


【解决方案1】:

另一种选择是创建一个类来扩展具有您感兴趣的受保护方法的第 3 方类。

public class ThirdPartyClass
{
   protected void foo(){}
}

public MyClass extends ThirdPartyClass
{

     public void callFoo()
     {
           foo();
     }

}

【讨论】:

  • 考虑到您收到了对象。你不能投射物体,可以吗?
  • @salman 你在编译时可以访问第三方类吗?
【解决方案2】:

您还可以扩展类,覆盖方法,并使被覆盖的方法公开。然后让它调用 super.method()。

【讨论】:

  • 考虑到您收到了对象。你不能投射物体,可以吗?
【解决方案3】:

您可以子类化方法,创建一个调用受保护方法并返回结果的公共方法。

如果你不能这样做(如果类是最终的),那么 setAccessible 几乎是你唯一的方法。

【讨论】:

  • 考虑到您收到了对象。你不能投射物体,可以吗?
  • 我假设您的意思是将其转换为另一种类型。不,您不能在运行时将对象类型(类)转换为另一种对象类型。您可以将其包装在另一个对象中,但受保护访问的问题仍然存在。此外,如果您的对象是使用 spring 或 hibernate 或任何其他使用运行时代理的框架生成的,则不能保证反射也能正常工作。目标代理不会包含任何在代理类中不公开的方法。
【解决方案4】:

另一种方法是扩展类(如果可能)并通过继承访问受保护的方法。如果您不创建对象,这是不可能的,因为您在编译时需要它,并且您需要自己创建对象。

一个狡猾的解决方案可能是使用组合。所以你在同一个包中创建一个类,例如其他对象包装器。因为它在同一个包中,所以您可以通过您公开的公共 API 调用对象的受保护方法。但不建议这样做,因为您不拥有要添加 Class 的包,并且您可以使您的代码非常脆弱,例如

package com.foo;

public class OtherObjectWrapper {
   private com.foo.OtherObject wrappedObject;

   public OtherObjectWrapper(com.foo.OtherObject wrappedObject) {
     this.wrappedObject = wrappedObject;
   }

   public void callTheProtectedMethod() {
     wrappedObject.callTheProtectedMethod();
   }
}

考虑一下 API 设计者在将方法标记为受保护时的想法?也许他们不知道自己在做什么,它应该是公开的,或者更糟糕的是,它应该是包私有或完全私有的。或者他们可能这样做了,并且他们确定只有同一包中的代码或通过继承才能访问受保护的方法。如果它受到保护,很可能是有原因的,所以要小心,因为你可能会将代码行为与可能改变和破坏代码的行为联系起来。还要看看谁拥有第三方对象,以及是否有更好的 API 来访问受保护方法的功能。

【讨论】:

  • 考虑到您收到了对象。你不能投射物体,可以吗?
【解决方案5】:

如果您可以将调用类放在同一个包中,您将可以访问该方法。 这和从该类继承是访问受保护方法的唯一非反射方式。

【讨论】:

【解决方案6】:

根据Java access modifiers,除了扩展对象(如果您收到对象,则不能)之外,还可以从与您收到的对象相同的包中的对象访问它。所以你的选择是在同一个包中创建一个包装类,它通过受保护的方法为你检索属性。

【讨论】:

    【解决方案7】:

    如前所述,子类化通常是访问该方法的标准方式。 通常不应使用其他方法(同一包中的包装器、反射),因为如果您不能扩展类(由于是最终的),通常有充分的理由很难访问该方法。

    如果库具有任何不错的质量,那么除了子类化来访问受保护的方法或根本不访问该方法之外,您绝对不必使用任何其他方式。

    【讨论】:

      【解决方案8】:

      如果一个类不是final,你可以使用匿名类来调用它的protected方法:

      new ClassWithProtectedMethod() {
          @Override
          protected void method() {
              super.method();
          }
      }.method();
      

      注意,将 method() 设为 public 是不必要的(因为新的匿名类在同一个包中)。

      【讨论】:

        猜你喜欢
        • 2019-08-18
        • 2020-07-26
        • 1970-01-01
        • 1970-01-01
        • 2018-04-20
        • 1970-01-01
        • 2012-01-12
        • 1970-01-01
        • 2011-08-14
        相关资源
        最近更新 更多