通过反射获取 Java 字段,而不是通过其 String 名称

发布于 2024-10-25 04:17:22 字数 1201 浏览 7 评论 0原文

如果我有字段本身,是否可以通过Java反射获取字段?这是一个原始的浮动(公共,没问题)。我不想将其名称用作字符串。

示例:

public class TVset {
  public float voltageA;
  public float voltageB;
  public float voltageC;
  public TVset(...) {...} // constructor
  public void function() {...} // it changes voltages
}

class Voltmeter{
  Object theObject;
  Field theField;

  Voltmeter(Object obj) {
    theObject = obj;
    Class theFieldClass = obj.getClass();
    Class theContainerClass = theFieldClass.getDeclaringClass();
    Field theField = ??? // <-- here I don't want to use a String
  }

  float getVoltage() {
    return theField.getFloat(theObject);
  }
}

TVset tv1 = new TVset(...);
TVset tv2 = new TVset(...);

Voltmeter meter = new Voltmeter(tv1.voltageB);
meter.getVoltage();
tv1.function();
meter.getVoltage(); <- should reflect the changed voltage
tv1.function();
meter.getVoltage(); <- should reflect the changed voltage
...

效果类似于通过引用传递浮点数,但不将其包装到包装类中。

我需要测量不同电视机上的不同电压,只需将行:更改

Voltmeter meter = new Voltmeter(tv1.voltageB);

为其他内容,例如:

Voltmeter meter = new Voltmeter(tv2.voltageA);

是否可以通过反射来做到这一点?

谢谢

Is it possible to get a Field through Java reflection if I have the field itself? It's a primitive float (public, no problem). I don't want to use its name as a String.

Example:

public class TVset {
  public float voltageA;
  public float voltageB;
  public float voltageC;
  public TVset(...) {...} // constructor
  public void function() {...} // it changes voltages
}

class Voltmeter{
  Object theObject;
  Field theField;

  Voltmeter(Object obj) {
    theObject = obj;
    Class theFieldClass = obj.getClass();
    Class theContainerClass = theFieldClass.getDeclaringClass();
    Field theField = ??? // <-- here I don't want to use a String
  }

  float getVoltage() {
    return theField.getFloat(theObject);
  }
}

TVset tv1 = new TVset(...);
TVset tv2 = new TVset(...);

Voltmeter meter = new Voltmeter(tv1.voltageB);
meter.getVoltage();
tv1.function();
meter.getVoltage(); <- should reflect the changed voltage
tv1.function();
meter.getVoltage(); <- should reflect the changed voltage
...

The effect is similar to passing the float by reference, but without wrapping it into a wrapper class.

I need to measure different voltages on different TV sets, just by changing the line:

Voltmeter meter = new Voltmeter(tv1.voltageB);

to something else, like:

Voltmeter meter = new Voltmeter(tv2.voltageA);

Is it possible to do it with reflection?

Thx

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

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

发布评论

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

