Introduction to INNER CLASSES
We can
declare a class inside another class such type of classes are called
innerclasses.This innerclasses concept has introduced in 1.1 version as the
part of event handling. By observing the utilities and functionalities of inner
class slowly the programmers are using this concept even in regular coding
also.
Ex1: With
out existing car object there is no chance of existing wheel object. Hence we have
to declare wheel class inside car class.
class car
{
class wheel
{
}
}
Ex:2
A map is a
collection of entry objects. With out existing Map object there is no chance of
existing entry object. Hence we have to define entry interface inside map
interface.
interface
Map
{
interface Entity
{
}
}
Based on
the purpose and position of inner class all the inner classes are divided into
4 categories.
1)
Normal/Regular inner classes
2) Method
local inner classes
3)
Anonymous inner classes
4) static
nested classes
Normal/Regular
inner classes
A class
declared inside another class directly with out static modifier is called
normal or regular inner class.
Ex:
class
Outter
{
int i;
char ch;
void set()
{....}
//similarlly i can have a class here
Class inner
{
//This can have its own members also
float f;
void display()
{
}
}//end inner class
}//end
outter class
Method local inner classes:
A regular inner class is scoped inside
another class’s curly braces, but outside any method code (in other words, at
the same level that an instance variable is declared). But you can also define
an inner class within a method:
Ex:-
class
MyExOuterClass
{
private String x = "Outer";
void doSomething()
private String x = "Outer";
void doSomething()
{
class MyExInnerClass
class MyExInnerClass
{
public void accesOuter()
public void accesOuter()
{
System.out.println("Outer x is " + x);
}
}
}
}
System.out.println("Outer x is " + x);
}
}
}
}
What a
Method-Local Inner Class Can and Cannot Do
class MyExOuterClass
A method-local inner class can be instantiated only within the method where the
inner class is defined. In other words, no other codes running in any other
method—inside or outside the outer class—can ever instantiate the method-local
inner class. Like regular inner class objects, the method-local inner class
object shares a special relationship with the enclosing outer class object, and
can access its private or any other members. However, the inner class object
cannot use the local variables of the method the inner class is in.
If you ask me, Why not? Think about it. The local variables of the method live
on the stack, and exist only for the lifetime of the method. You already know
that the scope of a local variable is limited to the method the variable is
declared in. When the method ends, the stack frame is destroyed and the
variable is gone. But even after the method completes, the inner class object
created within it might still be alive on the heap if, for example, a reference
to it was passed into some other code and then stored in an instance variable.
Because the local variables aren’t guaranteed to be alive as long as the
method-local inner class object, the inner class object can’t use them. Unless
the local variables are marked final! The following code attempts to access a
local variable from within a method-local inner class.
class MyExOuterClass
{
private String x = "Outer";
void doSomething()
private String x = "Outer";
void doSomething()
{
String z = "local variable";
class MyExInnerClass
String z = "local variable";
class MyExInnerClass
{
public void accesOuter()
public void accesOuter()
{
System.out.println("Outer x is " + x);
System.out.println("Local variable z is " + z);
// Won't Compile!
}
}
}
}
System.out.println("Outer x is " + x);
System.out.println("Local variable z is " + z);
// Won't Compile!
}
}
}
}
Compiling the preceding code makes the compiler spew out this error message:
MyExOuterClass.java:8: local variable z is accessed from within inner
class;needs to be declared final
System.out.println("Local variable z is " + z);
^
Marking the local variable z as final fixes the problem:
final String z = "local variable";
And just a reminder about modifiers within a method: the same rules apply to
method-local inner classes as to local variable declarations. You can’t, for
example, mark a method-local inner class public, private, protected, static,
transient, and the like. For the purpose of the exam, the only modifiers you
can apply to a method-local inner class are abstract and final, but as always,
never both at the same time.
Anonymous inner classes:
inner
classes declared without any class name at all (probably you figured out why we
call it anonymous).
Anonymous
Inner Classes - Type One
Check out the following code:
Check out the following code:
class Ferrari
{
public void drive()
public void drive()
{
System.out.println("Ferrari");
}
}
System.out.println("Ferrari");
}
}
class Car
{
Ferrari p = new Ferrari()
Ferrari p = new Ferrari()
{
public void drive()
public void drive()
{
System.out.println("anonymous Ferrari");
}
};
}
System.out.println("anonymous Ferrari");
}
};
}
Let’s look at what’s in the preceding code:
• We define two classes, Ferrari and Car.
• Ferrari has one method, drive().
• Car has one instance variable, declared as type Ferrari. That’s it for Car.
Car has no methods.
And here’s the big thing to get. The Ferrari reference variable refers not to
an instance of Ferrari, but to an instance of an anonymous (unnamed) subclass
of Ferrari.
Anonymous Inner Classes and
Polymorphism
Polymorphism is in play when anonymous inner classes are involved. Remember
that, as in the preceding Ferrari example, we’re using a superclass reference
variable type to refer to a subclass object. What are the implications? You can
only call methods on an anonymous inner class reference that are defined in the
reference variable type! This is no different from any other polymorphic
references, for example,
class McLarenF1 extends F1Car
{
void drive() { }
}
class F1Car
void drive() { }
}
class F1Car
{
void brake() { }
}
class Test
void brake() { }
}
class Test
{
public static void main (String[] args)
public static void main (String[] args)
{
F1Car h = new McLarenF1();
h.brake(); // Legal, class F1Car has an brake() method
h.drive(); // Not legal! Class F1Car doesn't have drive()
}
}
So on the exam, you must be able to spot an anonymous inner class that—rather than overriding a method of the superclass—defines its own new method. The method definition isn’t the problem, though; the real issue is how do you invoke that new method? The reference variable type (the superclass) won’t know anything about that new method (defined in the anonymous subclass), so the compiler will complain if you try to invoke any method on an anonymous inner class reference that is not in the superclass class definition.
Check out the following, illegal code:
F1Car h = new McLarenF1();
h.brake(); // Legal, class F1Car has an brake() method
h.drive(); // Not legal! Class F1Car doesn't have drive()
}
}
So on the exam, you must be able to spot an anonymous inner class that—rather than overriding a method of the superclass—defines its own new method. The method definition isn’t the problem, though; the real issue is how do you invoke that new method? The reference variable type (the superclass) won’t know anything about that new method (defined in the anonymous subclass), so the compiler will complain if you try to invoke any method on an anonymous inner class reference that is not in the superclass class definition.
Check out the following, illegal code:
class
Ferrari
{
public void drive()
public void drive()
{
System.out.println("Ferrari");
}
}
class Car
System.out.println("Ferrari");
}
}
class Car
{
Ferrari p = new Ferrari()
Ferrari p = new Ferrari()
{
public void brake()
public void brake()
{
System.out.println("anonymous sizzling Ferrari");
}
public void drive()
System.out.println("anonymous sizzling Ferrari");
}
public void drive()
{
System.out.println("anonymous Ferrari");
}
};
public void popIt()
System.out.println("anonymous Ferrari");
}
};
public void popIt()
{
p.drive(); // OK, Ferrari has a drive() method
p.brake(); // Not Legal! Ferrari does not have brake()
}
}
Compiling the preceding code gives us something like,
Anon.java:19: cannot resolve symbol
symbol : method brake()
location: class Ferrari
p.brake();
^
Anonymous Inner Classes Type Two
p.drive(); // OK, Ferrari has a drive() method
p.brake(); // Not Legal! Ferrari does not have brake()
}
}
Compiling the preceding code gives us something like,
Anon.java:19: cannot resolve symbol
symbol : method brake()
location: class Ferrari
p.brake();
^
Anonymous Inner Classes Type Two
The only difference between type one and type two is that type one creates an
anonymous subclass of the specified class type, whereas type two creates an
anonymous implementer of the specified nterface type. In the previous examples,
we defined a new anonymous subclass of type Ferrari as follows:
Ferrari p = new Ferrari() {
But if Ferrari were an interface type instead of a class type, then the new
anonymous class would be an implementer of the interface rather than a subclass
of the class. Look at the following example:
interface Drivable
{
public void drive();
}
class Car
public void drive();
}
class Car
{
Drivable c = new Drivable()
Drivable c = new Drivable()
{
public void drive()
public void drive()
{
System.out.println("anonymous Drivable implementer");
}
};
}
System.out.println("anonymous Drivable implementer");
}
};
}
The preceding code, like the Ferrari example, still creates an instance of an
anonymous inner class, but this time the new class is an implementer of the
Drivable interface. And note that this is the only time you will ever see the
syntax
new Drivable()
where Drivable is an interface rather than a non-abstract class type. Because
think about it, you can’t instantiate an interface, yet that’s what the code
looks like it’s doing. But of course it’s not instantiating a Drivable object,
it’s creating an instance of a new, anonymous, implementer of Drivable. You can
read this line:
Drivable c = new Drivable() {
as, “Declare a reference variable of type Drivable that, obviously, will refer
to an object from a class that implements the Drivable interface. But, oh yes,
we don’t yet have a class that implements Drivable, so we’re going to make one
right here, right now. We don’t need a name for the class, but it will be a class
that implements Drivable, and this curly brace starts the definition of the new
implementing class.”
One more thing to keep in mind about anonymous interface implementers—they can
implement only one interface. There simply isn’t any mechanism to say that your
anonymous inner class is going to implement multiple interfaces. In fact, an
anonymous inner class can’t even extend a class and implement an interface at
the same time. The inner class has to choose either to be a subclass of a named
class—and not directly implement any interfaces at all—or to implement a single
interface. By directly, we mean actually using the keyword implements as part
of the class declaration. If the anonymous inner class is a subclass of a class
type, it automatically becomes an implementer of any interfaces implemented by
the superclass.
Argument-Defined Anonymous Inner
Classes
If you understood what we’ve covered so far in this chapter, then this last
part will be a walk in the park. If you are still a little fuzzy on anonymous
classes, however, then you should reread the previous sections.
Imagine the following scenario. You’re typing along, creating the Perfect
Class, when you write code calling a method on a Class1 object, and that method
takes an object of type Interface1 (an interface).
{
void do() {
Class1 b = new Class1();
b.doSomething(!!!);
//Actually the !!! mean nothing. We don't have any argument matching // the input required here so I put the !!! to make it logical
}
}
interface Interface1
void do() {
Class1 b = new Class1();
b.doSomething(!!!);
//Actually the !!! mean nothing. We don't have any argument matching // the input required here so I put the !!! to make it logical
}
}
interface Interface1
{
void doSomethingElse();
}
class Class1
void doSomethingElse();
}
class Class1
{
void doSomething(Interface1 f) { }
}
1. class MyComplicatedClass {
2. void do() {
3. Class1 b = new Class1();
4. b.doSomething(new Interface1() {
5. public void doSomethingElse() {
6. System.out.println("Hey!!!");
7. }
8. });
9. }
10. }
11.
12. interface Interface1 {
13. void doSomethingElse();
14. }
15. class Class1 {
16. void doSomething(Interface1 f) { }
17. }
new Interface1() {
but if they’re just regular anonymous classes, then they end like this:
};
void doSomething(Interface1 f) { }
}
No problems here, except that you don’t have an object from a class that
implements Interface1, and you can’t instantiate one, either, because you don’t
even have a class that implements Interface1, let alone an instance of one. So
you first need a class that implements Interface1, and then you need an
instance of that class to pass to the Class1 class’s doSomething() method.
Knowing the smart Java programmer that you are, you simply define an anonymous
inner class, right inside the argument. That’s right, just where you least
expect to find a class. And here’s what it looks like:
1. class MyComplicatedClass {
2. void do() {
3. Class1 b = new Class1();
4. b.doSomething(new Interface1() {
5. public void doSomethingElse() {
6. System.out.println("Hey!!!");
7. }
8. });
9. }
10. }
11.
12. interface Interface1 {
13. void doSomethingElse();
14. }
15. class Class1 {
16. void doSomething(Interface1 f) { }
17. }
All the action starts on line 4. We’re calling doSomething() on a Class1
object, but the method takes an instance that IS-A Interface1, where Interface1
is an interface. So we must make both an implementation class and an instance
of that class, all right here in the argument to doSomething(). So that’s what
we do. We write
new Interface1() {
to start the new class definition for the anonymous class that implements the
Interface1 interface. Interface1 has a single method to implement, doSomethingElse(),
so on lines 5, 6, and 7 we implement the doSomethingElse() method. Then on line
8 more strange syntax appears. The first curly brace closes off the new
anonymous class definition. But don’t forget that this all happened as part of
a method argument, so the close parenthesis, ), finishes off the method
invocation, and then we must still end the statement that began on line 4, so
we end with a semicolon. Study this syntax! You will see anonymous inner
classes on the exam, and you’ll have to be very, very picky about the way
they’re closed. If they’re argument local, they end like this:
});but if they’re just regular anonymous classes, then they end like this:
};
Static nested classes:
Actually
static inner classes aren’t inner classes at all, by the standard definition of
an inner class. While an inner class enjoys that special relationship with the
outer class (or rather the instances of the two classes share a relationship),
a static MyStaticExInnerClass class does not. It is simply a non-inner (also
called “top-level”) class scoped within another. So with static classes it’s
really more about name-space resolution than about an implicit relationship
between the two classes.
A static MyStaticExInnerClass class is simply a class that’s a static member of the enclosing class:
class MyExOuter
{
static class StaticInner { }
}
Instantiating and Using Static Inner
Classes
class MyExOuter
static class StaticInner { }
}
The class itself isn’t really “static”; there’s no such thing as a static
class. The static modifier in this case says that the MyStaticExInnerClass
class is a static member of the outer class. That means it can be accessed, as
with other static members, without having an instance of the outer class.
You use standard syntax to access a static MyStaticExInnerClass class from its
enclosing class. The syntax for instantiating a static MyStaticExInnerClass
class from a non-enclosing class is a little different from a normal inner
class, and looks like this:
class MyExOuter
{
static class MyStaticExInner
static class MyStaticExInner
{
void do()
{
System.out.println("hi");
}
}
}
class Test
}
class Test
{
static class B2
static class B2
{
void goB2()
{
System.out.println("hi
2");
}
}
public static void main(String[] args) {
MyExOuter.MyStaticExInner n = new MyExOuter.MyStaticExInner();
n.do();
B2 b2 = new B2();
b2.goB2();
}
}
Which produces
hi
hi 2
public static void main(String[] args) {
MyExOuter.MyStaticExInner n = new MyExOuter.MyStaticExInner();
n.do();
B2 b2 = new B2();
b2.goB2();
}
}
Which produces
hi
hi 2
Post a Comment
Post a Comment