2011-12-02 41 views
2

我需要将基元的动态列表传递给Java方法。这可能是(int,int,float)或(double,char)或其他。我知道这是不可能的,所以我正在考虑解决这个问题的有效方法。由于我在Android上开发了一款游戏,我希望尽可能避免垃圾回收,因此我不想使用任何对象(例如由于自动装箱),而只使用原始数据类型。因此,在我的情况下,原始类对象(例如Integer)的集合或数组不是一个选项。将基元的动态列表传递给Java方法

所以我想我是否可以传递一个类对象给我的方法,它将包含我需要的所有原始值。然而,这不是我的问题的解决方案,因为如上所述,基元列表是可变的。因此,如果我在我的方法中采用这种方式,那么我不知道如何访问这个原始的基元列表(至少不是没有任何转换到对象,这是我想要避免的)。

现在我觉得在这里有点失落。我不知道Java中的任何其他可能的方式如何解决我的问题。我希望这只是我缺乏知识。您是否有人知道没有与对象进行转换的解决方案?

+1

你确定你不是在你的项目太快优化? 您可以传递三种不同类型的三个数组。传递第四类型的指标。然后将值从适当的偏移量拖到该给定类型的数组中。 – Marvo

+1

坦率地说,我认为我没有尽快优化,因为我已经知道在我的项目中我必须经常调用这个方法。而且我也知道,不幸的是auto(un)boxing往往会触发垃圾收集器的方式太多。 – Matthias

+0

你能解释为什么你需要这个要求吗?我在Java中编写了很多游戏,这对我来说从未是必要的,所以我很确定有一种避免分配的解决方法。 – mikera

回答

0

根本没有。变量编号参数的唯一方法是使用不支持基元的...运算符。所有的泛型也只支持基元。

我可以这么想的唯一的事情会是这样一类:

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

而当你添加到他们调整阵列。但这是真的,真的很糟糕,因为你基本上失去了系统中的所有参照完整性。我不会担心垃圾收集 - 如果你必须(或者更好的是,避免这个“未知的输入参数集”,并得到一个可靠的协议),我会解决你的问题,使用对象和自动装箱。一旦你有一个工作原型,看看你是否遇到性能问题,并然后作出必要的调整。你可能会发现JVM可以比你原先想象的更好地处理这些对象。

+0

首先,我无法避免未知组输入参数,因为我正在编写一个框架,它必须支持一组未定义的原始值(实际上这正是本框架的目的)。其次,不幸的是我不得不担心垃圾收集。在Android 2.2之前,如果经常调用GC,GC确实会在快速OpenGL应用程序中显着降低帧速率。在我的情况下,会发生这种情况,因为在游戏中这种方法经常被称为... – Matthias

+0

@Matthias问题是,除非你编码并分析它,否则你不知道它是否是一个问题。编码应该很容易,看看它是否有问题。 – corsiKa

+0

如果我问,它是什么框架? – corsiKa

0

尝试使用...操作:

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

这将autobox整数,想避免OP。 – corsiKa

0

你也可以将所有的原始元素转换为double然后传入一个double的数组。唯一的技巧就是你不能使用boolean类型。

+0

真正可以铸造到1.0和假为0.0 =) – mishadoff

+0

当然可以。 'd == 0'为false,'d!= 0'为true。简单。 – corsiKa

+0

这是一个很好的约定,但这是: 'double doublePrimitive =(double)booleanPrimitive;' 将不会在Java 6编译。 –

0

Fwiw,类似sum(int ...数字)不会autobox整数。它会创建一个int []来保存它们,所以会有一个对象分配;但它不会是每个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; 
+0

Fwiw?那是什么? – eeerahul

+0

“为它的价值” – yshavit

1

这或许会是有用的,提供一些背景,并解释你想要什么使用这种技术,因为这将可能是必要的最佳决定做法。

从概念上讲,你正在尝试做的东西是总是难以在传递一个管理栈上参数的任何语言。你期望可怜的编译器做什么?它可以让你在堆栈上推入任意数量的参数,并通过一些堆栈指针算术来访问它们(C语言可以让你尽可能多地使用指针,在Java这样的托管语言中不是那么好),或者它会需要将参考传递到其他地方(这意味着分配或某种形式的缓冲区)。

幸运的是,有几种方法可以做到通过在Java中有效的原始参数。这是我最有前途的方法列表,大致的顺序,你应该考虑其中:

  • 超载 - 有不同的原始参数的多个方法来处理所有可能的组合。如果参数数量较少,可能会成为最好/最简单/最轻量级的选项。由于编译器会静态调出重载的方法,所以性能也很好。
  • 原始阵列 - 传递的原始参数的任意数量的好方法。请注意,您可能需要将一个基本数组保留为缓冲区(否则必须在需要时分配它,这会影响您避免分配的目标!)。如果使用部分填充的基本数组,则还需要将偏移量和/或计数参数传递到数组中。
  • 通与原始字段对象 - 工作得很好,如果一套原始字段事先比较知名。请注意,你还必须保留一个类的实例来充当缓冲区(否则你将不得不在需要的时候分配它,这会挫伤你避免分配的目标!)。
  • 使用专门的原始集合库 - 例如Trove库。良好的性能和节省你不得不编写大量的代码,因为这些通常是精心设计和维护库。如果这些基元集合将长期存在,那么这是非常好的选择,也就是说,您不是纯粹为了传递某些参数而创建集合。
  • NIO缓冲器 - 大致等同于使用阵列或集合原语在性能方面。他们有一些开销,但如果你需要NIO缓冲区出于其他原因可能是更好的选择(例如,如果基元在网络代码或使用相同缓冲区类型的3D库代码中传递,或者如果数据需要被传递给本地代码)。他们也处理抵消和计数对你有用。
  • 代码生成 - 产生用于专门原始的方法适当bytceode(无论是提前时间或动态地)写入代码。这不是为了胆小鬼,而是获得绝对最佳表现的一种方式。你可能会想要使用像ASM这样的库,或者选择一种JVM语言,可以很容易地为你生成代码(Clojure温泉记住)。
+0

感谢,尤其是最后的想法可能是有趣的。由于我正在编写一个框架,它应该并将被用于多个应用程序(这也是这个问题的原因),所以这可能是值得的。我会检查出来的! – Matthias

+0

没问题 - 只是被警告,最后一种方法很难/很复杂,没有问题。如果你不小心,它也会让你的框架的用户感到困难。确保你真的需要它,然后沿着这条路走下去! – mikera