Showing posts with label expert. Show all posts
Showing posts with label expert. Show all posts

Wednesday, June 25, 2008

Java Inner Class Expert

Puzzle 1
Given the following code:

1. class MyOuter {
2. private int x = 7;
3. class MyInner {
4. public void seeOuter() {
5. System.out.println("Outer x is " + x);
6. }
7. }
8. }


What is happening when we try compile the code?
If you think, the output is Compilation fails then you're wrong. Line 5 looks interesting, because a private member is accessed from an inner class.

Is it possible?
Yes, it is. Remember, inner classes can access the outer class members.
So the right answer is: the code compiles without error.

Puzzle 2
Given the following code:

01. class MyOuter {
02. private int x = 7;
03. public void makeInner() {
04. MyInner in = new MyInner();
05. in.seeOuter();
06. }
07. class MyInner {
08. public void seeOuter() {
09. System.out.println("Outer x is " + x);
10. System.out.println("Inner class ref is " + this);
11. System.out.println("Outer class ref is " + MyOuter.this);
12. }
13. }
14. public static void main (String[] args) {
15. MyOuter.MyInner inner = new MyOuter().new MyInner();
16. inner.seeOuter();
17. }
18. }

What is happening when we try compile the code?
Line 11 and line 15 can be strange, but both are absolutely correct.
See the line 11 first:
11. System.out.println("Outer class ref is " + MyOuter.this);

To reference the “outer this” (the outer class instance) from within the inner
class code, we can use .this.

Line 15:
15. MyOuter.MyInner inner = new MyOuter().new MyInner();


To access the inner class, we must have an outer class instance. If we have one then the <OuterClassInstance>. new <InnerClassConstructorglt; create a new inner class instance.
So the right answer is: the code compiles without error.

Puzzle 3
Given the following code:

01. class MyOuter {
02. private String x = "Outer";
03. void doStuff() {
04. String z = "local variable";
05. class MyInner {
06. public void seeOuter() {
07. System.out.println("Outer x is " + x);
08. System.out.println("Local variable z is " + z);
09. }
10. }
11. }
12. }

What is happening when we try compile the code?

The result is Compilation fails. The problem is with the line 8:
MyInner is a Method-Local Inner class and the Method-Local Inner classes can not access the local variables.

Of course, there is an exception:
If the local variable is marked as final then it can be accessed from a Method-Local Inner class.

Saturday, June 21, 2008

Java Primitives Expert

Puzzle 1
Given the following code:

1. public class Example1 {
2. public static void main(String[] args) {
3. byte b = 1;
4. b = b + 1;
5. System.out.println("b: " + b );
6. }
7. }


What is the result?
The result is: Compilation fails.

Why?
The problem is in the line 4: possible loss of precision.
Decimal literals are implicit integers. So the type of literal 1 is integer. Before b + 1 expression computed, b is implicit converted to integer, and the type of b + 1 expression will be integer too.
We try assign an integer value (b + 1) to a byte variable, and it can be cause loss of precision so the compiler does not compile it.

Solution 1
Replace the line 4 to: b += 1; and auto cast will be work.

Solution 2
We can cast the (b + 1) expression explicit to byte: b = (byte) (b + 1);. We must use the brackets around the b + 1 expression, otherwise we cast just the variable b to byte, not the b + 1 expression.

Puzzle 2
Given the following code:

1. public class Example2 {
2. public static void main(String[] args) {
3. float f = 3.0;
5. System.out.println("f: " + f );
6. }
7. }


What is the result?
The result is: Compilation fails.

Why?
The problem is in the line 3: possible loss of precision.
Floating point literals are implicit double.

Solution 1
Cast explicit the 3.0 to float: f = (float) 3.0;.

Solution 2
Declare the 3.0 literal as float literal: f = 3.0f;

Puzzle 3
Giving the following expression:
( p <= q ) && ( q <= p ) && ( p != q )

Can this expression be true (If yes, when?).
Yes, it can.

How?
The answer is simply, autoboxing:
Declare the variables p and q as the following:

Integer p = new Integer(1000);

Integer q = new Integer(1000);

In this case our expression will be true, because
  • in the ( p <= q ) and ( q <= p ) expression p and q behave as primitive types so the expressions are true (because 1000 = 1000),
  • in the ( p != q ) expression p and q behave as objects, so we compare two object references and this references refer two different object, this expression is true.
  • ( p <= q ) is true, ( q <= p ) is true, ( p != q) is true, so ( p <= q ) && ( q <= p ) && ( p != q ) is true.
Puzzle 4 (my favorite)
Given the following code:

01. public class Example3 {
02. public static void main(String[] args) {
03. Integer i1 = 3;
04. Integer i2 = 3;
05. Integer i3 = 1000;
06. Integer i4 = 1000;
07. System.out.println("i1 == i2: " + (i1==i2) );
08. System.out.println("i3 == i4: " + (i3==i4) );
09. }
10. }


What is the output?
The output is:

i1 == i2: true
i3 == i4: false

Why?
First look the output is surprising.
The lines 3 - 6 are strange, but correct, because the autoboxing is worked.

We know the == operator compare object references. Variable i1 and i2 are object so we wait the i1 == i2 expressions will be false, but it's true!

And to top it all the i3 == i4 expression is false. How is it possible?

The answer is simply: Constant pool. JAVA use this pool (among other things) to store the decimal literals:

boolean:
  • true, false
char:
  • '\u0000' ... '\u007F'
byte:
  • -128...127
short
  • -128...127
int:
  • -128...127
long:
  • -128...127
When we use the new keyword then two, different object is constructed, and the == operator return with false:
  • Integer i1 = new Integer(2); Integer i2 = new Integer(2);
But when we don't use the new keyword, then the JAVA search the literal from Constant pool, and assign it to the references, then no object created:
  • Integer i1 = 2; Integer i2 = 2;
But remember, this works only type and range, given above!