17 Replies - 3579 Views - Last Post: 15 April 2010 - 03:33 AM
#1
Inner Classes and Their Usage
Posted 11 April 2010 - 12:27 PM
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.
Replies To: Inner Classes and Their Usage
#2
Re: Inner Classes and Their Usage
Posted 11 April 2010 - 02:01 PM
// 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
#3
Re: Inner Classes and Their Usage
Posted 11 April 2010 - 02:11 PM
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);
}
}
#4
Re: Inner Classes and Their Usage
Posted 11 April 2010 - 03:31 PM
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
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.
#5
Re: Inner Classes and Their Usage
Posted 12 April 2010 - 01:13 AM
#6
Re: Inner Classes and Their Usage
Posted 12 April 2010 - 05:17 AM
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.
#7
Re: Inner Classes and Their Usage
Posted 12 April 2010 - 08:46 AM
#8
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 03:40 AM
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();
}
}
#9
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 04:17 AM
Krishs, on 13 April 2010 - 04:40 AM, said:
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."
#10
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 07:38 AM
neotifa said:
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:
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.
#11
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 10:57 AM
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.
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);
}
}
}
#12
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 01:42 PM
Quote
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
c) Aid the outer object (like the singleton)
then that object should be considered being put elsewhere for visual appearance as described by baavgai
#13
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 04:01 PM
This post has been edited by macosxnerd101: 13 April 2010 - 05:04 PM
#14
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 05:01 PM
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);
}
}
#15
Re: Inner Classes and Their Usage
Posted 13 April 2010 - 05:10 PM
Quote
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 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.
|
|

New Topic/Question
Reply





MultiQuote









|