inner classes and encapsulation

If I declare a class named 'Inner' within a class 'Outer', then Outer can access all the members (including private) of Inner. Doesn't this break the principle of encapsulation?

I guess one explanation for this design might be "Inner is a member of Outer, so therefore Outer should have full access to it". However, this is not a sufficient justification (for me). Particularly in the case where Inner is a private class, and can only be used by Outer, the only possible intention that marking a member of Inner as private could have is "Outer can't touch this", but of course it can....

I've almost completely stopped using inner classes (apart from simple Swing listeners) since I discovered this. Am I missing something?

When you access private data members of the outer class, the JDK compiler creates package-access member functions in the outer class for the inner class to access the private members. This leaves a security hole.

In general we should avoid using inner classes. Use inner class only when an inner class is only relevant in the context of the outer class and/or inner class can be made private so that only outer class can access it. Inner classes are used primarily to implement helper classes like Iterators, Comparators etc which are used in the context of an outer class.

But even when an inner class (such as an Iterator) is used in the context of an outer class (such as a Collection), you could achieve the same thing without inner classes by (in this example) passing a reference to the Collection to the constructor of the Iterator.

This gives the Iterator access to the public members of the Collection object - the only members it should need to access - without using inner classes. By the way, is it true that the inner class can access the private members of the outer class (as well as vice versa)? If so, then inner classes are doubly bad

This gives the Iterator access to the public members of the Collection object - the only members it should need to access - without using inner classes.

Well... no. Show me how to write an Iterator over a Map using only the public API. Can't do it, right? The Iterator needs to know about the implementation of the Map. Now, there are various ways to implement this: for example, make the Map implementation's member package-protected, for example, and put the Iterator class in the package with it. You could make a package containing only these two classes.

But if you instead make the Iterator an inner class, then all the members are private, and no code outside of the Map implementation can diddle with it. Seems nicer to me, frankly.

Part of the problem here is that Java doesn't have protected interfaces. If a class implements an interface, all the methods that implement it have to be public. If that weren't the case, a Map implementation could provide an IteratorHelper interface that an Iterator could use. But in Java as it stands, all those methods, which aren't used by normal clients, would be there, public, cluttering up the interface.

Are you discussing about inner classes or about nested classes? static member classes are not inner classes. An inner class (non-static nested class) has can access private members of enclosing class, as well as vice versa. The advantage with inner class is that it can also be used to represent a one to many relationship (something which I have not found commonly). It also guarantees that the instance of inner class cannot be created unless there is an instance of the enclosing class. eg. one cannot have a Transaction unless there is an instance of Account and once a Transaction is created with a particular Account instance then it cannot become Transaction of another Account. Transaction could an inner class for Account in this case.

The static member classes are like any other class except for the access restrictions removed between the enclosing class and the member class. ie. you want to allow some class extra privileges. [ June 04, 2007: Message edited by: Pravin Jain ]

The Zen of Java Programming.

Dan Murphy
Ranch Hand

Joined: Mar 29, 2005
Posts: 126

posted Jun 04, 2007 22:02:00

0

The advantage with inner class is that it can also be used to represent a one to many relationship (something which I have not found commonly).

Can you achieve anything by modelling one-to-many relationships in this way that cannot be more simply represented with a class that has a member which is a Collection, array, etc.

It also guarantees that the instance of inner class cannot be created unless there is an instance of the enclosing class. eg. one cannot have a Transaction unless there is an instance of Account and once a Transaction is created with a particular Account instance then it cannot become Transaction of another Account. Transaction could an inner class for Account in this case.

Again, I don't think you need inner classes for this. If the Transaction class takes an Account as it's constructor parameter and stores the argument in a final field, you've achieved the same thing [ June 04, 2007: Message edited by: Dan Murphy ]

Dan Murphy
Ranch Hand

Joined: Mar 29, 2005
Posts: 126

posted Jun 04, 2007 22:12:00

0

Part of the problem here is that Java doesn't have protected interfaces. If a class implements an interface, all the methods that implement it have to be public. If that weren't the case, a Map implementation could provide an IteratorHelper interface that an Iterator could use. But in Java as it stands, all those methods, which aren't used by normal clients, would be there, public, cluttering up the interface.

For the sake of discussion, if a class could mark part of it's interface as protected, then how would you define which other classes could access the protected interface? Presumably it wouldn't work the same as the 'protected' scope identifier, because one wouldn't want to force (for example) an Iterator to extend Map in order to access it's protected interface. This would break the "is a" inheritance test. Providing access only to classes in the same package doesn't seem much better, as we'd (again) need to put only the Map and Iterator in the same package in order to allow only the Iterator to access the protected interface.

This compiles and runs just fine. The interface Bar is only accessible to Foo, subclasses of Foo, and other code in the same package. It's pretty rare that you'd have a use for this, but it's allowed.

However, what EFH probably meant to say is that Java does not allow interface members to be protected:

This doesn't compile. It doesn't matter if Bar is a nested interface or not - the methods inside an interface can never be protected, package, or private. They are implicitly public. It's possible that protected methods in interfaces could have been useful, but they're not allowed.

Can you achieve anything by modelling one-to-many relationships in this way that cannot be more simply represented with a class that has a member which is a Collection, array, etc.

[ June 04, 2007: Message edited by: Dan Murphy ]

Just for an example, I need to store an Identity object in my application. it may vary from a single concanated string to multiple strings from one implementation to another implementation.

The definition of the identity, persistence and display is all specific to Identity and hence is internal to it which should not be accessed by any external class. The example I have shown contains the atomic level definition of Identity contained in a simple Names inner class but it can easily be extended to include identification numbers, prefix, suffix etc.

PS: The code is to give an idea of where 1-N type of relationship may exist in an inner class. The code may not be tuned for correctness so I apologize for the same beforehand.

In some sense it is true that inner/nested classes "break" encapsulation. The important thing to notice is that there needs to be a balance - a system with "fully encapsulated classes" couldn't do anything, because the classes need a certain amount of coupling to communicate. So the design goal cannot be to *maximize* encapsulation, but to *manage* it.

Some classes are just naturally so strongly coupled to another class - such as the implementation of an Iterator to its Collection class - that it wouldn't give any benefit to encapsulate them from each other.

In fact it could probably be argued that they are so strongly coupled, that it makes sense to encapsulate the knowledge of how the iterator is implemented inside the collection class.

Does that sound reasonable?

The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus

However, what EFH probably meant to say is that Java does not allow interface members to be protected:

Yeah, that's the idea, anyway. I think I was using the words "interface" (as in, a set of methods on an object) and "interface" (the Java keyword) both in the same paragraph. If it were possible for HashMap and TreeMap and LinkedHashMap, etc, to implement a "MapIteratorHelper," the methods of which were visible only inside java.util, then you could reasonably implement a MapIterator class as a top-level class without making the data members of those Map classes non-private.

I’ve looked at a lot of different solutions, and in my humble opinion Aspose is the way to go. Here’s the link: http://aspose.com