1 2 Previous Next 17 Replies Latest reply on Jun 16, 2003 7:12 PM by 843797

    Inner Class calls method that is in both Enclosing and Super classes

    843797
      It seems to me that this question has got to have been asked and answered before, but I can't seem to find the answer in the forums or the JLS.

      An inner class can access methods in its enclosing class. It can also access methods in a class it extends. If both classes have the same method, what should happen when an inner class tries to call it. Does the compiler not allow it? Should it call the enclosing class's method? Should it call the super class's method?

      A reference to a specific paragraph in the JLS would be helpful too.

      I've observed different compilers do different things, and I'm trying to understand what is correct.

      Code Example:
      public class SuperClass
      {
          public String getName()
          {
              return "SuperClass";
          }
      }
      
      public class EnclosingClass
      {
          public String getName()
          {
              return "EnclosingClass";
          }
      
          private class InnerClass extends SuperClass
          {
              public void printName()
              {
                  System.out.println("name = " + getName());
              }
          }
      }
      Should the printName() method:
      (a) not compile
      (b) print "name = SuperClass"
      (c) print "name = EnclosingClass"
      (d) something else?

      Thanks!
      Dave
        • 1. Re: Inner Class calls method that is in both Enclosing and Super classes
          796447
          I didn't try it, but I would assume (b) would be the answer. And if this inner class wanted to call the EnclosingClass's getName() method, it would have to do something like EnclosingClass.this.getName();
          • 2. Re: Inner Class calls method that is in both Enclosing and Super classes
            796447
            I was almost right. The example actually doesn't compile, but it does if you add "this." before the call to getName().
            • 3. Re: Inner Class calls method that is in both Enclosing and Super classes
              843797
              I was almost right. The example actually doesn't
              compile, but it does if you add "this." before the
              call to getName().
              Thanks for the response, warnerja. As I mentioned, I've observed different compilers behave in different ways. I've seen one compiler refuse to compile, and another one chose a method (I forget which) and compiled just fine. I'm trying to understand which is correct according to the Java language, not a particular compiler's implementation.

              It is true that one can avoid the problem by more clearly specifying which method you want to call, but I'm trying to understand what should happen in this particular case.
              • 4. Re: Inner Class calls method that is in both Enclosing and Super classes
                843797
                I was almost right. The example actually doesn't
                compile, but it does if you add "this." before the
                call to getName().
                Thanks for the response, warnerja. As I mentioned,
                I've observed different compilers behave in different
                ways. I've seen one compiler refuse to compile, and
                another one chose a method (I forget which) and
                compiled just fine. I'm trying to understand which is
                correct according to the Java language, not a
                particular compiler's implementation.

                It is true that one can avoid the problem by more
                clearly specifying which method you want to call, but
                I'm trying to understand what should happen in this
                particular case.
                When it comes to inner classes, etc, you as the developer have complete control, so avoid this situation as well as many other confusing patterns. That's your best solution.
                • 5. Re: Inner Class calls method that is in both Enclosing and Super classes
                  843797
                  >
                  When it comes to inner classes, etc, you as the
                  developer have complete control, so avoid this
                  situation as well as many other confusing patterns.
                  That's your best solution.
                  Thanks for replying, absmiths, but that's not the most helpful reply. In writing my own code, I would definitely choose to avoid the situation or make the choice explicit. However, the purpose of the question was not to understand what I should do, but to better understand the intricacies of the Java language. That's why this is in the Advanced Language Topics forum.

                  Dave
                  • 6. Re: Inner Class calls method that is in both Enclosing and Super classes
                    843797
                    It did not compile for me either. JDK: Sun 1.4.1_02.

                    Personally I think the answer is obvious because of the rules of scope are consistent in Java. If you make a method called getName in the inner class, there is no question which method it uses. It uses the inner class method because that is the most specific scope. When you inherit from a class, all of it's public and protected methods are methods of your new class. They are not just accessed like they would be for an enclosing class, they are the class' methods.

                    Most likely the compiler was enhanced to cough when this happens because it would be very easy to think you are calling the enclosing class' method if you don't realize there is a corresponding method on the super class. But logic would indicate using the class' own method before another class' method.
                    • 7. Re: Inner Class calls method that is in both Enclosing and Super classes
                      843797
                      I could have sworn this ambiguitiy was resolved in a recent J2SDK release. I think it was 1.4.0 but I can't seem to find the relevant release note anymore.
                      • 8. Re: Inner Class calls method that is in both Enclosing and Super classes
                        843797
                        I found something in the JLS that may shed some light on this situation:
                        Section 15.12.1 Compile-Time Step 1: Determine Class or Interface to Search
                        
                        The first step in processing a method invocation at compile time is to figure out 
                        the name of the method to be invoked and which class or interface to check for 
                        definitions of methods of that name. There are several cases to consider, depending 
                        on the form that precedes the left parenthesis, as follows:
                        
                        * If the form is MethodName, then there are three subcases:
                            o If it is a simple name, that is, just an Identifier, then the name of the 
                              method is the Identifier. If the Identifier appears within the scope (?6.3) 
                              of a visible method declaration with that name, then there must be an 
                              enclosing type declaration of which that method is a member. Let T be the 
                              innermost such type declaration. The class or interface to search is T.
                            o If it is a qualified name of the form TypeName . Identifier, then the name of 
                              the method is the Identifier and the class to search is the one named by the 
                              TypeName. If TypeName is the name of an interface rather than a class, then a     
                              compile-time error occurs, because this form can invoke only static methods 
                              and interfaces have no static methods.
                            o In all other cases, the qualified name has the form FieldName . Identifier; 
                              then the name of the method is the Identifier and the class or interface to 
                              search is the declared type of the field named by the FieldName. 
                        The important part reads: Let T be the innermost such type declaration. The class or interface to search is T. I think that this section of JLS states that the member of the inner class should be the method chosen.
                        • 9. Re: Inner Class calls method that is in both Enclosing and Super classes
                          843797
                          check out:

                          http://developer.java.sun.com/developer/bugParade/bugs/4312064.html
                          http://developer.java.sun.com/developer/bugParade/bugs/4320844.html

                          also note from http://java.sun.com/j2se/1.3/compatibility.html#source:

                          "Inherited Members of an Enclosing Class are Now Accessible

                          The Java Language Specificaton, Second Edition, states that inherited members of a class are accesible within that class, including any nested classes. In 1.1 and 1.2 versions of the Java 2 SDK, the compiler considered a member accessible within a nested class only if it was actually declared in an enclosing class. The new compiler in the Java 2 SDK, v1.3 has been brought into conformance with the specification."
                          • 10. Re: Inner Class calls method that is in both Enclosing and Super classes
                            843797
                            "Inherited Members of an Enclosing Class are Now
                            Accessible

                            The Java Language Specificaton, Second Edition, states
                            that inherited members of a class are accesible within
                            that class, including any nested classes. In 1.1 and
                            1.2 versions of the Java 2 SDK, the compiler
                            considered a member accessible within a nested class
                            only if it was actually declared in an enclosing
                            class. The new compiler in the Java 2 SDK, v1.3 has
                            been brought into conformance with the specification."
                            The issue here does not relate to what you posted since the ambiguity comes from the inherited members of the nested class, not the enclosing class.
                            • 11. Re: Inner Class calls method that is in both Enclosing and Super classes
                              843797
                              "Inherited Members of an Enclosing Class are Now
                              Accessible

                              The Java Language Specificaton, Second Edition,
                              states
                              that inherited members of a class are accesible
                              within
                              that class, including any nested classes. In 1.1
                              and
                              1.2 versions of the Java 2 SDK, the compiler
                              considered a member accessible within a nested
                              class
                              only if it was actually declared in an enclosing
                              class. The new compiler in the Java 2 SDK, v1.3 has
                              been brought into conformance with the
                              specification."

                              The issue here does not relate to what you posted
                              since the ambiguity comes from the inherited members
                              of the nested class, not the enclosing
                              class.
                              The last quote in my prev post was simply a relevant extract from an otherwise long page. You get the overall picture by reading all links. I believe this picture to be as follows:

                              - the intent has always been to have elements inherited by inner classes shadow the elements with the same names but coming from outer classes

                              - until a certain time, the compiler was required [by JLS] to check for possible ambiguities and generate a warning that required the user to explicitly disambiguate the conflict

                              - later the correct shadowing behavior was assumed to be "silently implied" and JLS got amended to remove the compiler check [and a possible warning]

                              - this would have been a transparent change if not for some other conflicting compiler bugs, such as (a) elements inherited [vs declared] by the outer class not always visible to the inner class or (b) some nested elements not always getting inherited in the first place. The latter introduced a remote chance that the JLS/compiler change mentioned above could have silently changed what certain code patterns were doing [when introduced simultaneously with other compiler bug fixes].

                              Consider this variation of Dave's code:
                              class X
                              {
                                  public String getName ()
                                  {
                                      return "X";
                                  }
                              }
                              
                              class X2
                              {
                                  public String getName ()
                                  {
                                      return "X2";
                                  }
                              }
                              
                              public class Y extends X
                              {
                                  private class Inner extends X2
                                  {
                                      public String foo ()
                                      {
                                          return getName ();
                                      }
                                  }
                              }
                              This generates no warnings in either javac 1.2.2 or 1.4.1. Although superficially the compiler [and bytecode] behavior is the same, I believe the real reasons are different:

                              (1) the 1.2.2 compiler should generate an error but it happens to be cancelled out by another bug whereby it does not realize that X.getName() is actually also visible to Y.Inner.foo() [being inherited by Y].

                              (2) the 1.4.1 compiler does not generate a warning because it is compliant with the now amended JLS.

                              You can verify this by overriding getName() in Y: the 1.2.2 compiler will barf and the 1.4.1 one will remain silent.
                              • 12. Re: Inner Class calls method that is in both Enclosing and Super classes
                                843797
                                Good discussion, and I feel like I understand what's going on now.

                                Thanks everyone!

                                Dave
                                • 13. Re: Inner Class calls method that is in both Enclosing and Super classes
                                  843797
                                  Actually, there is still one small open issue.

                                  dubwai writes:
                                  It did not compile for me either. JDK: Sun 1.4.1_02.
                                  vladimp writes:
                                  (2) the 1.4.1 compiler does not generate a warning
                                  because it is compliant with the now amended
                                  JLS.

                                  You can verify this by overriding getName() in Y: the
                                  1.2.2 compiler will barf and the 1.4.1 one will remain
                                  silent.
                                  So does 1.4.1 support it or not?
                                  • 14. Re: Inner Class calls method that is in both Enclosing and Super classes
                                    843797
                                    You can verify this by overriding getName() in Y:
                                    the
                                    1.2.2 compiler will barf and the 1.4.1 one will
                                    remain
                                    silent.
                                    So does 1.4.1 support it or not?
                                    The compiler complains about this in 1.4.1_02. I believe he is mistaken. I can't speak to 1.2.2, though.
                                    1 2 Previous Next