Anonymous inner classes, and examples - 1

"Hi, Amigo!"

"But we've already said hello, Ellie!"

"Hey, don't argue with your aunt. In the 31st century, if you haven't seen someone for more than half an hour, it's customary to say hello again. So don't give me your attitude!"

"Anyway, it's time for another interesting topic: robot reproduction!"

"O_O."

"Just kidding, the new topic is anonymous inner classes."

"In Java, sometimes there are situations where you'll need a class to inherit several classes. Since Java doesn't support multiple inheritance, they've solved this problem using inner classes: in our class, we declare an inner class and make it inherit whatever class we need it to inherit. Here's an example:"

Example of an inner class that inherits the Thread class
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

 public void startTiger()
 {
  TigerThread thread = new TigerThread();
  thread.start();
 }

 class TigerThread extends Thread
 {
  public void run()
  {
   tigerRun();
  }
 }
}

"Let's dig into another example:"

We need a subclass of the Thread class in order to override its run method."

"That's why in the Tiger class we declared the TigerThread inner class, which inherits Thread and overrides the run method.

"For convenience, we defined two methods in the Tiger class: tigerRun and startTiger (which are analogous to Thread's run and start methods."

"In the tigerStart method, we create a TigerThread object and invoke its start() method."

"The JVM will create a new thread that will start running when TigerThread's run method is called."

"This method then calls our run method: tigerRun."

"I've worked with threads before, so this seems straightforward."

"Do we have to name the methods tigerRun and tigerStart?"

"No, we could have called them run and start, but I also wanted to demonstrate that we are not inheriting Thread. An explanation might have been more confusing."

"OK. Then I think I get it. But if tigerStart is called a second time, we'll create and start a second Thread object. Doesn't that mean that we'll have «one tiger running on two different threads»?"

"Well, aren't you sharp! You're right, and that's not good. Let's rewrite the code like this:"

Code
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

 public void startTiger()
 {
  thread.start();
 }

 private TigerThread thread = new TigerThread();

 private class TigerThread extends Thread
 {
  public void run()
  {
   tigerRun();
  }
 }
}

"It's not quite perfect. You still can't call a method like that twice. But this time, at least we won't create a second thread and make it seem like everything is fine."

"That's right. The second time a Tiger is started, you'll get an exception."

"I'm already spotting mistakes better than you, Ellie!"

"Yeah, you're doing great. Then let's move on to anonymous inner classes."

"Note several aspects of the code above:"

1) We inherited the Thread class, but implemented practically no code there. "It was more «we had to inherit the Thread class» rather than «we inherited it to extend it».

2) Only one TigerThread object will be created.

In other words, we wrote a whole bunch of code just to override one method and create one object.

Do you remember how I talked about the invention of constructors?

Before constructors After constructors
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
Thread thread = new Thread()
{
 public void run()
 {
  tigerRun();
 }
};

"I see the code became more compact, but I don't quite understand what's happening."

"We can combine four things into one:"

1) declaration of a derived class

2) method overriding

3) declaration of a variable

4) creation of an instance of a derived class.

"In fact, what we're doing is combining two operations: declaring a derived class and creating an instance of that class."

Without anonymous class With anonymous class
Cat tiger = new Tiger();

class Tiger extends Cat
{
}
Cat tiger = new Cat()
{
};

"Let's explore the syntax again:"

Declaration of a Thread variable
Thread thread = new Thread();
Declaration of a variable whose type is «an anonymous class that inherits Thread»
Thread thread = new Thread()
{

};

"Note that we aren't simply defining a new class. We're creating a variable—there's a semicolon at the end!"

"And if we want to override the run method, then we need to write this:"

Declaration of a Thread variable
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

"You catch on quickly. Well done!"

"Thanks. What if we need other methods that aren't part of the Thread class?"

"You can write them."

"Though anonymous, this is a full-fledged inner class:"

Java code Description
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};	 
Red: code for creating the variable.

Green: code for creating the object.

Blue: code for the anonymous derived class.

"A full-fledged inner class?"

"So I can use the variables of the outer class?"

"Absolutely."

"And I can pass something to the constructor?"

"Yes, but only the arguments for the superclass's constructor:"

Class Instance of an anonymous inner class
class Cat
{
 int x, y;
 Cat(int x, int y)
 {
  this.x = x;
  thix.y = y;
 }
}
Cat cat = new Cat(3,4)
{
  public void print()
  {
   System.out.println(x+" "+y);
  }
};

"We can't add our own parameters to someone else's constructor. But we can use the variables of the outer class, which compensates nicely for this shortcoming."

"What if I still really need to add other parameters to the constructor?"

"Then declare an ordinary (non-anonymous) inner class and use that."

"Right, I almost forgot about that."

"What if I declare a static variable? Would that make the anonymous class become a static nested class rather than an inner class? In other words, will it lack a reference to the outer class?"

"No. It would be an anonymous inner class. Look at these examples."

With anonymous class Without anonymous class
Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
static Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
static TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}

"I see. Only the static variable would be static, not the class."

"Yep."

"In fact, the compiler creates inner classes for all anonymous inner classes. These classes are usually named «1», «2», «3», etc."