简体   繁体   中英

Java Local Inner Class in a METHOD, how is it handled by the JVM?

If you look at the method below you will se a declared local class in a method. The reason why, is that the styleIt0 method for example is used several times and only in this method. It is only relevant to this method alone.

Breaking it out to a private method does not make it very clear as to where it is used and what it does just by looking it. I find having large blocks of code unreadable and often would like to break pieces out in small methods, although they are only relevant to one method.

Doing that for several methods in a class will make it very unclear where each private method is intended for and where it is used and that it is only used by a single method, compared to other private methods that might be shared between several methods.

That is why I sometimes prefer to declare other methods in a method. It would be great to be allowed to declare methods in a method in the "standard" fashion but the only way I believe something like that is possible up to Java 6, is by declaring methods in a local innerclass in the method as seen below.

My question here is :

Is there any performance concerns of such usage? What is the memory footprint for such a declared class and by repeated calls to a method with a local innerclass? Will the JVM compile this class once, at compile time, or is it treated in some other way?

Other thoughts:
Local innerclasses cannot be declared static, and their methods and properties cannot be static. I wonder why!?

Now I am forced to create a new instance each time the method is called. It would have been great to have static methods in a local innerclass and I see no good reason as to why that couldn't be possible? Inner methods would have been even better!

Some might argue that this is way of coding is not useful, is ugly or that such classes could be declared somewhere else. Please do not hijack the thread in that direction. I happen to find inner methods useful no matter what some might argue. My main interest relates to the performance issues of such usage in the Java language.

Thanks ( code below )

private void addBottomTable(Slide slide, User user) {
    class Styler {

        public void styleIt0(RichTextRun rt) {
            rt.setFontName(font);
            rt.setFontSize(12);
            rt.setBold(true);
        }

        public void styleIt1(RichTextRun rt) {
            rt.setFontName(font);
            rt.setFontSize(10);
            rt.setBold(true);
        }

        public void styleTable(Table table) {
            // Style the table
            double numberOfCakes = width / PADDING;
            int firstColumnWidth = (int) ((3 / 12d) * numberOfCakes * PADDING); // Take 3/12 of the cakes and calculate the width
            table.setColumnWidth(0, firstColumnWidth);

            table.setColumnWidth(1, width - firstColumnWidth - PADDING * 2); // Minus padding because we use that one for moveTo at the end, and we do want padding
                                                                             // at the end
            Line border = table.createBorder();
            border.setLineStyle(Line.PEN_PS_DASH);
            border.setLineColor(Color.black);
            border.setLineWidth(1.0);
            table.setAllBorders(border);
        }

    }
    Styler styler = new Styler();
    EmployeeCV employeeCV = user.getEmployeeCv();               
    Table table = new Table(3, 2);        
    styler.styleTable(table);        

    // == Cells ==
    // Row 0 = Specific strengths
    TextRun textRun = table.getCell(0, 0).getTextRun();
    RichTextRun rt = textRun.getRichTextRuns()[0];
    rt.setText("Specific strengths: ");
    styler.styleIt0(rt);

    // Content column
    textRun = table.getCell(0, 1).getTextRun();
    rt = textRun.getRichTextRuns()[0];

    StringBuffer s = new StringBuffer();
    List<LeadershipTopStrengths> strengths = employeeCV.getTopStrengthsList();
    int i = 0;
    while (i < strengths.size()) {

        LeadershipTopStrengths strength = strengths.get(i);

        if ( strength != null ) {
            s.append(safeEnumItemDescription(strength));

            // Add newline but not on the last one
            if (i < (strengths.size() - 1) )  { 
                s.append(SIMPLE_NEWLINE);
            }

            rt.setText(s.toString());
            styler.styleIt1(rt);
        }

        i++;
    }        

    // Row 1 = Mobility
    textRun = table.getCell(1, 0).getTextRun();
    rt = textRun.getRichTextRuns()[0];
    rt.setText("Mobility: ");
    styler.styleIt0(rt);

    // Content column
    textRun = table.getCell(1, 1).getTextRun();
    rt = textRun.getRichTextRuns()[0];

    s = new StringBuffer();
    List<InternationalMobility> mobilities = employeeCV.getInternationalMobilityList();
    i = 0;
    while (i < mobilities.size()) {

        InternationalMobility mobility = mobilities.get(i);            
        if(mobility != null){
            s.append(safeEnumItemDescription(mobility));    

            // Add newline but not on the last one
            if (i < (mobilities.size() - 1) )  { 
                s.append(SIMPLE_NEWLINE);
            }

            rt.setText(s.toString());
            styler.styleIt1(rt);

        }
        i++;
    }               

    // Row 2 = Additional
    textRun = table.getCell(2, 0).getTextRun();
    rt = textRun.getRichTextRuns()[0];
    rt.setText("Additional information: ");
    styler.styleIt0(rt);        

    // Content column
    // TableCell cell = table.getCell(2, 1);


    slide.addShape(table);
    table.moveTo(PADDING, height / 2 + PADDING * 2); // MoveTo must come after
}

The JVM doesn't compile classes, javac does.

And, in fact, the JVM knows essentially nothing about any form of inner class -- they are compiled as separate classes and the JVM treats them that way. All of the inner class functionality is done with compiler-generated swizzles (unless this has changed since Java 5). (And I've always suspected that there are several security holes as a result of this, but never bothered to try to find them.)

If you include the exact same class in more than one method, I don't know if the compiler somehow figures out that they are the same, to only generate one copy, or if it generates multiple copies. A few simple tests would tell you.

Inner methods could no doubt have been (relatively easily) implemented in Java, but the designers chose to avoid that complexity with Java 1 (especially given that their model was C) and then invested all their energy in inner classes later. No real reason, other that it didn't become anyone's pet idea, I suspect.

[Actually, there is a reason for not implementing inner classes, but not an insurmountable one. The original Java execution stack model would not have supported it without a "display" and some extra opcodes, and, since that original design, the Java designers have been remarkably reluctant to add even obviously needed new features to the JVM (as witnessed by the implementation of inner classes with no JVM mods). (Though, oddly, they implemented the highly incompatible and pervasive (and probably unnecessary) change to verification in 5.)]

To the question of why inner classes can't have static methods: There is no good reason why the JVM could not support this. The real issue is that the model of scope used by javac does not match the mental model of scope that most of us have. The difference between the two models did not become obvious until inner classes were introduced, and by that time making the change would have broken backwards compatibility.

We tend to think of the static context of a class as a separate level that the instance context is nested inside. In this model, an inner class has a static context nested in the static context of the outer class, and an instance context nested in both that context, and the instance context of the outer class:

Outer static <- Inner static <---\
        ^---Outer instance <- Inner instance

This kind of branched nesting of scope isn't what javac uses when resolving an identifier. It actually treats the static and instance levels of the scope as equivalent, with an extra check layered on top to disallow accessing instance methods from static context. Even when dealing with inheritance, it doesn't really branch off and search the superclass; it just copies all the definitions into the subclass so that it only has to search one place.

It is possible to implement a compiler that uses the intuitive scope model and so allows static members in inner classes (I've done it), but it would be incompatible with javac and the JLS.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM