泛型与遗留代码的互操作



我正在阅读Oracle的教程http://docs.oracle.com/javase/tutorial/extra/generics/legacy.html

但是我不明白这行是什么意思

因此,表示Java虚拟机的类型安全性和完整性永远不会有危险,即使存在未检查的警告。
谁能给我解释清楚一点吗?补充:JVM的"完整性"究竟是什么,"有风险"到底是什么意思?

这意味着JVM永远不会误以为对象是它不是的类型。欺骗运行时使其认为一段数据具有不同的类型是一种强大的攻击向量,特别是如果您可以欺骗运行时允许您将一个值赋给它认为是longint的数据,但实际上是一个指针。

JVM的基本安全模型依赖于对象是运行时认为的类型。

我读了一篇有趣的论文,详细介绍了对运行Java的机器的攻击,该攻击使用热灯来急剧增加内存错误。然后,他们使用了一个程序,该程序将数十亿个对象策略性地排列在内存中,并等待其中一个对象出现零星的位翻转。这样做会欺骗JVM,使其认为它正在处理不同类型的对象,并最终允许JVM运行任意代码(有关完整读取,请参阅使用内存错误攻击虚拟机)。

他们使用位翻转的事实与泛型无关。但是,在那篇文章中详细介绍了欺骗运行时认为对象是不同类型的能力。综上所述,假设您有AB类:

class A {
    public long data = 0;
}
class B {
}

如果你可以欺骗JVM允许这样做:

A aButActuallyB = someMagicAssignment(new B());

其中someMagicAssignment是一个方法,它可以接受对B的引用,并以某种方式返回作为A的引用对象。然后想想当你这样做的时候会发生什么:

aButActuallyB.data = 0x05124202;

您可能正在写入JVM原始内存中的任意数据!例如,该数据可以是方法的位置。将其更改为指向某些字节数组的内容可以允许您运行任意代码。

所以当Oracle说

Java虚拟机的类型安全性和完整性永远不会有风险,即使存在未检查的警告。

它的意思是,即使你可以这样做:

public static <T> T someMagicAssignment(B b){ 
   return (T) b; //unchecked cast warning
}

然后调用:

A a = MyClass.<A>someMagicAssignment(new B());

这仍然会在赋值a时做一个运行时检查。

因此,编写方法someMagicAssignment并不比以前容易。泛型没有以任何方式增加这种攻击向量的表面积,因为JVM在其内部类型系统中忽略了泛型。JVM永远不会允许您给一个方法一个List<String>,然后让该方法对该列表的元素执行String操作,而不在运行时检查这些元素实际上是String s。如果不手动检查,它永远不会允许您将B视为A

我认为他们想要的是泛型是在编译器中实现的,而不是在虚拟机中实现的,因此编译器发出的字节码是相同的,无论你是否抑制未检查的警告;抑制未检查的警告的实现方式不是绕过虚拟机级别的类型检查,而是绕过编译器级别的类型检查。

这仅仅意味着,当您的代码中有List<String> stringListList stringList时,一旦编译并运行,JVM就完全没有风险。JVM只看到List stringList

这是因为类型erasure,其中泛型参数化类型在运行时被擦除(删除)。

同一篇文章明确指出:

基本上,erasure删除(或擦除)所有泛型类型信息。尖括号之间的所有类型信息是因此,例如,像List<String>这样的参数化类型转换为List .

文档中的风险仅仅意味着,如果您有一个

的示例
List<String> stringList = new Arrays.asList("one", "two", "three");
String number = stringList.get(0);

JVM理解为:

List stringList = new Arrays.asList("one", "two", "three");
String number = (String)stringList.get(0);

虽然第二个版本会抱怨泛型原始类型,但是JVM删除了参数化的类型并隐式地检索元素作为Object,并且JVM的类型转换规则仍然适用。

JVM 从不存储/使用泛型信息(即使元数据驻留在类文件中)。

答案就在前面那句话里:

这样做的原因是泛型是由Java实现的编译器作为前端转换称为擦除。你可以(几乎)可以把它看作是源到源的翻译,因此通用的将漏洞()的版本转换为非泛型版本。

这意味着,由于擦除,具有泛型的源代码将编译成与非泛型源代码相同(或至少相似)的字节码。

最新更新