You are on page 1of 30

Me = new

Genius("Java");
Monday, September 8, 2008
Static Inner Classes

Static Member Classes


In this post I will tell you everything about Static Member Classes from inside
out. You must have been frustrated by remembering about the rules governing
Inner Classes. In this post I will tell you how Inner Classes actually work. This
will help you get a deep knowledge of Inner Classes which will help you a lot.
This code will tell how the compiler changes the Inner Classes. But remember,
that is a some difference in the code given here and what is generated by the
compiler. This article uses a simplified approach by removing and modifying
some of the code generated by the compiler.
Static Member Classes can also be called as Static Inner Classes. To begin with
let me tell you in brief about Static Member Classes.

 They can be declared inside top-level classes or other Static Member


Classes
 These are declared within other classes with the static modifier.
 They can declare static and non-static members.
 All accessibility modifiers can be used with these classes.
 To create an object of Static Member Class, you don't need an instance
of its enclosing class.
 An instance of enclosing class is not stored in an instance of a Static
Member Class.
 They can access static members of the enclosing class including
private static members.
 They can access non-static members of the enclosing class(including
private non-static members) on an object of the enclosing class.
 The reverse is also correct i.e. members of the enclosing class can
access static members of the Member Class directly and non-static
members of the Member Class on an Object of the Member Class.

If you are astonished by the above list of information, don't worry. In the
course of this tutorial, you will come across all these facts.
Now let's begin one by one how the compiler changes different types of codes
in an inner class. By the end you will know completely how all the code in an
inner class is transformed to make the inner class a normal top level class.

First lets see how an inner class accesses static members of the enclosing class
by their names.
Code
1. class Outer
2. {
3. static int a = 10;
4. static class Inner
5. {
6. void display()
7. {
8. System.out.println(a); //displays 10
9. }
10. }
11. }

Now when you compile the program the compiler converts the class Inner to a
normal top level class. But now the question arises that what will happen to
Statement # 8. Well the answer is simple, the compiler adds the name of the
enclosing class i.e. Outer before the name of the variable a. So after compilation,
the program given above will look like this-
Code after Comilation
1. class Outer
2. {
3. static int a = 10;
4. }
5. class Outer$Inner
6. {
7. void display()
8. {
9. System.out.println(Outer.a); //displays 10
10. }
11. }

Note the name of the member(inner) class after compilation. The compiler adds
the name of the enclosing class before the name of the member class seperated
by a $. The static keyword is also gone as top-level classes cannot be static. To
access the member class from any code outside the enclosing class, you have to
use the syntax <enclosingClassName>.<memberClassName>. So to access the class Inner
from outside the class Outer you will have to use the name of the class as
Outer.Inner.

Now you know that members of a class can access private members of the class.
So a member class can also access the private members of the enclosing class. But
how can the member class access private members of the enclosing class after
compilation. Since after compilation the member class is converted into a
normal top-level class, so it has no direct access to the private members of the
enclosing class. But the compiler creates some package visible methods to make this
possible.
Code
1. class Outer
2. {
3. private static int a = 10;
4. static class Inner
5. {
6. void display()
7. {
8. System.out.println(a); //displays 10
9. }
10. }
11. }

Now after compilation the class Inner will become a top-level class. At Statement #
8 the compiler adds a method call since this statement tries to access a private
member of the enclosing class. Lets see how this happens-
Code after Compilation
1. class Outer
2. {
3. private static int a = 10;
4. static int access$000()
5. {
6. return a;
7. }
8. }
9. class Outer$Inner
10. {
11. void display()
12. {
13. System.out.println(Outer.access$000()); //displays 10
14. }
15. }

Look how cleverly the compiler generates a method at Statement # 4 which has
access to private members of the class. This method returns the value of the
static field a. Notice the ugly name of the compiler generated method. You
cannot explicitly call this method in your code because the compiler will flag it
as an error. If a local declaration or a field in the inner class or its super class
hides the field of the enclosing class, you can access the field by placing the
name of the enclosing class before the field name. It goes like this-
Code
1. class Outer
2. {
3. static int a = 10;
4. private static int b = 20;
Code
5. static class Inner
6. {
7. String a;
8. String b;
9. void display()
10. {
11. System.out.println(Outer.a); //displays 10
12. System.out.println(Outer.b); //displays 20
13. }
14. }
15. }

The compiler generated code will look like this-


Code after Compilation
1. class Outer
2. {
3. static int a = 10;
4. private static int b = 20;
5. static int access$000()
6. {
7. return b;
8. }
9. }
10. class Outer$Inner
11. {
12. String a;
13. String b;
14. void display()
15. {
16. System.out.println(Outer.a); //displays 10
17. System.out.println(Outer.access$000()); //displays 20
18. }
19. }

