为什么在实例上调用方法时不需要导入类(Java)

时间:2009-04-24 13:35:05

标签: java compiler-construction

让我感到困惑的一个例子:

Thing.java:

import java.util.Date; 

class Thing { 
    static Date getDate() {return new Date();}
}

(相同包)TestUsesThing.java:

// not importing Date here.

public class TestUsesThing {

    public static void main(String[] args) {
        System.out.println(Thing.getDate().getTime()); // okay
        // Date date = new Date(); // naturally this wouldn't be okay
    }

}

为什么没有必要导入Date才能在其中一个上调用getTime()?

5 个答案:

答案 0 :(得分:25)

只需要在Java中导入,因此编译器知道键入

Date是什么
Date date = new Date();

导入与C / C ++中的#include不同;类路径上的所有类型都是可用的,但是你import它们只是为了不必编写完全限定的名称。在这种情况下,这是不必要的。

答案 1 :(得分:1)

好问题!!

我认为结果是java编译器处理表达式与语句之间的区别。

Date d = new Date(); // a statement

其中

new Thing().getDate().getTime()

是在println方法调用中发生的表达式。当您在新Thing()上调用getDate时,编译器会尝试通过查看Thing类的类型信息来处理表达式,这是获取Date类型声明的地方。 但是当你尝试在像

这样的语句中单独使用Date时
Date d = new Thing().getDate();

您要将结果分配给当前作用域中的类型(类TestUsesThing),编译器会尝试解析该作用域内的类型。因此,您会看到未知类型的编译器错误。

答案 2 :(得分:0)

Thing和TestUsesThing在同一个包中吗?如果是这样,那么你不必导入东西。您必须导入日期的原因是因为它位于不同的包中。

答案 3 :(得分:0)

import语句用于几件事。

  1. 编译器类型检查并避免命名冲突。
  2. 确保字节码链接
  3. 每当我们说

    System.out.println( new Thing().getDate().getTime() )
    

    编译器从左到右解析此语句并进入该类。

    第一级编译器解析。

    1. 转到事物类
    2. 编译没有来自Thing.class的任何链接或ClassVersion错误

    3. 检查Thing.class是否有getDate方法。
    4. 如果#3好,那么编译器指针仍然在Thing.class(它有日期导入语句),我可以调用Time方法。
    5. 作为消费者,TestUsesThing只获取长变量。

      System.out.println( new Thing().getDate() )
      

      5.1在这种情况下,我们隐式访问.toString()方法

答案 4 :(得分:0)

实际上,这是一个理想的例子,因为两个不同的标准Java Date类: java.util.Date java。 sql < /em>.Date

它如何知道使用哪一个?简单。 getDate()方法被声明为Thing类定义的一部分,该声明的一部分是其返回类型:

public java.util.Date getDate() {
  return this.date;
}

当然,如果你在Thing类的定义中有一个导入 - 并且它没有含糊不清,你只需说:

public Date getDate() {

如果你要解码Thing类的二进制文件,你会看到getDate方法的方法签名,它包含返回类型的完全限定类名(包括包)。

导入只是告诉编译器在引用没有明确限定条件的类时要采用的包。只要看到不合格的类名,就会扫描导入列表,并搜索包。如果没有歧义(例如同时导入java.util.date和java.sql.Date),将使用该类。如果您可以隐式确定类,或者类名是完全限定的,则无需导入。