Java inner class and static nested class - binary diff - java

There are many reasons to choose one design over another, and there are really good answers to it found in here:
Java inner class and static nested class
I am curious if there are any performance or memory/storage difference when choosing static inner class via a regular class.
How does the difference looks like after compilation?
To be clear, This question is not about giving advice what to use in each case. I just want to learn how Java works here, behind the scene.

The static nested class is the simplest form: it works just like a top level class, the only difference is the scope in which it is declared. Nothing is hidden there.
The non-static nested class have a hidden reference to an instance of the enclosing class, that's why you can reference non-static fields of the enclosing class from inside the inner class.
When you define an anonymous class in a method, you will also have a copy of all the local variables declare in the method and referenced from within the anonymous class. If the method is non-static, you will also have the hidden reference to the enclosing class.

Related

Oracle Java tutorial - static classes - possible error in tutorial

I'm new to Java, learning Java from the Oracle Java tutorial.
I'm now learning about nested classes, static classes and inner classes.
I found the following explanation which seems odd, and I think it is wrong.
From: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
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. Static nested classes do not have access to other members of the enclosing class
The last sentence "Static nested classes do not have access to other members of the enclosing class" is strange, but may refer to instance members, saying the static class is like a static method, having no access to instance variables.
But the next note is even stranger:
Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.
This seems odd, as it implies that a static class cannot access private instance members of the outer class. I've written the following code which compiles and runs, and demonstrates that a static class can access outer instance private variables.
public class A {
private int x;
static private int y;
static public class B{
static void doSomething(){
y++;
System.out.println("y is now " + y );
}
static void doSomethingElse(A a)
{
a.x++;
System.out.println("a.x is " + a.x );
}
}
}
// ------
public class Main {
public static void main(String[] args){
A a = new A();
A.B b = new A.B();
b.doSomething();
b.doSomethingElse(a);
}
}
Is this a mistake in the tutorial, or am I maybe not understanding something well?
Thanks
Is this a mistake at the tutorial, or maybe I'm not understanding somwthing well?
The error is in your understanding, and the tutorials are correct. Nowhere within your nested static class is there any direct manipulation of the instance fields of the outer class. I'm talking about these fields without an instance attached -- nowhere can you directly manipulate x without having it attached to an A instance.
So you can do this:
static void doSomethingElse(A a) {
a.x++; // x is part of the A instance passed into a parameter
System.out.println("a.x is " + a.x );
}
but you can't do this:
static void doSomethingElse2() {
x++;
System.out.println("x is " + x );
}
And this code would be the same if B were static nested or a stand-alone non-nested class.
You ask:
"A static nested class interacts with the instance members of its outer class just like any other top-level class"?
Exactly as is shown above -- a non-static nested class can directly interact with the a field (as doSomethingElse2() shows) without need of a supporting A instance, while both a static nested class and a stand alone class cannot. They both require the separate A instance, here which is passed into your doSomethingElse(A a) method parameter.
The main difference between a static nested and a stand-alone is that the former, the nested class, has access to private members of the outer class while the stand-alone does not. Perhaps this is your source of confusion.
Is this a mistake in the tutorial, or am I maybe not understanding something well?
You are understanding perfectly. The tutorial page is misleading, at best.
There are two separate notions going on here:
Whether you have permission to access a thing within the rules of Java access control (e.g., private, package-private, protected, public).
The meaning of "static". An instance of an "inner" nested class is always associated with an instance of the enclosing class (storing a reference to the enclosing class instance in a hidden instance field of the inner class). A "static" nested class doesn't have that.
The tutorial page is confusing the two notions.
A nested class is a member of its enclosing class.
Yep.
Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class.
Nope.
By supplying the instance yourself, you see that static classes do indeed have access to members of the enclosing class, including private instance fields, hence why a.x++; in your example compiles. That's access.
By using the words "access" and "private", the paragraph strongly suggests it is talking about access control within the definition given in the Java Language Specification. But it isn't. It is only trying to explain notion #2, about how instances of enclosing classes are associated with nested classes. And even then, it's still wrong, because static nested classes certainly have access to static members of the enclosing class, which the paragraph says they don't. Whoever wrote that page was sloppy.
Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.
This paragraph is still talking about what static means. It is not trying to say anything about access control, although it has the potential to be misunderstood.
Here is the correct access control rule, given by JLS§6.6.1 – Determining Accessibility:
[If] the member or constructor is declared private, [..] 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.
That definition is surprisingly short, but it covers everything relevant here.
It means that all nested classes (because they are "within the body of the top-level class") have access to all members and constructors of the enclosing class, regardless of whether the nested class is static or instance, and regardless of whether the accessed thing is static or instance.
Further, all nested classes also have access to all members and constructors of all other nested classes within the same top-level class.
And the top-level class has access to all members and constructors of all classes nested within it.
The sentence of the JLS I quoted refers to private access. But if the member or constructor is not private, then its access level can only be more permissive, at least package access, and classes enclosed within the same top-level type are inevitably in the same package too, so they would be accessible to each other even without special treatment.
Basically, the top-level (non-enclosed) class and everything within it constitute a nest. Everything within that nest can access everything else within it, in principle. If it's an instance member, you also need to somehow obtain an instance first, but that's always true.

