The Pragmatic Craftsman
:: Simplicity from complexity ::
Encapsulation vs Abstraction, a blog post I wrote a few years ago, is the most popular post on this blog. So I decided to revisit the subject. This time, I want to focus more on encapsulation.
Encapsulation = Information Hiding
Did you get that?
Don’t worry. By the end of this post, you’ll get it.
If you did, you can probably stop reading this post. You already know what encapsulation is. Good for you!
I know McConnell in Code Complete 2 has a great focus on Object Oriented coding, so I turned to his book initially. And I found a great analogy for abstraction and encapsulation.
|
Encapsulation is a stronger concept than abstraction. Abstraction helps to manage complexity by providing models that allow you to ignore implementation details. Encapsulation is the enforcer that prevents you from looking at the details even if you want to.
–Steve McConnell in Code Complete
|
This might sound confusing initially. Don’t worry. One thing to take away from it, though, is that encapsulation goes together with abstraction. In fact, McConnell says you cannot have just one, either you have both or you have none. I totally agree. There is no middle ground.
But this post is more about encapsulation…
|
The single most important factor that distinguishes a well-designed module from a poorly designed one is the degree to which the module hides its internal data and other implementation details from other modules.
–Joshua Bloch
|
Now we’re talking.
Mr. Bloch, another influential author, is basically telling you what encapsulation is: information hiding.
Once again, it’s a good analogy to have in your mind: Encapsulation = Information Hiding. That’s how you want to remember what encapsulation is.
On a practical level, how do you accomplish encapsulation? Steve McConnell, in in section 6.2 has some very good points:
It’s also important that encapsulation not only applies to classes. It’s easy to only think of classes. But if also applies to object, package, namespace, class or interface.
Real World Example
I found another great definition in the book I started reading, Design Patterns by Lasater.
“Think of encapsulation like your mortgage company,” recommends Lasater. You send of your mortgage payment every month and you get a statement back showing your loan data. Your mortgage company is hiding from you the accounting details. And you don’t really care, as long as your principle is decreasing after your payment is applied.
To take this a step further, here’s a class definition for the Mortgage payment. The idea of encapsulation is to only expose the necessary methods. Not more.
// taken from Design Patterns
class CustomerPayment {
public double postPayment(int loanId, double payment) {
// posts a payment
}
public List getAmortizedSchedule(int loanId) {
// return a schedule in array
}
There would be many more methods in the class. But they’re hidden. Hidden from the class interface. You cannot access them outside the class code. That’s in fact, a definition of encapsulation. Only exposing the required methods, in this case post payment and get schedule.
To take McConnell’s definition I mentioned earlier and apply it to the above example, proper abstraction allows you talk on a higher “abstract” level, about Customer Payment and not worrying about too many details. Encapsulation, like McConnell said, is “the enforcer,” and it is not allowing you to look at the details. How? By only exposing these 2 methods.
Just one more thing: encapsulation = information hiding.
If you just remember one thing about encapsulation, remember that. I hope I helped you.
Related
Encapsulation vs Abstraction – my related blog post
Reference
Design Patterns by Christopher G. Lasater
Code Complete 2 Steve McConnell — one of the best programming books that I recommend/sk
|
No matter who. No matter what. No matter when. Short term.Long term. Any term. Writing good code is ALWAYS faster than writing bad code.
—Robert Martin (@UncleBob)
|
Is it because of pressure?
Is it because you want to be faster than others?
Or is it just because that’s the way you’ve been doing things and it has worked for you?
I hope it’s not the case. I hope you take the time to do it right. Because if not, as the saying goes, will you have the time to do it over? Or how will you look at it when you see the project codebase turning into spaghetti. Because it will.
I wish it was so clear cut. It’s usually not.
But I do believe in the theory of broken windows. One little “slack,” one not needed “if” statement starts this process. And then it goes downhill. It’s just a matter of time before somebody else puts another if. And another. Soon enough, you start searching where things have broken. It’s no longer easy to fix stuff. So you put another conditional.
That’s how things degenerate.
I’ve seen it many times in my career.
But I try to do it right. I think about consequences of my actions. Consequences of putting one line of code that will make things worse for others, worse for the codebase.
I take pride and always try to leave things in no worse condition when I found it. If I can, I try to make it better. I don’t always succeed. But I try to adjust. Learn. And always have “do it right” attitude. I think it matters.
If we had more people that cared about the quality, our dev world would be a better place.
Related
Write Your Good Code First – blog post by James Sugrue and Uncle Bob’s quote that I found there that gave me motivation to write this post.

Pro JPA 2: Mastering the Java™ Persistence API
by Mike Keith, Merrick Schincario
ISBN 1430219564
Date Read 4/2010
My Rating

If you’re learning or planning to learn JPA 2, you must own this book. Why? It’s the most complete book on the subject out there. It’s like a JPA bible.
Just a warning: It’s not an easy read. You will most likely have to read some (if not all) chapters at least twice. Some even more. For your first read, it will probably feel dry. Only after you learn by doing, by practicing, you will start “getting it.” This was at least my experience. I really started seeing the power of the book after reading selective chapters again. But of course, your experience might be different.
This is your JPA 2 bible. JPA 2 seems easy on the surface. But if you’re doing a project at work and it requires some advanced mapping, for instance, it’s not so trivial. The nice thing about this book is that it covers the advanced topics as well. And it shows you plenty of examples.
Few missing pieces. Cache coverage is light. Not much to it. Sometimes I felt that a full example, rather than a snippet, would be more appropriate. A few times I had to search the internet to get it to work. And as I mentioned before, this book is not an easy read, be prepared.
Excellent job by the authors. Excellent resource on JPA2, which I think is a great ORM spec.
A few years ago, Cedric Beust, had a blog entry with the same title. I saved it. Here’s a summary of what he recommended for staying sharp:
- Reading (a lot of reading) is certainly a great way to accelerate your skills
- Studying other languages is also a fantastic and fascinating way of learning new concepts that change the way you think.
- Spend time with “curious” colleagues.
- Practice. Find the time!
It’s a very good entry. You should take the time now and read it.
How do you stay sharp?
I think it’s safe to say that you are not going to stay sharp by not doing anything. But that, I mean, just going to work and doing what’s required of you. Sure, it can happen, but imagine how much sharper you would be if you did something in addition to that.
To be honest, I don’t know a definite answer on what’s the key to staying sharp. There are different ways that can work for you. Rather than trying to tell you what you should do, I’m just going to explain what I do.
I’ve tried many things over the years. I would say that I’m an aggressive type. I spend a lot of time on learning and improvement. And I’m trying to adjust as I go along.
So, he’re what I do to stay sharp.
Reading. I think reading is critical. I try to read at least an hour every day. Book reading, that is. Sure, there is a lot of good and helpful material/articles on the web that you can read. I do that as well. I have my list of blogs that I read. I find reading them very helpful. It helps me to know the state of things. But reading books requires you to put the effort and spend some quality time with the book. It also means that the author had put some quality time to make the book. This combination means is more valuable than just reading an article.
Over the years, I have changed the way I read books. I have converted to reading most of the books in the PDF/electronic format. I find that much more useful. And easier. I can take notes. I can read the same book at work without actually carrying it to work. Sure, I still buy a hard copy from time to time, but only the select few.
Practicing. Reading will only take you so far. It’s easy to read. I know. I’ve done that for a few years. I was on a roll, reading 300+ pages per month. But I noticed that I am not learning that much. Certainly not as much as I’d like. Plus, the rate at which I started forgetting things concerned me. Why is that? Just reading is not enough. Reading something just once might not be enough as well. I am in the process of modifying this cycle. It looks more like this now: Read. Take notes. Practice. Re-Read. Notes. Practice. Do what works for you. One thing is clear: by reading alone you’re not going to grow. You’ve got to practice. The more the better.
Doing more with less. This is a recent revelation for me. It’s exciting to constantly move to new things. Have you noticed that getting a new book is very exciting? But after you put the book on a shelf and it sits there for a while, something happens. Your interest in that book decreases after a while. It’s not new anymore. Not in your mind. You have discovered something else that’s new. Maybe you got a different book. So you focus shifts, that new thing is more “interesting.” It’s the same with reading. Once I am almost at the end of a book, I’d like to move on to the next. Even writing a review for that book seems tedious. I’d like to start reading a new book right away. But I have to break that cycle. I noticed that this is one of the BIG reasons why I don’t learn as much as I’d like. I’m trying to do too many things. Not good. Here’s what I am trying to do now to break this cycle. Before I move on to the next great thing, I have to make sure that I really learned it. And that means re-reading the book. That means writing a project based on the new information. That means writing a blog entry. That means creating a wiki/learning page. You see: that means doing more with less!
I know that the old way didn’t work for me. It’s something that I had to change. It’s still too early for me to report the results. It’s not easy to adjust. But I believe it’s the right path for me.
Staying sharp is not easy. But if you read a few books a year, you will learn more than most. Steve McConnell is Code Complete says: “One book is more than most programmers read each year (DeMarco and Lister 1999). A little reading goes a long way toward professional advancement. If you read even one good programming book every two months, roughly 35 pages a week, you’ll soon have a firm grasp on the industry and distinguish yourself from nearly everyone around you.” You just have to remember to do something with that knowledge to make it “stick.”
|
Just as it is a good practice to make all fields private unless they need greater visibility, it is a good practice to make all fields final unless they need to be mutable.
–Brian Goetz
in Java Concurrency in Practice (page 48) |
Are you following these fundamental principles?
Just so we’re on the same page, an immutable object is on whose state cannot be changed after construction.
This view is supported by Joshua Bloch in Effective Java (2nd). Item 13 states: “Minimize the accessibility of classes and members.”
|
The single most important factor that distinguishes a well-designed module from a poorly designed one is the degree to which the module hides its internal data and other implementation details from other modules.
–Joshua Bloch
|
He goes on to say some fundamental principles.
|
A well designed module hides all of its implementation details, cleanly separating its API from its implementation. Modules then communicate only through their APIs and are oblivious to each others’ inner workings.
–Joshua Bloch
Effective Java (2nd), page 67 |
These are really the basics of information hiding or encapsulation. Basics of OOP programming! It’s a good idea to learn these well.
Think twice before making any fields public. Hold it. No, don’t make it public! Think twice before making it any other than private!
But to make sure you only expose what is absolutely needed requires some thought. You need your own judgment and experience.
As for the second part, item 15 states: “Minimize mutability.”
I think this one is a little harder to justify and not so obvious. But Bloch has some very good arguments. Together with Goetz, they convinced me that I should utilize immutability more often when I’m designing classes.
|
Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.
–Joshua Bloch
|
Convinced!
But how? Follow these 5 steps (as per Bloch).
1. Don’t provide any methods that modify the object’s state.
2. Ensure the class can’t be extended.
3. Make all fields final.
4. Make all fields private.
5. Ensure exclusive access to any mutable components.
Goets says it a little bit differently.
An object is immutable if:
– Its state cannot be modified after construction;
– All its fields are final;
– It is properly constructed (the this reference does not escape during construction)
Immutable objects pack a lot of goodies in them.
One more time. Tell me what are the benefits of immutable objects!
They are simple to understand.
They are thread safe.
They require no synchronization.
Let’s end with a great summary note from Bloch, “Classes should be immutable unless there’s a very good reason to make t hem mutable.”
But.
If…
“If a class cannot be made immutable, limit its mutablity as much as possible.”
Strong statements.
Learn these design principles!
All in all, I recommend reading Item 15 from the Effective Java book. And re-read a few times until it becomes part of your design logic.
It’s all about getting better.
It’s all about improving.
It’s good to learn from the pros. Everybody needs a little guidance. I know I do. (These 2 books are excellent! Recommended.)

Beginning Java™ EE 6 Platform with GlassFish™ 3
by Antonio Goncalves
ISBN 1430219548
Date Read 12/2009
My Rating

If you’ve been following the Java EE world, you know that Java EE 6 along with Glassfish v3 application server were released recently. This book has been around since mid year! And it’s still the only book on the subject. To me this was a great gift: I was able to get a complete sneak peek at the new technologies to be released ahead of time.
But was it worth it?
Great overview. If you want to learn what the buzz in the Java Enterprise (EE) world is all about, this is a great book to read. The author does a great job in keeping things at a fairly high level. He focuses on giving you just enough details (but not more), so you can actually start playing around with the technology. That makes this book easy to read. And practical — pragmatic!
Covers the important EE technologies. JPA. JSF. EJB. JMS. Web Services (SOAP and REST). JPA is covered really well. Four chapters dedicated to that. Four chapters for EJBs as well. And three for JSF. Two for each of the web services specs (one for SOAP and one for REST). The coverage on these should be enough to get you started and start playing around. The other technologies are covered very briefly.
Quick read. Not too deep. Not too shallow. This is the author’s style. It’s easy to read. The author gives you a lot of examples in between. On the other hand, at times, it would be nice to have a deeper treatment of a given technology.
Lots of examples. I love to see that. But not every chapter is treated the same. Some chapters have a complete example (Putting It All Together), and some don’t. I was able to run the examples from some chapters but not from all. I had to modify several to make it work. I wish a greater care was put in this area. It’s frustrating when you try to run something and you can’t. But if you’re willing to research it by yourself, you will learn more! I guess that’s the upside. But it does slow you down a bit.
Some technologies are not covered. CDI, is not there. Very light treatment of bean validation.
Overall, an excellent overview of Java EE 6, but not a complete guide/reference on the subject. I was very happy to see this book. And I’m very happy that I had read it. From what I see (at least on Amazon), a second edition will come out in a few months — might want to wait for that. Overall, a very good book on Java EE. Recommended.
I am excited. For the first time, I can say that Java EE development can actually be fun and cutting edge. Jeremy Norris recently said, and I retweeted it, “If you’ve chosen Spring by default since 2005 for your EE needs, you owe it to yourself to take a real close look at JEE6.” I totally agree.
Just to give you some background. My exposure to Java EE has been limited. I have not really programmed in it. I did for 6 months or so, but it was in the J2EE 1.3 world and it was ugly/slow/overly complicated. I’ve tried to stay away from J2EE. Spring was a bit different. I’ve done Spring programming for a few years and generally have a good experience with it. But I don’t like too much XML configuration. I don’t like the fact you can easily get “tied” to the framework, which I don’t consider a best practice. Spring is a vast improvement over J2EE, but it’s not optimal either.
But now, Java EE 6 and Spring 3 enter a different ball game. I’m interested to see how it plays out. One thing I’m sure: the newest Java EE will be a good Spring competitor. Will it win? We’ll see.
I’ve always wanted the Java EE platform to be easier. JEE 5 went in that direction, but not far enough. Java EE 6 takes a few more steps. And I believe that it has crossed the “innovative/fun/cutting edge” line while allowing you to do some powerful stuff. Of course, it remains to be seen, but that’s what I feel now.
Here are some of the reasons why I think so…
No XML configs. Gone are EJB descriptors. Gone are JSF navigation rules. You don’t need XML for dependency injection. All of this means that this is really a big step forward. In some cases you might still need an XML config, but I like how it’s “configuration by exception” — that is, you might need one if you want to setup something other than the default configuration.
JSF 2 is fun. If you’ve ever developed web apps in Java, you know that it’s not optimal. I don’t like it when I see Java code inside JSPs. Who uses JSPs any more, anyway? Working with Spring MVC/JSTL is limited. Not bad, but tedious. But with JSF 2 and Managed Beans, you get a really nice, simple, and powerful solution. All you really need is one Managed Bean and one XHTML file. Really easy to get started. And I find this model of development intuitive: your view is tightly connected with the data. You don’t have to marshall/unmarshall the request in your controller. It’s done for you. Nice and simple!
JPA 2 is easy to use and robust. Powerful as well. It’s an excellent solution as an ORM. Ability to use JPA as a stand alone solution is also great.
EJB 3.1 is easy. Yes, easy. Want proof? Add @Stateless to your Java class and you’re done. No more configuration is needed. Want more? Create a webapp, add a Java class, and add a @Stateless bean. Deploy it to an app server and you have an EJB application! Done! No, you don’t need to package it to an EAR file (I hated that). Really cool.
Glassfish v3 is solid. It fully supports Java EE 6. I believe it’s the best EE application server out there. Good job to the team! Plus, with a stack of Java EE 6, Glassfish v3, and Netbeans 6.8 (no, it’s not my IDE), you can have a simple JEE app running in 5 minutes or so.
Testability. Embeddable containers. EJB has one. JPA has one as well. It’s really simple to setup some powerful integration testing. This is some serious stuff. You can test your database logic fully with an embedded database. EJB container testing is easy as well! Built in Java EE 6. You can test your EJBs with JUnit!
There are many other nice features with this release. I don’t know them all. And again, these are just my observations. So far, I’ve only read Beginning Java EE 6 with Glassfish 3 and tried a few things. Nothing serious. I’m going to learn more. I’m going to create applications based on it. This is some really exciting stuff. I just hope corporations that are still in the J2EE world move into the Java EE 6 world soon. They have good reasons for doing so now.
Java gets a lot of blame for not allowing straight multiple inheritance and for not implementing closures. But according to Bruce Eckel, you can do a multiple inheritance in Java, you can do closures – sort of. You can accomplish that with inner classes!
In this final Part 4 entry, I will concentrate on these two advanced topics.
One way that you can do multiple inheritance is just by implementing two or more interfaces. Easy and already possible in Java. But what if you did not have an interface, but rather abstract or concrete class. You can no longer just extend two of them — Java limitation. Inner classes provide different options.
First, let’s take a look at two different ways you can implement multiple interfaces.
// Two ways that a class can implement multiple interfaces.
// Thinking in Java example
interface A {}
interface B {}
class X implements A, B {}
class Y implements A {
B makeB() {
// Anonymous inner class:
return new B() {};
}
}
public class MultiInterfaces {
static void takesA(A a) { }
static void takesB(B b) { }
public static void main(String[] args) {
X x = new X();
Y y = new Y();
takesA(x);
takesA(y);
takesB(x);
takesB(y.makeB());
}
} // /:~
Note how class Y implements multiple interfaces. I admit that I have never used it like that. But it does implement two interfaces.
What if you had an abstract or concrete class. You can’t extend two classes easily. Not without the use of inner classes! Here’s how inner classes allow you to do that.
// With concrete or abstract classes, innerą
// classes are the only way to produce the effect
// of "multiple implementation inheritance."
// Thinking in Java example
class D {}
abstract class E {}
class Z extends D {
E makeE() {
return new E() {};
}
}
public class MultiImplementation {
static void takesD(D d) {}
static void takesE(E e) {}
public static void main(String[] args) {
Z z = new Z();
takesD(z);
takesE(z.makeE());
}
} // /:~
Possible? Yes. Clean? Not really. But you can!
Eckel says that with inner classes you have these additional features:
1. The inner class can have multiple instances, each with its own state information that is independent of the information in the outer-class object.
2. In a single outer class you can have several inner classes, each of which implements the same interface or inherits from the same class in a different way.
3. The point of creation of the inner-class object is not tied to the creation of the outer-class object.
4. There is no potentially confusing “is-a” relationship with the inner class; it’s a separate entity.
What is a closure? “A closure is a callable object that retains information from the scope in which it was created,” says Eckel. If you’ve been reading this series, you know that an inner class maintains a link to the outer class — that’s in fact a closure.
The following example illustrates a closure. It’s long, but it’s worth getting comfortable with. (Plus, it’s the final example in the series!)
// Using inner classes for callbacks
interface Incrementable {
void increment();
}
// Very simple to just implement the interface:
class Callee1 implements Incrementable {
private int i = 0;
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement {
public void increment() {
System.out.println("Other operation");
}
static void f(MyIncrement mi) {
mi.increment();
}
}
// If your class must implement increment() in// some other way, you must use an inner class:
class Callee2 extends MyIncrement {
private int i = 0;
public void increment() {
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
public void increment() {
// Specify outer-class method, otherwise
// you'd get an infinite recursion:
Callee2.this.increment();
}
Incrementable getCallbackReference() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) {
callbackReference = cbh;
}
void go() {
callbackReference.increment();
}
}
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
/* Output:Other operation11
2
Other operation
2
Other operation
3
*///:~
}
This has been a long series — a first for me. I have learned a great deal about inner classes. I hope you find these helpful as well.
Inner classes have their uses. They can help you implement an elegant solution. They can help you accomplish things not easily doable using alternative ways. They can also complicate your code a great deal. They can make your code unreadable. Use it with care.
Reference
Thinking in Java (4th), Bruce Eckel
Java Inner Classes – Part 1 – Intro
Java Inner Classes – Part 2 – Anonymous
Java Inner Classes – Part 3 – Nested Classes
In Part 1, I’ve covered the basics, in part 2, anonymous inner classes. Is there anything left about inner classes? Yes, there is. I warned you that inner classes are a beast.
In this part, I’ll cover nested classes.
When you create an inner class, there is a connection between the enclosed class and the inner class. Because of that, the inner class can access and manipulate the enclosed class.
Take that connection away and you have a nested class. A nested class is a static inner class. With a nested class, 1) you don’t need an outer class to create the instance and 2) you can’t access non-static outer-class object from the nested instance. Below is an example.
public class StaticInner {
String s = "test";
public static class Inner {
private int counter = 1;
public int increment() {
return counter++;
}
public void printS() {
// StaticInner.this.s;
// ERROR: No enclosing instance of the type StaticInner is
// accessible in scope
}
}
public static class Inner2 {
private static int counter = 1;
public static int increment() {
return counter++;
}
}
public static class Inner3 {
public static class Inner3Inner {
public void sayHi() {
System.out.println("Hi");
}
}
}
public static void main(String[] args) {
System.out.println("Inner");
Inner inner = new Inner();
System.out.println(inner.increment()); // "1"
System.out.println(inner.increment()); "2"
Inner inner2 = new Inner();
System.out.println(inner2.increment()); // "1"
// Inner2 has a static method
System.out.println("Inner2");
System.out.println(Inner2.increment()); // "1"
System.out.println(Inner2.increment()); // "2"
// Inner3 has an inner class
System.out.println("Inner3Inner");
Inner3Inner subInner = new Inner3Inner();
subInner.sayHi(); // "Hi"
}
}
In the main method, you can see that you can just instantiate Inner with new Inner(). Also in Inner, printS method tries to access StaticInner variable but it’s not allowed to. There is no connection between the two classes.
Initially, I thought a “static class” can have only one instance. That’s not true. Inner can have multiple instances, inner2 is a seperate instance and has its own object.
Inner2 is an example of a static instance. You can refer to in directly by Inner2.increment().
Inner2 shows that static inners can have more than one layer, Inner3Inner is defined inside Inner3.
Yes, you read that correctly. You can have an inner class within an interface! I did not know this was possible. Not that I would want to use it, but still… Take a look at the following example.
// Thinking in Java example
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface {
public void howdy() {
System.out.println("Howdy!");
}
}
}
// Usage
ClassInInterface test = new Test();
test.howdy();
/* Output: Howdy!
*/// :~
It’s completely valid! Why would you want to do it that way? One valid reason is that if you wanted to have a common implementation of the interface. The downside is that the interface is “heavier” to carry around, but that’s probably very minor.
Back to the basic inner classes. Does a 2nd or 3rd level inner class have access to the layers above? Yes, it does, it has access to all layers. Thinking in Java has a great example, see below.
// Nested classes can access all members of all
// levels of the classes they are nested within.
class MNA {
private void f() { }
class A {
private void g() { }
public class B {
void h() {
g();
f();
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args) {
MNA mna = new MNA();
MNA.A mnaa = mna.new A();
MNA.A.B mnaab = mnaa.new B();
mnaab.h();
}
} // /:~
I don’t like long tutorials nor long chapters. That’s why I’m breaking these into parts. When will it end? I have done 3 parts already and I’m not done! In Part 4, I’ll try to cover another advanced topic, Multiple Inheritance. Bruce Eckel has an interesting example.
Reference
Thinking in Java (4th), Bruce Eckel
Java Inner Classes – Part 1 – Intro
Java Inner Classes – Part 2 – Anonymous
In Part 1, Java Inner Classes – Intro, I covered most of the basics of inner classes. But there is much more. Some of it might get complex and confusing. But with all of that, I am beginning to understand and value what Bruce Eckel tries to say when he introduces inner classes.
At first, inner classes look like a simple code-hiding mechanism: You place classes inside other classes. You’ll learn, however, that the inner class does more than that–it knows about and can communicate with the surrounding class–and the kind of code you can write with inner classes is more elegant and clear, although there’s certainly no guarantee of this.
Initially, inner classes may seem odd, and it will take some time to become comfortable using them in your designs. The need for inner classes isn’t always obvious, but after the basic syntax and semantics of inner classes have been described, the section “Why inner classes?” should begin to make clear the benefits of inner classes.
In part 2, I am going to cover even more obscure, but more advanced topics. I like to learn by example, this part is heavy on examples.
Did you know you can define a class within a method? Yes, you can. It’s called a local inner class. Example below.
// Nesting a class within a method.
// Example from Thinking in Java
public class Parcel5 {
public Destination destination(String s) {
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel5 p = new Parcel5();
Destination d = p.destination("Tasmania");
}
} // /:~
How about a class within an “if” statement. Yes, you can do that as well. It’s called a class within arbitrary scope, see below.
// Nesting a class within a scope.
// Thinking in Java example
public class Parcel6 {
private void internalTracking(boolean b) {
if (b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() {
return id;
}
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
// Can't use it here! Out of scope:
// ! TrackingSlip ts = new TrackingSlip("x");
}
public void track() {
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 p = new Parcel6();
p.track();
}
} // /:~
One other interesting part about the example above is that the class TrackingSlip will get compiled and a class file created. However, this class will only be accessible from within the scope it got created in.
Did you know you can return a class from inside the method body? A class that is not accessible from anywhere else. A class that has no name. Yes, that’s why it’s called anonymous. See example below.
// Returning an instance of an anonymous inner class.
// Thinking in Java example
public class Parcel7 {
public Contents contents() {
return new Contents() {
// Insert a class definition
private int i = 11;
public int value() {
return i;
}
}; Semicolon required in this case
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
} // /:~
Observe the syntax. The first statement in the method body is a return statement. It looks like you are returning a new instance of a class or interface. But that’s not it. You are actually creating/implementing the class, so you open a curly brackets { and close with }; and put the class definition inside. Very tricky and hard to get used to, I think.
Passing Arguments / Anonymous ConstructorWhat if you need to pass an argument and do some constructor initialization. It turns out you can.
// Creating a constructor for an anonymous inner class.
// Thinking in Java example
abstract class Base {
public Base(int i) {
print("Base constructor, i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i) {
return new Base(i) {{
print("Inside instance initializer");
}
public void f() {
print("In anonymous f()");
}};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
/** Output:
Base constructor, i = 47
Inside instance initializer
In anonymous
f()
*/// :~
One note about arguments. If you’re using them inside the inner class, they have to be passed as final. In the above case, it’s not used directly so a non-final argument is fine.
More: You can even define an instance variable in an inner class!
Here’s a snippet from Thinking in Java that illustrates that:
public Destination destination(final String dest, final float price) {
return new Destination() {
private int cost;
// Instance initialization for each object:
{cost = Math.round(price);
if(cost > 100)
System.out.println("Over budget!");
}
private String label = dest;
public String readLabel() {
return label;
}};
}
Note that in the above example, because price was used in the inner class, it had to be defined as final.
Here’s a final note from Bruce about anonymous inner classes.
Anonymous inner classes are somewhat limited compared to regular inheritance, because they can either extend a class or implement an interface, but not both. And if you do implement an interface, you can only implement one.
More fun with inner classes to come!
In Part 3, I’ll cover nested classes.
Reference
Thinking in Java (4th), Bruce Eckel
Java Inner Classes – Part 1 – Intro, The Pragmatic Craftsman