4

I don't understand why the following code errors in Java:

public abstract class TestClass
{
    private final int data;

    protected TestClass(int data) { this.data = data; }

    public final class InnerClass extends TestClass
    {
    private InnerClass(int data) { super(data); }

    public static final TestClass CONSTANT = new InnerClass(5);
    }
}

The error is on the public static final TestClass CONSTANT = new InnerClass(5); part. The errors are:

I:\Documents\NetBeansProjects\TestingGround\src\testingground\TestClass.java:22: error: non-static variable this cannot be referenced from a static context public static final TestClass CONSTANT = new InnerClass(5); ^ I:\Documents\NetBeansProjects\TestingGround\src\testingground\TestClass.java:22: error: Illegal static declaration in inner class TestClass.InnerClass public static final TestClass CONSTANT = new InnerClass(5); ^ modifier 'static' is only allowed in constant variable declarations 2 errors

If I try to achieve the same in C#, it works fine.

public abstract class TestClass
{
    private readonly int data;

    protected TestClass(int data) { this.data = data; }

    public sealed class InnerClass : TestClass
    {
        private InnerClass(int data) : base(data) { }

        public static readonly TestClass CONSTANT = new InnerClass(5);
    }
}

Why does Java not allow this?

2
  • I've updated title... Which unfortunately makes this question duplicate of many similar once bing.com/…... but not many answered by Jon Skeet - so lets have another one :) Feel free to reword title to better reflect your problem. Commented Mar 19, 2015 at 7:02
  • @AlexeiLevenkov None of the 'duplicates' address this particular issue. One is asking why a C# nested class doesn't have access to its outer class' internals like a Java inner class does. One asks what the difference between a Java static class and a C# static class are, but it's a bit of a cognitive leap from the given answers to the problem in this question. Commented Mar 19, 2015 at 7:17

2 Answers 2

7

To create an inner class (as opposed to a nested static class) you need an instance of the enclosing class - you don't have one in this case. Note that there's no direct equivalent of inner classes in C# - a nested class in C# is more like a nested static class in Java, and the meaning of static in a class declaration in C# is entirely different to the meaning of static in a class declaration in Java.

Option 1

If you really want it to be an inner class, you can write:

public static final TestClass CONSTANT = new SomeConcreteTestClass().new InnerClass(5);

(Where SomeConcreteTestClass is a concrete class extending TestClass)

or, horribly:

public static final TestClass CONSTANT = ((TestClass) null).new InnerClass(5);

Note that you'd need to move the declaration out of InnerClass though, as inner classes can't declare static variables other than compile-time constant expressions:

It is a compile-time error if an inner class declares a member that is explicitly or implicitly static, unless the member is a constant variable (§4.12.4).

So you'd end up with:

public abstract class TestClass
{
    private final int data;

    protected TestClass(int data) { this.data = data; }

    public final class InnerClass extends TestClass
    {
        private InnerClass(int data) { super(data); }        
    }
    public static final TestClass CONSTANT = ((TestClass) null).new InnerClass(5);
}

Option 2

Just make InnerClass static:

public static final class InnerClass extends TestClass

The addition of static there is the only change required. That's now much more like a C# nested class (although generics behave differently, as always...) Ideally at that point you'd rename the class, as it's not an inner class...

Sign up to request clarification or add additional context in comments.

1 Comment

I'll accept this in 4 minutes when I'm allowed. I was not aware it was possible to instantiate a static class in Java since I'm more used to C#. (Those weren't the actual names of my classes anyway, I simplified my classes for the sake of demonstration.) I know generics would apply differently, Java uses type erasure instead of whatever C#'s technique is, but thanks for the head up anyway. Most languages tend to treat generics differently for various reasons.
1

Java language does not allow an inner class to declare a member that is explicitly or implicitly static, unless the member is a constant variable, see JLS 8.1.3

3 Comments

That's basically a rewording of the second error, and thus not helpful.
@Pharap: Well, it's an explanation of the source of the second error, with a reference to the JLS. It's not a complete explanation, but I wouldn't say it's "not helpful".
@JonSkeet Aside from the fact it wasn't helpful, just copy and pasting a section of the JLS without further elaboration does not make for a very good answer, no matter how simple or complicated the question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.