11

Java中任何对象的编译时和运行时类型有什么区别?我正在阅读Effective Java书,Joshua Bloch 在 Item 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 typesvsrun time types对于任何类型的 object 之间的区别。

4

5 回答 5

17

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

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

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

public class typetest{
    public static void main(String[] args){
        Object x = args;
        String[] y = x;

        System.out.println(y[0])
    }
}

该变量x将始终具有 type String[],但编译器无法弄清楚这一点。因此,在将其分配给y.

于 2013-02-19T17:48:17.060 回答
2

一个例子

Number x;

if (userInput.equals("integer")) {
    x = new Integer(5);
} else {
    x = new Float(3.14);
}

两种相关的类型x

  • 名称 的类型x。在示例中,它是Number. 这是在编译时确定的,永远不会改变,因此它是静态类型
  • x所指的类型。在示例中,它可以是IntegerFloat,具体取决于某些外部条件。编译器在编译时无法知道类型。它是在运行时确定的(因此是动态类型),并且可以多次更改,只要它是静态类型的子类。
于 2019-09-18T15:06:18.883 回答
1

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

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

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

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

于 2013-02-19T21:19:01.810 回答
0

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

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

一旦将对象分配给变量,编译器就会将其视为变量的类型。因此,“编译时”的另一种用途可能是变量类型,只要您知道强制转换在运行时是合法的,您就可以在编译时通过转换为不同的类型来解决这个问题。

如果我只说一种类型,我认为变量的“运行时类型”是变量的实际底层(顶层?)子类;可以将其转换为的最低子类。但我也经常将任何对象视为其任何合法类型的实例。

希望有帮助。

于 2013-02-19T18:15:53.617 回答
0

Java 数组被称为“协变”,这意味着 String[] 是 Object[] 的子类型,并且在编译时检查类型规则。

Java 数组在运行时检查您想要存储到其中的对象(例如 String、Integer、WhatEver)是否与实际创建的数组的类型兼容。

例如:

String[] strings = new String[2];
strings[0] = "I am text"; 
Object[] objects = strings;
objects[1] = new Date(); // Compiles, but at runtime you get an ArrayStoreException
于 2020-11-17T15:04:22.037 回答