3

As far as I understand each single java class is compiled from a single java file to a single class file. (At least as long as no inner classes are involved.)

Is there any technical reason why javac needs access to the referenced classes to produce a class file?

Is it only for checking that the given method invocations are indeed valid, or are there really some bits of information from the referenced classes which need to be integrated in the generated class file?

Can you give an example in which javac needs to generate a different bytecode depending of the content of a referenced class?

Any good documentation on this topic?

2
  • 1
    It's not just to check that the method invocations are valid - it's to know what the return type is, etc. Java is a statically typed language, so when you refer to a type in code the compiler's going to check that it exists and that you're using it properly. Commented Oct 10, 2013 at 21:48
  • 1
    And it must also get the values of the compile-time constants from those referenced classes. Commented Oct 10, 2013 at 21:56

4 Answers 4

2

This is a somewhat subjective question but I like it.

As you wrote correctly, one big reason is for early error detection. If the compiler does not have the class files of dependent classes for reference it has to assume that every external reference is correct. Any errors in these can be only detected at run time. You don't want this.

There are holes here though. The dependent class can change later. For this reason and others, the available class definition at run time can be different from the one used at compile time resulting in runtime errors.

But what we have is better than the alternative.

There are some cases where elements from referenced classes is integrated into the current compilation unit, for example "constants". Consider the following two classes:

// 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 );
    }
}

Compile these two and then study the output of javap -c -l -private A2 and note the following:

  • The references to A1.s and A1.i include the actual values
  • If you remove the reference to A1.s2 then java A2 can be executed even if A1.class is deleted
Sign up to request clarification or add additional context in comments.

1 Comment

Another case of incorporating information into the class is method overloading. Method overloading is determined at compile time and baked into the classfile.
0

I suppose you answered by yourself, compiler needs referenced classes to check all referenced methods are properly called (with proper arguments), also it CAN optimize some of method calls if it knows what in this methods

5 Comments

Javac doesn't do optimization. Or at least not like that.
@Antimony this is why I wrote "can", also - are you sure about all javac compilers? (oracle, openjava, microsoft)
I don't know of any Java compiler that inlines methods at compile time. I assume that would be a violation of the language specification anyway, as I'm pretty sure only constant value expressions can be inlined (see Miserable Variable's answer).
@MikeStrobel agree, but sometimes inlining could be very useful :)
Yes, and any decent JIT compiler will perform inlining. But it breaks the dependency model to do inlining at compile time. If I compile against one class version, then drop in a replacement with changes to a method, I would expect all callers to that method to pick up the new behavior without having to recompile them. AFAIK, that behavior is guaranteed by the spec. It's not very useful to write a compiler that disregards the spec whenever it feels like it :).
0

Here's a reason: If you call a method x in a library, how can the compiler know that that method really exists? How can it know the return type? How can it know the number of parameters you pass in is correct? How can it know the types you pass in is correct?

In a dynamic language (like javascript), this is discovered at runtime, but the downside to that is the feedback loop is longer. The sooner you discover your error, the better. Java is static, so this classpath requirement makes your feedback loop shorter.

2 Comments

It makes perfect sense for error checking, but for the sole purpose of generating bytecode, the compiler does not need to know, whether the method really exists in that library.
@michas maybe not (I'm not sure), but the javac command compiles AND detects these kinds of errors. It couldn't do the latter without the classpath.
0

If I understand Jon's and Antimony's comments correctly in the following case A2 should compile differently depending on the return type in class 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");
    }
}

If I got things right the compiler must decide whether the call of method foo refers to the first or the second definition, and generate different bytecode for class A2 depending of the return type in class A1.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.