[英]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.