# 故障排除

> 原文： [https://docs.oracle.com/javase/tutorial/reflect/class/classTrouble.html](https://docs.oracle.com/javase/tutorial/reflect/class/classTrouble.html)

以下示例显示了在反映类时可能遇到的典型错误。

## 编译器警告：“注意：...使用未经检查或不安全的操作”

调用方法时，将检查参数值的类型并进行转换。 [``ClassWarning`` ](example/ClassWarning.java)调用 [`getMethod()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getMethod-java.lang.String-java.lang.Class...-) 导致典型的未经检查的转换警告：

```
import java.lang.reflect.Method;

public class ClassWarning {
    void m() {
	try {
	    Class c = ClassWarning.class;
	    Method m = c.getMethod("m");  // warning

        // production code should handle this exception more gracefully
	} catch (NoSuchMethodException x) {
    	    x.printStackTrace();
    	}
    }
}

```

```
$ javac ClassWarning.java
Note: ClassWarning.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ javac -Xlint:unchecked ClassWarning.java
ClassWarning.java:6: warning: [unchecked] unchecked call to getMethod
  (String,Class<?>...) as a member of the raw type Class
Method m = c.getMethod("m");  // warning
                      ^
1 warning

```

许多库方法已经使用通用声明进行了改进，包括 [`Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) 中的几个。由于`c`被声明为 _ 原始 _ 类型（没有类型参数）并且 [`getMethod()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getMethod-java.lang.String-java.lang.Class...-) 的相应参数是参数化类型，因此发生未经检查的转换。编译器需要生成警告。 （参见 [_Java 语言规范，Java SE 7 版 _](https://docs.oracle.com/javase/specs/jls/se7/html/index.html) ，[未经检查的转换](https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.9)和[方法调用转换](https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.3)。）

有两种可能的解决方案。更优选的是修改`c`的声明以包括适当的泛型类型。在这种情况下，声明应该是：

```
Class<?> c = warn.getClass();

```

或者，可以使用有问题的语句之前的预定义注释 [`@SuppressWarnings`](https://docs.oracle.com/javase/8/docs/api/java/lang/SuppressWarnings.html) 明确地抑制警告。

```
Class c = ClassWarning.class;
@SuppressWarnings("unchecked")
Method m = c.getMethod("m");  
// warning gone

```

* * *

**Tip:** As a general principle, warnings should not be ignored as they may indicate the presence of a bug. Parameterized declarations should be used as appropriate. If that is not possible (perhaps because an application must interact with a library vendor's code), annotate the offending line using [`@SuppressWarnings`](https://docs.oracle.com/javase/8/docs/api/java/lang/SuppressWarnings.html).

* * *

## 构造函数不可访问时的 InstantiationException

如果尝试创建类的新实例并且零参数构造函数不可见， [`Class.newInstance()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#newInstance--) 将抛出 [`InstantiationException`](https://docs.oracle.com/javase/8/docs/api/java/lang/InstantiationException.html) 。 [``ClassTrouble`` ](example/ClassTrouble.java)示例说明了产生的堆栈跟踪。

```
class Cls {
    private Cls() {}
}

public class ClassTrouble {
    public static void main(String... args) {
	try {
	    Class<?> c = Class.forName("Cls");
	    c.newInstance();  // InstantiationException

        // production code should handle these exceptions more gracefully
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}

```

```
$ java ClassTrouble
java.lang.IllegalAccessException: Class ClassTrouble can not access a member of
  class Cls with modifiers "private"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.Class.newInstance0(Class.java:349)
        at java.lang.Class.newInstance(Class.java:308)
        at ClassTrouble.main(ClassTrouble.java:9)

```

[`Class.newInstance()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#newInstance--) 的行为与`new`关键字非常相似，并且由于`new`失败的原因而失败。反射的典型解决方案是利用 [`java.lang.reflect.AccessibleObject`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html) 类来提供抑制访问控制检查的能力;然而，这种方法不起作用，因为 [`java.lang.Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) 不延长 [`AccessibleObject`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html) 。唯一的解决方案是修改代码以使用 [`Constructor.newInstance()`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Constructor.html#newInstance-java.lang.Object...-) ，它确实扩展了 [`AccessibleObject`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html) 。

* * *

**Tip:** In general, it is preferable to use [`Constructor.newInstance()`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Constructor.html#newInstance-java.lang.Object...-) for the reasons described in the [Creating New Class Instances](../member/ctorInstance.html) section in the [Members](../member/index.html) lesson.

* * *

使用 [`Constructor.newInstance()`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Constructor.html#newInstance-java.lang.Object...-) 的潜在问题的其他示例可以在[成员](../member/index.html)课程的[构造函数故障排除](../member/ctorTrouble.html)部分找到。