评论(4

相思碎 2024-11-01 04:17:22

要使用反射,您必须使用字符串。您可以使用对象来包装可变浮点或简单的浮点[1],而不是使用浮点;

顺便说一句,除非你有充分的理由,否则我不会使用 float,double 的舍入误差要小得多。

public class TVset {
  public double[] voltageA = { 0.0 };
  public double[] voltageB = { 0.0 };
  public double[] voltageC = { 0.0 };
}

class Voltmeter{
  final double[] theField;

  Voltmeter(double[] theField) {
    this.theField = theField;
  }

  double getVoltage() {
    return theField[0];
  }
}
// works just fine.
Voltmeter meter = new Voltmeter(tv1.voltageB);

编辑:使用抽象访问器。这是最快的方法。 AFAIK,差异小于 10 纳秒。

public abstract class Voltmeter{ // or use an interface
  public abstract double get();
  public abstract void set(double voltage);
}

public class TVset {
  private double _voltageA = 0.0;
  private double _voltageB = 0.0;
  private double _voltageC = 0.0;
  public final Voltmeter voltageA = new Voltmeter() {
     public double get() { return _voltageA; }
     public void set(double voltage) { _voltageA = voltage; }
  }
  public final Voltmeter voltageB = new Voltmeter() {
     public double get() { return _voltageB; }
     public void set(double voltage) { _voltageB = voltage; }
  }
  public final Voltmeter voltageC = new Voltmeter() {
     public double get() { return _voltageC; }
     public void set(double voltage) { _voltageC = voltage; }
  }
}

就我个人而言,如果速度至关重要,我会直接按名称使用字段。没有比这更简单或更快的了。

To use reflection you have to use a String. Instead of using a float you can use an object to wrap mutable float or a simple float[1];

BTW I wouldn't use float unless you have a really good reason, double suffers far less rounding error.

public class TVset {
  public double[] voltageA = { 0.0 };
  public double[] voltageB = { 0.0 };
  public double[] voltageC = { 0.0 };
}

class Voltmeter{
  final double[] theField;

  Voltmeter(double[] theField) {
    this.theField = theField;
  }

  double getVoltage() {
    return theField[0];
  }
}
// works just fine.
Voltmeter meter = new Voltmeter(tv1.voltageB);

EDIT: Using an abstract accessor. This is the fastest way to do this. AFAIK,the difference is less than 10 nano-seconds.

public abstract class Voltmeter{ // or use an interface
  public abstract double get();
  public abstract void set(double voltage);
}

public class TVset {
  private double _voltageA = 0.0;
  private double _voltageB = 0.0;
  private double _voltageC = 0.0;
  public final Voltmeter voltageA = new Voltmeter() {
     public double get() { return _voltageA; }
     public void set(double voltage) { _voltageA = voltage; }
  }
  public final Voltmeter voltageB = new Voltmeter() {
     public double get() { return _voltageB; }
     public void set(double voltage) { _voltageB = voltage; }
  }
  public final Voltmeter voltageC = new Voltmeter() {
     public double get() { return _voltageC; }
     public void set(double voltage) { _voltageC = voltage; }
  }
}

Personally, if speed is critical, I would just use the fields directly by name. You won't get simpler or faster than that.

海螺姑娘 2024-11-01 04:17:22

为了完整起见,我添加了解决此问题的委托方法。我也不建议让您的花车可供公众使用。

public class stackoverflow_5383947 {

    public static class Tvset {

        public float voltageA;
        public float voltageB;
        public float voltageC;

        public Tvset() {
        }

        public void function() {
            voltageA++;
        }
    };

    public static class Voltmeter {

        private VoltageDelegate _delegate;

        public Voltmeter(VoltageDelegate delegate) {
            _delegate = delegate;
        }

        float getVoltage() {
            return _delegate.getVoltage();
        }
    };

    public static interface VoltageDelegate {

        public float getVoltage();
    }   

    public static void main(String[] args) {
        final Tvset tv1 = new Tvset();
        Voltmeter meter = new Voltmeter(new VoltageDelegate()   {
            public float getVoltage() {
                return tv1.voltageA;
            }
        });

        System.out.println(meter.getVoltage());
        tv1.function();
        System.out.println(meter.getVoltage());
        tv1.function();
        System.out.println(meter.getVoltage());
    }
}

Just for completeness I've included the delegate way of solving this. I would also not recommend having your floats with public access.

public class stackoverflow_5383947 {

    public static class Tvset {

        public float voltageA;
        public float voltageB;
        public float voltageC;

        public Tvset() {
        }

        public void function() {
            voltageA++;
        }
    };

    public static class Voltmeter {

        private VoltageDelegate _delegate;

        public Voltmeter(VoltageDelegate delegate) {
            _delegate = delegate;
        }

        float getVoltage() {
            return _delegate.getVoltage();
        }
    };

    public static interface VoltageDelegate {

        public float getVoltage();
    }   

    public static void main(String[] args) {
        final Tvset tv1 = new Tvset();
        Voltmeter meter = new Voltmeter(new VoltageDelegate()   {
            public float getVoltage() {
                return tv1.voltageA;
            }
        });

        System.out.println(meter.getVoltage());
        tv1.function();
        System.out.println(meter.getVoltage());
        tv1.function();
        System.out.println(meter.getVoltage());
    }
}
極樂鬼 2024-11-01 04:17:22

如果您控制 TVSet 但由于某种原因需要使用反射,避免错误的一个好方法是将您需要的方法/字段名称编写为 TVSet 类中的字符串常量。

但是,如果您关心的是性能,那么反射就不是最佳选择,因为通过反射访问字段或方法可能比通过 getter 或直接访问慢得多。

If you control the TVSet but need to use reflection for some reason, a good way to avoid errors is to write the method/field names that you need as String Constants in the TVSet class.

However if your concern is performance, reflection is not the way to go because accessing a field or method through reflection can be much slower than accessing through getters or directly.

a√萤火虫的光℡ 2024-11-01 04:17:22

这是一个变体,您可以在其中提供 float 值而不是字符串。

class Voltmeter{
  Object container;
  Field theField;

  Voltmeter(Object obj, float currentValue) {
    container = obj;
    Class<?> containerClass = obj.getClass();
    Field[] fields = containerClass.getFields();
    for(Field f : fields) {
       if (f.getType() == float.class &&
           f.getFloat(container) == currentValue) {
          this.theField = f;
          break;
       }
    }
  }

  float getVoltage() {
    return theField.getFloat(container);
  }
}

然后这样调用它:

Voltmeter meter = new Voltmeter(tv1, tv1.voltageB);

仅当电压表创建时的电压不同(而不是 NaN)时它才起作用,因为它采用具有正确值的第一个字段。我认为这并没有真正提高效率。

我真的不会推荐这个。

Here a variant where you can give your float value instead of a string.

class Voltmeter{
  Object container;
  Field theField;

  Voltmeter(Object obj, float currentValue) {
    container = obj;
    Class<?> containerClass = obj.getClass();
    Field[] fields = containerClass.getFields();
    for(Field f : fields) {
       if (f.getType() == float.class &&
           f.getFloat(container) == currentValue) {
          this.theField = f;
          break;
       }
    }
  }

  float getVoltage() {
    return theField.getFloat(container);
  }
}

Then call it like this:

Voltmeter meter = new Voltmeter(tv1, tv1.voltageB);

It works only if the voltages in the moment of Voltmeter creation are different (and not NaN), as it takes the first Field with the right value. And it is not really more efficient, I think.

I wouldn't really recommend this.

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