Question

I am reading "Practical API design" and find following paragraph:

"The other reason to prefer methods over fields can be found in the JVM specification. You’re permitted to move a method from a class to one of its superclasses and still maintain binary compatibility. So, a method initially introduced as Dimension javax.swing.JComponent. getPreferredSize(Dimension d) can be deleted in a new version and moved to Dimension java.awt.Component.getPreferredSize(Dimension d), as the JComponent is a subclass of Component. A change like this really happened in JDK 1.2, and this could be done only because the field was encapsulated by a method. An operation like this isn’t allowed for fields. Once a field is defined in a class, it has to stay there forever to maintain binary compatibility, which is another reason to keep fields private"

since I agree using getter/setter is better way. But I don't understand why moving public field to parent class will break binary compatibility? You should still be able to access that field through child class as long as the it is public in parent.

Was it helpful?

Solution

Once a field is defined in a class, it has to stay there forever to maintain binary compatibility

That would be very surprising:

The Java Language Specification, Java SE 7 Edition, defines the binary name of an unqualified field access expression as follows:

Given a legal expression denoting a field access in a class C, referencing a non-constant (§13.4.9) field named f declared in a (possibly distinct) class or interface D, we define the qualifying type of the field reference as follows:

  • If the expression is of the form Primary.f then:
    • If the compile-time type of Primary is an intersection type (§4.9) V1 & ... & Vn, then the qualifying type of the reference is V1.
    • Otherwise, the compile-time type of Primary is the qualifying type of the reference.

(The Language Specification for Java 1.5 uses the exact same wording)

That is, the binary name of a field access expression does not refer to the type that declares the field, only to the type of the primary expression we use to access that field, so whichever superclass of that type declares the field, the compiler is required to emit the same field reference into the class file.

Indeed, when I tried just now to evolve from

package p;

public class Super {

}

package p;

public class Sub extends Super {
    public String message;

    @Override
    public String toString() {
        return message;
    }
}

to

package p;

public class Super {
    public String message;
}

package p;

public class Sub extends Super {
    @Override
    public String toString() {
        return message;
    }
}

without recompiling

package p;

public class Main {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.message = "hello";
        System.out.println(sub);
        System.out.println(sub.message);
    }
}

I still received the output of

hello
hello

, not a LinkageError.

To conclude, that claim is not true for Java 7. It may have been true for JDK 1.4 or earlier, which was declared end-of-life more than 5 years ago. Either way, perhaps you should use a better/more recent book?

OTHER TIPS

If I remember correctly the book explains this, but I don't have it at hand currently. I think it was about subtle differences between the Java language and the class file format (which is used by other languages than Java as well).

Check the book a bit before or after. Ask if you have more questions about that part.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top