簡體   English   中英

為什么 java 允許這樣做?

[英]why does java allow this?

這樣做在語法上是合法的:

String [] s = new String[1];
Object [] o = s;

o[0] = new Integer(42);

但當然它會在運行時崩潰。

我的問題是:首先允許這項任務有什么意義?

問題是賦值Object [] o = s; - 我想這就是你所說的“這個”。

技術術語是數組協方差,如果沒有它,您將無法擁有處理 arrays 的代碼。 例如, java.util.Arrays中的大多數非原始數組方法都是無用的,因為您只能將它們與實際的Object[]實例一起使用。 顯然,Java 的設計者認為這比完整的類型安全更重要。

當您查看在 Java 5 中引入的 Java 的 generics 時,您會看到另一種解決方案:通過通配符顯式協方差。 但是,這會導致相當大的復雜性(請參閱關於?通配符的問題的常量 stream),Java 的原始設計者希望避免復雜性。

允許這種分配的重點是不允許它會使以下事情變得不可能:

ArrayList[] lists = new ArrayList[10];
lists[0] = new ArrayList();

List[] genericLists = lists;
lists[0].add("someObject");

如果編譯器禁止您的 String -> Object 情況,那么它還必須禁止 ArrayList -> List 以及從子類分配給其超類類型之一的任何其他實例。 這使得諸如 Java 之類的面向對象語言的許多特性變得毫無用處。 當然,更典型的做法是:

List[] lists = new List[10];
lists[0] = new ArrayList();
lists[0].add("someObject");

但無論如何,編譯器無法過濾掉這些情況,同時不允許許多有用且合法的用例,因此程序員有責任確保他們所做的事情是理智的。 如果你想要的是一個Object[] ,那么就這樣聲明你的變量。 如果您將某些內容聲明為String[] ,將其轉換為Object[] ,然后忘記您真正擁有的是String[] ,那么這只是程序員錯誤。

這是不允許的,運行該代碼時會出現java.lang.ArrayStoreException: java.lang.Integer

編譯器允許這樣做,因為您將 String[] 轉換為 Object[],這是正確的。 這類似於

Integer i = new Integer(10);
Object o = i;
String s = (String) o;

編譯器不會抱怨,但您會在運行時獲得 ClassCastExeption。

編譯器無法知道(沒有 static 分析) o實際上是一個String[] ,因此即使它在運行時失敗也允許賦值。 沒有什么可以阻止將例如Integer[]分配給o ,它只是不會發生。

必須允許賦值,因為編譯器無法推斷數組在運行時是否只保存(或不保存)字符串。 它拋出一個[ArrayStoreException][1]在運行時檢查。

考慮一下:

String [] s = new String[1];
Object [] o = s;

o = new Integer[1];

o[0] = new Integer(1);

這種情況是有效的並且運行正常。 為了提供更廣泛的視角,恕我直言,Arrays 是 Java 中的低級泄漏抽象。

通常,編譯器無法判斷o是否已分配為String[] 考慮一下:

String[] s = new String[1];
Object[] o;

if (complexFunction(System.currentTimeMillis())) {
  o = s;
} else {
  o = new Integer[1];
}

o[0] = 42;

編譯器在設計時不會知道o將采用什么類型 - 所以它只允許賦值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM