Static methods for operations on inner class
I’m working through Algorithms Fourth Edition (Sedgewick) and am confused by some of the linked-list exercises which seem to be asking to implement static methods for the non-static nodes. For example,
1.3.27 Write a method max() that takes a reference to the first node in a linked list as argument and returns the value of the maximum key in the list. Assume that all keys are positive integers, and return 0 if the list is empty.
1.3.31 Implement a nested class DoubleNode for building doubly-linked lists, where each node contains a reference to the item preceding it and the item following it in the list ( null if there is no such item). Then implement static methods for the following tasks: insert at the beginning, insert at the end, remove from the beginning, remove from the end, insert before a given node, insert after a given node, and remove a given node.
As I understand (and confirmed by SO answers here and here) this isn’t possible. As expected, Eclipse gives errors if I try to write a static method in the superclass:
public class DoublyLinkedList < public static void insertStart(DoubleNode first) < // implementation >private class DoubleNode < Item item; DoubleNode next; DoubleNode previous; >>
(gives the error Cannot make a static reference to the non-static type DoubleNode ); or in the inner class:
public class DoublyLinkedList < private class DoubleNode < Item item; DoubleNode next; DoubleNode previous; public static void insertStart(DoubleNode first) < // implementation >> >
(gives the error The method insertStart cannot be declared static; static methods can only be declared in a static or top level type ). I could write the required methods as instance methods for the DoublyLinkedList class, and this would seem most natural to me. However, I feel that I might be missing out on something important here. The author explicitly states that the methods should be static, and also suggests taking a reference to the first node as an argument (which would be unnecessary for an instance method as the class will have an instance variable for the first node). What am I missing?
Is it possible to make anonymous inner classes in Java static?
In Java, nested classes can be either static or not. If they are static , they do not contain a reference to the pointer of the containing instance (they are also not called inner classes anymore, they are called nested classes). Forgetting to make an nested class static when it does not need that reference can lead to problems with garbage collection or escape analysis. Is it possible to make an anonymous inner class static as well? Or does the compiler figure this out automatically (which it could, because there cannot be any subclasses)? For example, if I make an anonymous comparator, I almost never need the reference to the outside:
Collections.sort(list, new Comparator() < int compare(String a, String b)< return a.toUpperCase().compareTo(b.toUpperCase()); >>
What are the problems with «garbage collection or escape analysis» when forgetting to make an inner class static? I thought this is about performance only.
Your inner class instance keeps a reference to its outer instance alive, even if you do not need it. This could keep stuff from getting garbage-collected. Picture a (resource-heavy) factory object that creates lightweight instances of something. After the factory has done its work (e.g. during application startup), it could be disposed of, but that only works if the things it has created do not link back.
I know, this is only an example, but since it is a recurring one, it should be mentioned that Collections.sort(list, String.CASE_INSENSITIVE_ORDER) works since Java 2, read, since the Collection API exists…
6 Answers 6
No, you can’t, and no, the compiler can’t figure it out. This is why FindBugs always suggests changing anonymous inner classes to named static nested classes if they don’t use their implicit this reference.
Edit: Tom Hawtin — tackline says that if the anonymous class is created in a static context (e.g. in the main method), the anonymous class is in fact static . But the JLS disagrees:
An anonymous class is never abstract (§8.1.1.1). An anonymous class is always an inner class (§8.1.3); it is never static (§8.1.1, §8.5.1). An anonymous class is always implicitly final (§8.1.1.2).
Roedy Green’s Java Glossary says that the fact that anonymous classes are allowed in a static context is implementation-dependent:
If you want to baffle those maintaining your code, wags have discovered javac.exe will permit anonymous classes inside static init code and static methods, even though the language spec says than anonymous classes are never static . These anonymous classes, of course, have no access to the instance fields of the object. I don’t recommend doing this. The feature could be pulled at any time.
Edit 2: The JLS actually covers static contexts more explicitly in §15.9.2:
- If C is an anonymous class, then:
- If the class instance creation expression occurs in a static context (§8.1.3), then i has no immediately enclosing instance.
- Otherwise, the immediately enclosing instance of i is this .
So an anonymous class in a static context is roughly equivalent to a static nested class in that it does not keep a reference to the enclosing class, even though it’s technically not a static class.
Why are static methods allowed inside a non-static inner class in Java 16?
We know that a non-static inner class can be accessed using the instance of the outer class, so a static method is less meaningful inside a non-static class. But from Java 16 static methods are allowed inside a non-static inner class. Why did this restriction exist in the first place? Why is this allowed in the newer version?
public class OuterClass < class InnerClass < static void printMe() < System.out.println("Inside inner class"); >> public static void main(String[] args) < InnerClass.printMe(); >>
re Why it is allowed in the newer version? Probably because it’s useful. I’ve occasionally wished for this. A method encapsulated in its rightful place that nevertheless does not depend on any instance, inner or outer, seems well-defined.
@AndyTurner My impression was that they wanted to pretend that each instance of the outer class had a whole new inner class, as if outer1.InnerClass was a different class from outer2.InnerClass. Of course, that’s not how it actually works, but by prohibiting static they could keep the illusion up a bit longer.
@AndyTurner The answer from user253751 is mostly correct — at the time nested was added (Java 1.1), there were multiple possible interpretations of static within another class, so the question was deferred.
2 Answers 2
You’re asking for reasoning of a change in Java 16, so you should start by checking the Release Notes to see if it has anything to say. It does:
JEP 395: Records (JDK-8246771)
tools/javac
Records have been added to the Java language. Records are a new kind of class in the Java language. They act as transparent carriers for immutable data with less ceremony than normal classes.Since nested classes were first introduced to Java, with the exception of static final fields initialized by constant expressions, nested class declarations that are inner have been prohibited from declaring static members. This restriction applies to non-static member classes, local classes, and anonymous classes.
JEP 384: Records (Second Preview) added support for local interfaces, enum classes, and record classes, all of which are static definitions. This was a well-received enhancement, permitting coding styles that reduce the scope of certain declarations to local contexts.
While JEP 384 allowed for static local classes and interfaces, it did not relax the restriction on static member classes and interfaces of inner classes. An inner class could declare a static interface inside one of its method bodies, but not as a class member.
As a natural next step, JEP 395 further relaxes nesting restrictions, and permits static classes, methods, fields, etc., to be declared within inner classes.
For further details, see JEP 395.
The specific reasoning is given in JEP 395
Static members of inner classes
It is currently specified to be a compile-time error if an inner class declares a member that is explicitly or implicitly static, unless the member is a constant variable. This means that, for example, an inner class cannot declare a record class member, since nested record classes are implicitly static.
We relax this restriction in order to allow an inner class to declare members that are either explicitly or implicitly static. In particular, this allows an inner class to declare a static member that is a record class.
In other words, it was necessary to remove the restriction on static members of inner classes for a particular case; i.e. to allow record classes to be declared in inner classes. But they decided to take the opportunity to remove the restriction in all cases.
This implies that the designers have concluded that the original restriction as a whole was neither necessary for technical reasons or desirable.
why did this restriction exist in the first place?
That is a more difficult question. The decision to make that restriction would have been made in 1996 or early 1997 when Java 1.1 was being designed. It is unlikely that anyone can still accurately remember the reasons behind original decision. So unless someone can find a contemporaneous written source, we will never know for sure.
(Brian Goetz commented above: «. at the time nested was added (Java 1.1), there were multiple possible interpretations of static within another class, so the question was deferred.». That certainly makes sense, but this could be (just) one person’s recollection of something that happened ~25 years ago. If it was me, I wouldn’t be confident in my memory from that far back. Unless I had contemporaneous minutes, notes, etc to refer to.)
There is some speculation about the rationale for the original restriction here: