将原语的动态列表传递给Java方法



我需要将原语的动态列表传递给Java方法。可以是(int, int, float)或者(double, char)等等。我知道那是不可能的,所以我在想解决这个问题的有效方法。

因为我正在Android上开发一款游戏,我希望尽可能避免垃圾收集,所以我不想使用任何对象(例如因为自动装箱),而只想使用原始数据类型。因此,在我的例子中,原始类对象的集合或数组(例如Integer)不是一个选项。

所以我在考虑是否可以将一个类对象传递给我的方法,它将包含我需要的所有基本值。然而,这并不能解决我的问题,因为如前所述,原语列表是可变的。因此,如果我在我的方法中这样做,我就不知道如何访问这个动态的原语列表(至少不需要任何对象转换,这是我想要避免的)。

现在我觉得有点迷路了。我不知道在Java中如何解决我的问题的任何其他可能的方法。我希望那只是我缺乏知识。你们中有谁知道没有对象转换的解决方案吗?

提供更多的上下文并解释您想使用此技术的确切目的可能会很有用,因为这可能是决定最佳方法所必需的。

从概念上讲,您正在尝试在任何在托管堆栈上传递参数的语言中总是困难的事情。你希望可怜的编译器做什么?它可以让你在堆栈上推入任意数量的参数,并通过一些堆栈指针算术来访问它们(在C中很好,可以让你随心所欲地使用指针,在Java这样的托管语言中就不那么好了),或者它需要传递对其他地方存储的引用(这意味着分配或某种形式的缓冲区)。

幸运的是,在Java中有几种方法可以有效地传递原语参数。以下是我列出的最有前途的方法,大致是您应该考虑的顺序:

  • 重载 -有多个方法,具有不同的基本参数来处理所有可能的组合。如果参数相对较少,可能是最好/最简单/最轻量级的选择。性能也很好,因为编译器会静态地计算出要调用哪个重载方法。
  • 原始数组 -传递任意数量的原始参数的好方法。请注意,您可能需要保留一个原始数组作为缓冲区(否则您将不得不在需要时分配它,这违背了避免分配的目标!)。如果你使用部分填充的原始数组,你还需要向数组传递偏移量和/或计数参数。
  • 传递带有原语字段的对象 -如果原语字段集事先相对已知,则效果良好。请注意,您还必须保留一个类的实例来充当缓冲区(否则您将不得不在需要时分配它,这违背了避免分配的目标!)。
  • 使用专门的原始集合库 -例如Trove库。出色的性能,并且节省了编写大量代码的时间,因为这些库通常都是经过良好设计和维护的。如果这些原语的集合是长期存在的,这是一个很好的选择,也就是说,你不是纯粹为了传递一些参数而创建集合。
  • NIO Buffers—在性能方面大致相当于使用数组或原语集合。它们有一点开销,但如果您出于其他原因需要NIO缓冲区,则可能是更好的选择(例如,如果在使用相同缓冲区类型的网络代码或3D库代码中传递原语,或者如果需要将数据传递给本机代码)。它们还可以为您处理偏移量和计数,这可能会有所帮助。
  • 代码生成 -编写代码,为专门的基本方法生成适当的字节码(提前或动态)。这并不适合胆小的人,但却是获得绝对最佳性能的一种方法。您可能想使用像ASM这样的库,或者选择一种可以轻松地为您生成代码的JVM语言(Clojure)。

根本没有。在方法中拥有变量参数的唯一方法是使用...操作符,该操作符不支持原语。所有泛型也只支持原语。

我唯一能想到的就是这样一个类:

class ReallyBadPrimitives {
    char[] chars;
    int[] ints;
    float[] floats;
}

并在添加时调整数组的大小。但这是非常非常糟糕的,因为你基本上失去了系统中所有的参照完整性。

我不会担心垃圾收集——如果有必要,我会使用对象和自动装箱来解决你的问题(或者更好的是,避免这种"未知的输入参数集",并得到一个可靠的协议)。一旦你有了一个工作原型,看看你是否遇到了性能问题,然后,然后做出必要的调整。您可能会发现JVM处理这些对象的能力比您最初想象的要好。

尝试使用...运算符:

static int sum (int ... numbers)
        {
           int total = 0;
           for (int i = 0; i < numbers.length; i++)
                total += numbers [i];
           return total;
        }

您可以使用BitSet类似于c++位字段。http://docs.oracle.com/javase/1.3/docs/api/java/util/BitSet.html

您也可以将所有原语转换为double,然后只需传递double数组。唯一的技巧是你不能使用boolean类型。

不,像sum(int…数字)不会自动框整型。它会创建一个int[]来保存它们,所以会有一个对象分配;但它不会是per int

public class VarArgs {
    public static void main(String[] args) {
        System.out.println(variableInts(1, 2));
        System.out.println(variableIntegers(1, 2, 3));
    }   
    private static String variableInts(int... args) {
        // args is an int[], and ints can't have getClass(), so this doesn't compile
        // args[0].getClass();
        return args.getClass().toString() + " ";
    }   
    private static String variableIntegers(Integer... args) {
        // args is an Integer[], and Integers can have getClass()
        args[0].getClass();
        return args.getClass().toString();
    }   
}
输出:

class [I 
class [Ljava.lang.Integer;

最新更新