LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Java: what's the difference between an inner class and a static inner class? (https://www.linuxquestions.org/questions/programming-9/java-whats-the-difference-between-an-inner-class-and-a-static-inner-class-700204/)

irey 01-27-2009 08:34 AM

Java: what's the difference between an inner class and a static inner class?
 
Hi everyone,

I've read the java language specification 100 times but I still don't understand this detail. If I declare an inner class like this:
Code:

public class Trie {
    private class TrieNode {
        //...
    }
    //...
}

What's the difference if TrieNode is declared static?

This curiosity arose cause I'm using a code analyzer (findbugs) to get some more warnings and try to write cleaner code. It suggested making the inner class static to improve performance. (?)

indienick 01-27-2009 09:06 AM

When you declare something, in Java, as "static" it is only created once, in the running virtual machine image.

For example - your inner class TrieNode. In your example it's a regular inner class. Every time a chunk of code within Trie creates a new TrieNode object, a new instance of that object is created.

Now, should you declare it static (which I do not recommend, in your case)...well, to put it simply, that portion of your program won't work. Static declarations means it is - simply - created once, and only once; static classes cannot have a constructor. An example of a static class would be the java.lang.System class. Static declarations limit that item to only existing once; useful for things like enumerations and constants - data that may change but does not need to be re-made.

And, unless I am mistaken, you do not actually declare a class static, just the elements within it.

An example for where you might use a static declaration:
Code:

[i]/* Constants and functions for doing calculations for CNC machining */[i]
public class CNCMath {
  /* Millimeters to inches conversion ratios and function */
  static final float MMTOINRATIO = 0.039370078;
  static float millimetersToInches(int mm) { return (mm * MMTOINRATIO); }
  static float millimetersToInches(float mm) { return (mm * MMTOINRATIO); }

  /* Inches to millimeters stuff */
  static final float INTOMMRATIO = 25.4;
  static float inchesToMillimeters(int inch) { return (in * INTOMMRATIO); }
}

Then, when I want to get a value from either of those (trivial) functions, I just go (assuming I have a variable - cm - of type "CNCMachine" defined somewhere, already):
Code:

...
cm.move(X_AXIS, CNCMath.millimetersToInches(83));
...


irey 01-27-2009 10:05 AM

Yes, I already knew about static members and static methods. In practice it means that a static member can be accessed just by the class name and no instance is required.

But now I realised that 'static' does not only apply to methods and members: an inner class can be declared static too. My program compiles and runs cleanly, but I don't know what changes.

Anyway I looked at the java sources and System is not a static class, it's just a normal class with static methods.

indienick 01-27-2009 10:10 AM

Quote:

Originally Posted by irey
Anyway I looked at the java sources and System is not a static class, it's just a normal class with static methods.

Sorry about that misinformation.

In that case, I do not know what the difference would be. I do not know in down-'n-dirty info on how Java handles stacks and heaps, but I wonder if the difference is analogous to C++ where creating a new class by object or by reference to an object? (I do not know C++, so maybe I am just blowing wind, here.)

EDIT: I found this link - http://www.javaworld.com/javaworld/j...a-static2.html - I don't know if it will help you, or not.

tuxdev 01-27-2009 12:42 PM

The main difference between a static and non-static inner class is that a non-static inner class has a sort of secondary implicit "this" to an instance of the outer class and therefore can access member data of the outer class or call member methods. This also means that you cannot create a non-static inner class independently from an outer class, which can be problematic in some cases. I personally recommend that you always make an inner class static unless you must have access to the outer class' members.

jay73 01-27-2009 09:18 PM

Here is one of my early experiments. It contrasts two cases, one involving a non-static inner class and the other a static one. I hope it makes some sense.


Code:

class Outer{
   
    //inside the outer class, one can refer to inner class directly (outside Outer class, one will need to qualify using name of outer class - see OtherOuter class)
    public Inner inner = new Inner();
   
    private int val = 10;

    //non-static inner cannot exist on its own; it requires that an instance of Outer exist first
    class Inner{   
       
        private int val = 20;
       
        public Outer getOuter(){
            //the outer instance can be called using the dot notation (Outer.this)
            return Outer.this;
            }
           
        public Inner getSelf(){
            //inner class can refer to itself using regular "this"
            return this;
            }
           
        public int getOuterVal(){
            // use dot.this notation to refer to "val" member of outer class
            // as Inner is non-static, outer member "val" does not need to be static itself
            return Outer.this.val;
            }

        public int getOwnVal(){
            //and plain "val" to refer to its own val member
            return val;
            }   

        //non-static inner class cannot contain static inner classes; this is only possible in static inner classes; uncomment to see error message   
        //static class Nested{}   
       
        //but non-static inner classes are OK   
        class OtherNested{}   
        }
   
    //alternative method of producing an instance of the inner class   
    public Inner getInner(){
        return inner;
        }       
   
    }
   
class OtherOuter{
   
    //same as previous
    public OtherInner oi = new OtherInner();
   
    //this HAS to be made static if it is to be accessed from the static inner class - a static inner class can refer to static members of outer class only
    //(unless, of course, one creates a new instance of the outer class inside the inner class)
    private  static int val = 10;
   
    static class OtherInner{
       
        private int val = 20;
       
        public OtherOuter getOtherOuter(){
            // a static class exists on its own, i.e. it has no connection whatsoever to any outer class
            // as a consequence, one cannot refer to the outer class using the dot.this notation but one has to create a new instance of it
            return new OtherOuter();
            //return OtherOuter.this;  /*this will not work; uncomment to see the error*/
            }
           
        public OtherInner getSelf(){
            return this;
            }

        public int getOuterVal(){
            // dot.this notation is illegal in inner class so we need an alternative way to access outer class member val
            return new OtherOuter().val;
            }

        public int getOwnVal(){
            return val;
            }   
       
        //static inner class can contain static inner classes itself   
        static class Nested{}   
        }
        //as well as non-static inner classes
        class OtherNested{}
       
    public OtherInner getOtherInner(){
        return oi;
        }   
    }   
   
public class InnerTest{
   
    public static void main (String [] args){
       
        //must create instance of Outer first
        Outer outer = new Outer();
        //only then can an instance of the inner class be created
        Outer.Inner inner = outer.new Inner();
        //alternative approach; still requires an instance of Outer
        Outer.Inner inner2 = outer.getInner();
        //get reference to outer from the inner class
        Outer outer2 = inner.getOuter();
        //and compare to the outer instance we created directly; they are the same
        System.out.println(outer ==outer2);
       
        //notice the syntax here: instance of inner can be created without creating an instance of the outer class first
        OtherOuter.OtherInner altIn = new OtherOuter.OtherInner();
        //now we can create an intance of outer from the inner class
        OtherOuter altOut = altIn.getOtherOuter();
        }
       
       
    }


irey 01-28-2009 03:34 AM

Thanks a lot to everyone. It's quite clear now.


All times are GMT -5. The time now is 06:19 AM.