Now that you know everything about how a Static Member Class can access all
the static members of the enclosing class, lets see how the static member class
accesses the non-static members of the enclosing class on an object of the
enclosing class.
Code
1. class Outer
2. {
3. int a = 10;
4. private int b = 20;
5. static class Inner
6. {
7. void display()
8. {
9. Outer outer = new Outer();
10. System.out.println(outer.a); //displays 10
11. System.out.println(outer.b); //displays 20
Code
12. }
13. }
14. }

There is no problem in the Statement # 10 as it accesses a non-private member of


the enclosing class. There is nothing wrong with it. But Statement # 11 tries to
access a private member of the enclosing class. This is how it is made possible after
compilation-
Code after Compilation
1. class Outer
2. {
3. int a = 10;
4. private int b = 20;
5. static int access$000(Outer outer)
6. {
7. return outer.b;
8. }
9. }
10. class Outer$Inner
11. {
12. void display()
13. {
14. Outer outer = new Outer();
15. System.out.println(outer.a); //displays 10
16. System.out.println(Outer.access$000(outer)); //displays 20
17. }
18. }

In this case the compiler generates a static package visible method at Statement #
5 which takes an object of the enclosing class as parameter. Statement # 16
accesses the private non-static member of the enclosing class by calling this
method and sending the instance of the enclosing class as argument. The
method returns the value of the field on the object passed to it.

Till now you have only seen how to access the value of fields from an Inner
Class. But you can also mutate i.e. set the value of fields and make method
calls. The example below shows you how this happens for non-private members-
Code
1. class Outer
2. {
3. int a = 10;
4. static int b = 20;
5. int getProduct()
6. {
7. return a * b;
8. }
9. static int getCube()
10. {
Code
11. return b * b * b;
12. }
13. static class Inner
14. {
15. void display()
16. {
17. b = 2;
18. System.out.println(b); //displays 2
19. System.out.println(getCube()); //displays 8
20. Outer outer = new Outer();
21. outer.a = 100;
22. System.out.println(outer.getProduct()); //displays
23. 200
24. System.out.println(outer.a); //displays
25. 100
26. }
}
}

There is not much changes made in this code by the compiler. So the code after
compilation would look as-

Code after Compilation


1. class Outer
2. {
3. int a = 10;
4. static int b = 20;
5. int getProduct()
6. {
7. return a * b;
8. }
9. static int getCube()
10. {
11. return b * b * b;
12. }
13. }
14. class Outer$Inner
15. {
16. void display()
17. {
18. Outer.b = 2;
19. System.out.println(Outer.b); //displays 2
20. System.out.println(Outer.getCube()); //displays 8
21. Outer outer = new Outer();
22. outer.a = 100;
23. System.out.println(outer.getProduct()); //displays 200
24. System.out.println(outer.a); //displays 100
25. }
26. }

The compiler adds the name of the class Outer before the field and method
names at Statements # 18, 19 and 20. This is the only change made by the compiler
(apart from making the class Inner a top level class). Its easy enough! But if what
we are trying to access is private member of the enclosing class, then the code
becomes a bit complicated. Lets see how you can mutate the values of private
fields of the enclosing class-
Code
1. class Outer
2. {
3. private int a = 10;
4. private static int b = 20;
5. static class Inner
6. {
7. void display()
8. {
9. b = 2;
10. Outer outer = new Outer();
11. outer.a = 100;
12. }
13. }
14. }

For Statement # 9 the compiler will generate a static package visible method that
takes the value that you set with the assignment. For Statement # 11 the
compiler generates another static package visible method that takes the object
of the class Outer and the value that you assign to the field. These methods are
shown at Statements # 5 and 9 in the code below-
Code after Compilation
1. class Outer
2. {
3. private int a = 10;
4. private static int b = 20;
5. static void access$000(int val)
6. {
7. b = val;
8. }
9. static void access$100(Outer outer, int val)
10. {
11. outer.a = val;
12. }
13. }
14. class Outer$Inner
15. {
16. void display()
17. {
18. Outer.access$000(2); //b = 2;
19. Outer outer = new Outer();
20. Outer.access$100(outer, 100); //outer.a = 100;
21. }
22. }

The statements at Statements # 18 and 20 are generated by the compiler. The original
statements are shown in comments. Now lets see how you can call private methods of the
enclosing class-
Code
1. class Outer
2. {
3. private void getProduct(int x, int y)
4. {
5. System.out.println(x * y);
6. }
7. private static int getCube(int x)
8. {
9. return x * x * x;
10. }
11. static class Inner
12. {
13. void display()
14. {
15. System.out.println(getCube(3)); //displays 9
16. Outer outer = new Outer();
17. outer.getProduct(10,20); //displays 200
18. }
19. }
20. }

