我可以提供一个接口来允许另一个类让我访问它的私有变量吗?

发布于 2024-12-19 07:46:51 字数 1162 浏览 2 评论 0原文

首先,澄清一下:我所说的“接口”是指组件之间的任何交互点,不一定是“抽象类型”类型的接口。 (尽管如果我可以使用这样的接口来做到这一点,那就太好了。)

我正在编写一个旨在扩展的类。问题域是全局优化,因此任何对我的类进行子类化的最终用户程序员(我称他们为史蒂夫)将提供他们自己的问题和算法来解决它;我只是提供框架(网络、用户界面等)。 Steve 的程序可能需要任意数量的配置设置;我希望我的代码能够以与获取自己的设置相同的方式从用户那里获取这些设置(可以是从 GUI 控制面板、XML 配置文件或其他任何设置)。 Steve 不应该复制我的任何代码,也不应该破坏 Java 的类型安全或封装模型。

理想情况下,Steve 能够按照以下方式编写一些内容:

public class SteveClass extends MyFrameworkClass {

    @Configurable
    private int foo;

    @Configurable
    private String bar;

    private boolean baz;

    // implementations of my abstract methods, etc.

}

Configurable 是我要提供的注释,它指示带注释的变量是我应该从用户那里获取的配置设置。正如您所看到的,我还希望 Steve 能够声明其他实例变量供他自己内部使用,但我从未接触过。

我打算通过在 MyFrameworkClass 中包含一个方法来实现这一点,该方法将迭代 getClass().getDeclaredFields() 并识别具有 Configurable 的字段> 注释。然后它将用户输入写入这些字段。它不必看起来完全像这样,有注释等等,但你明白了。

当然,这样做的问题是 foobar 是私有的,MyFrameworkClass 中的代码无法写入它们,即使是反射式也是如此。如果它们是包私有的,那将无济于事,因为史蒂夫的代码不会与我的代码位于同一个包中,而且我不想要求他将它们公开,或者添加任何其他接口,允许除了我访问这些字段。

有没有办法做我想做的事情,要么通过摆弄 SecurityManager 要么做一些完全不同的事情?

First, a clarification: By "interface", I mean any point of interaction between components, not necessarily the "abstract type" kind of interface. (Although if I can use such an interface to do this, great.)

I'm writing a class which is designed to be extended. The problem domain is global optimization, so any end-user-programmer who subclasses my class (I'll call them Steve) will be providing their own problem and algorithm to solve it; I just provide the framework (networking, user interface, etc.). Steve's program might require any number of configuration settings; I want my code to be able to get those settings from the user the same way it gets its own settings (be that from a GUI control panel, an XML configuration file, or whatever). Steve should not have to duplicate any of my code, nor should he have to break Java's type safety or encapsulation model.

Ideally, Steve would be able to write something along these lines:

public class SteveClass extends MyFrameworkClass {

    @Configurable
    private int foo;

    @Configurable
    private String bar;

    private boolean baz;

    // implementations of my abstract methods, etc.

}

Configurable is an annotation that I would provide, that indicates that the annotated variable is a configuration setting that I should get from the user. As you can see, I also want Steve to be able to declare other instance variables for his own internal use, that I never touch.

I was going to implement this by including a method in MyFrameworkClass that would iterate through getClass().getDeclaredFields() and identify the fields that have Configurable annotations. It would then writes the user input to those fields. It doesn't have to look exactly like this, with annotations and all, but you get the idea.

The problem with this, of course, is that foo and bar are private and code in MyFrameworkClass can't write to them, even reflectively. It wouldn't help if they were package-private, since Steve's code won't be in the same package as mine, and I'd rather not require him to make them public, or to add any other interface that would allow anyone but me to access the fields.

Is there any way to do what I want, either by fiddling with SecurityManager or doing something completely different?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

如若梦似彩虹 2024-12-26 07:46:51

如果我处于您的位置,我会尝试找到一种使用 Spring 框架来为我完成此操作的方法。然后,用户可以这样写:

@Component
public class SteveClass {
    @Value("${steve.foo}")
    private int foo;

    @Value("${steve.bar}")
    private String bar;

    private boolean baz;

    @Autowired(required = false)
    private DaveClass dave;
}

您所要做的就是构建一个上下文,其中包含这些可用的属性;这是非常微不足道的。 (Spring 确实在安全场景后面探索,但它以“正确”的方式这样做;您需要做的就是确保 Spring 是可信的,并且代码的其余部分不需要几乎相同级别的权限.) 当然,它还为 Steve 提供了大量其他工具来帮助他构建应用程序,但这是另一个问题的故事了。

If I was in your position, I'd be trying to find a way to use the Spring framework to do this for me. That would then let users write this:

@Component
public class SteveClass {
    @Value("${steve.foo}")
    private int foo;

    @Value("${steve.bar}")
    private String bar;

    private boolean baz;

    @Autowired(required = false)
    private DaveClass dave;
}

All you'd have to do then is to build a context that has those properties available within it; that's pretty trivial. (Spring does poke around behind the security scenes, but it does so in the “correct” way; all you need to do is to ensure that Spring is trusted, and the rest of your code doesn't need nearly the same level of permissions.) Of course, it also gives Steve plenty of other tools to help him build his app, but that's a story for another question.

⊕婉儿 2024-12-26 07:46:51

您可以使用 Class.getDeclaredFields 获取类的所有声明字段(包括非公共字段),然后使用 Field.setAccessible(true) 获取对其的访问权限。

Field foo = HasPrivate.class.getDeclaredField("foo");
foo.setAccessible(true);
SteveClass steve = new SteveClass();
System.out.println(steve); // "0" -- I set up SteveClass.toString() to just print foo
foo.setInt(hp, 1234);
System.out.println(steve); // "1234"

但这意味着您依赖 SecurityManager 来允许您执行此操作。默认情况下是这样,但这可能不适用于所有用户。如果这是一个令人望而却步的要求,还有其他不太方便但可能更强大的选项(例如要求构造函数采用 Configuration 对象,然后用户可以从中获取值)。

You can use Class.getDeclaredFields to get all of the class's declared fields (including non-public ones), and then Field.setAccessible(true) to gain access to it.

Field foo = HasPrivate.class.getDeclaredField("foo");
foo.setAccessible(true);
SteveClass steve = new SteveClass();
System.out.println(steve); // "0" -- I set up SteveClass.toString() to just print foo
foo.setInt(hp, 1234);
System.out.println(steve); // "1234"

But that means you're depending on the SecurityManager to allow you to do that. It does by default, but that may not work for all users. If that's a prohibitive requirement, there are other, less convenient but potentially more robust options (like requiring that the constructor take a Configuration object, which the user can then get values from).

橘和柠 2024-12-26 07:46:51
  1. 创建配置界面

    接口配置
    {
        int foo();
    
        字符串栏 ( ) ;
    }
    
  2. 使用配置界面

    public class SteveClass 扩展 MyFrameworkClass {
        私有配置配置;
    
        // 我的抽象方法的实现等
    
    }
    

我认为这就是所谓的委托。

  1. Create a Configuration interface

    interface Configuration
    {
        int foo ( ) ;
    
        String bar ( ) ;
    }
    
  2. Use the Configuration interface

    public class SteveClass extends MyFrameworkClass {
        private Configuration configuration ;
    
        // implementations of my abstract methods, etc.
    
    }
    

I think this is called delegation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文