aspose file tools*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes a method in a private class is accessible Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "a method in a private class is accessible" Watch "a method in a private class is accessible" New topic
Author

a method in a private class is accessible

Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
Why is m() accessible from Test?

A member is accessible if and only if the type is accessible and the member is declared to permit access. JLS 6.6.1
[ April 21, 2003: Message edited by: Marlene Miller ]
Jessica Sant
Sheriff

Joined: Oct 17, 2001
Posts: 4313

I hate inner classes questions -- but I'll try anyway:
the createInner() method -- inside the Outer class has access to the class Inner.
They're both in the same class -- so it has access to the private member. Just like if you had declared a private variable -- and created a public getter method for it.
So, when class Test accesses the "public getter method" for the private member Inner -- it can -- 'cause its accessing it through a public method.
Isn't your code snippet basically the same as this:

[ April 21, 2003: Message edited by: Jessica Sant ]

- Jess
Blog:KnitClimbJava | Twitter: jsant | Ravelry: wingedsheep
Roger Chung-Wee
Ranch Hand

Joined: Sep 29, 2002
Posts: 1683
If Inner were not private, you'd instantiate it with something like this:
Outer.Inner in = oref.new Inner();
But you can get around it like you have by using a non-private method to return the object. It's not disimilar to using a factory method to control the number of objects of a class that has a private constructor.
So, having got hold of an Inner object, you can get hold of m() - because it is not private. Make m() private and it won't compile.
Another nice question.
[ April 21, 2003: Message edited by: Roger Chung-Wee ]

SCJP 1.4, SCWCD 1.3, SCBCD 1.3
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
Jessica, thank you for considering my question. There is an important different between the two examples.
In your example, something.createStringBuffer() returns a reference to an object whose class is public.
In my example, oref.createInner() returns a reference to an object whose class is private. Then a method of that private class is invoked.
Thomas Paul
mister krabs
Ranch Hand

Joined: May 05, 2000
Posts: 13974
Marlene, your example is no different than using a public get method to return a private variable.


Associate Instructor - Hofstra University
Amazon Top 750 reviewer - Blog - Unresolved References - Book Review Blog
Corey McGlone
Ranch Hand

Joined: Dec 20, 2001
Posts: 3271
Originally posted by Marlene Miller:
There is an important different between the two examples.
In your example, something.createStringBuffer() returns a reference to an object whose class is public.
In my example, oref.createInner() returns a reference to an object whose class is private. Then a method of that private class is invoked.

That's right, Marlene - the class is defined as a private member of class Outer. However, a setter method allows an outside class to have access to a private member. Take a look at this simple code:

As you can see, I'm getting a reference to a private member through a public getter method. Now that I've got the reference to the member variable, I've gotten past the fact that it was private. Now, I need only worry about whether or not the method I want to invoke is accessible - I've already gained access to the private member.
In my case, the method reverse is public, so I can invoke it. In your case, the method m is default, so it can be accessed by classes within the same package - therefore it is accessible and you have no problem invoking it.
Basically, what I'm trying to point out is that, but using the public getter method, you're obtaining a reference to a private member. Normally, this isn't something you'd want to do because it doesn't necessarily follow good OO philosophy. However, that doesn't make it illegal.
I hope that helps,
Corey


SCJP Tipline, etc.
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
It's not disimilar to using a factory method to control the number of objects of a class that has a private constructor.
Roger, Yes, it is like a factory method, except that factory methods are static.
So, having got hold of an Inner object, you can get hold of m() - because it is not private.

But JLS 6.6.1 says the member (the method m) of a reference type (the class Inner) is accessible only if the class (Inner) declaring or inheriting the member (m) is accessible.
Marlene, your example is no different than using a public get method to return a private variable.
Thomas, a method returns a value. The value is a copy of the value in the private variable.
If that value is a reference to an object, and if a method of the object is invoked, the compiler checks the accessibility of the method. By JLS 6.6.1, the method is accessible if the class declaring or inheriting the method is accessible.
In your case, the method m is default, so it can be accessed by classes within the same package - therefore it is accessible and you have no problem invoking it.
Corey, A member (the method m) of a reference type (the class Inner) is accessible only if the type (Inner) is accessible and the member (m) is declared to permit access. JLS 6.6.1 Inner is not accessible from Test.
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
We may be at an impasse. 4 : 1. hmmmm.
But I would like to try one more thing. Let�s walk through the steps to resolve a method name at compile-time.
oref.createInner() is a reference to an object of type Outer.Inner. Does the compiler care where that reference came from? No.
Compile-time step 1: Determine the class or interface to search. If the form is Primary.Identifier, then the class or interface to be searched is the type of the Primary expression (Outer.Inner).
Compile-time step 2: Determine the method signature. Find the methods that are applicable and accessible. Whether a method declaration is accessible at a method invocation depends on the access modifier (default) and on where the method invocation appears (class Test).
A method of a class is accessible if the class is accessible and the method is declared to permit access.
[ April 21, 2003: Message edited by: Marlene Miller ]
Roger Chung-Wee
Ranch Hand

Joined: Sep 29, 2002
Posts: 1683
Method m() is accessible because it has default access. This is permissible according to the JLS "only when the access occurs from within the package in which the type is declared".
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
Roger, you are quoting a bullet item that is part of a higher-level bullet item. Both parts have to be accounted for.
Thomas Paul
mister krabs
Ranch Hand