Why would you use private static inner class? Defeats the purpose of static inner class?

I've read all the articles I could find on static inner classes, and from what I understand:
An instance of a static inner class can be created without previously creating the outer class. This is one main difference between static and non-static inner classes.
But none of the articles answer this question:
Why would you have a private static inner class, if the purpose of having a static inner class is so that you can create it without the outer class?
For example, Java's LinkedList implementation contains the private static class Node<E>. If we try instantiating LinkedList<String>.Node<String> it won't work since it's private. And I don't see why you would want to create a Node without a LinkedList either, since you just use the LinkedList's add() interface. So can't this just be a non-static inner class?
For me it seems like private and static for inner classes are contradictory, and if you want to be both private and static that's weird. So could someone please explain what I'm missing?
Thanks!
Remember that an non-static nested class ("inner class") instance has a reference to its containing instance. That isn't free. If you don't need it, you shouldn't have it.
LinkedList is an excellent example of exactly why you'd have a static nested class: LinkedList needs multiple instances of LinkedList.Node, and it doesn't need those instances to have a reference to the list itself. That would be pointless overhead. So the Node class is static in order not to have those back references to the list. It's also private because it's only for internal use by LinkedList.
Side note on terminology: There is no "static inner class" in Java. If it's static, it's not an inner class, it's a static nested class. More in the tutorial.

Working with Math class without instantiating it

I am new to programming and was studying "Head First Java", I just saw a problem where there was used Math class like this
int x= Math.round(float value);
and it was mentioned we don't need to instantiate Math class because its constructor is set private. What does that mean? Until now I read we need to instantiate that class and reference variable to play around with methods and instance variables of the class how does Math class work like this?
we don't need to instantiate Math class because its Constructor is set Private
Because all the methods in Math class are static you can use the class name to invoke them. So there is no use instantiating the class , hence the constructor was declared private. it will also prevent sub classing the Math class, since it is the only constructor.
Look at the open source code :
Don't let anyone instantiate this class.
private Math() {} // only constructor defined in Math class
The methods of Math class doesn't depend on the internal state of the class , they are just like utility functions . So it was wise to declare them as static. static methods can be invoked by directly using the classname , hence no use of instantiating the class. They belong to the class, not specific objects of that class.
You can refer the JLS 8.4.3.2 :
A class method is always invoked without reference to a particular object.
The Math class have all methods as a static, and you need to get the method from the class itself. No need to create instance variable to access Static variable and methods
Refer Math Class java doc. you find all method here static i,e. Math.round
Private constructors means that they can only be called upon from within the class to which they belong, a good example of the use of private constructors can be found here Can a constructor in Java be private?
Private constructors do however have nothing to do with the fact that you can use methods from the MATH class without instantiating them. This is because the methods of MATH class are static i.e. a static method can be called upon without instantiating an object of the class to which the methods belong.
As said in the comments above, you have no use of instantiating a MATH object, therefore the constructor is private, but you could use the MATH methods anyway had the constructor been public.

Can a top-level class or interface have the "static" modifier?

