Accessing outer-class fields through inner-class instance from outer-class - java

This is a short subquestion of a larger question I am working towards to.
Why can't I access the outer classes field through an instance of inner class in outer class in line 8?
The field is visible from inner class.
The problem persists for non-static methods in outer class.
The visibility of the field does not matter. Its visible from inner class either way.
The field could be accessed through a (private) getter in inner class, but one of the reasons for my problem is, that i would like to avoid those.
It's supposed to become a variation of the immutable builder pattern, so outer and inner class are developed in close coherence. That's the only reason I would dare to access the fields directly w/o getters.
public class OuterClass {
private static OuterClass instanceOf(InnerClass innerClass) {
return new OuterClass(innerClass.outerField);
}
public static OuterClass instanceOf(int arg) {
return new OuterClass(arg);
}
private int outerField;
private OuterClass(int arg) {
this.outerField = arg;
}
// Outer class getters...
public InnerClass build() {
return new InnerClass(this);
}
public class InnerClass {
private InnerClass(OuterClass outerClass) {
outerField = outerClass.outerField;
}
// Inner class setters......
public OuterClass build() {
return OuterClass.instanceOf(this);
}
} // End InnerClass
} // End OuterClass

Why can't I access the outer classes field through an instance of
inner class in outer class in line 8?
Because the field is a field of the class OuterClass and not of the class InnerClass. So to access it, you need an instance of the class OuterClass, not of the class InnerClass.
Sure, inside InnerClass definition, you can implicitly access all the fields of OuterClass. But that's only a matter of access from inside this context. You're not specifying what is the object of which you're trying to access the field, so the language automatically selects that for you. It's usually this.field, but in the case of a field from the containing class, it's actually OuterClass.this.field.
Once you're trying to indicate what is the object of which you're trying to access a field, rather than let the language implicitly select that object for you, well this object must actually be of the class that contains the field.

Related

Java: Can I create a variable type of inner class in an outer class?

