Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4362349

Cannot override abstract method in same package

XMLWordPrintable

    • hopper
    • generic
    • generic
    • Verified



      Name: stC104175 Date: 08/14/2000


      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
      Classic VM (build 1.3.0, J2RE 1.3.0 IBM build cx130-20000623 (JIT enabled:
      jitc))


      The behavior of compiler with regards to method inheritance and overriding has
      changed between various JDKs, and illustrates an ambiguity in the JLS that needs
      to be clarified.

      =========
      package secure;

      public abstract class A {
        public static void main(String[] args) {
          A a = new C();
          System.out.println(a.message());
        }

        abstract String message();
      }

      class C extends other.B {
        String message() { return "Hello, world"; }
      }
      =========
      package other;

      public abstract class B extends secure.A {
      }
      =========
      =========
      Compiled under JDK1.1.8:
      (no errors)
      output of java secure.A:
      Hello, world
      output of java other.B:
      Hello, world
      output of java secure.C:
      Hello, world

      =========
      Compiled under JDK1.2.2:
      secure/A.java:5: class secure.C is an abstract class. It can't be instantiated.
          System.out.println(new C().message());
                             ^
      secure/A.java:11: class secure.C must be declared abstract. The package-private
      abstract method java.lang.String message() in superclass class secure.A is
      inaccessible and cannot be overridden.
      class C extends other.B {
            ^
      2 errors
      (other/B.class exists after compilation)
      output of java other.B:
      Exception in thread "main" java.lang.NoClassDefFoundError: secure/A
              at java.lang.ClassLoader.defineClass0(Native Method)
              at java.lang.ClassLoader.defineClass(ClassLoader.java:474)
              at
      java.security.SecureClassLoader.defineClass(SecureClassLoader.java:106)
              at java.net.URLClassLoader.defineClass(URLClassLoader.java:247)
              at java.net.URLClassLoader.access$1(URLClassLoader.java:215)
              at java.net.URLClassLoader$1.run(URLClassLoader.java, Compiled Code)
              at java.security.AccessController.doPrivileged(Native Method)
              at java.net.URLClassLoader.findClass(URLClassLoader.java, Compiled Code)
              at java.lang.ClassLoader.loadClass(ClassLoader.java, Compiled Code)
              at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java, Compiled
      Code)
              at java.lang.ClassLoader.loadClass(ClassLoader.java, Compiled Code)
              at java.lang.ClassLoader.loadClassInternal(ClassLoader.java, Compiled
      Code)

      ==========
      Compiled under JDK1.3:

      1) Compiling only secure/A.java (with C defined in A.java), compiling
      secure/A.java and other/B.java together (with C defined in A.java):
      secure/A.java:11: secure.C should be declared abstract; it does not define
      message() in secure.A
      class C extends other.B {
      ^
      1 error
      (secure/A.class exists after compilation)
      output of java secure.A:
      Exception in thread "main" java.lang.NoClassDefFoundError: secure/C
              at secure.A.main(A.java:5)

      2) Compiling only other/B.java (with C defined in A.java):
      ./secure/A.java:11: cyclic inheritance involving other.B
      class C extends other.B {
                           ^
      1 error
      (no classfiles exist after compilation)

      3) Compiling only other/B.java (where C is in C.java):
      ./secure/C.java:3: secure.C should be declared abstract; it does not define
      message() in secure.A
      class C extends other.B {
      ^
      1 error
      (both secure/A.class and other/B.class exist)
      output of java secure.A:
      Exception in thread "main" java.lang.NoClassDefFoundError: secure/C
              at secure.A.main(A.java:5)
      output of java other.B:
      Exception in thread "main" java.lang.NoClassDefFoundError: secure/C
              at secure.A.main(A.java:5)

      4) compiling only secure/C.java (with C defined in C.java):
      secure/C.java:3: secure.C should be declared abstract; it does not define
      message() in secure.A
      class C extends other.B {
      ^
      1 error
      (no classfiles exist after compilation)


      ==========
      Compiled under jikes (Version 1.12 8/1/2000):
      (no errors)
      output, from the JVM of any JDK (1.1.8, 1.2.2, or 1.3), of secure.A, other.B,
      and secure.C:
      Hello, world


      ==========
      The appearance of that cyclic inheritance comment under compilation 2 with JDK
      1.3 relates to bug 4326631.

      One question is why JDK 1.2.2 and JDK 1.3 generate classfiles when the
      compilation fails in an error. If I change line 5 of A to reference a
      non-existant type D, no classfiles are generated.

      The real question, though, is the proper interpretation of the JLS.
      Section 6.6.1:
      "A member (class, interface, field, or method) of a reference (class, interface,
      or array) type or a constructor of a class type is accessible only if the type
      is accessible and the member or constructor is declared to permit access:
      ...
      " Otherwise, we say there is default access, which is permitted only
      when the access occurs from within the package in which the type is declared. "

      Section 8.1.3:
      "The subclass relationship is the transitive closure of the direct subclass
      relationship. A class A is a subclass of class C if either of the following is
      true:

      " A is the direct subclass of C.
      " There exists a class B such that A is a subclass of B, and B is a
      subclass of C, applying this definition recursively. "

      Section 8.4.6.1:
      "An instance method m1 declared in a class C overrides another method with the
      same signature, m2, declared in class A if both

      " 1.C is a subclass of A.
      " 2.Either
                  m2 is non-private and accessible from C, or
                  m1 overrides a method m3, m3 distinct from m1, m3 distinct from m2,
      such that m3 overrides m2.

      "Moreover, if m1 is not abstract, then m1 is said to implement any and all
      declarations of abstract methods that it overrides."


      I take this to mean that secure.C is a subclass of secure.A (by 8.1.3), the
      abstract method A.message is accessible from C as it is in the same package (by
      6.6.1), and therefore, C.message satisfies the first half of 8.4.6.1 condition
      2. And, since C.message is not abstract, it should implement A.message, and the
      class C need not be abstract. This appears to be the interpretation of
      JDK1.1.8, as well as jikes. And, the VM of JDK1.3 does not throw any exceptions
      when running this code; so it passes verification.

      If this interpretation is wrong, then there is a specification bug, and 8.4.6.1
      needs to add another condition that all intermediate superclasses between C and
      A must be able to access m2 or something that overrides m2. In my example, this
      condition does not hold, as other.B is unable to access or override A.message,
      and is an intermediate superclass between C and A, explaining the error message
      given during compilation.

      If you do change the specification, you may consider making it a compile-time
      error to extend a class that contains abstract methods that you are unable to
      implement. Using JDK 1.3, there is no way that I can make other.B or any
      extension thereof implement the method A.message; so there is no point in being
      able to compile B except for its class (static) methods.
      (Review ID: 108262)
      ======================================================================

            gafter Neal Gafter (Inactive)
            stompkinsunw Sean Tompkins (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: