2011-12-02 54 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