Java Reflection to set attributes

2020-02-14 07:57发布

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!

3条回答
祖国的老花朵
2楼-- · 2020-02-14 08:18

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.

查看更多
劫难
3楼-- · 2020-02-14 08:30

I think I may be overthinking this problem (i.e., I shouldn't be using reflection to set variables in this way)

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

  1. You should consider whether all the fields should be mutable. (Do you really need setters?)
  2. Whether the fields should even be visible. (Do you need any accessors at all?)

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.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2020-02-14 08:37
  1. When they are private you need to call fld.setAccessible(true);
  2. Yes, why don't you just set the fields directly and avoid reflection? It doesn't look like you're doing anything dynamic. It's just that they are private -- why? Perhaps you mean to expose getters/setters and make the fields private? If so, then you should just invoke the public setters.
查看更多
登录 后发表回答