参考成员按参数名称?

时间:2014-06-13 17:29:56

标签: java

假设我有这样一个类:

class ASDF {
    int a;
    int b;
    int c;
}

ASDF[] myArray;

一系列规模的ASDF。有没有办法编写一个接受ASDF成员名称和ASDF数组的函数,并对给定成员名称的所有成员求和?

即,我想要一个像这样工作的函数:

sumMember(myArray, a);

将返回所有' a'的总和。 ASDF中的成员变量。但是,有三个以上的成员变量,因此为每个变量设置一个函数并不现实。

4 个答案:

答案 0 :(得分:6)

您可以使用反射或地图或......

或者,如果你可以使用Java 8,你可以传递一个lambda来指向你感兴趣的成员。它不是你想要的那么短,但也不是太糟糕:

public static int sumMembers(ASDF[] array, ToIntFunction<ASDF> member) {
  return Arrays.stream(array).mapToInt(member).sum();
}

样品使用:

public static void main(String[] args) {
  ASDF[] array = {new ASDF(), new ASDF()};
  array[0].a = 1;
  array[1].a = 2;

  //THIS IS HOW YOU CALL IT
  int sum = sumMembers(array, a -> a.a);
}

答案 1 :(得分:1)

如果类和字段为public,那么您可以使用reflection按名称获取字段值,因此您可以编写sumMember以便

sumMember(myArray, "a");

作品。

Reflection tends to be overpowered并使用静态分析工具(如重构)进行干扰,因此您可以使用interface Getter对字段进行抽象,如

public interface Getter<V, O> {
  V get(O source);
}

public static <O>
double sumMember(Iterable<? extends O> toSum, Getter<Double, O> getter) {
  double runningSum = 0.0;
  for (O o : toSum) { runningSum += getter(toSum); }
  return runningSum;
}

然后使用它

sumMember(Arrays.asList(yourArray),  // Xlate btw array and Iterable
          new Getter<Double, ASDF>() {  // ASDF x -> x.a
            public Double get(ASDF asdf) { return asdf.a; }
          });

或使用Java8 lambda创建getter。

答案 2 :(得分:1)

将公共领域放在一个类中通常被认为是糟糕的设计实践。如果该类具有可管理的成员数,全部为int,那么最好创建字段private并为每个字段添加getter函数:

class ASDF {
    private int a;
    private int b;
    private int c;

    public int getA() {
        return a;
    }
    public int getB() { ... and so on
}

(我假设你会为这些字段提供更好的名称。)如果是这种情况,那么你可以使用Java 8的成员函数语法轻松编写sum函数,将其中一个函数作为参数:

int sumMember(ASDF[] array, toIntFunction<ASDF> func) {
    int sum = 0;
    for (ASDF element : array) {
         sum += func.applyAsInt(element);
    }
    return sum;
}

sumA = sumMember(myArray, ASDF::getA);
sumB = sumMember(myArray, ASDF::getB);

等等。 ToIntFunction位于java.util.function,其描述为here。 [另外,在assylias中使用lambda'的答案也很有效,写起来很简单;在这种情况下,你可以在没有getter函数的情况下解决它,但我仍然认为以这种方式使用公共字段是一个坏主意。]

但是,如果有大量int成员,或者您有一个类,其唯一目的是拥有多个int成员(即除了getter或setter之外没有其他方法)那么你可能不想要个别成员。相反,您需要一个使用数组或某种集合的类来保存成员,这样就可以通过String名称或其他类型的键或索引来访问成员。

答案 3 :(得分:0)

您可以使用反射按字段名称引用, 但这是一个糟糕的主意。

相反, 创建一个知道所需值的类,并将其返回到sumMember方法。

以下是一些代码:

public int sumMember(
    final ASDF[] itIsTerribleToUseArraysLikeThis
    final ValueRetriever valueRetriever)
{
    int returnValue = 0;

    for (ASDF current : itIsTerribleToUseArraysLikeThis)
    {
        returnValue += valueRetriever.getValue(current);
    }

    return returnValue;
}

public interface ValueRetriever
{
    public int getValue(ASDF structure);
}

public class AValueRetriever implements ValueRetriever
{
    public int getValue(final ASDF structure)
    {
        if (structure != null)
        {
            return structure.a;
        }
        else
        {
            return 0;
        }
    }
}

sumMember(myArray, new AValueRetriever());

注意: 你的代码在几个方面很糟糕。

  1. ASDF是一种结构。如果您使用C语言或其他非oo语言编写代码,这很好。在Java中,它很糟糕。使用对象。

  2. 传递阵列也很糟糕。 Java(和其他oo语言)提供了很好的集合实现。使用这些。查看List