将Class.forName(“ java.lang.String”)/'Class.forName(“ some_str_var”)'强制转换为Class <string>:为什么前者会产生未经检查的编译器警告?

时间:2018-12-25 10:16:31

标签: java generics reflection

这行代码

 Class<String> cls =  (Class<String>) Class.forName("java.lang.String");

给出编译器警告Type safety: Unchecked cast from Class<capture#1-of ?> to Class<String>

此外,根据API定义,它返回返回Class<?>

Class<?> Class.forName(String arg)

我不明白为什么将从Class<?>Class<String>的转换视为未选中(也就是说,编译器无法检查在编译时是否可以进行这种转换)。

如果是

Class<String> cls =  (Class<String>) Class.forName("some_str_var");

我可以理解,编译器在编译时无法知道Class.forName()的返回类型(因为参数是变量,而不是文字),并且在运行时会擦除类型信息。

但是Class.forName("java.lang.String")在编译过程中明显Class<?>(并且LHS中的cls变量仍然是Class<String>),还没有擦除任何类型信息(编译器看到的是源代码,不是字节代码并删除了type-in​​fo),编译器可以检查所有内容。

2 个答案:

答案 0 :(得分:5)

在此调用中,编译器未对字符串常量... [02:05:55:833] com.gluonhq.higgs.Compiler: halfway done round 14 [02:05:56:201] com.gluonhq.higgs.Compiler: done round 14 [02:05:56:201] com.gluonhq.higgs.Compiler: Waiting for remaing classes to be compiled on executor [02:05:56:202] com.gluonhq.higgs.Compiler: active count = 0 and coresize = 2 and queuesize = 0 [02:05:56:202] com.gluonhq.higgs.Compiler: shutdown executor [02:05:56:202] com.gluonhq.higgs.Compiler: shutdown executor done [02:05:56:202] com.gluonhq.higgs.Compiler: await term done [02:05:56:202] com.gluonhq.higgs.Compiler: All classes are now compiled [02:05:56:202] com.gluonhq.higgs.Compiler: Compiled 0 classes in 25.835 seconds [02:05:56:224] com.gluonhq.higgs.Higgs: non-fatal issue for class com.gluonhq.impl.charm.a.b.b.f (no known superclass) [02:05:56:225] com.gluonhq.higgs.Higgs: non-fatal issue for class com.gluonhq.impl.charm.a.b.b.m (no known superclass) [02:05:56:226] com.gluonhq.higgs.Higgs: non-fatal issue for class com.gluonhq.impl.charm.a.b.b.o (no known superclass) [02:05:56:226] com.gluonhq.higgs.Higgs: non-fatal issue for class com.gluonhq.impl.charm.a.b.b.v (no known superclass) [02:05:56:232] com.gluonhq.higgs.Higgs: ERROR for class com.sun.javafx.property.adapter.PropertyDescriptor$Listener [02:05:56:233] com.gluonhq.higgs.Higgs: ERROR for class com.sun.javafx.property.adapter.ReadOnlyPropertyDescriptor$ReadOnlyListener [02:05:56:263] com.gluonhq.higgs.Higgs: non-fatal issue for class javafx.scene.web.JSObjectIosImpl (no known superclass) [02:05:56:267] com.gluonhq.higgs.Higgs: non-fatal issue for class net.miginfocom.layout.BoundSize$1 (no known superclass) [02:05:56:268] com.gluonhq.higgs.Higgs: ERROR for class net.miginfocom.layout.LayoutUtil$1 [02:05:56:269] com.gluonhq.higgs.Higgs: non-fatal issue for class net.miginfocom.layout.UnitValue$1 (no known superclass) ERR: Launch simulator on simudid: B3D4F644-FC5F-4DBE-8586-9C3D0D6E4E70 and launchDir = /Users/user/Documents/tesla/teslaApp/build/gvm/teslaApp.app [SUB] Failed to install application. Error Domain=IXUserPresentableErrorDomain Code=1 "This app could not be installed at this time." UserInfo={NSLocalizedFailureReason=Failed to chmod /Users/user/Library/Developer/CoreSimulator/Devices/B3D4F644-FC5F-4DBE-8586-9C3D0D6E4E70/data/Bundle/Application/4C023753-2AC3-42BC-95E9-C46FCF4996D6/teslaApp.app/TeslaTasks : No such file or directory, NSUnderlyingError=0x7fdf2cf19870 {Error Domain=MIInstallerErrorDomain Code=4 "Failed to chmod /Users/user/Library/Developer/CoreSimulator/Devices/B3D4F644-FC5F-4DBE-8586-9C3D0D6E4E70/data/Bundle/Application/4C023753-2AC3-42BC-95E9-C46FCF4996D6/teslaApp.app/TeslaTasks : No such file or directory" UserInfo={NSLocalizedDescription=Failed to chmod /Users/user/Library/Developer/CoreSimulator/Devices/B3D4F644-FC5F-4DBE-8586-9C3D0D6E4E70/data/Bundle/Application/4C023753-2AC3-42BC-95E9-C46FCF4996D6/teslaApp.app/TeslaTasks : No such file or directory, LegacyErrorString=ExecutableTwiddleFailed, FunctionName=-[MIExecutableBundle makeExecutableWithError:], SourceFileLine=1221, NSUnderlyingError=0x7fdf2cf1b180 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}}, NSLocalizedRecoverySuggestion=Failed to chmod /Users/user/Library/Developer/CoreSimulator/Devices/B3D4F644-FC5F-4DBE-8586-9C3D0D6E4E70/data/Bundle/Application/4C023753-2AC3-42BC-95E9-C46FCF4996D6/teslaApp.app/TeslaTasks : No such file or directory, NSLocalizedDescription=This app could not be installed at this time.} 进行任何特殊处理:

"java.lang.String"

Class.forName("java.lang.String") 只是众多方法之一,就像传递给它的参数只是众多字符串之一一样。

因此以下两个对于编译器是相同的(就返回类型而言):

Class.forName

String className = "java.lang.String";
Class<String> stringClass = Class.forName(className);

编译器不会检查常量参数来推断它必然是Class<String> stringClass = Class.forName("java.lang.String"); 。如果要以类型安全的方式获取Class<String>,则必须使用:

Class<String>

答案 1 :(得分:1)

由字符串"java.lang.String"表示的类恰好在编译时可用,因为它是标准库的一部分。因此,编译器原则上可以执行class.forName()并检查返回的类是否与类型声明匹配。

但这将是特例。通常,该字符串可能会指定一个在编译时根本不可用的类-例如,它可能在可运行时动态加载的可插入库中。

因此,编译器仅采用最简单,最通用的方法。编译器很复杂,设计人员通常选择不增加更多的复杂性,而只会增加一些特殊情况。

我还怀疑自定义类加载器的可能性可能会使实现此检查变得困难。即使在标准库中,编译时可用的类也可能没有保证(由Java语言规范保证)在运行时可用,即使对于标准库也是如此-即使它们通常是 一样。