Java反射设置属性
我有一个具有许多可设置/可获取属性的类。我想使用反射来设置这些属性,但我对我的实现有两个问题
这是我的类中的一些精简代码,
class Q {
public String question_1;
public String question_2;
public String question_3;
public String answer_1;
public String answer_2;
public String answer_3;
//etc. etc. Many String attributes
// … constructor and other stuff are omitted
// here is my method for "dynamically" setting each attribute
public void set_attribute(String a_raw_string, String my_field) {
try {
Class cls = Class.forName("com.xyz.models.Q");
Field fld = cls.getField(my_field);
fld.set(this, a_raw_string);
}
catch (Throwable e) {
System.err.println(e);
}
}
然后我设置了如下所示的各种字段:
Q q = new Q();
q.set_attribute("abcde", "question_1");
q.set_attribute("defgh", "question_2");
// etc.
这有效(即,实例变量是在我调用 set_attribute 时设置的。
但是,它们仅在实例变量被声明为公共时才起作用。当它们被声明为私有时,我会得到一个 NoSuchFieldException
问题 1: 为什么这样做?当字段是私有的时,我会得到这个错误?我天真的假设是,由于 set_attribute 函数是类的一部分,它应该可以不受限制地访问实例变量。
问题 2:我想我可能是。过度思考这个问题(即,我不应该使用反射以这种方式设置变量)。 我想使用反射的原因是因为声明大量的 setter 方法是一件很痛苦的事情……所以我想知道是否有人以更好的方式解决了这个烦恼。
谢谢!
I have a class that has many settable/gettable attributes. I'd like to use reflection to set these attributes, but I have 2 questions about my implementation
Here is some stripped down code from my class
class Q {
public String question_1;
public String question_2;
public String question_3;
public String answer_1;
public String answer_2;
public String answer_3;
//etc. etc. Many String attributes
// … constructor and other stuff are omitted
// here is my method for "dynamically" setting each attribute
public void set_attribute(String a_raw_string, String my_field) {
try {
Class cls = Class.forName("com.xyz.models.Q");
Field fld = cls.getField(my_field);
fld.set(this, a_raw_string);
}
catch (Throwable e) {
System.err.println(e);
}
}
I then set various fields like this:
Q q = new Q();
q.set_attribute("abcde", "question_1");
q.set_attribute("defgh", "question_2");
// etc.
This works (i.e., the instance variables are set when I call set_attribute.
However, they only work when the instance variables are declared public. When they are declared private I get a NoSuchFieldException
QUESTION 1: Why do I get that error when the fields are private? My naive assumption is that since the set_attribute function is part of the class, it should have unfettered access to the instance variables.
QUESTION 2: I think I may be overthinking this problem (i.e., I shouldn't be using reflection to set variables in this way). Is there a more recommended approach?
The reason that I want to use reflection is because it's a pain in the ass to declare a ton of setter methods…so I'm wondering if someone has solved this annoyance in a better way.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的。反射相当慢,只能作为最后的手段使用。如果这只是为了避免出现太多冗余代码,请考虑使用自动代码生成。对于纯数据对象,我强烈建议使用协议缓冲区;它将生成 getter / setter(您只需要声明字段)。此外,它还允许在 C++、Java 和 Python 之间轻松进行数据通信。
如果您有一个包含很多字段但不是纯数据对象的类...那么
将字段设置为“final”,在构造函数中初始化它们,并通过实现的接口不提供访问或提供有限的访问通常是一个好主意。
Yep. Reflection is fairly slow and should only be used as a last resort. If this is simply to avoid having so much redundant code, consider using automatic code generation. For pure data objects, I would strongly recommend using protocol buffers; it will generate the getters / setters (you only need to declare the fields). Plus it allows for easy communication of the data between C++, Java, and Python.
If you have a class that has a lot of fields but isn't a pure data object... well
It is often a good idea to make fields "final", initialize them in the constructor(s), and provide no access or provide limited access through an implemented interface.
使用 setter 方法是为类成员变量设置值的公认方法,绝对不应该使用反射,因为代码将更难理解并且运行速度更慢。
大多数 IDE(例如 Eclipse 或 NetBeans)都包含用于自动为类的字段创建 getter 和 setter 方法的工具。
Using setter methods is the accepted way to set values for class member variables, reflection should definitely not be used for that as the code will be harder to understand and run much more slowly.
Most IDEs (eg Eclipse or NetBeans) include tools for automatically creating getter and setter methods for a class's fields.
fld.setAccessible(true);