For both these methods, the compiler generates static package visible methods
which inturn calls these methods which are unavailable to the inner class after
compilation. The methods generated by the compiler for the mehods and their call are
shown in the code below-
Code after Compilation
1. class Outer
2. {
3. private void getProduct(int x, int y)
4. {
5. System.out.println(x * y);
6. }
7. private static int getCube(int x)
8. {
9. return b * b * b;
10. }
11. static int access$000(int x)
12. {
13. return getCube(x);
14. }
15. static void access$100(Outer outer, int x, int y)
16. {
17. outer.getProduct(x, y);
18. }
19. }
20. class Outer$Inner
21. {
22. void display()
23. {
Code after Compilation
24. System.out.println(Outer.access$000(3));
25. //System.out.println(getCube(3));
26. Outer outer = new Outer();
27. Outer.access$100(outer, 10, 20);
28. //outer.getProduct(10, 20);
}
}

The methods at Statements # 11 and 15 call the methods getCube() and getProduct()
respectively. The methods calls at Statements # 24 and 27 are generated by the
compiler. The original calls are shown in comments. Lets see the opposite of
this i.e. accessing the private members of the inner class from the members of the
enclosing class.
Code
1. class Outer
2. {
3. static class Inner
4. {
5. static int staticVal = 10;
6. int nonPrivateVal = 20;
7. private int privateVal = 30;
8. void nonPrivateDisplay()
9. {
10. System.out.println("Non-Private Display!");
11. }
12. private void privateDisplay()
13. {
14. System.out.println("Private Display!");
15. }
16. }
17. void display()
18. {
19. System.out.println(Inner.staticVal); //displays 10
20. Inner in = new Inner();
21. System.out.println(in.nonPrivateVal); //displays 20
22. System.out.println(in.privateVal); //displays 30
23. in.nonPrivateDisplay(); //displays Non-
24. Private Display!
25. in.privateDisplay(); //displays
26. Private Display!
}
}

The compiler will generate package visible methods for the access statements
at Statements # 22 and 24. So the code would look like this-
Code after Compilation
1. class Outer
2. {
3. void display()
4. {
Code after Compilation
System.out.println(Inner.staticVal); //displays
10
Outer.Inner in = new Outer.Inner();
5.
System.out.println(in.nonPrivateVal); //displays
6.
20
7.
System.out.println(Outer.Inner.access$000(in)); //displays
8.
30
9.
in.nonPrivateDisplay(); //displays
10.
Non-Private Display!
11.
Outer.Inner.access$100(in); //displays
12.
Private Display!
13.
}
14.
}
15.
class Outer$Inner
16.
{
17.
static int staticVal = 10;
18.
int nonPrivateVal = 20;
19.
private int privateVal = 30;
20.
void nonPrivateDisplay()
21.
{
22.
System.out.println("Non-Private Display!");
23.
}
24.
private void privateDisplay()
25.
{
26.
System.out.println("Private Display!");
27.
}
28.
static int access$000(Outer$Inner inner)
29.
{
30.
return inner.privateVal;
31.
}
32.
static void access$100(Outer$Inner inner)
33.
{
34.
inner.privateDisplay();
}
}

Note that I have used the name Outer.Inner to represent the inner class in the
enclosing class at Statements # 6, 8 and 10. This is just to avoid any confusion as
the name Outer.Inner must be used to represent the inner class from any code
outside the enclosing class. There is one last thing that you must note before
we move to Non Static Member Classes. If you don't access some members of
the enclosing class from the inner class then the compiler doesn't generates methods
for them. For Example-
Code
1. class Outer
2. {
3. static int a = 10;
4. static class Inner
5. {
6. void display()
7. {
Code
8. System.out.println("Hello!");
9. }
10. }
11. }

The code above will not be altered much by the compiler. Since the field a is
not accessed in the inner class so no method will be generated for that. So the code
after compilation will look like this-
Code after Compilation
1. class Outer
2. {
3. private static int a = 10;
4. }
5. class Outer$Inner
6. {
7. void display()
8. {
9. System.out.println("Hello!");
10. }
11. }

I think now you know about Static Member classes from inside out. I hope this
will help you a lot. View my other posts to learn more about the other forms of
Inner Classes.
Posted by Ankit Garg at 5:09 AM 5 comments
Labels: Changes made to Inner Classes by the Compiler, Inner Classes in Java, Java Inner Classes after Compilation, Static Inner Classes in Java, Static Member
Classes

Non-Static Inner Classes

Non-Static Member
Classes
Lets again start with the introduction of Non-Static Member Classes.

 They can be declared inside top-level classes or other Member Classes.


 They can declare only non-static members and static constants.
 All accessibility modifiers can be used with these classes.
 To create an object of Non-Static Member Class, you need an instance of
its enclosing class.
 An instance of enclosing class is stored in an instance of a Non-Static
Member Class.
 They can access all the members of the enclosing class including
private members.
 The reverse is also correct i.e. members of the enclosing class can
access static(constants) members of the Member Class directly and
non-static members of the Member Class on an Object of the Member
Class.

If you have not read how Static Member Classes work, then I recommend that
you read Static Member Classes first before continuing. This is because I will
not re-mention how a member class accesses static members including private
static members of the enclosing class.

The main difference between Static Member Class and Non-Static Member
class is that the every object of a Non-Static Member Class has an object of the
enclosing class stored within it. This is why you can access non-static members of
the enclosing class in a Non-Static Member Class. But how does this happens.
See the code below which shows a simple example of how to create an instance
of a non-static inner class.

Code
1. class Outer
2. {
3. class Inner
4. {
5. }
6. void display()
7. {
8. Inner in = new Inner();
9. }
10. }

At Statement # 8 you can see that an instance of the non-static member class has
been created. But the question still remains that how does that instance which
is created at Statement # 8 has an instance of the enclosing class in it. If you
have studied inner classes closely than you must be knowing that the code at
Statement # 8 implicitly uses the this reference to create the inner class instance.
So the code implicitly looks like this-

Code
1. class Outer
2. {
3. class Inner
4. {
5. }
6. void display()
7. {
8. Inner in = this.new Inner();
Code
9. }
10. }

You may have noticed this if you mistakenly typed this code in you program-

Code
1. class Outer
2. {
3. class Inner
4. {
5. }
6. public static void main(String[] args)
7. {
8. Inner in = new Inner();
9. }
10. }

If you compile this program you will get this error-

Outer.java:8: non-static variable this cannot be referenced from a


static context
Inner obj = new Inner();
^
1 error

You get this error because the compiler will asume that you want to create the
instance of the inner class with the this reference. So to create
an instance of the inner class from a static method, you have to explicitly use an
instance of the enclosing class like this-

Code
1. class Outer
2. {
3. class Inner
4. {
5. }
6. public static void main(String[] args)
7. {
8. Outer out = new Outer();
9. Inner in = out.new Inner();
10. }
11. }

Now lets come to the point. What's the use of this enclosing class instance?
Well the instance of the enclosing class that you use with the new operator is
passed to the constructor of the inner class. It doesn't matter whether you
provide a constructor for the inner class or not. The compiler adds the object
of the enclosing class as the last parameter of the inner class. The compiler
also adds some code to the inner class constructor that stores the object of the
enclosing class passed to it into a field that stores the reference of the conclosing class.
This field is also added to the class by the compiler. Lets see the code generated by the
compiler for the class that we created above-

Code after Compilation


1. class Outer
2. {
3. public static void main(String[] args)
4. {
5. Outer out = new Outer();
6. Outer.Inner in = new Outer.Inner(out);
7. }
8. }
9. class Outer$Inner
10. {
11. Outer$Inner(Outer outer)
12. {
13. this$0 = outer;
14. }
15. final Outer this$0;
16. }

This final reference of the enclosing class is used to access the non-static
members of the enclosing class. The non static inner class accesses the static
members of the enclosing class in the same way as static inner class accesses
them. We will see here how it accesses the non-static members of the enclosing
class. See the code below-

Code
1. class Outer
2. {
3. int a = 10;
4. private int b = 20;
5. class Inner
6. {
7. void display()
8. {
9. System.out.println(a);
10. System.out.println(b);
11. }
12. }
13. }
Remember how the static inner class accessed the non-static members of the
enclosing class on an instance of the enclosing class. The non-static inner class
will also access the non-static members of the enclosing class in the same way. The
difference will be that an implicit reference to the enclosing class will be used. So the
code after compilation would look like this-

Code after Compilation


1. class Outer
2. {
3. int a = 10;
4. private int b = 20;
5. static int access$000(Outer outer)
6. {
7. return outer.b;
8. }
9. }
10. class Outer$Inner
11. {
12. Outer$Inner(Outer outer)
13. {
14. this$0 = outer;
15. }
16. void display()
17. {
18. System.out.println(this$0.a);
19. System.out.println(Outer.access$000(this$0)); //System.out.println(b);
20. }
21. final Outer this$0;
22. }

Look how cleverly the compiler utilizes the enclosing class instance at
Statements # 18 and 19. Again here the compiler generates an accessor method at
Statement # 5 so that the private member b can be accessed by the access
statement in the display() method in the inner class. But what will happen if a
declaration in the inner class or it's super class hides the enclosing class' instance
member. You might know that in such a case a special form of this reference is
used. Lets see the special form of this reference in action.

Code
1. class Outer
2. {
3. int a = 10;
4. class Inner
5. {
6. int a = 100;
7. void display()
8. {
9. System.out.println(a);
10. System.out.println(Outer.this.a);
Code
11. }
12. }
13. }

