Java why invocation of private method works [duplicate] - java

I don't understand why this compiles. f() and g() are visible from the inner classes, despite being private. Are they treated special specially because they are inner classes?
If A and B are not static classes, it's still the same.
class NotPrivate {
private static class A {
private void f() {
new B().g();
}
}
private static class B {
private void g() {
new A().f();
}
}
}

(Edit: expanded on the answer to answer some of the comments)
The compiler takes the inner classes and turns them into top-level classes. Since private methods are only available to the inner class the compiler has to add new "synthetic" methods that have package level access so that the top-level classes have access to it.
Something like this (the $ ones are added by the compiler):
class A
{
private void f()
{
final B b;
b = new B();
// call changed by the compiler
b.$g();
}
// method generated by the compiler - visible by classes in the same package
void $f()
{
f();
}
}
class B
{
private void g()
{
final A a;
a = new A();
// call changed by the compiler
a.$f();
}
// method generated by the compiler - visible by classes in the same package
void $g()
{
g();
}
}
Non-static classes are the same, but they have the addition of a reference to the outer class so that the methods can be called on it.
The reason Java does it this way is that they did not want to require VM changes to support inner classes, so all of the changes had to be at the compiler level.
The compiler takes the inner class and turns it into a top level class (thus, at the VM level there is no such thing as an inner class). The compiler then also has to generate the new "forwarding" methods. They are made at the package level (not public) to ensure that only classes in the same package can access them. The compiler also updated the method calls to the private methods to the generated "forwarding" methods.
You can avoid having the compiler generate the method my declaring the methods as "package" (the absence of public, private, and protected). The downside to that is that any class in the package can call the methods.
Edit:
Yes, you can call the generated (synthetic) method, but DON'T DO THIS!:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Class<?> clazz;
clazz = Class.forName("NotPrivate$A");
for(final Method method : clazz.getDeclaredMethods())
{
if(method.isSynthetic())
{
final Constructor constructor;
final Object instance;
constructor = clazz.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
instance = constructor.newInstance();
method.setAccessible(true);
method.invoke(null, instance);
}
}
}
}

I think this quote sums it up nicely:
...inner classes can access all members of the declaring class, even private members. In fact, the inner class itself is said to be a member of the class; therefore, following the rules of object-oriented engineering, it should have access to all members of the class.
And following from that, since both inner classes are really just part of the containing class, they should be able to access each others private members as well.

Java compiles in special accessors with $ in them. So you can't write Java that access the private methods. Explained here:
http://www.retrologic.com/innerclasses.doc7.html
There is one more category of compiler-generated members. A private member m of a class C may be used by another class D, if one class encloses the other, or if they are enclosed by a common class. Since the virtual machine does not know about this sort of grouping, the compiler creates a local protocol of access methods in C to allow D to read, write, or call the member m. These methods have names of the form access$0, access$1, etc. They are never public. Access methods are unique in that they may be added to enclosing classes, not just inner classes.

As User 'A Dude' explained it in the comments of the accepted answer:
It compiles, because it is required to be working in that way by the language specifation, ie. the Java Lang Spec says so:
6.6.1 Determining Accessibility (at least since JLS6)
"Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor."
I.e. the "access-scope" of a private member is: everywhere within the lexical boundaries of the top-level class body.
That means: all private members that are defined within the class-body of the outermost class can be accessed from everywhere else in this class-body.
For instance the private method of an inner class can be accessed from methods of the outer class or from any method of another inner class of the outer class.

Related

Aren't Anonymous Inner Classes actually subclasses?

Assume that A is a custom class, and consider the following declaration of an anonymous inner class:
A Obj = new A() {
#Override
public String toString() {
return "Hello!";
}
}
In this scenario, Obj is an instance of an anonymous inner class whose toString method has been overridden. Since it was declared with type A, the anonymous class must be a subclass of A. So then, why isn't this class called an Anonymous Subclass instead of an anonymous inner class? Where does the 'inner' come from?
Yes, obj is an instance of a subclass of A. And you can verify the superclass by calling obj.getClass().getSuperclass():
That prints something like:
class stackoverflow.Test$1 //obj.getClass()
class stackoverflow.A //obj.getClass().getSuperclass()
So then, why isn't this class called an Anonymous Subclass instead of an anonymous inner class?
Those are just semantics. It's a name. There could be many reasons, however, one of which being that anonymous classes can implement interfaces directly:
Runnable r = new Runnable() {
public void run() {}
}
This is not a subclass of anything (but Object, but what isn't a subclass of Object...), but it's an anonymous class too.
Why isn't this class called an Anonymous Subclass instead of an anonymous inner class?
Because (in general) anonymous inner class aren't necessarily subclasses1. An anonymous inner class can extend an interface rather than a class.
Because the "subclass-ness" is not important2 in most contexts where we talk about anonymous inner classes.
Because humans are lazy3 and "Anonymous Inner Subclasses" is one extra syllable. Or to put it another way, there is a natural tendency for people to optimize their speech and writing patterns.
Because ... convention.
Where does the 'inner' come from?
Inner has a technical meaning in Java. It means two things.
It means that the class is declared inside another class.
It means that the class is permitted to refer to the this of an instance of the enclosing class.
See the nice taxonomy in #Andreas's answer.
Historical footnote.
In fact, the official terminology is Anonymous Class. Indeed, Sun used the terminology "Anonymous Class" rather than "Anonymous Inner Class" way back in Java 1.1 when the construct was added to the language. For example, the "Inner Class Specification" from the Java 1.1.4 release notes refers to them as "Anonymous Classes" ... most of the time.
I suspect that what happened was that there was some inconsistency in earlier Sun presentations or papers, and various non-Sun authors latched onto the "anonymous inner class" version in their writings. The Sun team tried to quietly correct this by using "Anonymous Class" in the official Java Language Spec and Tutorial. But it was too late. The books were in the bookshops, the articles were on the web.
1 - Except in the trivial sense. Every class that isn't Object must be a subclass of some class.
2 - Likewise, you would normally say "I am taking the dog for a walk", not "I am taking the black Labrador for a walk".
3 - In this case, "good lazy".
Subclass and inner class are two different aspects of the anonymous class. Because of the syntax, an anonymous class is obviously a subclass of the named class, so the inner aspect is more relevant for the categorization.
Java classes are categories like this1:
Top-Level class (§7.6)
Nested class (§8.5, §9.5)
Static Nested class
Inner class (§8.1.3)
Local class (§14.3)
Anonymous class (§15.9.5)
As you can see, an anonymous class is an inner nested class.
The categorization doesn't specify whether the class is a subclass, a base class, or a standalone class. Classes of any category can be a subclass or base class. As ernest_k mentioned in another answer, an anonymous class may be defined from an interface, in which case it's not a subclass at all.
1) Excerpt of bigger hierarchy at end of this other answer.
To answer your question's title, yes, they are. Anonymous inner classes are actually subclasses.
"Since it was declared with type A, the anonymous class, [Obj], must be a subclass of A."
Good job. :)
Anyways, to answer why the "inner" is there: If you declare an anonymous class inside another class (and the anonymous class isn't declared statically, more on that below) then it would be able to access its surrounding class just like an inner class would. For example:
public class Outer {
private final int someRandomValue = 4;
public final Object anonymousInnerInstance = new Object() {
#Override
public String toString() {
// Notice how this class has access to a field declared inside a different
// class. More specifically, this anonymous class can access someRandomValue,
// even though someRandomValue belongs to the class, Outer.
return "Anonymous Inner Class: " + someRandomValue;
}
};
public class RegularInner {
#Override
public String toString() {
// This regular inner class is inside Outer, (just like the anonymous class),
// and can access any of Outer's fields (amongst Outer's other things).
return "Regular Inner Class: " + someRandomValue;
}
}
public final RegularInner regularInnerInstance = new RegularInner();
public static void main(String[] args) {
Outer outerInstance = new Outer();
System.out.println(outerInstance.anonymousInnerInstance);
System.out.println(outerInstance.regularInnerInstance);
// By the way, you can make new RegularInner instances off of our Outer
// instance:
RegularInner newInnerInstance = outerInstance.new RegularInner();
// When you write "outerInstance.new SomeClass()" you're saying:
// "I'd like to initialize my 'SomeClass' object with 'outerInstance',
// as its container." This effectively means that any variables that
// belong to Outer that your SomeClass needs to access, it will access
// from the Outer instance you gave it.
}
}
So, anonymousInnerInstance's underlying class, and the class RegularInner, both have access to Outer's fields, and other instance-specific content belonging to Outer. That's why an anonymous class may sometimes be called an "inner" class.
Any instance of an inner class needs to be created with an instance of an outer class to back it up, or it won't know which object, (not class), it belongs to.
Static Trash
If an anonymous class is declared as static, it won't have access to its surrounding class's content and wouldn't be an "inner" class (instead, it would be an anonymous "nested" class).
public class Outer {
private final int someRandomValue = 4;
public static final Object anonymousStaticInstance = new Object() {
#Override
public String toString() {
// someRandomValue belongs to an INSTANCE of Outer. (So each Outer object you
// have has its own someRandomValue). Since this anonymous class
// is now static, it is no longer tied to an instance of Outer. It doesn't have
// an Outer object that it can read "someRandomValue" from. The same goes for
// RegularStatic, below.
return "Anonymous Inner Class: " + someRandomValue;
}
};
public static class RegularStatic {
#Override
public String toString() {
return "Regular Inner Class: " + someRandomValue;
}
}
public final RegularStatic regularInnerInstance = new RegularStatic();
public static void main(String[] args) {
Outer outerInstance = new Outer();
System.out.println(outerInstance.anonymousStaticInstance);// Java warns you here and
// tells you to access anonymousStaticInstance statically. This is because
// anonymousStaticInstance no longer belongs to any given instance of Outer.
// There is only one anonymousStaticInstance, that "belongs" to the class Outer,
// rather than multiple anonymousInnerInstances which each belong to an instance
// of Outer.
System.out.println(outerInstance.regularInnerInstance);
}
}
Remember that anonymous classes can be "inner" OR "nested". So when talking about them in general, just say "anonymous class". (Anonymous inner classes are a type of anonymous class). Also, do make sure to read the comments as they give most of the explanation.
Any questions? :)

Java - Private member vs default member of a private inner class

Since an enclosing class can access the private fields of its inner class, when should be they declared private, default or public for a private inner class?
At first glance, it seems irrelevant to specify an access modifier on the members of inner classes. As you pointed out, the containing class can access all members anyway.
Here are a few additional considerations though:
Sometimes inner classes are declared public and serve as part of the interface definition of the containing class. Perhaps the outer class has a method that returns an instance of the inner class. In this case, the inner class is subject to the same best practices for member visibility as top-level classes. It's preferrable to keep implementation details private in this case.
Although it wouldn't be enforced by the compiler, marking an inner class's members as private can document for future maintainers that those members are not intended to be accessed directly by the outer class code. Of course, at that point, it might warrant refactoring the inner class to its own top-level class.
Sometimes inner classes are used in combination with reflection-based frameworks that only operate on public members. For example, the Jackson JSON serializer by default only operates on public members. It is possible to make it operate on private members by doing a few things like adding a public getter. This is extra work, so it may be more convenient to declare the member public in the first place.
If the above points do not apply, and in the absence of any other requirements, the simplest and shortest code is to omit the access modifier entirely (default/package-private). This would be a coding style question for a project to consider.
It's a good style to declare everything private unless there is a reason to use package private or public visibility. And this reason should not be it's more convenient.
Everything that is not private may be used outside of your class and thus changes to any non-private aspect of your code may break other code places or even external code that relies on your code. Making more difficult or sometimes even impossible to do refactorings and change the inner workings of your classes.
In the special case of a private inner class everything is only visible to your containing class. That is the visibility of the inner classes' members is not of importance. To the other extreme, if you are working on a library its common practice to only expose interfaces as contract. Keeping the implementation details completely hidden.
Not only the outer class but also other classes can access inner class and its members .So when you want to make the inner class members accessible by only its outer class you can declare them as private . consider the fallowing example
There are 2 classes in same package com.exercise.test and classes in it are OtherClass and SampleClassWithInner which contains inner class InnerClass
the members of InnerClass declared as private is not accessible in OtherClass. Where as it is accessible in SampleClassWithInner
refer this code for more clarity
package com.exercise.test;
//import com.exercise.test.SampleClassWithInner.InnerClass;
public class OtherClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
SampleClassWithInner sampleobj = new SampleClassWithInner();
SampleClassWithInner.InnerClass innerobj = sampleobj.new InnerClass();
// innerobj.var1=5; //compile time error
innerobj.setVar1(5); // ok works
// System.out.println("value of inner variable declared in other
// class"+innerobj.var1);// compile time error
System.out.println("value of inner variable declared in other class "
+ innerobj.getVar1());
sampleobj.innerMethodDemo();
}
}
and
package com.exercise.test;
public class SampleClassWithInner {
class InnerClass {
private int var1;
private int var2;
public int getVar1() {
return var1;
}
public void setVar1(int var1) {
this.var1 = var1;
}
public int getVar2() {
return var2;
}
public void setVar2(int var2) {
this.var2 = var2;
}
}
public void innerMethodDemo() {
InnerClass obj = new InnerClass();
obj.var1 = 10;
System.out.println("this is form the method in outer class " +
obj.var1);
}
}

how does HashMap.keySet() work [duplicate]

This question already has answers here:
Why is an anonymous inner class containing nothing generated from this code?
(5 answers)
Closed 9 years ago.
I have an Outer class which has a private Inner class.
In my Outer class method, I instantiate the Inner class as follows:
Outer outer = new Outer();
Inner inner = outer.new Inner();
The compiler converts this code to:
Outer outer = new Outer();
Inner inner = new Inner(outer, null);
Using reflection shows that the Inner class has the following synthesized constructors:
private Outer$Inner(Outer)
Outer$Inner(Outer,Outer$Inner)
Since the Inner class is private, the compiler adds that private constructor to it so nobody can instantiate that class. But obviously the Outer class should be able to instantiate it, so the compiler adds that other package private constructor which in turn calls the private constructor. Also, since the package-private constructor has that $ in its name, normal Java code can't call it.
Question: why synthesize one private and one package-private constructor? Why not synthesize only the package-private constructor and be done with it?
If you write the code like,
public class Outer {
private class Inner {}
}
You will note that there is only one constructor private Outer$Inner(Outer)
This constructor is required by Section 8.8.9 of the JLS, which says that if no constructor is defined a default constructor must be generated, and in this case the default constructor must be private,
In a class type, if the class is declared public, then the default
constructor is implicitly given the access modifier public (§6.6); if
the class is declared protected, then the default constructor is
implicitly given the access modifier protected (§6.6); if the class is
declared private, then the default constructor is implicitly given the
access modifier private (§6.6); otherwise, the default constructor has
the default access implied by no access modifier.
However, when you you instantiate an instance of Inner inside Outer with code like,
public class Outer {
private class Inner {}
public String foo() {
return new Inner().toString();
}
}
The compiler has to generate a constructor that Outer can legally call (you can't legally call the private default constructor because it is private). So a new synthetic constructor must be generated by the compiler. The new constructor must be synthetic, according to section 13.1 of the JLS
Any constructs introduced by the compiler that do not have a
corresponding construct in the source code must be marked as
synthetic, except for default constructors and the class
initialization method.
This second constructor has no corresponding construct in the source code, so this new constructor must be synthetic. The first private constructor must still be generated, since the JLS requires a private default constructor.
This is not an answer, which I think has been well covered by sbridges. It is simply a working example that produces the behaviour you describe:
public class Outer {
private class Inner {
}
public static void main(String[] args) {
printConstructors();
//only one constructor is printed but two would appear if you
//uncommented the line below
//new Outer().new Inner();
}
private static void printConstructors() {
Constructor[] constructors = Outer.Inner.class.getDeclaredConstructors();
for (Constructor c : constructors) {
System.out.println(c.toGenericString());
}
}
}
The most likely answer is to respect what you declared in your source code. Doing this still allows to use the private constructor by reflection as you declared it.
This also avoids to check whether the private constructor is actually called within the Inner class.

Variables in private interface

I was trying to test working of private interfaces and wrote the code below. I can understand that a situation might arise to declare private interfaces if we don't want any other class to implement them but what about variables? Interface variables are implicitly public static final and hence i was able to access them even if interface was declared private. This can be seen in code below.
public class PrivateInterfaceTest {
/**
* #param args
*/
public static void main(String[] args) {
TestingInterfaceClass test = new TestingInterfaceClass();
TestingInterfaceClass.inner innerTest = test.new inner();
System.out.println(innerTest.i);
}
}
class TestingInterfaceClass {
private interface InnerInterface {
int i = 0;
}
class inner implements InnerInterface {
}
}
Does it mean that we can never really have private interface in true sense? And does it really make sense to if have private interface if we can access variables outside private interface?
EDIT:
Just want to add that same situation will not arise if we have private inner class. A private variable in inner class will never get exposed.
Your member interface is private. The inherited static field is not private.
A private member interface cannot be used as a type outside the enclosing top-level class or enum. This can be useful to prevent external code from implementing an interface you may wish to change. From the JLS:
The access modifiers protected and private pertain only to member interfaces within a directly enclosing class or enum declaration (§8.5.1).
The interface field is public, and inherited by the class that implements the interface. From the JLS:
A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class.
If you want to make the field accessible only within the classes that implement the member interface, you can put its declaration in the enclosing top-level scope.
class TestingInterfaceClass {
private static final int i = 0;
private interface InnerInterface {
// ...
}
class inner implements InnerInterface {
// ...
}
}
As I see, it is not the problem with private interface InnerInterface. It is the inner class which is at default scope inside TestingInterfaceClass exposing the content of InnerInterface. If you don't want the content of InnerInterface to be known to the world, you should also declare all the classes (specifically TestingInterfaceClass) as private.
Because every variable in an interface is public static final, it should be the responsibility of the class (implementing it) whether it should take care of the content inherited from private interface
Even though it's allowed, we don't need (and shouldn't use) an instance to access an static field.
Following is the way to access it -
System.out.println(TestingInterfaceClass.inner.i);
//note you cannot access the InnerInterface like this here because it's private
The inner has inherited the public static field i and i should be visible wherever the inner itself is visible.
Usually, interfaces are used to expose the behaviors of an object, while the implementations are hidden. But in your case, you are attempting the opposite.
The Interface variables are implicitly public static final, but you can't reach this variables because you can't reach previously the interface that contains these variable, which you have declared as private. First you need to be able to see the interface, and after that, go into content of the interface.

Why is a static class illegal in Java?

I'm developing an Android application but have hit a bit of a brick wall, I keep getting the error:
Illegal modifier for the class FavsPopupFragment; only public, abstract & final are permitted
This happened after following this answer to another SO question. Here is the code that I have:
package com.package.name;
/* Imports were here */
public static class FavsPopupFragment extends SherlockDialogFragment {
static FavsPopupFragment newInstance() {
FavsPopupFragment frag = new FavsPopupFragment();
return frag;
}
}
The error appears on the class name. I don't understand why this won't work, please help. Thank you.
You can't create a top level static class; that's what the compiler is trying to tell you. Also have a look at the answer here as to why this is the case. The gist is:
What the static boils down to is that an instance of the class can
stand on its own. Or, the other way around: a non-static inner class
(= instance inner class) cannot exist without an instance of the outer
class. Since a top-level class does not have an outer class, it can't
be anything but static.
Because all top-level classes are static, having the static keyword in
a top-level class definition is pointless.
As the previous answers stated, you can't use the static keyword in top level classes. But i wonder, why did you want it to be static?
Let me show you how a static / non static inner class is used in an example:
public class A
{
public class B{}
public static class C{}
public static void foo()
{
B b = new B(); //incorrect
A a = new A();
A.B b = a.new B(); //correct
C c = new C(); //correct
}
public void bar()
{
B b = new B();
C c = new C(); // both are correct
}
}
And from a completely different class:
public class D
{
public void foo()
{
A.B b = new A.B() //incorrect
A a = new A()
A.B b = a.new B() //correct
A.C c = new A.C() //correct
}
}
1. static canNOT be used at Package level.
2. static is possible within the Class level.
3. But you can still use static on a class, when the class is an inner class, ie. (static inner class), commonly known as Top level class.
A top-level class is by definition already top-level, so there is no point in declaring it static; it is an error to do so. The compiler will detect and report this error.
Remove static from class definition. Only nested classes can be static.
for the class FavsPopupFragment; only public, abstract & final are
permitted
I don't think you can create instances of a static class using the new keyword. This is a fragment anyway, so it probably should not be static anyway.
You cant use static modifier for top level classes, though there can be nested classes which can be modified with static keyword.
In this case either you need to remove the static modifier, or make sure this class nested into another top level class.
Extra info
There's no such thing as a static class. The static modifier in this
case (static nested) says that the nested class is a static member of the outer class.
That means it can be accessed, as with other static members, without
having an instance of the outer class.
Just as a static method does not have access to the instance variables
and nonstatic methods of the class, a static nested class does not
have access to the instance variables and nonstatic methods of the
outer class
static can be used at the inner class level. Top level can't be static, as said before, only public, abstract & final are permitted.
static is mainly used inside class level for methods and variables.
The access modifier supported for top level are class are as follows :
1) public
2) default
3) abstract
4) final
5) strictfp.
Reason: Top level class
Because the static keyword is meant for providing memory and executing logic without creating Objects, a class does not have a value logic directly, so the static keyword is not allowed for outer class and mainly as mentioned above static can't be used at Package level. It only used within the Class level.

Categories

Resources