2014-09-01 51 views
3

考慮下面的代碼工作:的Java:在編譯時對象的隱式轉換不工作,但與反思

import java.lang.reflect.Array; 
import java.lang.reflect.Method; 

public class Test { 

    public static void test_function(int[] values) { 
    System.out.println("Class of values : " + values.getClass()); 
    System.out.println(values[0]); 
    } 

    public static void main(String[] args) { 

    Object a = Array.newInstance(int.class, 3); 
    Array.set(a, 0, 5); 

    Class a_class   = a.getClass(); 
    Class int_array_class = int[].class; 

    System.out.println("Class of int[] : " + int[].class); 
    System.out.println("Class of a  : " + a.getClass()); 
    System.out.println("int_array_class : " + int_array_class); 
    System.out.println("a_class   : " + a_class); 

    // These instructions will provoke a compile-time error 
    // test_function(a); 
    // test_function(a_class.cast(a)); 
    // test_function(int_array_class.cast(a)); 

    // The following call won't cause any problem 
    test_function((int[]) a); 

    Method testf = null; 
    try { 
     testf = Test.class.getMethod("test_function", int[].class); 
     testf.invoke(null, a); // Does not provoke exception at run-time either 
     testf.invoke(null, a_class.cast(a)); 
     testf.invoke(null, int_array_class.cast(a)); 
    } 
    catch(Exception e) { 
     e.printStackTrace(); 
    } 

    } 

} 

我注意到,通過明確對象的方法不起作用。這三個評論說明會招來以下錯誤,如果未加註釋:

Test.java:25: error: method test_function in class Test cannot be applied to given types; 
    test_function(a); 
    ^
    required: int[] 
    found: Object 
    reason: actual argument Object cannot be converted to int[] by method invocation conversion 
Test.java:26: error: method test_function in class Test cannot be applied to given types; 
    test_function(a_class.cast(a)); 
    ^
    required: int[] 
    found: Object 
    reason: actual argument Object cannot be converted to int[] by method invocation conversion 
Test.java:27: error: method test_function in class Test cannot be applied to given types; 
    test_function(int_array_class.cast(a)); 
    ^
    required: int[] 
    found: Object 
    reason: actual argument Object cannot be converted to int[] by method invocation conversion 
3 errors 

然而,傳遞對象通過反射做工精細,併產生預期的結果。

Class of int[] : class [I 
Class of a  : class [I 
int_array_class : class [I 
a_class   : class [I 
Class of values : class [I 
5 
Class of values : class [I 
5 
Class of values : class [I 
5 
Class of values : class [I 
5 

所以,問題是:爲什麼編譯器拒絕編譯在運行時正常工作三個commentend說明?

回答

7

Reflectional訪問能夠確定在運行時實際類型的對象的。另一方面,編譯器只知道聲明的類型。它沒有任何其他可能性來檢查實際類型的參數。

您的變量a被宣告爲Object。因此與

test_function(a); 

你試圖調用與根本不存在簽名void test_function(Object)的方法。一個簡單的演員 - 因爲你的程序員知道正確的類型 - 將幫助這裏:

test_function((int[]) a); // works fine (even at runtime) 

另外兩個方法調用是相同的,但是卻又有點不同。您聲明a_classint_array_class的類型爲Class。這是一種原始類型,因此編譯器不知道這些變量可以引用哪種類型的類。編譯器必須推斷類型Object。這導致了和以前一樣的問題(和解決方案)。

但是,Class是一個通用類型,可以參數化。隨着下面的變化,最後的方法調用無需明確鑄造:

Class<int[]> int_array_class = int[].class; 
test_function(int_array_class.cast(a)); 
0

test_function需要一個int []作爲參數,您將它傳遞給一個對象引用(Object a)。難怪它不會編譯。

0

您的三個註釋函數需要顯式強制轉換爲int[]才能編譯。與此類似,

test_function((int[]) a); 
test_function((int[]) a_class.cast(a)); 
test_function((int[]) int_array_class.cast(a)); 

他們跑無一例外,當我測試了他們的Java 8