Are inner classes commonly used in Java? Are they

2020-02-23 06:37发布

问题:


Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.

Closed 4 years ago.

Are inner classes commonly used in Java? Are these the same as nested classes? Or have these been replaced in Java by something better? I have a book on version 5 and it has an example using an inner class, but I thought I read somewere that inner classes were "bad."

I have no idea and was hoping for thoughts on it.

Thank you.

回答1:

Inner classes are frequently used, and something very similar - anonymous classes - are practically indispensable, as they are the closest thing Java has to closures. So if you can't remember where you heard that inner classes are bad, try to forget about it!



回答2:

They're not "bad" as such.

They can be subject to abuse (inner classes of inner classes, for example). As soon as my inner class spans more than a few lines, I prefer to extract it into its own class. It aids readability, and testing in some instances.

There's one gotcha which isn't immediately obvious, and worth remembering. Any non-static inner class will have an implicit reference to the surrounding outer class (an implicit 'this ' reference). This isn't normally an issue, but if you come to serialise the inner class (say, using XStream), you'll find that this can cause you unexpected grief.



回答3:

I don't think they are evil or bad. Maybe they are not widely used, but they do have many uses,callbacks being one of them. A special advantage is that they can extend from a different class than the outer class, so you could have multiple inheritance.

I would say that one of the issues with inner classes is that their syntax is somewhat "ugly". That's something that discourages some people. Here at work there are many of them.



回答4:

A good example of an inner class is the iterator implementation for a given collection type. Its a class that implements a public interface, but has no business existing except in association with another class. It allows you to model things that in C++ you would be forced to do with the friend operator.



回答5:

Non-static inner classes can hide a performance problem. They do have access to member fields on the enclosing class, but not directly, but via getters which are created automatically. This will be slower then just copying the members of the enclosing class to the inner class.

Some other problems with non-static inner classes are described here



回答6:

They are useful and can be very commonly used. While you should be cautious about abusing the functionality, they aren't much more liable to be abused than any other language feature.



回答7:

The key thing to remember is that you are going to trade flexibility for simplicity and cohesion by making the two classes more tightly coupled. You may want the classes to be tightly bound, but you are giving up the ability to transparently swap other classes into the place of what is currently your embedded class by not defining your class from an interface outside of the containing class.



回答8:

Consider following example :

public class OuterClass {

private AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass() {
    @Override
    protected void printAboutme() {
        System.out.println("AnonymousInnerClass.printAboutMe.........");
        Class clazz = this.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

            String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
            message = message + " " + field.getType().getSimpleName();
            message = message + " " + field.getName();

            System.out.println(message);
        }
    }
};

public void displayAnonymousInnerClass() {
    anonymousInnerClass.printAboutme();
}

public void displayStaticInnerClass() {
    NestedStaticClass staticInnerClass = new NestedStaticClass();
    staticInnerClass.printAboutMe();
}

public void displayInnerClass() {
    InnerClass innerClass = new InnerClass();
    innerClass.printAboutMe();
}

public void displayMethodInnerClass(){

    class MethodInnerClass {

        private String sampleField = "Method Inner Class";
        public void printAboutMe() {
            System.out.println("MethodInnerClass.printAboutMe.........");
            Class clazz = this.getClass();

            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {

                String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
                message = message + " " + field.getType().getSimpleName();
                message = message + " " + field.getName();

                System.out.println(message);
            }
        }
    }

    MethodInnerClass methodInnerClass = new MethodInnerClass();
    methodInnerClass.printAboutMe();
}

class InnerClass {
    private String sampleField = "Inner Class";
    public void printAboutMe() {
        System.out.println("InnerClass.printAboutMe.........");
        Class clazz = this.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

            String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
            message = message + " " + field.getType().getSimpleName();
            message = message + " " + field.getName();

            System.out.println(message);
        }
    }
}


abstract class AnonymousInnerClass {
    protected String sampleField = "Anonymous Inner Class";
    protected abstract void printAboutme();
}

static class NestedStaticClass {
    private String sampleField = "NestedStaticClass";
    public void printAboutMe() {
        System.out.println("NestedStaticClass.printAboutMe.........");
        Class clazz = this.getClass();

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

            String message = Modifier.isPublic(field.getModifiers()) ? "public":(Modifier.isPrivate(field.getModifiers())?"private":"protected");
            message = message + " " + field.getType().getSimpleName();
            message = message + " " + field.getName();

            System.out.println(message);
        }
    }
}

}

in this example there is comparison of every type of non static nested class with static nested class.Now if you run display method of Outer class for each nested class you will see output of each nested class printAboutMe() method,which has some reflection code to print all the member variables of nested classes.

You will see for non nested classes there is one extra member variable other than declared variable string in code,which is only present at run time.

for instance if we execute following code for InnerClass. :-

public class NestedClassesDemo {

public static void main(String[] args) {
    OuterClass outerClass = new OuterClass();
    outerClass.displayInnerClass();
}

}

output is like this :-

InnerClass.printAboutMe.........
private String sampleField
protected OuterClass this$0

Note there is mystery member variable this$0 of type enclosing class(Outer class).

Now you are clear that inner classes keep reference to outer class.So image scenario where you pass reference of inner class to other outer world class and then reference never gets released to in turn OuterClass is also referenced , hence leak.

So this makes using inner classes bad if not used prpperly.

There not such case with static inner classes.Please run all display methods.Also if any problem in code please do point out.