So We were covering the topic of LinkedList and noticed a variable of type Node (inner class name) was declared on the outer class SingleLinkedList. Why is this behavior allowed? I knew you could access members of your inner class in your outer class but not declare variables of the inner class
private class SingleLinkedList {
private Node head; //This here is my doubt
//.
//.
//.
private class Node {
// reference to the next node in the chain, or null if there isn't one.
Node next;
// data carried by this node. could be of any type you need.
Object data;
// Node constructor
public Node(Object dataValue) {
next = null;
data = dataValue;
}
}
Thanks in advance.
Think about it: if not in the "SingleLinkedList" class scope, where else can "Node" be used?
nothing wrong with it, you define an inner class, then an instance of it. you can also declare instances of inner classes later defined in the outer class - the compiler is smart enough to make several passes through the code and find the references.
About the second question, you can do:
class Person {
class Friend {
Person p1,p2;
Friend(Person a, Person b) { p1=a;p2=a}
}
List<Friend> friends;
}
But this will fail:
class Person {
Person(String name) {}
class Friend {
Person p1=new Person("john"), p2=new Person("mike");
Friend(Person a, Person b) { p1=a;p2=a}
}
List<Friend> friends;
}
Java allows you to define a class within another class, i.e. a nested class or an inner class. In Java, an inner/nested class is a member of its enclosing class.
class OuterClass {
...
class InnerClass {
...
}
}
Q1: Why is this behavior allowed?
A1: Here are three compelling reasons:
More encapsulation: If InnerClass above was declared private, it can only be accessed by members of OuterClass. It would be invisible to the outside world.
A class used only one place: If InnerClass is only used by OuterClass and no other class and is a component of OuterClass, it would make it more appropriate to define it inside OuterClass.
More readability: Nesting classes in the location where they are relevant and used, makes the code more readable.
Q2: I knew you could access members of your inner class in your outer class but not declare variables of the inner class
A2: Yes, as mentioned before, inner classes are members of the enclosing class.
So you can declare a variable of the inner class within the enclosing class (OuterClass).
Also, an instance of InnerClass only exists within an instance of the OuterClass. The inner instance has direct access to the methods and fields of its enclosing instance (even if they are declared private).
To take this one step further, to create an object of inner class from a scope outside of both classes, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

Cannot access a field from a static extending class contained in the same .java file

I cannot figure out if this is a hidden feature I have never discovered or a bug from IntelliJ Idea.
Having this class,
public class StackOverflow {
private String abc;
public static class StackOverflowExtended extends StackOverflow {
public StackOverflowExtended() {
abc = "";
}
}
}
IntelliJ tells me that I cannot access abc because either it has private access or because I'm in a static context.
As soon as I access abc by super, it starts working.
public class StackOverflow {
private String abc;
public static class StackOverflowExtended extends StackOverflow {
public StackOverflowExtended() {
super.abc = "";
}
}
}
There's no bugs or hidden features going on. You're probably mixing up inheritance and inner classes.
A non-static inner class can access the variables of its outer class, even if they're private.
public class StackOverflow {
private String abc;
public class StackOverflowExtended extends StackOverflow {
public StackOverflowExtended() {
abc = "";
}
}
}
A static inner class cannot access the fields of its outer class, because it's static. It can exist without having an instance of its outer class.
The reason why super.abc works on the static inner class, is due to it being its subclass. Accessibility independent of its scope, is then again due to it being an inner class.
The scope and accessibility of any private member (field, constructor or method) is the complete body of its declaring class, including any nested classes.
If the inner class is non-static, it is bound to the instance of the outer class, so you can access the private instance variable.
In your case, the inner class is static, so you need to specify an object instance of the outer class, such as super (because in your case the inner class extends the outer class).
The only "weird" thing is that when you try to access it using this.abc, it fails because then apparently the rule that subclasses cannot access private members of their parents takes precedence.

What's the advantage of making an inner class as static with Java?

I have an inner class in my Java class.
When I run find bugs, it recommends(warns) to make it as static.
What's the point of this warning? What's the advantage of making a inner class as static?
If the nested class does not access any of the variables of the enclosing class, it can be made static. The advantage of this is that you do not need an enclosing instance of the outer class to use the nested class.
An inner class, by default, has an implicit reference to an object of the outer class. If you instantiate an object of this from the code of the outer class, this is all done for you. If you do otherwise you need to provide the object yourself.
A static inner class does not have this.
That means it can be instantiated outside the scope of an outer class object. It also means that if you 'export' an instance of the inner class, it will not prevent the current object to be collected.
As a basic rule, if the inner class has no reason to access the outer one, you should make it static by default.
A static inner class is a semantically simpler thing. It's just like a top-level class except you have more options for visibility (e.g. you can make it private).
An important reason to avoid non-static inner classes is that they are more complex. There is the hidden reference to the outer class (maybe even more than one). And a simple name in a method of the inner class may now be one of three things: a local, a field, or a field of an outer class.
An artifact of that complexity is that the hidden reference to the outer class can lead to memory leaks. Say the inner class is a listener and could be a static inner class. As long as the listener is registered, it holds a reference to the instance of the outer class, which may in turn hold on to large amounts of memory. Making the listener static may allow the outer instance to be garbage collected.
A Non-static inner class has an implicit reference to outer class. If you make the class as static, you could save some memory and code.
Benefits of static inner classes:
Instantiation of static inner class does not rely on external class guidance, and the memory overhead of instantiation.
Static inner class does not hold external class guidance, does not affect the collection of external class, to avoid the extension of the external class in memory survival time leading to memory leakage.
We already have good answers, here are my 5 cents:
Both static and non-static inner classes are used when we need to separate logical functionalities yet using the methods and variables of the outer class. Both of the inner classes have access to the private variables of the outer class.
Advantages of static inner class:
1) static classes can access the static variables from outer class
2) static classes can be treated like an independent class
Non-static inner class:
1) cannot use static members of the outer class
2) cannot be treated like an independent class
public class NestedClassDemo {
private int a = 100;
int b = 200;
private static int c = 500;
public NestedClassDemo() {
TestInnerStatic teststat = new TestInnerStatic();
System.out.println("const of NestedClassDemo, a is:"+a+", b is:"+b+".."+teststat.teststat_a);
}
public String getTask1(){
return new TestInnerClass().getTask1();
}
public String getTask2(){
return getTask1();
}
class TestInnerClass{
int test_a = 10;
TestInnerClass() {
System.out.println("const of testinner private member of outerlcass"+a+"..."+c);
}
String getTask1(){
return "task1 from inner:"+test_a+","+a;
}
}
static class TestInnerStatic{
int teststat_a = 20;
public TestInnerStatic() {
System.out.println("const of testinnerstat:"+teststat_a+" member of outer:"+c);
}
String getTask1stat(){
return "task1 from inner stat:"+teststat_a+","+c;
}
}
public static void main(String[] args){
TestInnerStatic teststat = new TestInnerStatic();
System.out.println(teststat.teststat_a);
NestedClassDemo nestdemo = new NestedClassDemo();
System.out.println(nestdemo.getTask1()+"...."+nestdemo.getTask2());
}
}
Accessing the static inner and non-static inner class from outside:
public class TestClass {
public static void main(String[] args){
NestedClassDemo.TestInnerClass a = new NestedClassDemo().new TestInnerClass();
NestedClassDemo.TestInnerStatic b = new NestedClassDemo.TestInnerStatic();
}
}
The official java doc for static inner class can be found at https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Referencing non static variable from within static Inner Class

I need to reference a variable of a top level class from a method within a static class.
This method should act on unique instances of the top level class and so it feels like I shouldn't instantiate the top level class inside the static class.
Basically I want something like
public class TopLevel{
// private
int innerV
public static class Inner implements X {
for(i=0; i<innerV,i++){
doSomething
}
}
}
Is it possible to just say this.innerV or something similar in the for loop and similar places?
From a static inner class, you can't refer to (nonstatic) members of the outer class directly. If you remove the static qualifier, it will work, because instances of nonstatic inner classes are implicitly tied to an instance of the containing class, so they can refer to its members directly.
Declaring your inner class static removes this link, so you need to either pass an instance of the outer class to the inner class method (or its constructor) as a parameter, or create it inside the method.
You can't do that. Create a TopLevel instance and if you make an innerV accessor (getter/setter) or make it public, than you can.
public class TopLevel {
public int innerV
public static class Inner implements X {
for(i=0; i<innerV,i++){
TopLevel tl = new TopLevel()
tl.innerV = 12345678;
}
}
}
You can't do that because it doesn't make sense, any more than referring to a non-static member from a static function makes sense. There is no current instance of the outer class in the context of the static inner class to get the instance variable from.

Can an outer class access the members of inner class?

The inner class is the class defined inside a class, and the inner class can be declared as public, private, protected. If the inner class defined as private and protected, can outer class access the members of inner class? and can inner class access members of outer class?
If the inner class defined as private
and protected, can outer class access
the members of inner class?
Yes. These qualifiers will only affect the visibility of the inner class in classes that derive from the outer class.
Can inner class access members of
outer class?
Yes, including the ones declared private, just as any instance method can.
In general, you can (access private fields on inner classes and vice-versa). The following code compiles under Eclipse:
public class Outer {
private int x;
public void f() {
Inner inner = new Inner();
inner.g();
inner.y = 5;
}
private class Inner {
private int y;
public void g() { x = 5; }
}
}
That said, you can configure your IDE/compiler to treat accesses to such fields as errors (in Eclipse this setting is called "Access to non-accessible member of an enclosing type", under Preferences -> Java -> Compiler -> Error/Warnings -> Code Style)
Explanation is in context of regular inner class[Regular inner classes cannot have static members declared inside them]
You can access any field of outer class from inner class directly.
class Outer {
private static int x = 0;
class Inner {
void print() {
System.out.println(x); // x can be directly accessed
}
}
public static void main(String[] args) {
new Outer().new Inner().print();
}
}
Even Outer class can access any field of Inner class but through object of inner class.
class Outer {
private class Inner {
private int x = 10;
}
void print() {
Inner inner = new Inner();
System.out.println(inner.x);
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.print();
}
}
"A nested class is a class defined
within another class. A nested class
should exist only to serve its
enclosing class. If a nested class
would be useful in some other context,
then it should be a top-level class.
There are four kinds of nested
classes: static member classes,
nonstatic member classes, anonymous
classes, and local classes. All but
the first kind are known as inner
classes."
(Joshua Bloch, from the book Effective Java.)
As for your questions: it is very easy to test by yourself. But the answer is yes (even for private members), as long as you are not trying to access a non-static member (other than from a reference) from a static context, or trying to access a member which is in an inaccessible scope.
That is, very much as one would expect =).
Yes! You can access both an inner class member from outer class, and vice-versa(irrespective of the access modifier).
However, for a static nested class you cannot access its field just by the field name, and you need to access it like
InnerClass.staticInnerField
though you can access the static fields of the outer class from the inner class directly by the fields names.

Categories

Resources