【问题标题】:Why is import of class not needed when calling method on instance (Java)为什么在实例上调用方法时不需要导入类(Java)
【发布时间】:2009-04-24 13:35:05
【问题描述】:

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

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 compiler-construction


    【解决方案1】:

    只需要在 Java 中导入,这样编译器就知道如果您键入 Date 是什么

    Date date = new Date();
    

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

    【讨论】:

    • +1:我自己也在学习 Java,在我读过的所有材料中,我不记得看到过这样解释的信息。这很清楚。谢谢。
    • 另一个相关的评论是所有的 java.lang 包都是自动导入的。所以这意味着你可以在没有 import 语句的情况下使用 System 之类的东西。
    • 这是真的。换句话说,这不是关于它在哪里?,而是它是什么?
    • 我创建了package1package2package2PersonReturnPerson 类。 ReturnPerson.returnPerson() 方法返回 Person 实例。 Person 具有打印虚拟消息的 print() 方法。在package1.Test 类中,我导入ReturnPerson,在package1.Test.main() 中,我导入new ReturnPerson.returnPerson.print()。它给了我The method print() from the type Person2 is not visible 错误?为什么会这样?
    • @anir:这是一个不同的问题。如果该方法不可见,这并不意味着编译器不知道它。这意味着无法从您调用它的地方调用该方法。例如,private 方法不能在类外调用。并且没有标记为publicprivate 的方法,因此是包私有的,不能从不同的包中调用。
    【解决方案2】:

    好问题!!

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

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

    在哪里

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

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

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

    您将结果分配给当前范围内的类型(类 TestUsesThing ),编译器尝试解析该范围内的类型。结果,您会看到未知类型的编译器错误。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 是的,抱歉,问题确实是关于日期导入,而不是我现在澄清的类之间的关系。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

        当然,如果您在 Thing 类的定义中有一个导入 - 而且它没有歧义,您只需说:

        public Date getDate() {
        

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

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

        【讨论】:

          猜你喜欢
          • 2020-12-31
          • 2012-04-25
          • 1970-01-01
          • 2013-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-03
          • 1970-01-01
          相关资源
          最近更新 更多