Hi Martin,
Let me try to explain why...
On 08/25/2016 08:56 AM, Martin Lehmann wrote:
package pkgmain;
import pkgx.*;
public class Main {
public static void main(String[] args) {
DataFactory myDataFactory = new DataFactory();
// all OK
System.out.println("Factory.createData(): " +
myDataFactory.createData().getName());
System.out.println("Factory.createInternalData1().toString(): " +
myDataFactory.createInternalData1().toString());
System.out.println("Factory.createInternalData1(): " +
myDataFactory.createInternalData1().getName());
...these, I hope, are understandable. You are invoking the methods upon
the exported type.
// [1]*does* compile though return type of
// 'DataFactory.createInternalData2()' is not visible here
System.out.println("Factory.createInternalData2(): " +
myDataFactory.createInternalData2());
"Factory.createInternalData2(): " +
myDataFactory.createInternalData2()
...is (or was, until replaced with an invokedynamic which should behave
the same) equivalent to calling:
new StringBuilder().append("Factory.createInternalData2():
").append(myDataFactory.createInternalData2()).toString()
...the 2nd append is StringBuilder::append(Object) method. Compiler
knows that InternalData type will not be needed to invoke that method at
runtime, so it doesn't require you to have access to that type at
compile time either.
// [2] does not compile. error: toString() in Object is
// defined in an inaccessible class or interface
// surprise! why is [1] OK while adding toString() is not?
System.out.println("Factory.createInternalData2().toString(): " +
myDataFactory.createInternalData2().toString());
I think this is to restrictive. If the compiler succeeded in compiling
this code, It would compile the toString() invocation as:
invokevirtual #4 // Method
java/lang/Object.toString:()Ljava/lang/String;
...which doesn't need to access InternalData type at runtime. So the
compile time error should not be there IMO.
Are you sure you didn't have the toString() method overridden in
InternalData at time of compilation?
Maybe the compiler is intentionally over restrictive here so that this
type of code change (adding overriding public method to the concealed
class) can not break the compilation? The error message is confusing, at
least: "toString() in Object is defined in an inaccessible class or
interface". How can Object be inaccessible?
// [3] does not compile. error: getName() in InternalData is
// defined in an inaccessible class or interface
// suprise! getName() is overloaded, available in exported class Data
System.out.println("Factory.createInternalData2().getName(): " +
myDataFactory.createInternalData2().getName());
}
}
This would compile down to:
invokevirtual #X // Method
pkginternal/InternalData.toString:()Ljava/lang/String;
...because the compiler notices the static type of the .toString()
target is InternalData which declares the toString() method (and
overrides Object::toString method). So InternalData should be accessible
at runtime for this invocation to succeed and at compile time for
compilation to succeed. Note that the following should compile though
(and run too):
((Data) myDataFactory.createInternalData2()).getName()
Regards, Peter