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

时间:2013-02-19 17:41:00

标签: java generics effective-java

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

5 个答案:

答案 0 :(得分:13)

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

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

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

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

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

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

答案 1 :(得分:1)

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

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

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

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

答案 2 :(得分:0)

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

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

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

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

希望有所帮助。

答案 3 :(得分:0)

简单

Number x;

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

x

相关的两种类型
  • 名称的类型x。在示例中,它是Number。这是在编译时确定的,并且永远不会更改,因此它是静态类型
  • x的类型。在示例中,根据某些外部条件,它可以是IntegerFloat。编译器在编译时无法知道类型。它是在运行时确定的(因此为动态类型),并且可以多次更改,只要它是静态类型的子类即可。

答案 4 :(得分:0)

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

Java数组会在RUNTIME处检查您想存储到其中的对象(例如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