泛型Java中任何对象的编译时类型与运行时类型之间的区别是什么?
Java中任何对象的编译时和运行时类型有什么区别?我正在阅读{a1}这本书,Joshua Bloch在第26项中多次提到了数组实例的编译时类型和运行时类型,主要是为了描述有时抑制强制转换警告是安全的
// Appropriate suppression of unchecked warning
public E pop() {
if (size == 0)
throw new EmptyStackException();
// push requires elements to be of type E, so cast is correct
@SuppressWarnings("unchecked") E result = (E) elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
在这里,作者将在数组上下文中讨论这些不同类型的types
。但是通过这个问题,我想了解任何类型的对象compile time types
与run time types
之间的区别
# 1 楼答案
Java是一种静态类型语言,因此编译器将尝试确定所有内容的类型,并确保所有内容都是类型安全的。不幸的是,静态类型推断本身是有限的。编译器必须是保守的,并且也无法查看运行时信息。因此,即使某些代码确实是类型安全的,也无法证明它是类型安全的
运行时类型是指运行时变量的实际类型。作为程序员,希望您比编译器更了解这一点,因此当您知道这样做是安全的时,您可以抑制警告
例如,考虑下面的代码(不编译)
变量
x
将始终具有类型String[]
,但编译器无法解决这一问题。因此,在将其分配给y
时需要显式强制转换# 2 楼答案
我认为“编译时类型”是一个变量在编译时可以显示的任何类型。这将包括声明的类、任何超类和任何实现的接口
在运行时,给定对象只有一个最低级别的类;它可以合法地转换或分配给该类的变量,也可以转换或分配给其任何子类或实现接口的任何变量。编译器将(通常,无论如何)允许您将其强制转换为任何内容,但是如果您试图分配不合法的内容,运行时将抛出异常
一旦将一个对象分配给变量,编译器就会将其视为变量的类型。所以“编译时”的另一个用法可能是变量类型,只要知道在运行时强制转换是合法的,就可以在编译时通过强制转换到不同的类型来解决这个问题
如果我只说一种类型,我认为变量的“运行时类型”是实际的底部(顶部?)变量的level子类;可以将其转换到的最低子类。但我也经常认为任何对象都是其任何合法类型的实例
希望有帮助
# 3 楼答案
一个例子
有两种类型与
x
相关Number
。这是在编译时确定的,并且永远不会更改,因此它是静态类型x
所指的类型。在本例中,它可以是Integer
或Float
,具体取决于某些外部条件。编译器在编译时无法知道类型。它是在运行时确定的(因此动态类型),并且可以多次更改,只要它是静态类型的子类李># 4 楼答案
Java是静态类型的。这意味着该语言中的每个表达式(包括变量)都有一个类型,该类型在编译时根据该语言的规则是已知的。这称为静态类型(您称之为“编译时类型”)。Java中的类型是基元类型和引用类型
此外,Java中运行时的每个对象都有一个“类”(这里,“类”包括虚拟数组“类”),这在运行时是已知的。对象的类是创建对象时使用的类
部分混淆源于这样一个事实:Java中的每个类(以及接口和数组类型)都有一个对应的引用类型,带有类(或接口或数组类型)的名称。引用类型的值是引用,它可以是
null
或指向对象。Java语言的设计使得引用类型X
(如果不是null
)的引用总是指向类为类X或其子类的对象(或者对于接口,其类实现接口X)请注意,运行时类应用对象,但对象不是Java中的值。另一方面,类型应用于变量和表达式,它们是编译时概念。变量或表达式永远不能具有对象的值,因为没有对象类型;它可以具有指向对象的引用的值
# 5 楼答案
Java数组被称为“协变”,这意味着字符串[]是对象[]的子类型,类型规则在编译时检查
Java数组在运行时检查要存储到其中的对象(例如字符串、整数等)是否与实际创建数组的类型兼容
例如: