Why java compiler is not restricting from accessing a private attribute from other class?
I have inner class which has a attribute 'a' with modifier 'private'. I can able to access this variable with its instance variable out side the class. see the code below.
package com.test;
public class Test {
public Test() {
}
public static void main(String[] args) {
new Test().execute(); // test method
}
public void execute() {
InnerClass innerClassInstance = new InnerClass();
// accessing private member from other class instance, HOW?
System.out.println(innerClassInstance.a);
InnerStaticClass innerStaticClassInstance = new InnerStaticClass();
// accessing private member from other class instance, HOW?
System.out.println(innerStaticClassInstance.a);
}
private final class InnerClass {
private int a; // accessible only in InnerClass??
}
private final static class InnerStaticClass {
private int a; // accessible only in InnerClass??
}
}
A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Sorry, I misread the question.
Looks at JLS http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.1
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, a field in inner-class (which is obviously inside class body) can be accessed by outer class even if it's private.
See the Java language specification:
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.
your Inner class is a member of your Test class so, Test class can access private member of Inner class too.
Try like this it will give compile error
public class Test {
public Test() {
}
public static void main(String[] args) {
new Test().execute(); // test method
}
public void execute() {
InnerClass innerClassInstance = new InnerClass();
// accessing private member from other class instance, HOW?
System.out.println(innerClassInstance.a);
InnerStaticClass innerStaticClassInstance = new InnerStaticClass();
// accessing private member from other class instance, HOW?
System.out.println(innerStaticClassInstance.a);
}
}
class InnerClass {
private int a; // accessible only in InnerClass??
}
final class InnerStaticClass {
private int a; // accessible only in InnerClass??
}
These nested classes are meant for that .When you have private
members in a class ,we write nested class to do unit testing.
Related
I have a class which has another static inner class:
class A {
private List<String> list;
public static class B {
// I want to update list here without making list as static
// I don't have an object for outer class
}
}
You generally use static classes when you don't need access to the instance variables. If you need to access the instance variables make the class non-static.
As you can see from other answers that you will need a non-static inner class to do that.
If you really cannot make your inner class non-static then you can add required getter and setter method in outer class and access them by creating an instance of outer class from inside inner static class:
public class A {
private List<String> list = new ArrayList<>();
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public static class B {
// i want to update list here without making list as static
void updList() {
A a = new A();
a.setList(someOtherList);
System.out.println(a.getList());
}
}
}
No, you'll need a non-static inner class to do that.
From the JLS §8.5.1:
The static keyword may modify the declaration of a member type C within the body of a non-inner class or interface T. Its effect is to declare that C is not an inner class. Just as a static method of T has no current instance of T in its body, C also has no current instance of T, nor does it have any lexically enclosing instances.
It is a compile-time error if a static class contains a usage of a non-static member of an enclosing class.
In your code, list is an instance variable of class A and B is nested static class. The rules of accessing static and not static member don't change for nested static class.
The variable list is instance variable so a can't be accessed from static context.
To enable this, you need to change static nester class to inner class.
class A {
private List<String> list = new ArrayList<String>();
public class B {
public void someMethod(){
list.add("abc");
}
}
}
private List<String> list;
Here list is an instance variable while the inner class is static which means that class B is the same across different class A instances; one cannot access it. And, that too for a very good and obvious reason.
One solution that you can use is pass reference of member list to the constructor of class B with a weakReference to avoid memory leak.
Something like this:
class A {
private List<String> list;
public static class B {
WeakReference<List<String>> innerList;
//constructor
B(WeakReference<List<String>> innerList){
this.innerList = innerList;
}
}
I'm currently reading Effective Java by Joshua Bloch and I love it! But on page 112 (Item 24) Bloch writes:
A static member class is the simplest kind of nested class. It is best
thought of as an ordinary class that happens to be declared inside
another class and has access to all of the enclosing class’s members,
even those declared private.
And that really confuses me. I would rather say:
A static member class is the simplest kind of nested class. It is best
thought of as an ordinary class that happens to be declared inside
another class and has access to all of the enclosing class’s static members,
even those declared private.
Here is a snippet that illustrates my understanding of the quote:
public class OuterClass {
public void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
public void sayHello() {
printMessage("Hello world!"); //error: Cannot make a static reference to the non-static method printMessage(String)
}
}
}
You can see that InnerClass's sayHello method does not have access to OuterClass's printMessage method as it is declared in a static inner class while the printMessage method is an instance method. It looks like the author suggests that a static member class can access nonstatic fields of the enclosing class. I am convinced that I have misunderstood something in his last sentence but I cannot figure out what. Any help will be appreciated!
edit: I changed the visibility of the two methods because it is irrelevant to my question. I'm interested in static members, not private members.
Just because InnerClass is static, doesn't mean it couldn't obtain a reference to an instance of OuterClass through other means, most commonly as a parameter, e.g.
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
private void sayHello(OuterClass outer) {
outer.printMessage("Hello world!"); // allowed
}
}
}
If InnerClass had not been nested inside OuterClass, it would not have had access to the private method.
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
}
class InnerClass {
private void sayHello(OuterClass outer) {
outer.printMessage("Hello world!"); // ERROR: The method printMessage(String) from the type OuterClass is not visible
}
}
Note the error message. It's not saying you don't have access. It's saying the method cannot be called. Instance methods don't mean anything without an instance to
call them on. What the error message is telling you is that you don't have that instance.
What Bloch is telling you is that if that instance existed, code in the inner class could call private instance methods on it.
Say we have the following class:
public class OuterClass {
public void publicInstanceMethod() {}
public static void publicClassMethod() {}
private void privateInstanceMethod() {}
private static void privateClassMethod() {}
}
If we try to call those private methods from some random class, we can't:
class SomeOtherClass {
void doTheThing() {
OuterClass.publicClassMethod();
OuterClass.privateClassMethod(); // Error: privateClassMethod() has private access in OuterClass
}
void doTheThingWithTheThing(OuterClass oc) {
oc.publicInstanceMethod();
oc.privateInstanceMethod(); // Error: privateInstanceMethod() has private access in OuterClass
}
}
Note that those error messages say private access.
If we add a method to OuterClass itself, we can call those methods:
public class OuterClass {
// ...declarations etc.
private void doAThing() {
publicInstanceMethod(); // OK; same as this.publicInstanceMethod();
privateInstanceMethod(); // OK; same as this.privateInstanceMethod();
publicClassMethod();
privateClassMethod();
}
}
Or if we add a static inner class:
public class OuterClass {
// ...declarations etc.
private static class StaticInnerClass {
private void doTheThingWithTheThing(OuterClass oc) {
publicClassMethod(); // OK
privateClassMethod(); // OK, because we're "inside"
oc.publicInstanceMethod(); // OK, because we have an instance
oc.privateInstanceMethod(); // OK, because we have an instance
publicInstanceMethod(); // no instance -> Error: non-static method publicInstanceMethod() cannot be referenced from a static context
privateInstanceMethod(); // no instance -> Error: java: non-static method privateInstanceMethod() cannot be referenced from a static context
}
}
}
If we add a non-static inner class, it looks like we can do magic:
public class OuterClass {
// ...declarations etc.
private class NonStaticInnerClass {
private void doTheThing() {
publicClassMethod(); // OK
privateClassMethod(); // OK
publicInstanceMethod(); // OK
privateInstanceMethod(); // OK
}
}
}
However, there's trickery going on here: a non-static inner class is always associated with an instance of the outer class, and what you're really looking at is:
private class NonStaticInnerClass {
private void doTheThing() {
publicClassMethod(); // OK
privateClassMethod(); // OK
OuterClass.this.publicInstanceMethod(); // still OK
OuterClass.this.privateInstanceMethod(); // still OK
}
}
Here, OuterClass.this is special syntax for accessing that outer instance. But you only need it if it's ambiguous, e.g. if the outer and inner classes have methods with the same name.
Note too that the non-static class can still do the things the static one can do:
private class NonStaticInnerClass {
private void doTheThingWithTheThing(OuterClass oc) {
// 'oc' does *not* have to be the same instance as 'OuterClass.this'
oc.publicInstanceMethod();
oc.privateInstanceMethod();
}
}
In short: public and private are always about access. The point Bloch is making is that inner classes have access that other classes don't. But no amount of access allows you to call an instance method without telling the compiler what instance you want to call it on.
The way you showed it requires inheritance. But methods and fields could be access in this way:
public class OuterClass {
private void printMessage(String message) {
System.out.println(message);
}
private static class InnerClass {
private void sayHello() {
OuterClass outer = new OuterClass();
outer.printMessage("Hello world!");
}
}
}
But, that the static inner class doesn't have access to the printMessage function doesn't have to do with that it is an inner class, but that it is static and can't invoke a non-static method. I think that the use of the word "static" you proposed was implicit in the first sentence. What he is pointing out, or chose to emphasize, is just that the inner class can still access private methods of its parent class. He might have just though it unnecessary or confusing to make the static/non-static distinction in the same sentence, too.
The way I see it, the text is absolutely right. Static member classes can access the private members of the enclosing classes (sort of). Let me show you an example:
public class OuterClass {
String _name;
int _age;
public OuterClass(String name) {
_name = name;
}
public static OuterClass CreateOuterClass(String name, int age) {
OuterClass instance = new OuterClass(name);
instance._age = age; // Notice that the private field "_age" of the enclosing class is visible/accessible inside this static method (as it would also be inside of a static member class).
return instance;
}
}
I was reading Effective Java 2 - Item 22 and it says in the title:
"Favor static member classes over non-static"
but at the end of the chapter
Implementations of the collection interfaces, such as Set and List,
typically use nonstatic member classes to implement their iterators:
// Typical use of a nonstatic member class
public class MySet<E> extends AbstractSet<E> {
... // Bulk of the class omitted
public Iterator<E> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<E> {
...
}
}
I made a test program to see if there is any difference between them and here it is.
public class JavaApplication7 {
public static void main(String[] args) {
// TODO code application logic here
JavaApplication7 t = new JavaApplication7();
Inner nonStaticObject = t.getAClass();
Sinner staticObject = new JavaApplication7.Sinner();
nonStaticObject.testIt();
staticObject.testIt();
}
public Inner getAClass(){
return new Inner();
}
static class Sinner{
public void testIt(){
System.out.println("I am inner");
}
}
class Inner{
public void testIt(){
System.out.println("I am inner");
}
}
}
The output is
I am inner
I am inner
So, they did the same job.
I wonder Why non-static class is used in this example?
An iterator usually needs to refer to the collection used to create it in the first place. You can do that with a static nested class which is explicitly provided with a reference to the collection - or you can just use an inner class, which has that reference implicitly.
Basically, if every instance of the nested class needs an instance of the enclosing class to operate (and that instance doesn't change), then you might as well make it an inner class. Otherwise, make it a static nested class.
the difference is that non-static inner class have an implicit reference to the containing class.
public class JavaApplication7 {
//You can access this attribute in non-static inner class
private String anyAttribute;
public Inner getAClass(){
return new Inner();
}
static class Sinner{
public void testIt(){
//Here, you cannot access JavaApplication7.this
}
}
class Inner{
public void testIt(){
//Here, you can access JavaApplication7.this
//You can also access *anyAttribute* or call non-static method getAClass()
}
}
}
The difference between static and non-static nested classes is that the non-static ones are implicitly associated with an instance of the outer class, which they can refer to as OuterClassName.this. This reference is useful when implementing iterators, as they need access to the members of the collection they are related to. You could achieve the same thing by using a static nested class which is explicitly handed a reference to the outer class.
there is no such thing as a static inner class, It is static nested class. "Each instance of a nonstatic [nested] class is implicitly associated with an enclosing instance of its containing class... It is possible to invoke methods on the enclosing instance."
A static nested class does not have access to the enclosing instance.
reference: this so thread
In the case of creating instance, the instance of non s
static inner class is created with the reference of
object of outer class in which it is defined……this
means it have inclosing instance …….
But the instance of static inner class
is created with the reference of Outer class, not with
the reference of object of outer class…..this means it
have not inclosing instance…
For example……
class A
{
class B
{
// static int x; not allowed here…..
}
static class C
{
static int x; // allowed here
}
}
class Test
{
public static void main(String… str)
{
A o=new A();
A.B obj1 =o.new B();//need of inclosing instance
A.C obj2 =new A.C();
// not need of reference of object of outer class….
}
}
I have a class with private fieds and also a static abstract inner class with the generic type extending the outer class type, that tries to access the outer class private fields but get's the following error:
- error: a has private access in Outer
- error: doSomething has private access in Outer
See code below:
public abstract class Outer extends SomeOuter
{
private Object a;
private void doSomething(){}
public static absract class Inner<T extends Outer> extends SomeOuter.SomeInner<T> {
public InnerMethod(T p) {
p.a; //error: a has private access in Outer
p.doSomething() //error: doSomething has private access in Outer
}
}
}
I'm compiling using jdk 1.7
Can anyone please tell me why am getting this error.
An Inner class can access private field of enclosing class and a static inner class can also access any private members of enclosing class .
The class itself isn't really "static"; there's no such thing as a static class. The
static modifier in this case 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.
Since it is a static member , it is able to access outer class's private members , because within class private members are accessible.
eg.
class One
{
private int i=0;
class Two
{
void go()
{
System.out.println(new One().i); //accessible
}
}
}
class two
{
private int i=3;
static class one
{
void go()
{
System.out.println(new two().i); //accessible in static class
}
}
}
But here ,
Inner<T extends Outer> extends SomeOuter.SomeInner<T>
T is a class which extends Outer , doesn't mean it is inner.
That why it is giving error.
thats how private modifier works if you ever declare any method or variable as private than that things can not be accessed out side the class
A static embedded class is effectively an outer class. It can't access the private members of another class. See the accepted answer to:
Static nested class in Java, why?
Both the Object and the function you're trying to use are declared as private, which means they cannot be used outside the Object. If you want to use them in child classes as well, declare them as protected.
Changes the scope of the fields on the Outer class to protected so that classes extending Outer may access these fields.
public abstract class Outer extends SomeOuter
{
protected Object a;
protected void doSomething(){}
public static absract class Inner<T extends Outer> extends SomeOuter.SomeInner<T> {
public InnerMethod(T p) {
p.a; //error: a has private access in Outer
p.doSomething() //error: doSomething has private access in Outer
}
}
}
Thats what you have private modifier for. Though it is the inner class, it cannot access the private members of the outer class. So, declare it as protected, as you are extending the outer class to inner class
What is the example of indirect access to private member of superclass from subclass?
A nested class has access to all the private members of its enclosing
class—both fields and methods. Therefore, a public or protected nested
class inherited by a subclass has indirect access to all of the
private members of the superclass.
Quote from http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
In the quote, we talk about "nested" class
here is an example of how an inner class can access private fields of the outer class.
class OuterClass {
private int x = 7;
public void makeInner(){
InnerClass in = new InnerClass();
in.seeOuter();
}
class InnerClass {
public void seeOuter() {
System.out.println("Outer x is " + x);
}
}
public static void main(String[] args) {
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
inner.seeOuter();
}
}
Finally, if you extend a class with the InnerClass, they will also access the private fields of the OuterClass if your InnerClass is public or protected
It is to be supposed (but the compiler does not enforce it, only warns), that a private method will end being used by a public, protected or default method (otherwise it is useless).
So, the extending class can "indirectly" call the private method by calling the public, protected or default method that ends calling the private method.
Yes, we can access private members of a superclass in the child class through the public method of the superclass which can be invoked from the child class's reference variable heaving the reference id of child class.
for example:-
class Base
{
private int x=10;
void show()
{
System.out.println(x);
}
}
class Child extends Base
{
public static void main(String... s)// public static void main(String[] args)
{
//rom jdk 1.7 main can be defined like above
Child c=new Child();
c.show();
}
}
The output will be 10