Hi Peter,

 

thanks for your explanations.

 

I do now understand the behaviour of case [1] ..., thanks!

 

About case [2] you wrote

*  Are you sure you didn't have the toString() method overridden in
InternalData at time of compilation?

Yes, I am sure. I agree, this should compile. At least this compiler error
message is confusing.

 

About case [3] you wrote

*  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.

 

I am a bit confused here, as you mention toString() . But in case [3]
getName() is not related to toString() - at least not that I can see. 

 

InternalData.getName() overwrites Data.getName() , both returning a
hard-coded String as result value.

 

So did you mean getName() instead of toString() ? I.e. did you mean:

*  ...because the compiler notices the static type of the ***.getName()***
target is InternalData which declares the ***getName()*** method (and
overrides ***Data::getName*** method). So InternalData should be accessible
at runtime for this invocation to succeed and at compile time for
compilation to succeed. 

If you did not mean this, I would be lost here... ;-)

 

Finally:

*  Note that the following should compile though (and run too): ((Data)
myDataFactory.createInternalData2()).getName()

Yep, indeed. Compiles and runs.

 

Thanks again.

 

Cheers, Martin

 

 

From: Peter Levart [mailto:peter.lev...@gmail.com] 
Sent: Thursday, August 25, 2016 1:42 PM
To: Martin Lehmann <martin.lehm...@gmx.de>; jigsaw-dev@openjdk.java.net
Subject: Re: Question on returning instances of a (not exported) derived
class

 

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

Reply via email to