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();
    }
  }
}

我注意到显式地将Object传递给方法是不起作用的。如果未注释,三条注释指令将引发以下错误:

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

所以问题是:为什么编译器拒绝编译在运行时运行良好的三条注释指令

Reflectional访问能够在运行时确定对象的实际类型。另一方面,编译器只知道已声明的类型。它没有任何其他检查参数实际类型的可能性。

您的变量a被声明为Object。因此,使用

test_function(a);

您尝试调用一个签名为void test_function(Object)的方法,但该方法根本不存在。一个简单的转换-正如程序员所知道的正确类型-将在这里有所帮助:

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

另外两个方法调用是相同的,但有点不同。您使用类型Class声明了a_classint_array_class。这是一个原始类型,因此编译器不知道这些变量可以引用哪种类型的类。编译器必须推断类型Object。这导致了与以前相同的问题(和解决方案)。

但是,Class是一个泛型类型,可以参数化。通过以下更改,最后一个方法调用在没有显式强制转换的情况下工作:

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

test_function需要一个int[]作为参数,而您正在向它传递一个对象引用(object a)。难怪它不编译。

您的三个注释掉的函数需要显式转换为int[]才能编译。像这样,

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

当我在Java8上测试它们时,它们毫无例外地运行着。

相关内容

  • 没有找到相关文章

最新更新