为什么我必须指定一个类路径来编译java到类?

时间:2013-10-10 21:44:42

标签: java javac bytecode

据我所知,每个java类都是从单个java文件编译成单个类文件。 (至少只要涉及没有内部类别。)

是否有任何技术原因导致javac需要访问引用的类来生成类文件?

仅用于检查给定的方法调用是否确实有效,或者是否真的有一些来自引用类的信息需要集成到生成的类文件中?

您能举例说明javac需要根据引用类的内容生成不同的字节码吗?

有关此主题的任何好文档吗?

4 个答案:

答案 0 :(得分:2)

这是一个有点主观的问题,但我喜欢它。

正如您所写,正确的一个原因是早期错误检测。如果编译器没有依赖类的类文件以供参考,则必须假设每个外部引用都是正确的。只能在运行时检测到这些错误。你不想要这个。

虽然这里有漏洞。依赖类可以稍后更改。出于这个原因和其他原因,运行时的可用类定义可能与编译时使用的类定义不同,从而导致运行时错误。

但我们所拥有的比替代方案更好。

在某些情况下,引用类的元素会集成到当前编译单元中,例如“常量”。考虑以下两个类:

// File A1.java
class A1 {
    static final String s = "string"; // constant
    static String s2 = "string2"; // not constant
    static final int i = 5;  // constant
}

// File A2.java
class A2 {
    public static void main(String args[]) {
        System.out.println("A1.s: " + A1.s);
        System.out.println("A1.s2: " + A1.s2);
        System.out.println("A1.i: " + A1.i );
    }
}

编译这两个,然后研究javap -c -l -private A2的输出并注意以下内容:

  • 对A1.s和A1.i的引用包括实际值
  • 如果删除对A1.s2的引用,即使 A1.class已删除,也可以执行java A2

答案 1 :(得分:0)

我想您自己回答,编译器需要引用类来检查所有引用的方法是否被正确调用(使用正确的参数),如果它知道这些方法中的内容,它还可以优化一些方法调用

答案 2 :(得分:0)

这是一个原因:如果在库中调用方法x,编译器如何知道该方法确实存在?怎么知道返回类型?如何知道传入的参数数量是否正确?如何知道你传入的类型是否正确?

在动态语言(如javascript)中,这是在运行时发现的,但缺点是反馈循环更长。你越早发现错误就越好。 Java是静态的,因此此类路径要求使您的反馈循环更短。

答案 3 :(得分:0)

如果我在以下情况下正确理解Jon和锑的评论,A2应该根据A1类的返回类型进行不同的编译。

// File A1.java
class A1 {
    public ??? bar(){
        return null;
    }
}

// File A2.java
class A2 {
    public static void main(String args[]) {
        foo(A1.bar());
    }
    private void foo(Integer x){
        System.out.println("1");
    }
    private void foo(String x){
        System.out.println("2");
    }
}

如果我把事情做对了,编译器必须决定方法foo的调用是指第一个还是第二个定义,并根据A1类中的返回类型为类A2生成不同的字节码。