Java中任何对象的编译时类型与运行时类型有什么区别?

Java中任何对象的编译时间和运行时类型有什么区别? 我正在阅读有效的Java书籍,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之间的区别。

Java是一种静态类型语言,因此编译器将尝试确定所有类型,并确保一切都是类型安全的。 不幸的是,静态类型推断本质上是有限的。 编译器必须保守,并且也无法查看运行时信息。 因此,它将无法certificate某些代码是类型安全的,即使它确实存在。

运行时类型是指运行时变量的实际类型。 作为程序员,您希望比编译器更好地了解它,因此当您知道这样做是安全的时,您可以禁止警告。

例如,考虑以下代码(不会编译)

 public class typetest{ public static void main(String[] args){ Object x = args; String[] y = x; System.out.println(y[0]) } } 

变量x将始终具有String[]类型,但编译器无法解决此问题。 因此,在将其分配给y时需要显式强制转换。

Java是静态类型的。 这意味着语言中的每个表达式(包括变量)都具有在编译时根据语言规则已知的类型。 这称为静态类型(您称之为“编译时类型”)。 Java中的类型是基本类型和引用类型。

此外,Java中运行时的每个对象都有一个“类”(这里,“类”包括虚构数组“类”),这在运行时是已知的。 对象的类是创建对象的类。

部分混淆来自于Java中的每个类(以及接口和数组类型)都具有相应的引用类型,具有类的名称(或接口或数组类型)。 引用类型的值是引用,可以为null或指向对象。 Java语言的设计使得引用类型 X引用 (如果不是null将始终指向其类为 X或其子的对象(或者对于其类实现接口 X的接口 )。

请注意,运行时类应用对象 ,但对象不是Java中的值。 另一方面,类型适用于变量和表达式,它们是编译时概念。 变量或表达式永远不能具有对象的值,因为没有对象类型; 它可以具有指向对象的引用值。

我认为“编译时类型”是一个变量可以在编译时显示的任何类型。 那将包括声明的类,任何超类和任何实现的接口。

在运行时,给定对象只有一个最低级别的类; 它可以合法地转换或分配给该类的变量,但也可以转换为任何子类或实现的接口的任何变量。 编译器 (通常,无论如何)允许您将其强制转换为任何内容,但如果您尝试分配不合法的内容,运行时将抛出exception。

将对象分配给变量后,编译器会将其视为变量类型。 因此,“编译时”的另一个用途可能是变量类型,只要您知道转换在运行时是合法的,您就可以在编译时通过转换为其他类型来绕过它。

如果我只提到一种类型,我会将变量的“运行时类型”视为变量的实际底部(顶部?)级子类; 它可以投射的最低子类。 但我也经常将任何对象视为其任何合法类型的实例化。

希望有所帮助。