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

让我迷惑的东西 – 一个例子:

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()?

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

 Date date = new Date(); 

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

好问题 !!

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

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

在哪里

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

是一个表达式,因为它发生在println方法调用中。 当您在新Thing()上调用getDate时,编译器会尝试通过查看Thing类的类型信息来处理表达式,这是获取Date类型声明的地方。 但是,当您尝试在类似的语句中单独使用Date时

 Date d = new Thing().getDate(); 

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

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

import语句用于几件事。

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

每当我们说

 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()方法

实际上,这是一个理想的例子,因为有两种不同的标准Java Date类: java.util.Datejava。 sql日期

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

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

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

 public Date getDate() { 

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

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