Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我可以提供一个接口来允许另一个类让我访问它的私有变量吗?_Java_Reflection_Encapsulation_Api Design - Fatal编程技术网

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

Java 我可以提供一个接口来允许另一个类让我访问它的私有变量吗?,java,reflection,encapsulation,api-design,Java,Reflection,Encapsulation,Api Design,首先,澄清一下:所谓“接口”,我指的是组件之间的任何交互点,不一定是“抽象类型”的接口。(虽然如果我能使用这样的界面来实现这一点,那就太好了。) 我正在写一个扩展类。问题域是全局优化,因此任何将我的类划分为子类的最终用户程序员(我称他们为Steve)都将提供他们自己的问题和算法来解决它;我只提供框架(网络、用户界面等)。Steve的程序可能需要任意数量的配置设置;我希望我的代码能够像从GUI控制面板、XML配置文件或其他任何地方获取设置一样,从用户那里获取这些设置。Steve不应该复制我的任何代

首先,澄清一下:所谓“接口”,我指的是组件之间的任何交互点,不一定是“抽象类型”的接口。(虽然如果我能使用这样的界面来实现这一点,那就太好了。)

我正在写一个扩展类。问题域是全局优化,因此任何将我的类划分为子类的最终用户程序员(我称他们为Steve)都将提供他们自己的问题和算法来解决它;我只提供框架(网络、用户界面等)。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()
,并识别具有
可配置
注释的字段。然后,它会将用户输入写入这些字段。它不必看起来完全像这样,有注释等等,但是你明白了

当然,这方面的问题是
foo
bar
是私有的,
MyFrameworkClass
中的代码不能写入它们,甚至不能反射。如果它们是包私有的,那就没用了,因为Steve的代码不会和我的代码在同一个包中,我不希望他将它们公开,或者添加任何其他接口,允许除我之外的任何人访问这些字段


有没有什么方法可以实现我想要的,或者通过摆弄
SecurityManager
或者做一些完全不同的事情?

您可以使用
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才能做到这一点。默认情况下是这样,但这可能不适用于所有用户。如果这是一个禁止性要求,那么还有其他不太方便但可能更健壮的选项(比如要求构造函数获取配置对象,然后用户可以从中获取值)

  • 创建一个配置接口

    interface Configuration
    {
        int foo ( ) ;
    
        String bar ( ) ;
    }
    
    public class SteveClass extends MyFrameworkClass {
        private Configuration configuration ;
    
        // implementations of my abstract methods, etc.
    
    }
    
  • 使用配置界面

    interface Configuration
    {
        int foo ( ) ;
    
        String bar ( ) ;
    }
    
    public class SteveClass extends MyFrameworkClass {
        private Configuration configuration ;
    
        // implementations of my abstract methods, etc.
    
    }
    

  • 我想这就是所谓的委托。

    如果我处在您的位置,我会试图找到一种方法来使用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提供了大量其他工具来帮助他构建应用程序,但这是另一个问题。

    使用映射存储参数和列表存储变量名如何?您可以直接使用地图(迭代并获取参数,或者你可以有一个包含参数名的列表,然后在映射中获取/设置这些变量。@Manishharma类型安全。这些参数不会都是相同的类型,因此它必须是对象的映射,每次使用它们时都会进行类型转换。这会变得很麻烦,而且不是一个非常干净的解决方案。我们e
    protected
    关键字。它允许访问不在同一个包中的子类…这可能会起作用。我不知道当超类试图使用反射来访问子类的受保护字段时JVM会怎么想。@Dunes不幸的是,
    protected
    只允许子类继承(而不是直接访问)一个超类成员,这不是我在这里需要的。原则上,我不反对通过另一个对象传递数据。但是我可以用类型安全的方式来做吗?看起来我仍然有同样的问题。这取决于类型安全的含义。你可以有不同的方法--
    Configuration.getInt(“foo”)
    配置.getString(“bar”)
    并在配置不正确时引发异常。您还可以提供一个带注释的公共静态方法,返回一个映射。这并不能解决我的问题,因为我没有指定扩展类的人所指定的配置变量。当然,幕后Spring使用的是yshavit提到的技术。但这使它们易于使用。我对此并不熟悉。我会研究一下。@Taymon:我应该提到的是,我对GUI配置的工作原理不太了解;现在我倾向于编写服务器端软件,因为没有交互显示…