Search code examples
javainheritanceinner-classes

"no enclosing instance of type file1 is in scope" error with inner classes


I have some code (essentially it imports this other class which has an inner class which I'm trying to access), but it brings up this error:

file2.java:5: error: no enclosing instance of type file1 is in scope
    public static class file3 extends file2.Inner {

What does "no enclosing instance of type file1 is in scope" mean?

Here is the code:

package test;
import secret.file1;

public class file2 extends file1 {
    public static class file3 extends file2.Inner {
        public static void main(String[] args) {
            file3 outer = new file3();
            System.out.println(outer.x);
        }
    }
}

file1's code:

package secret;

public class file1 {
    protected class Inner {
        public int x = 8;
    }
}

Solution

  • The Problem

    You're trying to make a nested class a subclass of an inner class, and that is practically not possible the way you've done it. There is a way to do it, see Savior's answer for the syntax, but in your situation, it doesn't help you. The key difference between a nested class and an inner class is that an inner class is tied to a specific instance of the outer class, whereas a nested class isn't tied to any particular instance. To illustrate this difference, let's modify your code a bit:

    public class file1 {
        private int x;
    
        public file1(int x) {
            this.x = x;
        }
    
        // No static keyword, so this is an inner class:
        protected class Inner {
            public void printXInner() {
                // This is legal:
                System.out.println(x);
            }
        }
    
        // Has static keyword, so this is a nested class:
        protected static class Nested {
            public void printXNested() {
                // This is NOT legal:
                System.out.println(x);
            }
        }
    }
    

    The printXInner() method is perfectly legal because Inner is tied to a specific instance of file1, so it can access the instance-specific (non-static) field x. However, the printXNested() method will throw a compile-time exception, because it doesn't know which x you want to use. You could have lots of instances of file1, and each instance could have a different value for x.

    Now, why is this important, and how is it relevant to your code? Well, let's say Java just decided to allow what you're trying to do; you can extend inner classes. If we're still using the modified code above, we could write something like this:

    public class file2 extends file1.Inner {
        public void printXFile2() {
            printXInner(); // Uh oh, what should the program do here?
        }
    }
    

    This code seems perfectly harmless, it extends Inner and it calls the printXInner() method. Except our old problem comes up again: which x should it print? We haven't specified which instance of file1 to use. So you're essentially trying to use an inner class in a static context.


    Now, hopefully you're thinking "Okay, I understand why there's a problem, but how do I fix it?" You've basically got two options: you can change your inner class to be a nested class, you can change your file2 class to be an inner class. Which option you choose will depend on the structure of your code. You need to decide if you want Inner to be tied to a specific instance of file1 or not.

    Fix #1

    Change the inner class to be a nested class. This is the way to go if you don't need to access instance-specific data from your nested class. Maybe you have a car class, and you want to have a nested class for the wheels. If we're talking about this in the sense of a car parts store, the wheels aren't attached to any car, so we don't want our nested class to be attached to any instance of the outer class. Simply modify file1 like so:

    public class file1 {
        // Added static keyword:
        protected static class Nested {
            public int x = 8;
        }
    }
    

    Fix #2

    Make the subclass extend the inner class of a specific instance of the superclass. This is the way to go if you need to access instance-specific data from your inner class. Maybe you have a car class, and you want to have an inner class for the wheels. If we're talking about this in the sense of a driving simulator, then the wheels are attached to a specific car and they stay attached. Hence, we want our inner class to be attached to a specific instance of the outer class. Simply modify file3 like so:

    public class file2 extends file1 {
        // Removed static keyword:
        public class file3 extends Inner { ... }
    }
    

    This may create a secondary problem, though. You can't have a main method inside an inner class, because at startup, there are no instances of the outer class, so the JRE can't call a method of the inner class. A workaround is to put the main method in the outer class, and call a method on a specific instance from there. You could implement this like so:

    public class file2 extends file1 {
        public static void main(String[] args) {
            new file2().file3.doSomething();
        }
    
        public class file3 extends Inner {
            public static void doSomething() {
                file3 instance = new file3();
                System.out.println(instance.x);
            }
        }
    }
    

    TL;DR

    Inner classes are different from nested classes. Inner classes are bound to a specific instance of the outer class, while nested classes are not bound to any particular instance. You cannot reference an inner class without specifying an instance, because that goes against the definition of an inner class.