Can a top-level class or interface be declared as static?
Example:
// File A.java
static Class A
{
...
}
No. static only applies to nested classes and tells that instances of the nested class do not need an instance of the surrounding class to be instantiated. As such, it makes no sense as applied to top classes.
Nope, top-level classes cannot be declared static; see JLS Section 8.1.1.
Not all modifiers are applicable to all kinds of class declarations ... The access modifier static pertains only to member classes ...
In java a top level class can't be defined as static.
read this
basically, you can make a static inner class but not top level class(outer one)
I think this post get a better explanation.
http://www.javaworld.com/javaworld/javaqa/1999-08/01-qa-static2.html
hopefully, it helps
All top level classes by default are static.
For those too hooked up about definition of statics and compiler errors.
A class itself is an object with application scope. So it's implicitly static.

static class in java

How do I declare a static class in java? eclipse wants me to remove "static" from the declaration.
static public class Constants {
First to answer your question:
Only a Nested class can be declared static. A top level class cannot declared be static.
Secondly, Inner class is a nested class that is not explicitly declared static. See the java language spec. So contrary to some answers here, Inner classes cannot be static
To quote an example from the spec:
class HasStatic{
static int j = 100;
}
class Outer{
class Inner extends HasStatic{
static final int x = 3; // ok - compile-time constant
static int y = 4; // compile-time error, an inner class
}
static class NestedButNotInner{
static int z = 5; // ok, not an inner class
}
interface NeverInner{} // interfaces are never inner
}
If by 'static' you mean 'can have only static members', there's no such thing in Java.
Inner classes (and only them) can be static, but that's a different concept. Inner static classes can still have instance members.
Eclipse complains correctly, your code won't compile as Top level class can't be declared as static.
You need to first understand what static class means.
static class :
Top level class can't be declared as static. Only Member and Nested top-level classes can be defined as static.
You declare member classes when you want to use variables and methods of the containing class without explicit delegation. When you declare a member class, you can instantiate that member class only within the context of an object of the outer class in which this member class is declared. If you want to remove this restriction, you declare the member class a static class.When you declare a member class with a static modifier, it becomes a nested top-level class and can be used as a normal top-level class as explained above.
nested top-level class is a member classes with a static modifier. A nested top-level class is just like any other top-level class except that it is declared within another class or interface. Nested top-level classes are typically used as a convenient way to group related classes without creating a new package.
Also check when should we go for static class,variables and methods in java
As you have already been told from the other comments, classes cannot be declared static. However there are alternatives to this problem.
The most simple one is to precede all member variables and methods with the static modifier. This essentially does what you want.
A slightly more involved alternative is to make the class a singleton. This is a class in which through the use of a private constructor, and an instanceOf() method, or just an Enum, you can only have one instance of that class. Semantically and syntactically you treat that instance as an ordinary instance of whatever particular class you are making a singleton, but you can only have a single instance of that class, which you retrieve via SomeObject.instanceOf(), or in an Enum implementation, SomeObject.INSTANCE.
You would normally use Enums to implement this, minus the edge cases where you are extending another class.
For more complete information on singletons visit the link below.
Design Patterns in Java - Singleton
There is no direct equivalent of C# static classes in Java, but the closest thing in my opinion is an empty enum, which might seem weird at first, but makes sense the more you think about it. An enum in Java (unlike in C#) is essentially a set of singleton instances that all implement the same abstract base class and interfaces. The quickest and safest way to make a normal singleton in Java is like so:
enum Foo {
INSTANCE;
public Bar doSomething(Baz baz) {
return Bar.fromBaz(baz); // yadda yadda
}
}
So since we are dealing with sets of singletons, it make sense that we can have an empty set. And an empty set means there can be no instances. This is conceptually the same as a static class in C#.
enum MyUtilities {
;
static Bar doSomething(Baz baz) {
return Bar.fromBaz(baz); // yadda yadda
}
static final String SOME_CONSTANT = "QUX";
}
This is great because you won't lose test coverage because of hard to test private constructors in a final class, and the code is cleaner than a final class with an empty private constructor.
Now, if the static classes are meant to all work on a single Interface and you have control of that Interface, then you should implement the static methods on that Interface itself (something you can't do in C#).
All top level classes are implicitly static, meaning they can be accessed by everybody. So it makes sense only to make inner classes optionally static.

Categories

Resources