有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

泛型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 typesrun time types之间的区别


共 (5) 个答案

  1. # 1 楼答案

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

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

    例如,考虑下面的代码(不编译)

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

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

  2. # 2 楼答案

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

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

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

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

    希望有帮助

  3. # 3 楼答案

    一个例子

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

    有两种类型与x相关

    • 名称的类型。在这个例子中,它是Number。这是在编译时确定的,并且永远不会更改,因此它是静态类型
    • x所指的类型。在本例中,它可以是IntegerFloat,具体取决于某些外部条件。编译器在编译时无法知道类型。它是在运行时确定的(因此动态类型),并且可以多次更改,只要它是静态类型的子类
  4. # 4 楼答案

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

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

    部分混淆源于这样一个事实:Java中的每个类(以及接口和数组类型)都有一个对应的引用类型,带有类(或接口或数组类型)的名称。引用类型的值是引用,它可以是null或指向对象。Java语言的设计使得引用类型X(如果不是null)的引用总是指向类为X或其子类的对象(或者对于接口,其类实现接口X)

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

  5. # 5 楼答案

    Java数组被称为“协变”,这意味着字符串[]是对象[]的子类型,类型规则在编译时检查

    Java数组在运行时检查要存储到其中的对象(例如字符串、整数等)是否与实际创建数组的类型兼容

    例如:

    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