The special syntax of the this reference can be seen at Statement # 10. The rule
behind it is simple. This syntax of the this
reference (<enclosing class name>.this) represents the enclosing class instance
stored by the compiler in the non-static inner class. Look how
the Statement # 10 in the code above is changed into Statement # 15 in the code
below-

Code after Compilation


1. class Outer
2. {
3. int a = 10;
4. }
5. class Outer$Inner
6. {
7. int a = 100;
8. Outer$Inner(Outer outer)
9. {
10. this$0 = outer;
11. }
12. void display()
13. {
14. System.out.println(a);
15. System.out.println(this$0.a); //System.out.println(Outer.this.a);
16. }
17. final Outer this$0;
18. }

The code must have made it clear to you that the special syntax of the this
reference is just a trick to use the final enclosing class reference which is not
available before compilation. There is nothing more in non-static inner classes.
The enclosing class members can access the members of a non-static inner
class just as they access the members of a static inner class. The only
difference is that to create an instance of a non-static inner class, you need an
instance of the enclosing class while enclosing class instance is not required to
create an instance of a static inner class.
Posted by Ankit Garg at 4:43 AM 0 comments
Labels: Changes made to Inner Classes by the Compiler, How Inner Classes Work, Inner Classes Tutorial Java, Java Inner Classes after Compilation, Non-Static
Member Classes, Problem with Inner Classes

Local Classes in Java

Local Classes
Static Local Classes
As always, lets begin with an introduction of Static Local Classes-

 These are classes declared inside static methods.


 They can declare non-static members and static constants.
 No accessibility modifiers can be used with these classes.
 To create an object of Static Local Class, you don't need an instance of
its enclosing class.
 An instance of enclosing class is not stored in an instance of a Static
Local Class.
 They can access static members of the enclosing class including
private static members.
 They can access non-static members of the enclosing class(including
private non-static members) on an object of the enclosing class.
 They can access non-hidden final local variables i.e. variables of the
enclosing method including final parameters passed to the enclosing
method.
 They must be declared before use.
 An object of a Static Local Class can only be created inside the enclosing
method as it is local to that method.
 All the constants declared in a method which are used in the local class
must be assigned a value before the declaration of the local class.

If you have not read how Static Member Classes and Non-Static Member Classes
work, then I recommend that you read Static Member Classes and Non-Static
Member Classes first before continuing.

How a Static Local Class access the static and non-static


members of the enclosing class is similar to what you have seen in Static
Member Class. We must directly jump to how the Static Local Class accesses
the final local variables. Well the concept is just simple. When you create a
local class the compiler adds the final local variables as a paremeter to the
local class constructor and stores them in corresponding final variables that the
compiler adds to the local class. Lets see this phenomenon-
Code
1. class Outer
2. {
3. static void containerMethod(final int a)
4. {
5. final int b = 10;
6. class Local
7. {
8. void display()
Code
9. {
10. System.out.println(a);
11. System.out.println(b);
12. }
13. }
14. Local local = new Local();
15. }
16. }

Now when you compile the program, the compiler generates a constructor for
the class Local and adds two int variables as parameters to the constructor. At
Statement # 14 the compiler adds a and b as arguments to the constructor call. Lets see
the modified code-
Code after Compilation
1. class Outer
2. {
3. static void containerMethod(final int a)
4. {
5. final int b = 10;
6. Outer.Local local = new Outer.Local(a, b);
7. }
8. }
9. class Outer$Local
10. {
11. final int val$a;
12. final int val$b;
13. Outer$Local(int a, int b)
14. {
15. val$a = a;
16. val$b = b;
17. }
18. void display()
19. {
20. System.out.println(val$a); //System.out.println(a);
21. System.out.println(val$b); //System.out.println(b);
22. }
23. }

You might be asking why didn't the compiler replace the name of constants
with the actual value of the constants. Well the compiler could have done that
for b as it is known at compile time that the value of b is 10. But what if b was
declared and initialized in separate statements. Then b would have not been a
compile time constant. What about a? Its value is not known at compilation
time. The value will be passed as a parameter. This is why compiler caches the
final local constants in a local class instead of replacing the name of the constant
with the value of the constant.
The local class can only access the non-hidden final local variables. If a
declaration in the local class or its super class hides the final local variables, they
become inaccessible. There is no way to access them. For Example-
Code
1. class Outer
2. {
3. static void containerMethod()
4. {
5. final int a = 10;
6. class Local
7. {
8. int a = 100; //hides local a
9. void display()
10. {
11. System.out.println(a); //displays 100
12. }
13. }
14. Local local = new Local();
15. }
16. }

The declaration at Statement # 8 hides the local declaration of a at Statement # 5.


The variable a declared at Statement # 5 cannot be accessed from the methods of
the methods of class Local by any means. As you must have read that a Static
Local Class must be declared before use. This means that it cannot be specified
as the return type of the method in which it is declared. Then is the Static
Local Class only created for the enclosing method. Well it can be used if you
specify the super class of the Static Local Class as the return type of the method.
But then also you can only call method declared in the super class. So you can override
the methods of the super class and provide new implementation for those methods. As
you know that methods are called on the actual object stored in a reference so the code in
methods declared by you will be called. See the example below to understand how it
works-
Code
1. class Base
2. {
3. public void display()
4. {
5. System.out.println(&qt;Base..&qt;);
6. }
7. }
8. class Outer
9. {
10. static Base containerMethod()
11. {
12. class Local extends Base
13. {
14. public void display()
15. {
16. System.out.println("Local..");
17. }
18. public void hello()
19. {
20. System.out.println("Hello!!");
Code
21. }
22. }
23. return new Local();
24. }
25. }
26. class MainClass
27. {
28. public static void main(String[] args)
29. {
30. Base base = Outer.containerMethod();
31. base.display(); //displays Local..
32. //base.hello(); //not a member of base
33. }
34. }

The method containerMethod declared at Statement # 10 contains a class


Local which extends the class Base declared at Statement # 1. Class Local
overrides the method display of the class Base. The return type of
containerMethod is Base so it can return an object of type Local(as it is the
sub-class of Base). The main method recieves an object of class Local into a
reference of class Base. When it calls the method display on that object, the
implementation of display method at Statement # 14 is called. The Statement
# 32 is not valid as the declared type of reference variable base is Base and
method hello is not declared in class Base.
Non-Static Local Classes
Again lets begin with an introduction of Non-Static Local Classes-

 These are classes declared inside non-static methods.


 They can declare non-static members and static constants.
 No accessibility modifiers can be used with these classes.
 To create an object of Non-Static Local Class, you need an instance of
its enclosing class.
 An instance of enclosing class is stored in an instance of a Non-Static
Local Class.
 They can access all members of the enclosing class including private
members.
 They can access non-static members of the enclosing class(including
private non-static members) on an object of the enclosing class.
 They can access non-hidden final local variables i.e. variables of the
enclosing method including final parameters passed to the enclosing
method.
 They must be declared before use.
 An object of a Non-Static Local Class can only be created inside the
enclosing method as it is local to that method.
How a Local Class access the final local variables, static and non-static members
of the enclosing class is similar to what you have seen in Static Local Class. We
will be jumping directly to how they get an enclosing instance. Well this is
similar to Non-Static Member Classes. The compiler adds the this reference
wherever we create an instance of the local class in the method.
Code
1. class Outer
2. {
3. int a = 10;
4. private int b = 20;
5. void method()
6. {
7. class Local
8. {
9. void display()
10. {
11. System.out.println(a);
12. System.out.println(b);
13. }
14. }
15. Local local = new Local();
16. }
17. }

You might have guessed it what the compiler will do here. At Statement # 15 it
will add this reference as a parameter to the constructor. The Local class will
store the this reference with itself and use it to access a and b.
Code after Compilation

1. class Outer
2. {
3. int a = 10;
4. private int b = 20;
5. static int access$000(Outer outer)
6. {
7. return outer.b;
8. }
9. void method()
10. {
11. Outer$Local1 local = new Outer$Local1(this);
12. }
13. }
14. class Outer$Local1
15. {
16. Outer$Local1(Outer outer)
17. {
18. this$0 = outer;
19. }
20. void display()
21. {
22. System.out.println(this$0.a);
Code after Compilation

23. System.out.println(Outer.access$000(this$0)); //System.out.println(b);


24. }
25. final Outer this$0;
26. }

As you can see that the local class has become a regular class again with an
ugly name Outer$Local1. The compiler has also created a constructor for the local
class and added a reference of the Outer class as an argument to it. Remeber you
cannot use any other object than this to create an instance of the local class. For
example the following code will not compile-
Code

1. class Outer
2. {
3. void method()
4. {
5. class Local
6. {
7. }
8. Outer outer = new Outer();
9. Local local = outer.new Local();
10. }
11. }

This code will generate this error-

Outer.java:9: cannot find symbol


symbol : class Local
location : class Outer
Local local = outer.new Local();
^
1 error

Posted by Ankit Garg at 1:46 AM 0 comments


Labels: Changes made to Inner Classes by the Compiler, Inner Classes in Java, Java Inner Classes after Compilation, Local Classes, Method Local Classes, Non-
Static Local Classes, Static Local Classes

Rules for Arrays

Arrays of References
This article is about the compile time checks and runtime exceptions related to
Arrays. It will give you a precise list of rules about when the compiler will
reject your code, when JVM will throw an Exception and when will the code
run normally.

We will use this inheritance hierarchy as a reference in this article.


First Scenario - Declaring and Intializing an Array

When you declare and intialize an array, it looks like this-

ArrayType[] arrayName = new ActualArrayType[size];

In this code you will have to remember thise rule-

 ActualArrayType must be a sub-type or same type as ArrayType for


compilation to succed.

This rule is simple. ActualArrayType must be assignable to ArrayType for


ActualArrayType[] to be assigned to ArrayType[]. But this rule is only
applicable to reference type arrays. Primitive Array types of assignable
primitive types are not assignable to each other. This means that int[] is not
assignable to long[] while int is not assignable to long.

In our hierarchy, you can create an array of type Car, and assign it an array of
type Car or Porsche or Lamborghini or their sub-types. So here is a list of valid
and invalid array assignments-

Car[] carArr = new Car[3]; //Valid, Same-type

Car[] carArr = new Lamborghini[3]; //Valid, Sub-type


Car[] carArr = new Bozter[3]; //Valid, Indirect Sub-type

Porsche[] porscheArr = new Cayman[3]; //Valid, Sub-type

Porsche[] porscheArr = new Car[3]; //Invalid, Super-type

Porsche[] porscheArr = new Lamborghini[3]; //Invalid, Sibling

The statements above tell which codes are valid and which are not along with
why they are valid/invalid.

Second Scenario - Assigning value to an Element in


the Array

Each element in the array can be assigned a seperate value. The assignment is
done like this-

ObjectType anObject = new ActualObjectType();

ArrayType[] arrayName = new ActualArrayType[size];


arrayName[indexValue] = anObject;

The rules regarding the values that can be assigned to an array element for
successful compilation and successful execution are as below

 ObjectType must be a sub-type or same type as ArrayType for


compilation to succed.
 ActualObjectType must be a sub-type or same type as
ActualArrayType(Note: there is no [] here) for successful execution.
Otherwise an ArrayStoreException will be thrown
 And as everyone knows indexValue must be less than size of array and
greater than or equal to 0 otherwise there will be an
ArrayIndexOutOfBoundsException on run time.

Here is a list of valid and invalid array assignments-

Car[] carArr = new Car[3];

Car carObj = new Car();

carArr[0] = carObj;
The above code will both compile and run successfully as it follows all the
rules.

Porsche[] porscheArr = new Boxter[3];

Porsche porscheObj = new Boxter();

porscheArr[0] = porscheObj;

The above code will both compile and run successfully. This is because type of
porscheObj(i.e. Porsche) is assignable to type of elements of porscheArr(i.e.
Porsche). The actual type of both porscheObj and elements of porscheArr are
also assignable.

Porsche[] porscheArr = new Cayman[3];

Porsche porscheObj = new Boxter();

porscheArr[0] = porscheObj;

The above code will compile successfully. This is because type of


porscheObj(i.e. Porsche) is assignable to type of porscheArr(i.e. Porsche). But
this code will generate an ArrayStoreException as the actual type of
porscheObj(i.e. Boxter) is not assignable to actual type of porscheArr(i.e.
Cayman).

Porsche[] porscheArr = new Porsche[3];

Car carObj = new Porsche();

porscheArr[0] = carObj;

The above compilation will not succed as the type of carObj(i.e. Car) is not
same type or sub-type of type of elements of porscheArr(i.e. Porsche).

Porsche[] porscheArr = new Porsche[3];

Lamborghini lamborghiniObj = new Lamborghini();

porscheArr[0] = lamborghiniObj;

The above compilation will not succed as the type of lamborghiniObj(i.e.


Lamborghini) is not same type or sub-type of elements of porscheArr(i.e.
Porsche).
And last but not the least
Car[] carArr = new Car[3];

Car carObj = new Car();

carArr[3] = carObj;

The above code will compile but will throw an


ArrayIndexOutOfBoundsException as the index used in the assignment is not
less than the size of the array.

Third Scenario - Assigning value to an Element in


the Array using a Type Cast

You can assign value to an element in the array using a cast like this-

ObjectType anObject = new ActualObjectType();

ArrayType[] arrayName = new ActualArrayType[size];


arrayName[indexValue] = (CastType)anObject;

When you use a Cast for assigning a value to an element in the array using a
Cast these rules are applied.

 CastType must be a super-type or sub-type or same type as ObjectType


for compilation to succed.
 CastType must be same type or sub-type of ArrayType for compilation to
succed.
 If ObjectType is same type or sub-type of ArrayType then the cast is not
neccesary.
 ActualObjectType must be a sub-type or same type as CastType for
successful execution. Otherwise an ClassCastException will be thrown
 ActualObjectType must be a sub-type or same type as
ActualArrayType(Note: there is no [] here) for successful execution.
Otherwise an ArrayStoreException will be thrown
 Again as everyone knows indexValue must be less than size of array and
greater than or equal to 0 otherwise there will be an
ArrayIndexOutOfBoundsException on run time.

Now let's see these rules in our hierarchy-

Porsche[] porscheArr = new Porsche[3];


Car carObj = new Boxter();

porscheArr[0] = (Porsche)carObj;

The above code will compile and run successfully. The case is necessary as type
of carObj(i.e. Car) is not a sub-type or same type as the type of each element
of porscheArr(i.e. Porsche). The code will run successfully as the type of the
Cast(i.e. Porsche) and the type of object stored in carObj(i.e. Boxter) are
compatible and the type of elements of porscheArr(i.e. Porsche) and the type
of object stored in carObj(i.e. Boxter) are compatible.

Car[] carArr = new Porsche[3];

Porsche porscheObj = new Porsche();

carArr[0] = (Porsche)porscheObj;

The above code will compile and run successfully. However the cast is not
neccesary.

Porsche[] porscheArr = new Porsche[3];

Car carObj = new Lamborghini();

porscheArr[0] = (Porsche)carObj;

The above code will compile successfully. The cast is also necessary. But it will
throw a ClassCastException at run time as the actual object stored in
carObj(i.e. Lamborghini) is incompatible with the cast type(i.e. Porsche).

Porsche[] porscheArr = new Boxter[3];

Car carObj = new Cayman();

porscheArr[0] = (Porsche)carObj;

The above code will compile successfully. The cast is also necessary. But it will
throw an ArrayStoreException at run time as the actual object stored in
carObj(i.e. Cayman) is incompatible with the actual type of elements of
Porsche array(i.e. Boxter).

Fourth Scenario - Assigning an Array to another


This can be done as follows-

ArrayType[] arrayName = new ActualArrayType[size];

NewArrayType[] newArrayName = arrayName;

OR
ArrayType[] arrayName = new ActualArrayType[size];

NewArrayType[] newArrayName = (CastType[])arrayName;

The rules regarding this type of assignment are-

 NewArrayType must be a super-type or same type as ArrayType for


compilation to succed.
 CastType must be same type or sub-type of ArrayType for compilation to
succed.
 If CastType is same type or sub type as ActualArrayType then
ClassCastException is thrown.

If you are wondering that what would happen if ActualArrayType and


NewArrayType are not compatible at run time then what will happen, then
there is a good news for you. This scenario can never occur. So don't worry
about it.

Let's see a few Examples to clear this thing-


Porsche[] porscheArr = new Boxter[3];

Boxter[] boxterArr = porscheArr;

The above code will not compile successfully. Although you can see that the
code will run successfully, even then it will not compile as type of
porscheArr(i.e. Porsche) is not same type or sub type of type of boxterArr(i.e.
Boxter).

Porsche[] porscheArr = new Boxter[3];

Boxter[] boxterArr = (Boxter[])porscheArr;

The above code will compile and run successfully.

Porsche[] porscheArr = new Cayman[3];

Boxter[] boxterArr = (Boxter[])porscheArr;

The above code will compile successfully. But it will throw a


ClassCastException at run time as the actual array stored in porscheArr(i.e.
Cayman) is inconvertible to type of cast(i.e. Boxter).
Fifth Scenario - Using the new Array reference to
change an element of the Array
This scenario is similar to the Second Scenario but I am including it here for
those who might think it as a seperate scenario

You can assign an array to another array reference and then assign a new value
to an element of the Array as follows

ArrayType[] arrayName = new ActualArrayType[size];

NewArrayType[] newArrayName = arrayName;

ObjectType anObject = new ActualObjectType();

newArrayName = anObject;

The rules regarding this scenario are-

 ObjectType must be a super-type or same type as NewArrayType for


compilation to succed.
 ActualObjectType must be same type or sub-type of ActualArrayType for
the program to run successfully.

Let's see our hierarchy in action again-

Porsche[] porscheArr = new Porsche[3];

Lamborghini lamborghiniObj = new Lamborghini();


Car[] carArr = porscheArr;

carArr = lamborghiniObj;

The above code will compile successfully as type of lamborghini(i.e.


Lamborghini) is assignable to corresponding non-array type carArr(i.e. Car
which is non-array type of Car[]). But it will throw an ArrayStoreException at
run type as type of lamborghiniObj(i.e. Lamborghini) is not assignable to actual
type of elements stored in carArr(i.e. Porsche).

This concludes this topic. If you have any doubts then please leave a comment
and I will clear your doubts.
Posted by Ankit Garg at 12:10 AM 1 comments
Labels: Problem ragarding assignment in Arrays, reason for ArrayStoreException, Rules governing assignment of Array elements
Subscribe to: Posts (Atom)
Blog Archive
 ▼ 2008 (4)
o ▼ September (4)
 Static Inner Classes
 Non-Static Inner Classes
 Local Classes in Java
 Rules for Arrays

Know about Me

Ankit Garg
SCJP 6, 98%
View my complete profile

Ya! I look Great!

That's Me

You might also like