Why can't inner classes have static (non-final) fields and methods?
This question has been posted before but the posted answers were: it's a design decision or because inner classes happen in the context of the outer class and cannot declare static methods.
Yet these answers do not clarify my question. What would be the consequences of allowing static fields and methods on inner classes? My guess is that both restrictions are connected. Since static methods would require access to other static methods and non-final static variables of the inner class or even from the outer class (to be able to change internal states), this would lead a inner class to behave like a static one. The JVM could limit access from static methods in inner classes to static methods and data inside the inner class, though. Yet this raises the question: why can't we declare static non-final variables inside inner classes?
Is this design or there are problems?
Kind regards
Declaring static variables in non-static inner class seems contradictory to intend of creating inner non-static class.
If you declaring some variables and methods static you do it when it make sense to access them without creating instance of class, if you declaring inner class non-static its instance type, so intent is to access it via its instance not staticly. If you declare inner class static, therefore separate it from outer class, you can declare variables and methods static.
You asked what would be consequences if java allowed you to declare static methods/fields in inner non-static classes. Well probably there would be none. But it just doesn't make sense, therefore it's a design choice.
To answer why... ->
Inner class object is strongly associated with Outer class object that means without existing Outer class object there is no chance of existing Inner class Object, so defining any static variable/method inside Inner class would not fulfill this requirement
In case of static nested class -> Inner class object is NOT strongly associated with Outer class object
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.
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.
If I declare a variable as private in an inner class, the variable is visible to the outer class. I am unable to understand the logic here. Shouldn't it ideally be only accessible within an inner class?
I think the answer is subjective as the question basically seems to be asking why Sun/Oracle's language designers decided to allow a certain behavior.
That said, here is an attempt at an answer...
First some terminology, a class declared within a class is a nested class. An inner class is a non-static nested class which must reside within an instance of the outer class. So the inner class is a part of the outer class and in that sense, all members of the inner class are to an extent members of the outer class.
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.
Another thought is that the valid use cases for an inner class preclude the necessity to allow the inner class to hide members from the outer class. That is, there is no notion that the outer class would not be coupled to the inner class.
Why allow private at all then? Because private members can still be hidden from other classes which may gain access to an instance of an inner class.
I'm new to Java and have the following question regarding inner classes:
When implementing an inner class, do I need to declare its attributes and methods scope i.e. public, private, protected?
EDIT: With the absence of delegates (as in C#) could someone mention how best to implement a messaging system in Java that enables communication between multiple forms (Jframe)?
I have read that I can use inner classes for this but I'm also told I should not implement inner classes more than a few lines in size. Which school should I follow?
If you want to.
An inner class is roughly speaking like any other class. (Except that if you don't declare it static, it will have an EnclosingClass.this reference.)
I would suggest treating inner classes as private.
In Java, an outer class and all of its nested (including inner) classes can fiddle with each others privates. (The generated bytecode may be pointlessly verbose with additional synthetic access methods, but this is highly unlikely to matter.)
From an interface point of view, a class having weird inner class types is a bit weird. And more difficult to test if you are into that sort of thing. Too often nested type are created because creating a new file in a bad IDE is a bit of a pain - don't be tempted with nasty shortcuts.
Having said that inner classes are very useful. Use them with taste.
when implementing a inner class do i need to declare its attributes and methods scope i.e. public, private, protected?
It depends completely on how you wanted the inner class to behave.
By default, an inner class is non-static:
public class Example1
{
int a;
public class Example2
{
int b;
void test () {}
}
}
A non-static inner class can be instantiated only inside a non-static method of the outer class. This is because every instance of a non-static inner class must be associated with an instance of the outer class. In a sense, every instance of a non-static inner class exists ``inside'' an instance of the outer class. A single instance of the outer class may have associated with it more than one instance of the inner class.
Because an instance of a non-static inner class has an associated instance of the outer class, the methods of the inner class can access directly any of the members (fields or methods) of the outer class instance. For example, the test method defined above can access both a and b directly
A class defined within another class is called a nested class. Like other members of a class, a nested class can be declared static or not. A nonstatic nested class is called an inner class. An instance of an inner class can exist only within an instance of its enclosing class and has access to its enclosing class's members even if they are declared private.
The following table shows the types of nested classes:
Types of Nested Classes Type Scope Inner
static nested class member no
inner [non-static] class member yes
local class local yes
anonymous class only the point
where it is
defined yes
Although this is not an answer your question but make sure you are aware of the "static" modifier of inner classes.
public class Stuff {
public static class SubStuff {
//private or protected
}
}
Is different than this:
public class Stuff {
public class SubStuff {
//only private
}
}
If you have a static inner class than you might want protected variables, protected methods so on. But for inner classes that are not static generally you want everything private.
Google for the difference.
Inner can be seen by only the enclosing class. Its mostly used to achieve a utility function within the class. Lets use Door and Password as example.
public class Door {
public boolean isPassword(String key) {
//local inner class - its hidden from the world
class Password{
public boolean isPassword(String key) {
if(!key.equals("xyz")) {
System.out.println("Not Password. Door is locked");
return false;
}else {
System.out.println("Password corect. Door is opened");
return true;
}
}
}
return new Password().isPassword(key);
}
}