Email address:
Password:
SCJP/OCPJP 1.6 certification
Practice Exams and Training
SCJP Online Training » Discussions

Question about nested classes

Hi Frederick!

I have a question about Q#11

"So the runNow() method in class A is invisible to the class B, and class C, even though class B is an inner class" - that is because B is a static class and instance members are not available from static context - so the explanation was about that?

Also when reading JLS "Any local variable, formal parameter, or exception parameter used but not declared in an inner class must be declared final.

Any local variable used but not declared in an inner class must be definitely assigned before the body of the inner class." - why it MUST be declared final by the way?

Or I have to take it for granted? And why it MUST be assigned before the body of the inner class?


Thank you

This question does not have anything to do with static/nonstatic nature, but since you asked a couple of questions on it, I'll give you a bit of thoughts at first:


Let's say we have a static nested class B which extends its own outer class A (as same as in this question)


class A {
  static class B extends A {
  }
}


What we know about the static inner class B here is it does NOT require an object of class A to be initialized. Without having an object of class A, you could simply initialize the class B just like this:


A.B obj = new A.B();


However, class B is not just a nested class of A - it also extends the class A. Now, as it happens in cases where a class extends another, when you create an object of the subclass, it also instantiates its super classes in an implicit sense. That said, as you instantiate the class 'B', here, there will be an instance of class A attached to it. For this reason, you should be able to access non-static stuff of the super class, from its static nested class:


class A {

   int x = 4;

   static class B extends A {

      public void someMethod() {
          System.out.println(x);
      }
 
   }

}


The above code compiles even though 'x' is non-static, and now you know why.


The original question does not take this into account because it does not have to deal with instance variables.


I think the other question you are asking relates to the idea of using method-local variables inside an inner class. Since that does not fall with this question, can you please create a new question by going through this link: http://www.examlab.org/post/new/java-for-scjp-and-ocpjp


I'll make sure to answer it with details.

I must also add that you are currently not subscribed to the tutoring service. If you subscribe by upgrading your account, I can provide more helpful tutoring service for you.

Hi Frederick!

Thank you for your replies, I will upgrade my account as soon as possible.

BTW, I was asking about the static context because of compilation error messages I am getting, when trying to refer private method from a static inner classes - I am getting like this "Non-static method runNow() cannot be referenced from a static context"- what is a bit confusing, as the problem here is that we try to access private member in the child class, which is not allowed in a way java implements inheritance.Why it is coplaing this way?

This is the code sample for illustration


class A {
    int x = 4;
    private String runNow(){
        return "High";
    }
    static class B extends A {
        public void someMethod() {
            System.out.println(x);
        }
        public void print(){
            System.out.print(runNow());//compilation error about non-static method from a static context, 
            // not about accessing private 
        }
    }
}

Oh okay, so you are after what exactly the compiler says, but it takes a really good thinking.


It says that because that's the order the compiler sees at things. Think of it in this way: when there is an inner class, which extends its own outer class, is trying to access its outer class members, there are two different channels the inner class can do that:


Channel 1: Through the members inherited from the outer class to the inner class due to inheritance.

Channel 2: Through direct access to the outer class / outer class object (in case of a non-static inner class).


.. in the above order.


You can create a little program to see which channel it uses. Let's consider this one for example:


class A {
	
   public int x = 4;
    
   class B extends A {
        
      public void increase(){
         x++;
      }
        
      void printInnerX() {
         System.out.println(x);
      }
        
   }
    
   public void printOuterX() {
      System.out.println(x);
   }
    
   public static void main(String args[]) {
      new A().main();
   }
    
   public void main() {
      A a = new A();
      A.B b = a.new B();
    	
      b.increase();
    	
      a.printOuterX();
      b.printInnerX();
   }
    
}


This should give you the output of "4, 5".


Let's see why: the important part is at line-29, which calls the increase() method in the inner class. In line-8, you are trying to increase x. In order to increase x, the JVM has to see how it can access 'x'. So, it has channel-1 and channel-2. It first tries with ch-1, which has the idea of accessing the variable through inheritance. Since x is a public variable here, it sees it can access it through inheritance, and therefore, it uses ch-1, and increases x in the space of A inherited to B.


This leaves the original A object 'a' unaffected. So, as line-31 tries to access 'x', it therefore prints 4 - the unaffected value in that object.


When it comes to the line-32, it makes line-12 access 'x' again. Same is before, it sees it can use ch-1, so it uses it, and accesses the 'x' in the space of A inherited to B, which is now 5. So it prints 5.



I know it seems all okay so far, but here's the most important twist: go to line-3 and replace public with private, so 'x' becomes a private variable.

Guess how this would change the outcome! The twist is the program will now print "5, 5" (instead of "5, 4" which it printed when 'x' was public). This is an extreme case, where a simple change to a visibility modifier would give you the completely opposite outcome!


What happens in this case is ch-1 becomes unavailable due to the variable x being private. This is because when x is private, it does not get inherited to the sub classes of that class. Now, since ch-1 is unavailable, the JVM has to look for ch-2, which is the direct access to the outer class object object (which is same the object what a refers in this case). Since that is the only 'x' it can increase and print, it will print "5, 5" this time.


Does this channel conflict give you a little clue as to why the compiler complains about you trying to access a non-static member from a static context, instead of talking about the private member being unavailable?

Hi! Thank you for the great example and detailed explanation.Yes, it is clear now)

ExamLab © 2008 - 2024