Inner Classes and Their Usage

  • (2 Pages)
  • +
  • 1
  • 2

17 Replies - 4119 Views - Last Post: 15 April 2010 - 03:33 AM

#1 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10564
  • View blog
  • Posts: 39,091
  • Joined: 27-December 08

Inner Classes and Their Usage

Post icon  Posted 11 April 2010 - 12:27 PM

So yesterday I was helping out on this thread on the Poker Bidding Program regarding flipping JFrames, not JPanels, based on a button click from one of these JFrames. So my initial response was to use an inner class to design the JInternalFrame inside an outer class which extended JFrame. Then, when a button was clicked in the JInternalFrame, it would flip to the next() JInternalFrame from the CardLayout object in the outer class.

In my opinion, this is a rare example of how inner classes can be used for purposes beyond implementing Listener or Iterator interfaces. What are everyone's thoughts on inner classes? How could/should they be used? Discuss.

Is This A Good Question/Topic? 0
  • +

Replies To: Inner Classes and Their Usage

#2 Martyr2  Icon User is offline

  • Programming Theoretician
  • member icon

Reputation: 4333
  • View blog
  • Posts: 12,128
  • Joined: 18-April 07

Re: Inner Classes and Their Usage

Posted 11 April 2010 - 02:01 PM

Inner classes are largely a design choice option. There are several instances where you may want to group classes together into another class to share information. For instance, you could create a Point class which has private members x and y. In that class you can then define several other classes that may work on that specific instances coordinates such as translation to a polar coordinate or something similar.

// Gives you a Point class as normal and we assign it a point..
Point p = new Point();

p.x = 10;
p.y = 10;

// Or you can then have that class give you a PolarCoordinate representation of that point...
Point.PolarCoordinate pc = p.new PolarCoordinate();



Could you do this with a method instead? Sure. However this way can also make it easier to create a class for a complex item (think an entire subsystem) than having to put together a huge string of private methods. It allows you to package classes together so you could do...

Point.OtherCoordinate oc = p.new OtherCoordinate();
Point.AnotherCoordinate ac = p.new AnotherCoordinate();
..etc



All objects, all taking advantage of the original x and y coordinate of Point but returning different instance types. Again, all can be accomplished in other ways but this has the advantages of...

1) Condensing multiple classes into a single packaged logically grouped class
2) Allows inner classes to share variables of its outer class (since these inner classes are privately scoped as well)
3) And may make code more readable, refactored and overall more simplistic for complex sub items for a larger class.

Am I a big proponent of it? Welllll.... Personally I rather choose other methods when showing people on boards like this just because inner classes don't always seem intuitive and if it is not intuitive then it can lead to confusion. However, if you are experienced, inner classes can save a lot of work if used properly and your design calls for it.

:)

This post has been edited by Martyr2: 11 April 2010 - 02:03 PM

Was This Post Helpful? 4
  • +
  • -

#3 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5829
  • View blog
  • Posts: 12,683
  • Joined: 16-October 07

Re: Inner Classes and Their Usage

Posted 11 April 2010 - 02:11 PM

The more I can limit the scope of anything, the better. If a class is only used by one other class exclusively, it makes sense to just hide it inside.

The only real downside to this is code organization. Having a class with a bunch of other class code floating around inside it can get hard to follow. To this end, I'll often just have them share a file instead. e.g.
class StatusBar extends JPanel { /*..*/ }

class MainFrame extends JFrame { /*..*/ }

public class App {
	public static void main(String[] args){
		new MainFrame().setVisible(true);
	}
}


Was This Post Helpful? 2
  • +
  • -

#4 Dogstopper  Icon User is offline

  • The Ninjaducky
  • member icon



Reputation: 2872
  • View blog
  • Posts: 11,031
  • Joined: 15-July 08

Re: Inner Classes and Their Usage

Posted 11 April 2010 - 03:31 PM

I have to agree with both of you guys on this one. It helps to limit scope in a fashion that really aids in the overall design. So many times, I have seen ActionEvents and other events implemented in their own class, which is useful when they have to do a seriously large task and needs access to multiple data fields and methods of both the outer class and itself. I find it more organized to stick the ActionListener methods together in their own inner class than stick all of the method in the one class that only the ActionListerner uses.

class OuterGUI extends JPanel {
   
    private JButton b;
    public OuterGUI() {
        ...
        b = new JButton("Click");
        b.setActionListener(new InnerListerner);
    }

    public void outerMethod1() {...}
    public void outerMethod2(int i) {...}
    public void outerMethod3() {...}

    class InnerListener implements ActionListener {
        
        private int innerInt;
        public InnerListener() {
            ...
        }
 
        private void innerMethod1() {...}
        private void innerMethod2(int i) {...}

        public void actionPerformed(ActionEvent e) {
            innerMethod1();
            outerMethod2(innerInt);
            outerMethod3();
            innerMethod2(innerInt);
         }
    }
}



In this design, the ActionListener's personal variables and methods sit in their own class so that it is more organized than with all those jumbled in with the outerGUI's methods and variables. Could we make these methods? Sure! But this is more organized. I quote Martyr2's post here again:

Quote

Could you do this with a method instead? Sure. However this way can also make it easier to create a class for a complex item (think an entire subsystem) than having to put together a huge string of private methods.


On a tutorial series that I wrote here, I actually encouraged inner classes where they probably weren't needed. It consisted of a JPanel inside a JFrame with the same idea as above. I just wanted to share variables, but keep some separate from the others.
Was This Post Helpful? 1
  • +
  • -

#5 Raynes  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 611
  • View blog
  • Posts: 2,815
  • Joined: 05-January 09

Re: Inner Classes and Their Usage

Posted 12 April 2010 - 01:13 AM

It's also relevant to note that the only way to do anything similar to closures in Java is with anonymous inner classes.
Was This Post Helpful? 0
  • +
  • -

#6 cfoley  Icon User is online

  • Cabbage
  • member icon

Reputation: 1992
  • View blog
  • Posts: 4,144
  • Joined: 11-December 07

Re: Inner Classes and Their Usage

Posted 12 April 2010 - 05:17 AM

One thing I use an inner class for is to get around this:

class MyStuff extends JPanel {

   public void paint(Graphics g) { // or paintComponent
      // custom rendering code
   }

}


Often people extend JPanel or JFrame in order to use them (with or without custom rendering). It works but I find it really messy. I prefer something like this:


class MyStuff {

   private final CustomJPanel jp = new CustomJPanel();
   public Component getComponent() {return jp;}

   private class CustomJPanel extends JPanel {
      public void paint(Graphics g) { // or paintComponent
         // custom rendering code
      }
   }

}


Of course, if you don't have custom rendering, the field's type is just JPanel and you don't need an inner class. The "done thing" of extending JPanels and JFrames seems like a misuse of inheritence to me. By analogy, you wouldn't extend an ArrayList just to use it.
Was This Post Helpful? 0
  • +
  • -

#7 NeoTifa  Icon User is offline

  • Whorediot
  • member icon





Reputation: 2670
  • View blog
  • Posts: 15,713
  • Joined: 24-September 08

Re: Inner Classes and Their Usage

Posted 12 April 2010 - 08:46 AM

Only time I use them really is for action listeners
Was This Post Helpful? 0
  • +
  • -

#8 Krishs  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 23
  • View blog
  • Posts: 105
  • Joined: 06-April 10

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 03:40 AM

There is one more use of Inner classes. To implement threading that is intact
from outside world.
We could have inner class implementing or subclassing Thread class that do
some internal work. following code demonstate that...
public class TestThread
{
	public TestThread()
	{
		new InnerClassThread().start() ;
		MyWork();
	}
	public void MyWork()
	{
		for(int i = 0 ; i < 20 ; i++) {
			System.out.println("My Work " + i);
		}
	}
	public class InnerClassThread extends Thread
	{
		public void run()
		{
			for(int i = 0 ; i< 10 ; i++ ){
				System.out.println("Inner class Thread " + i);
				try {
					Thread.sleep(500);
				}catch(InterruptedException e) {}
			}
		}
	}
	
	public static void main(String[] args) {
		new TestThread();
	}
}


Was This Post Helpful? 0
  • +
  • -

#9 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5829
  • View blog
  • Posts: 12,683
  • Joined: 16-October 07

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 04:17 AM

View PostKrishs, on 13 April 2010 - 04:40 AM, said:

There is one more use...


More than one, I would think. ;)

Anonymous classes allow Java's draconian Object Oriented vision to keep up looser, functional, design elements. Particularly the delegates in C#. In Java, you have class. Raynes alluded to this earlier.

e.g.
import java.util.*;

public class Sorter {
	// inner class: not the example
	class BestActor {
		public String firstName, lastName, movie;
		public int age;
		public BestActor(String firstName, String lastName, String movie, int age) {
			this.firstName = firstName;
			this.lastName = lastName;
			this.movie = movie;
			this.age = age;
		}
		public String toString() { return age + " " + lastName + ", " + firstName + " (" + movie + ")"; }
	}
	
	
	private void show(String title, Object [] array) {
		System.out.println("--- " + title + " ---");
		for(int i=0; i<array.length; i++){ System.out.println(i + " " + array[i]); }
		System.out.println("");
		System.out.println("");
	}
	
	public void test() {
		BestActor [] actors = new BestActor [] {
			new BestActor("Forest","Whitaker","The Last King of Scotland",45), new BestActor("Kevin","Spacey","American Beauty",40),
			new BestActor("Daniel","Day-Lewis","There Will Be Blood",50), new BestActor("Tom","Hanks","Forrest Gump",38),
			new BestActor("Denzel","Washington","Training Day",47), new BestActor("Jeff","Bridges","Crazy Heart",60),
			new BestActor("Anthony","Hopkins","The Silence of the Lambs",54),
			new BestActor("Russell","Crowe","Gladiator",36), new BestActor("Nicolas","Cage","Leaving Las Vegas",32),
		};
		show("Starting Order", actors);
		
		// anon class, on the fly
		Arrays.sort(actors, new Comparator<BestActor>() {
			public int compare(BestActor obj1, BestActor obj2) {
				return obj1.age - obj2.age;
			}
		});
		show("By Age", actors);
		
		Arrays.sort(actors, new Comparator<BestActor>() {
			public int compare(BestActor obj1, BestActor obj2) {
				return obj1.lastName.compareTo(obj2.lastName);
			}
		});
		show("By Name", actors);
		
	}
	
	public static void main(String[] args) {
		new Sorter().test();
	}
}



In C++, you can use function pointers or a class for the sorting built ins. In C#, you can use delegates or interfaces. Java only supports interfaces, but allows such things to be constructed dynamically. When asked if Java would ever have delegate style construct, the response was something like "you have anonymous classes, what more could you need."
Was This Post Helpful? 1
  • +
  • -

#10 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10564
  • View blog
  • Posts: 39,091
  • Joined: 27-December 08

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 07:38 AM

neotifa said:

Only time I use them really is for action listeners

Personally, I use them rarely for ActionListeners unless I don't want the outer class, usually a container of some sort, from listenening to events from other classes. However, usually if I implement ActionListener, I do so for multiple components; in which case, I test for individual components. There are also rare instances that the design shown in Dogstopper's example may be useful; that is, having the implementing Listener class perform functionality beyond listening for Events.

baavgai said:

The more I can limit the scope of anything, the better. If a class is only used by one other class exclusively, it makes sense to just hide it inside.

I completely agree. I think Maps are the best example of this in the design of the Entry<K,V> inner-class.

@cfoley: I generally avoid inner classes for component design unless I plan to use multiple instances of that component. As baavgai said, it makes your code very hard to read. You can always define these types of classes with no access modifier so that they will be package protected. This comes more into play when working with LayoutManagers like CardLayout, BoxLayout, and BorderLayout.
Was This Post Helpful? 0
  • +
  • -

#11 cfoley  Icon User is online

  • Cabbage
  • member icon

Reputation: 1992
  • View blog
  • Posts: 4,144
  • Joined: 11-December 07

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 10:57 AM

Sure, I take the point that it can get a bit hard to follow, and package private is a sensible option. Actually, my example was a little wrong. This is more like what I actually do, and is could be easily done with an anonymous inner class too:

I'm not a big fan of large, involved inner classes but this one is small enough to not confuse me, and I like the way the scope is limited and the JPanel methods are accessed separately from MyStuff methods. This last point was the real reason for me to think about keeping the JPanel separate.

Anyway, thanks for the comments. :) It's always nice to get another perspective.

class MyStuff {

   private final CustomJPanel jp = new CustomJPanel();
   public Component getComponent() {return jp;}

   private void performCustomRendering(Graphics2D g2) {
      // custom rendering code
   }

   private class CustomJPanel extends JPanel {
      public void paint(Graphics g) { // or paintComponent
         performCustomRendering((Graphids2d)g);
      }
   }

}

Was This Post Helpful? 0
  • +
  • -

#12 Dogstopper  Icon User is offline

  • The Ninjaducky
  • member icon



Reputation: 2872
  • View blog
  • Posts: 11,031
  • Joined: 15-July 08

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 01:42 PM

Of course, there is always the idea of a singleton, where there is always just a single instance of a particular object in existence. This is best implemented using nested classes as you can see from Wikipedia. :D

Quote

The solution of Bill Pugh
University of Maryland Computer Science researcher Bill Pugh has written about the code issues underlying the Singleton pattern when implemented in Java.[8] Pugh's efforts on the "Double-checked locking" idiom led to changes in the Java memory model in Java 5 and to what is generally regarded as the standard method to implement Singletons in Java. The technique known as the initialization on demand holder idiom, is as lazy as possible, and works in all known versions of Java. It takes advantage of language guarantees about class initialization, and will therefore work correctly in all Java-compliant compilers and virtual machines.
The nested class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that getInstance() is called. Thus, this solution is thread-safe without requiring special language constructs (i.e. volatile or synchronized).
 public class Singleton {
   // Private constructor prevents instantiation from other classes
   private Singleton() {}
 
   /**
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before.
    */
   private static class SingletonHolder { 
     private static final Singleton INSTANCE = new Singleton();
   }
 
   public static Singleton getInstance() {
     return SingletonHolder.INSTANCE;
   }
 }



As you can see, the nested classes here only help in aiding the outer class, which really should be the goal of an inner class. If an inner class does not:
a) Require methods and variables of an outer class
B) Need to be separate from outer class for "information hiding"
c) Aid the outer object (like the singleton)

then that object should be considered being put elsewhere for visual appearance as described by baavgai
Was This Post Helpful? 2
  • +
  • -

#13 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10564
  • View blog
  • Posts: 39,091
  • Joined: 27-December 08

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 04:01 PM

@cfoley: I agree with Dogstopper here. If you are not planning on using multiple instances of CustomJPanel, then I wouldn't suggest using your current design. It doesn't look like you have to hide the CustomJPanel from other classes, nor does there appear to be a good reason to leave the performCustomRendering() method in the outer class. I think in this case, package protected for the class is the best way to go.

This post has been edited by macosxnerd101: 13 April 2010 - 05:04 PM

Was This Post Helpful? 0
  • +
  • -

#14 cfoley  Icon User is online

  • Cabbage
  • member icon

Reputation: 1992
  • View blog
  • Posts: 4,144
  • Joined: 11-December 07

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 05:01 PM

Oh, I like that dogstopper. Thanks for pointing me to the wikipedia article.

macosxnerd101, I have posted a version of my code below that I think matches your design description. I had to add a field to CustomJPanel so it can reference the rendering method in MyStuff.

Taking dogstopper's points, my inner class does require a method of the outer class. While you see no reason to make the performCustomRendering method private, I see no need to increase the scope beyond that, and you should always limit scope as much as possible.

You could also argue that it aids the outer object, though I admit I could be clutching at straws here.

I don't think your design is bad, but I think mine presents a cleaner, simpler public interface. I still don't understand why you don't like it.

class MyStuff {

	private final CustomJPanel jp = new CustomJPanel(this);
	public Component getComponent() {return jp;}

	void performCustomRendering(Graphics2D g2) {
		// custom rendering code
	}

}


class CustomJPanel extends JPanel {
	
	private final MyStuff renderer;

	CustomJPanel(MyStuff stuff) {
		renderer = stuff;
	}


	public void paint(Graphics g) { // or paintComponent
		renderer.performCustomRendering((Graphics2D)g);
	}
}


Was This Post Helpful? 0
  • +
  • -

#15 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10564
  • View blog
  • Posts: 39,091
  • Joined: 27-December 08

Re: Inner Classes and Their Usage

Posted 13 April 2010 - 05:10 PM

Quote

Taking dogstopper's points, my inner class does require a method of the outer class. While you see no reason to make the performCustomRendering method private, I see no need to increase the scope beyond that, and you should always limit scope as much as possible.

Whoops. I meant to imply that your JPanel subclass should be package protected, not an inner class. Sorry about that. Then move the performCustomRendering() method into your JPanel subclass. That would be the more OO way, utilizing encapsulation. If you want to keep this method private, make sure to invoke it when you override the paint() method JPanel inherits from JComponent to do custom painting.

Quote

I don't think your design is bad, but I think mine presents a cleaner, simpler public interface. I still don't understand why you don't like it.

I think the relation you want to model here is the has-a relation. That is, your MyStuff class has-a CustomJPanel object. Inner-classes are good when you want an extra crutch to lean on in your outer class. However, if the class you want to be encapsulated in the inner class does not provide a crutch for the outer class(like the HashMap.Entry class does for HashMap) and there is no good reason to hide the entire class, then the has-a model is the better choice than the inner class model. Remember- when you encapsulate a private class in an outer class, it is not possible to extend that class and add to its functionality, which the ability to do so is a big part of OOP.
Was This Post Helpful? 1
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2