通过反射获取Java字段,但不从其String名称获取

时间:2011-03-21 21:27:17

标签: java reflection floating-point field primitive

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

示例:

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
...

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

我需要在不同的电视机上测量不同的电压,只需更改线路:

Voltmeter meter = new Voltmeter(tv1.voltageB);

以其他方式,例如:

Voltmeter meter = new Voltmeter(tv2.voltageA);

可以用反射来做吗?

THX

4 个答案:

答案 0 :(得分:2)

要使用反射,您必须使用String。而不是使用浮点数,你可以使用一个对象来包装可变浮点数或一个简单的浮点数[1];

顺便说一句,除非你有一个很好的理由,否则我不会使用浮点数,双重遭受更少的舍入错误。

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; }
  }
}

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

答案 1 :(得分:2)

为了完整起见,我已经包含了解决此问题的代表方式。我也不建议你的花车可以公开访问。

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());
    }
}

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

这是一个变体,您可以在其中提供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)时,它才有效,因为第一个字段具有正确的值。我认为它并没有真正提高效率。

我不会真的推荐这个。