Joined: May 05, 2000
Posts: 13974
Marlene, you are mis-quoting the JLS.
You said: By JLS 6.6.1, the method is accessible if the class declaring or inheriting the method is accessible.
But that is not what the JLS says. It says: A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible and the member or constructor is declared to permit access:
The type in this case is the variable returned by the createInner() method which is accessible to Test.
The Vector class is interesting in that it creates an Enumerotor using an anonymous class within a member and then returns. What is the accessibility of an anonymous class to classes outside of that class?
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
Thomas, thank you for all of your efforts to enlighten me.
(1) �By JLS 6.6.1� I mean �it follows from�. It�s a convention in some math proofs.
The type in this case is the variable returned by the createInner() method which is accessible to Test.
(2) Since I am trying to determine why the method m is accessible, I look at 6.6.1 for an access rule that applies to methods. I find the same rule you found: �A member (class, interface, field, or method) of a reference (class, interface, or array) type�� Then I apply it to my example: method m of class type Inner. type means the class Inner.
What is the accessibility of an anonymous class to classes outside of that class?
(3) Reflection tells us the anonymous class Vector$1 does not have the public, protected or private modifier. So I suppose the anonymous class has default access. By JLS 8.2.1.4, since the anonymous class has a public superinterface, an instance of the anonymous class is available outside the package java.util.

(4) I am getting nervous. Someone is not going to like all this JLS stuff.
[ April 21, 2003: Message edited by: Marlene Miller ]
Thomas Paul
mister krabs
Ranch Hand

Joined: May 05, 2000
Posts: 13974
Declaring an inner class to be private only means that the inner class can not be instantiated from outside the enclosing class. It says nothing about the accessibility of the methods inside the inner class.
Jignesh Malavia
Author
Ranch Hand

Joined: May 18, 2001
Posts: 81
Interesting discussion going on here! Here's what I found.
If I declare the method m() as public (instead of default) in the Inner class then the compiler flags an error as follows:
---------------------------
Test.java:16: m() in Outer.Inner is not defined in a public class or interface;
cannot be accessed from outside package
int i = oref.createInner().m();
^
1 error
---------------------------
This is exactly what Marlene is talking about (am i correct?) and I think it makes sense. Since the Inner class itself is private and is not accessible to Test, the members of the Inner class should not be accessible either regardless of their own access control. The compiler follows this rule when it sees the public method m() in a private Inner class but it fails to recognize the same rule when it sees the same method with default access, even though default is more restrictive than public in all respect.
May be this is a loophole in the JLS itself (I haven't dug that deep into it) or may be there is a bug in the algorithm the compiler is using. For example, instead of checking the class access control first, the compiler checks the method access control first and then it checks the class access only if the method is public. Otherwise it assumes that since the method access is default and since both the classes, Inner and Test, are in same package, it is ok to go ahead, like Roger pointed out.
If I declare m() as private, then I get the error as expected
---------------------------
Test.java:16: m() has private access in Outer.Inner
int i = oref.createInner().m();
^
1 error
---------------------------
Then I tried declaring m() as protected and it compiles fine just like the default case, which again proves that the compiler lets it go based on the fact that protected members of one class (Inner) are accesible from another class (Test) if they are in the same package, without checking the access control of the Inner class itself with respect to Outer class.
Finally, I separated the two classes and put them in different packages. It did not compile for any of the access control modifiers, including default, as expected.
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
If I declare the method m() as public (instead of default) in the Inner class then the compiler flags an error as follows:
Now that is Very Interesting! Thank you Jignesh for digging deeper and thank you for contributing your ideas.
I have been thinking about submitting my example to the Java Spec Report (JSP) discussion group. I�ll keep you informed, if I learn something.
Praveen Kumar Mathaley
Ranch Hand

Joined: Apr 14, 2003
Posts: 45
Consider the following JLS Rule.
8.2.1.4 Accessing Members of Inaccessible Classes
Even though a class might not be declared public, instances of the class might be available at run time to code outside the package in which it is declared if it has a public superclass or superinterface. An instance of the class can be assigned to a variable of such a public type. An invocation of a public method of the object referred to by such a variable may invoke a method of the class if it implements or overrides a method of the public superclass or superinterface.
(In this situation, the method is necessarily declared public, even though it is declared in a class that is not public.)
John Zoetebier
Ranch Hand

Joined: Mar 28, 2003
Posts: 76
Marlene says:
A member is accessible if and only if the type is accessible and the member is declared to permit access. JLS 6.6.1

Your code does not violate this rule.
As already mentioned in previous postings, the method returns a copy of a private variable, in this case a private inner class.
I cannot see a fundamental difference between your code and a getter method which returns a copy of a private variable.
The JLS does not put any restraint on the type of variable that can be returned by a method, more specific a getter method.
So, I cannot see any problem here.
If I miss something, please explain.
Chang Duan
Greenhorn

Joined: Apr 23, 2003
Posts: 1
After go through the JLS, I think Marlene has a point here.
The essential question is: what does the word "private" mean in a private inner class?
1) This class can NOT be instantiated outside the enclosing class body.
2) But can an object of such class be used for method calls (via a reference) outside the enclosing class body?
Seem JLS does not give explicit rules dealing with the second situation.
Jose Botella
Ranch Hand

Joined: Jul 03, 2001
Posts: 2120
I think the compiler does not check the accesibility of a type that is not mentioned in the code, even thought, it is able to search declarations on it.
That is,
oref.createInner().m();
compiles, whereas
new Outer().new Inner().m();
does not.
______________________________________
By the way, Welcome to the Ranch, Chang
[ April 23, 2003: Message edited by: Jose Botella ]

SCJP2. Please Indent your code using UBB Code
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: a method in a private class is accessible