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

通过反射获取Java字段,而不是从其字符串名称获取,java,reflection,floating-point,field,primitive,Java,Reflection,Floating Point,Field,Primitive,如果我有字段本身,是否可以通过Java反射获得字段?这是一个原始的浮动(公共的,没问题)。我不想将其名称用作字符串 例如: public class TVset { public float voltageA; public float voltageB; public float voltageC; public TVset(...) {...} // constructor public void function() {...} // it changes voltag

如果我有字段本身,是否可以通过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(tv2.voltageA);
有可能通过反射来实现吗


Thx要使用反射,必须使用字符串。您可以使用对象包装可变浮点或简单浮点[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);
编辑:使用抽象访问器。这是最快的方法。好吧,相差不到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],而不是使用浮点

顺便说一句,除非你们有很好的理由,否则我不会使用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);
编辑:使用抽象访问器。这是最快的方法。好吧,相差不到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; }
  }
}

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

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


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

如果您控制电视机,但出于某种原因需要使用反射,避免错误的一个好方法是将所需的方法/字段名作为字符串常量写入TVSet类


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

为了完整起见,我已经包含了解决此问题的委托方法。我也不建议让你的花车公开

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

为了完整起见,我加入了解决这个问题的代理方法。我也不建议让你的花车公开

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

这里是一个变体,您可以使用
浮点值而不是字符串

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);
  }
}
只有当电压表创建瞬间的电压不同(而不是NaN)时,它才起作用,因为它使用正确值的第一个字段。我认为这并不是真的更有效


我真的不建议这样做。

这里有一个变体,您可以给您的
浮点值而不是字符串

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);
  }
}
只有当电压表创建瞬间的电压不同(而不是NaN)时,它才起作用,因为它使用正确值的第一个字段。我认为这并不是真的更有效


我真的不建议这样做。

你能详细说明一下“我不想使用字符串”吗?我只是觉得写新的电压表(tv2,“voltageA”)很难看,因为我确切地知道TVset中的字段是什么,我可以写新的(tv2.voltageA)。另外,如果我无意中写了新的(tv2.vltageA),编译器会在运行前对我大喊大叫。你能详细解释一下“我不想使用字符串”吗?我只是觉得写新的伏特计(tv2,voltageA)很难看,因为我确切地知道TVset中的字段是什么,我可以写新的(tv2.voltageA)。另外,如果我无意中编写了新代码(tv2.vltageA),编译器会在运行前对我大喊大叫。但这不会带来性能损失吗?TVset对象每秒需要进行数百万次电压更新。这就是我使用基本浮点的原因(精度不是问题)。它比使用反射要小得多。如果需要,每秒可以执行1亿次更新。如果希望避免使用数组,可以使用抽象访问器类。这个抽象访问器类是如何工作的?请举个例子好吗?谢谢你的耐心。(顺便说一句,我意识到最初的问题非常愚蠢,因为当tv1.voltageA作为一个参数传递时,它已经被解析为一个普通浮点,因此接收方类无法知道它来自何处。)啊哈。谢谢你的例子。本质上,它的工作原理类似于Andrew Finnell的委托解决方案,但不是将访问器作为伏特计构造函数的参数当场构建,而是建议在TVset本身内部预构建所有这些访问器。很好。唯一(绝对次要)的缺点是,对于我决定添加到电视机中的每个新voltageX,我需要记住构建相应的访问器。但那绝对没问题。太多了!但这不会带来性能惩罚吗?TVset对象每秒需要进行数百万次电压更新。这就是我使用基本浮点的原因(精度不是问题)。它比使用反射要小得多。如果需要,每秒可以执行1亿次更新。如果希望避免使用数组,可以使用抽象访问器类。这个抽象访问器类是如何工作的?请举个例子好吗?谢谢你的耐心。(顺便说一句,我意识到最初的问题非常愚蠢,因为当tv1.voltageA作为一个参数传递时,它已经被解析为一个普通浮点,因此接收方类无法知道它来自何处。)啊哈。谢谢你的例子。本质上,它的工作原理类似于Andrew Finnell的委托解决方案,但不是将访问器作为伏特计构造函数的参数当场构建,而是建议在TVset本身内部预构建所有这些访问器。很好。唯一(绝对次要)的缺点是,对于每一个新的电压X,我决定添加到电视机中