Why inner class have access to private field of input object param of such class?
private class Inner {
private int privatefield = 0;
public void method( Inner inner ) {
privatefield = 1; //ok
inner.privatefield = 1; //this line confusing me (broken incapsulation)
}
}
This has nothing to do with inner classes per se.
The code within a class always has access to private members of the same class in Java. The notion of private/public etc refers to where the code lives, not whether it refers to "this" instance or a different one. Protected access is a little bit more complicated than other access, but the same general principle applies.
See JLS section 6.6 for more details. In particular:
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.
And that explains why one nested class has access to another nested class's private fields, so long as they're nested within the same top-level class, as per your comments. It's an odd rule, I agree - and I prefer C#'s approach in terms of private accessibility and nested types - but the above quote shows that the compiler is obeying the rules of the JLS.
I suspect the reasoning is that if you're working within the same top-level class, you're responsible for all the code within that class, including the nested classes - so you're trusted not to abuse them.
Why inner class have access to private field of input object param of such class?
Even though private, inner class is a member of outer class
private members are accessible for the class members.
Any method within a class can access a global variable inside that class. The private parameter only makes it so that OTHER classes can not access the variable.
In this case the methods in Inner will be able to find the var and methods outside of Inner will not be able to.
If you see Docs of Controlling Access to Members of a Class
The private modifier specifies that the member can only be accessed in its own class.
Since privatefield is member of your class, you have access inside the class.
Since the method(Inner inner) resides in the Inner class, hence method(Inner inner) can access the member private to the Inner class.
Access modifiers define the scope in which your variable can be accesses and not whether individual instances can access it or not!
private int privatefield = 0;
Your variable is non static so it will be accesses by instance of the class. So inner.privatefield makes sense. Now your variable privatefield is private which means you can access it inside your Inner class. Since your are accessing the variable inside method() which is inside Inner class there is no problem and is perfectly valid.
Consider that your class isn't nested neither private, cause it's irrelevant with your question. It has to do with scope visibility.
Declaration says
private modifier — the field is accessible only within its own class.
Since you access the privatefield property inside the class that is declared even if it's a member of a different instance your encapsulation isn't broken,private scope is maintained.
Related
I'm refactoring an android project which is getting to big. Running lint gives me the JSME issue Private member access between outer and inner classes. Considering the following example
public class Outer {
private Inner mInner = new Inner();
private class Inner {}
}
I get the information
Name
private field Inner mInner
Location
class Outer (default package)
Problem synopsis
Access to private member of class 'Inner' at line 2
Problem resolution
Make 'Inner' constructor package-local
Applying the problem resolution changes the source to
public class Outer {
private Inner mInner = new Inner();
private class Inner {
Inner() {}
}
}
I'm a little confused at the moment. Until now I thought the example would be equivalent to
public class Outer {
private Inner mInner = new Inner();
private class Inner {
public Inner() {}
}
}
Am I wrong in this case or is it an issue of lint?
Section 8.8.9 of the Java language specification, "Default constructor" says:
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.
You're wrong in your understanding, but the linter is not being particularly clear, and the advice probably isn't relevant for Android (which isn't J2ME).
As David explained, the inner class's implicit default constructor has the same access modifier as the class itself, but private members are accessible within the same compilation unit (Java file). There's no language reason to avoid the private constructor.
However, internally, since the classes are compiled into separate output files, the compiler has to create synthetic adapter methods to provide the classes access to the private members. The runtime disadvantage of these methods is irrelevant for desktop applications, but for something as cramped as J2ME, the difference might be worth eliminating by making the member accessible directly (using package scope).
Android performs significant post-processing on the class files, and Android devices are not nearly as constrained as J2ME devices. Unless you're writing code to target both platforms, I'd change the lint configuration.
Consider the following code:
public class Foo
{
class Bar
{
private String barbar;
public Bar( String b ) { barbar = b; }
}
class Meh
{
Bar b = new Bar("BAR!");
public void displayName() {
System.out.println( b.barbar );
}
}
}
Java allows class Meh to access the private instance variable, barbar, which is declared as private within Bar.
I know this question has been asked before here. However, the answer just basically reiterates that the observed scope is what it is (that barbar is accessible within the braces of class Foo), but offers no explanation. After some Googling, I hadn't been able to land on a good discussion of this behavior. What I would like to know is if there's a specific rationale for this scoping behavior. I would have expected barbar to be private "within the braces" of class Bar.
The fundamental aspect of this is that inner classes (as opposed to static nested classes) are part of their enclosing class. They aren't separate from it, or from each other. So just like other parts of the enclosing class (constructors and methods) have access to all of its private information, so do all the members of the inner classes. Inner classes are, in some sense, a bit of a fiction that we use as a convenient abstraction mechanism. And since inner classes are part of the enclosing class, their private information is its private information, and so is shared with other inner classes.
As per the JLS
The body of a class declares members (fields and methods and nested
classes and interfaces), instance and static initializers, and
constructors. The scope of a member is the
entire body of the declaration of the class to which the member
belongs. Field, method, member class, member interface, and
constructor declarations may include the access modifiers
public, protected, or private.
So, as per the example, class Bar and class Meh both belongs class Foo.
Hence, any member of Foo will have access to all its other members regardless its a field method or nested class/interface as per the first line in the specs.
Comment questioin:
If I made the variable within Bar to be public instead of private would it then become accessible outside of Foo even though it's from an inner class?
Yes of course it is accessible from outside of the class.
Look at the below example
class A {
Foo foo = new Foo();
Foo.Bar bar = foo.new Bar("name");
public void someOtherMethod() {
bar.barbar = "someOtherName";
//this is valid only if barbar is public
//or if it is default and within the same package
}
}
The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class. They are intended to be used when you have 2 requirements:
Some piece of functionality in your outer class would be most clear if it was implemented in a separate class.
Even though it's in a separate class, the functionality is very closely tied to way that the outer class works.
Given these requirements, inner classes have full access to their outer class. Since they're basically a member of the outer class, it makes sense that they have access to methods and attributes of the outer class -- including privates.
I don't think you're going to find the rationale behind the design of the language unless you talk to the people who designed it. However, one can often get insight into the "why" through the Java Language Specification. Section 6.3 (Scope of a Declaration) lays out the rules for scoping and has examples of the rules in action.
Specifically, the behavior you're asking about is covered by the statement:
The scope of a local class declaration immediately enclosed by a block
is the rest of the immediately enclosing block, including its own
class declaration.
Your two local classes have the same scope, i.e. the "immediately enclosing block", specifically class Foo.
Perhaps in your question you can explain why you think barbar should be inaccessible to the enclosing class, and then we can address any misconceptions you have about how Java works.
class OuterClass {
class InnerClass {
static int i = 100; // compile error
static void f() { } // compile error
}
}
Although it's not possible to access the static field with OuterClass.InnerClass.i, if I want to record something that should be static, e.g. the number of InnerClass objects created, it would be helpful to make that field static. So why does Java prohibit static fields/methods in inner classes?
EDIT: I know how to make the compiler happy with static nested class (or static inner class), but what I want to know is why java forbids static fields/methods inside inner classes (or ordinary inner class) from both the language design and implementation aspects, if someone knows more about it.
what I want to know is why java forbids static fields/methods inside inner classes
Because those inner classes are "instance" inner classes. That is, they are like an instance attribute of the enclosing object.
Since they're "instance" classes, it doesn't make any sense to allow static features, for static is meant to work without an instance in the first place.
It's like you try to create a static/instance attribute at the same time.
Take the following example:
class Employee {
public String name;
}
If you create two instances of employee:
Employee a = new Employee();
a.name = "Oscar";
Employee b = new Employee();
b.name = "jcyang";
It is clear why each one has its own value for the property name, right?
The same happens with the inner class; each inner class instance is independent of the other inner class instance.
So if you attempt to create a counter class attribute, there is no way to share that value across two different instances.
class Employee {
public String name;
class InnerData {
static count; // ??? count of which ? a or b?
}
}
When you create the instance a and b in the example above, what would be a correct value for the static variable count? It is not possible to determine it, because the existence of the InnerData class depends completely on each of the enclosing objects.
That's why, when the class is declared as static, it doesn't need anymore a living instance, to live itself. Now that there is no dependency, you may freely declare a static attribute.
I think this sounds reiterative but if you think about the differences between instance vs. class attributes, it will make sense.
The idea behind inner classes is to operate in the context of the enclosing instance. Somehow, allowing static variables and methods contradicts this motivation?
8.1.2 Inner Classes and Enclosing Instances
An inner class is a nested class that is not explicitly or implicitly declared static. Inner classes may not declare static initializers (§8.7) or member interfaces. Inner classes may not declare static members, unless they are compile-time constant fields (§15.28).
InnerClass cannot have static members because it belongs to an instance (of OuterClass). If you declare InnerClass as static to detach it from the instance, your code will compile.
class OuterClass {
static class InnerClass {
static int i = 100; // no compile error
static void f() { } // no compile error
}
}
BTW: You'll still be able to create instances of InnerClass. static in this context allows that to happen without an enclosing instance of OuterClass.
From Java 16 onwards, this is no longer the case. Quoting from JEP 395 (on finalizing records):
Relax the longstanding restriction whereby an inner class cannot declare a member that is explicitly or implicitly static. This will become legal and, in particular, will allow an inner class to declare a member that is a record class.
Indeed, the following code can be compiled with Java 16 (tried with 16.ea.27):
public class NestingClasses {
public class NestedClass {
static final String CONSTANT = new String(
"DOES NOT COMPILE WITH JAVA <16");
static String constant() {
return CONSTANT;
}
}
}
Actually, you can declare static fields if they are constants and are written in compile time.
class OuterClass {
void foo() {
class Inner{
static final int a = 5; // fine
static final String s = "hello"; // fine
static final Object o = new Object(); // compile error, because cannot be written during compilation
}
}
}
class Initialization sequence is a critical reason.
As inner classes are dependent on the instance of enclosing/Outer class, so Outer class need to be initialized before the initialization of the Inner class.
This is JLS says about class Initialization. The point we need is, class T will be initialize if
A static field declared by T is used and the field is not a constant variable.
So if inner class have an static field accessing that will cause initializing the inner class, but that will not ensure that the enclosing class is initialized.
It would violate some basic rules. you can skip to the last section (to two cases) to avoid noob stuff
One thing about static nested class, when some nested class is static it will behave just like a normal class in every way and it is associated with the Outer class.
But the concept of Inner class/ non-static nested class is it will be associated with the instance of outer/enclosing class. Please note associated with instance not the class.
Now associating with instance clearly means that (from the concept of instance variable) it will exist inside a instance and will be different among instances.
Now, when we make something static we expect it will be initialized when the class is being loaded and should be shared among all instances. But for being non-static, even inner classes themselves (you can definitely forget about instance of inner class for now) are not shared with all instance of the outer/enclosing class (at least conceptually), then how can we expect that some variable of inner class will be shared among all the instance of the inner class.
So if Java allow us to use static variable inside not static nested class. there will be two cases.
If it is shared with all the instance of inner class it will violate the concept of context of instance(instance variable). It's a NO then.
If it is not shared with all instance it will violate the the concept of being static. Again NO.
Here is the motivation that I find best suitable for this "limit":
You can implement the behavior of a static field of an inner class as an instance field of the outer object;
So you do not need static fields/methods.
The behaviour I mean is that all inner class instances of some object share a field(or method).
So, suppose you wanted to count all the inner class instances, you would do:
public class Outer{
int nofInner; //this will count the inner class
//instances of this (Outer)object
//(you know, they "belong" to an object)
static int totalNofInner; //this will count all
//inner class instances of all Outer objects
class Inner {
public Inner(){
nofInner++;
totalNofInner++;
}
}
}
In simple words, non-static inner classes are instance variable for outer class, and they are created only when an outer class is created and an outer class object is created at run-time while static variables are created at class loading time.
So non-static inner class is runtime thing that's why static not the part of a non-static inner class.
NOTE: treat inner classes always like a variable for an outer class they may be static or non-static like any other variables.
Because it would cause ambiguity in the meaning of "static".
Inner classes cannot declare static members other than
compile-time constants. There would be an ambiguity about the meaning
of “static.” Does it mean there is only one instance in the virtual
machine? Or only one instance per outer object? The language designers
decided not to tackle this issue.
Taken from "Core Java SE 9 for the Impatient" by Cay S. Horstmann. Pg 90 Chapter 2.6.3
In the Java language designers' own words:
Since nested classes were first introduced to Java, nested class
declarations that are inner have been prohibited from declaring static
members... It simplifies the language's task of resolving and
validating references to in-scope variables, methods, etc.
There was never any particularly grand conceptual or philosophical reason to prohibit this.
Simplifying things for the language was deemed an insufficient reason to continue to maintain this restriction. Along with the introduction of records in Java 16, they made the decision to relax the restriction.
Class Inner will be initialize if a static field declared by Inner is used and the field is not a constant variable.
class Outer{
class Inner{
static Inner obj = new Inner();
}
public static void main(String[] args){
Inner i = Inner.obj; // It woulds violate the basic rule: without existing Outer class Object there is no chance of existing Inner class Object.
}
}
I guess it's for consistency. While there doesn't seem to be any technical limitation for it, you wouldn't be able to access static members of the internal class from the outside, i.e. OuterClass.InnerClass.i because the middle step is not static.
Although, this is a very basic code, it seems there is something fundamentally flawed in Java, or the JVM used by the Eclipse IDE I have used to run the code.
The code runs even though it should not (I think)! The code in A.java simply displays "Hello, I am A!"
Here it is:
import java.lang.*;
import java.util.*;
class A {
private void methodA() {System.out.println("Hello, I am A!");}
public static void main(String[] args) {
A a = new A();
a.methodA(); }
}
I do not understand why, after creating an instance of class A, main() succeeds in running a private method of class A on that instance. Yes, the main method belongs to class A, but it is not accessing the private method from inside the current object in the context of the "this" reference. In fact, since it is a static method, it cannot access non-static members from within the class. Instead of main(), a non-static member method could have invoked methodA() from inside only. But that is another issue since I have not defined any non-static second method.
Now that the inside-view is talked about, let's come back to the point, the outside-view. As you can see, main() attempts to invoke methodA from outside the object and succeeds! Why isn't private getting treated as private?
I am pulling my hair....
Anyone, please reply...
Yes, the main method belongs to class A, but it is not accessing the private method from inside the current object in the context of the "this" reference.
That doesn't matter. That's just not the model of accessibility that Java uses. What's important is the class in which the code is written, not whether it's accessing members in the same object.
This is very useful, as otherwise (for example) it would be impossible to implement an equals method using private members of both classes.
This may not be how you would have chosen to specify the language, but it is how Java is specified. See JLS 6.6.1 for details of accessibility. In particular:
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.
Note that protected access is slightly odd here - a protected instance member of class SuperClass can only be accessed within code in SubClass via an expression of either SubClass or a further subclass. But it still doesn't have to be "the same" object.
private modifer
Methods, Variables and Constructors that are declared private can only be accessed within the declared class itself.
private means "private to the class". Not "private to the instance".
That's what allows implementing things like static factory methods calling private constructors, or equals() or compareTo() methods comparing private fields of objects of the same class, or copy constructors, etc.
Private members of enclosing classes are also accessible from inner classes of this enclosing class, and vice-versa.
After the technically correct answers here's my two cents why I think it is quite reasonable to implement private that way:
As I see it the main reason that private methods and attributes exists is "implementation hiding". You are declaring "Don't use this method from outside my class(!), since it might change or disapear anytime I like". So it makes sense to disallow access from outside the class. But if I'm accessing it from another object of the same class I and make any implementation changes I'm well aware of the changes and the accesses of the private members and can act accordingly.
Another thing to think about:
If class B extends class A, then any B-object also is an A-object, but it can't access the private A-methods. Why would that be if private methods were private to the object?
While this is obviously a RTFM case, somehow I failed to find a concise source explaining it all.
public class Outer {
private class Inner {
}
}
Private class Inner is an inner class of a public class Outer.
My question is about visibility of Inner from outside `Outer'.
Should I be able to instantiate Inner in another class? If yes, are there any limitations (like this class being in the same package, etc.)?
Can Inner be used as a concrete type when using collections? For example, should I be able to declare ArrayList <Inner> in another class?
If another class extends Outer will Inner come along in terms of the above questions?
Inner is private, therefore only its parent, Outer, can do anything at all with it.
The "FM" in this case is the Java Language Specification. You want section 6.6.1 which includes:
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.
So the constructor can be called anywhere within the declaration of Outer (including within any other nested classes that Outer declares), but nowhere else. Access is not inherited - it's as simple as whether the source code that's trying to call the constructor is within the source code of Outer.