JDK-8356941 : AbstractMethodError in HotSpot Due to Incorrect Handling of Private Method
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 11
  • Priority: P3
  • Status: In Progress
  • Resolution: Unresolved
  • OS: windows
  • CPU: x86_64
  • Submitted: 2025-05-12
  • Updated: 2025-07-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26Unresolved
Related Reports
Relates :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
OS:
	Operating System Name: Windows 11
	Operating System Architecture: amd64
	Operating System Version: 10.0
	
OpenJDK version:
java version "1.8.0_441"
Java(TM) SE Runtime Environment (build 1.8.0_441-b07)
Java HotSpot(TM) 64-Bit Server VM (build 25.441-b07, mixed mode)

java version "11.0.26" 2025-01-21 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.26+7-LTS-187)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.26+7-LTS-187, mixed mode)

A DESCRIPTION OF THE PROBLEM :
Given a test case, we found that the execution results of this test case on  different versions are different, the simplified test case can be found below. In summary, Hotspot(1.8.0_441) threw IllegalAccessError while the other threw AbstractMethodError. 

REGRESSION : Last worked in version 8

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The following code can be used to generate the test cases(.class file) that reproduces the above process:

```java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class BytecodeUtil {
    public static void main(String args[]) {
        // create package
        String baseDir = "./your_dir"; // your base dir
        String packageName = "P0";
        File folder = new File(baseDir + "/" + packageName);
        folder.mkdirs();

        String P0_I0_bytecodeInStr = "CAFEBABE00000034000F01000550302F49300700010100106A6176612F6C616E672F4F626A6563740700030100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000703000000000100063C696E69743E010004284929560C000A000B0A0008000C010004436F64650601000200040000000000010001000500060001000E00000016000300010000000ABB0008591209B7000DB0000000000000" ;
        String P0_C1_bytecodeInStr = "CAFEBABE00000034000E01000550302F43310700010100106A6176612F6C616E672F4F626A65637407000301000550302F493007000501000550302F49320700070100063C696E69743E0100032829560C0009000A0A0004000B010004436F64650021000200040002000600080000000100010009000A0001000D0000001100010001000000052AB7000CB1000000000000" ;
        String P0_Helper_bytecodeInStr = "CAFEBABE00000034001E01000950302F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433101000928294C50302F43313B01000550302F433107000B0A000C0007010005676574433301000928294C50302F43333B01000550302F43330700100A00110007010005676574433401000928294C50302F43343B01000550302F43340700150A00160007010005676574433501000928294C50302F43353B01000550302F433507001A0A001B0007010004436F64650021000200040000000000050001000500060001001D0000001100010001000000052AB70008B10000000000090009000A0001001D00000016000200010000000ABB000C59B7000D4B2AB0000000000009000E000F0001001D00000016000200010000000ABB001159B700124B2AB0000000000009001300140001001D00000016000200010000000ABB001659B700174B2AB0000000000009001800190001001D00000016000200010000000ABB001B59B7001C4B2AB0000000000000" ;
        String P0_I2_bytecodeInStr = "CAFEBABE00000034000F01000550302F49320700010100106A6176612F6C616E672F4F626A6563740700030100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000703000000020100063C696E69743E010004284929560C000A000B0A0008000C010004436F64650601000200040000000000010001000500060001000E00000016000300010000000ABB0008591209B7000DB0000000000000" ;
        String P0_C3_bytecodeInStr = "CAFEBABE00000034002D01000550302F43330700010100106A6176612F6C616E672F4F626A65637407000301000550302F49300700050100063C696E69743E0100032829560C000700080A000400090100047465737401001528294C6A6176612F6C616E672F496E74656765723B01000950302F48656C70657207000D010005676574433501000928294C50302F43353B0C000F00100A000E00110100016D0C0013000C0B000600140100046D61696E010016285B4C6A6176612F6C616E672F537472696E673B29560C000B000C0A000200180100106A6176612F6C616E672F53797374656D07001A0100036F75740100154C6A6176612F696F2F5072696E7453747265616D3B0C001C001D09001B001E01000E52657475726E2076616C75653A200800200100136A6176612F696F2F5072696E7453747265616D0700220100057072696E74010015284C6A6176612F6C616E672F537472696E673B29560C002400250A002300260100077072696E746C6E010015284C6A6176612F6C616E672F4F626A6563743B29560C002800290A0023002A010004436F646500210002000400010006000000030001000700080001002C0000001100010001000000052AB7000AB1000000000009000B000C0001002C00000017000100010000000BB800124B2AB900150100B0000000000009001600170001002C0000001E0003000200000012B800194CB2001F591221B600272BB6002BB1000000000000" ;
        String P0_C4_bytecodeInStr = "CAFEBABE00000034001401000550302F43340700010100106A6176612F6C616E672F4F626A65637407000301000550302F49300700050100063C696E69743E0100032829560C000700080A000400090100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000D0300000004010004284929560C000700100A000E0011010004436F64650021000200040001000600000002000100070008000100130000001100010001000000052AB7000AB1000000000002000B000C0001001300000016000300010000000ABB000E59120FB70012B0000000000000" ;
        String P0_C5_bytecodeInStr = "CAFEBABE00000034000A01000550302F433507000101000550302F43340700030100063C696E69743E0100032829560C000500060A00040007010004436F6465002100020004000000000001000100050006000100090000001100010001000000052AB70008B1000000000000" ;

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "I0.class")) {
            byte[] P0_I0_bytecode =  hexStringToByteArray(P0_I0_bytecodeInStr);
            fos.write(P0_I0_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "C1.class")) {
            byte[] P0_I0_bytecode =  hexStringToByteArray(P0_C1_bytecodeInStr);
            fos.write(P0_I0_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "Helper.class")) {
            byte[] P0_Helper_bytecode =  hexStringToByteArray(P0_Helper_bytecodeInStr);
            fos.write(P0_Helper_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "I2.class")) {
            byte[] P0_I2_bytecode =  hexStringToByteArray(P0_I2_bytecodeInStr);
            fos.write(P0_I2_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "C3.class")) {
            byte[] P0_C3_bytecode =  hexStringToByteArray(P0_C3_bytecodeInStr);
            fos.write(P0_C3_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "C4.class")) {
            byte[] P0_C4_bytecode =  hexStringToByteArray(P0_C4_bytecodeInStr);
            fos.write(P0_C4_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "C5.class")) {
            byte[] P0_C5_bytecode =  hexStringToByteArray(P0_C5_bytecodeInStr);
            fos.write(P0_C5_bytecode);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static byte[] hexStringToByteArray(String hexString) {
        int length = hexString.length();
        byte[] byteArray = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            int byteValue = Integer.parseInt(hexString.substring(i, i + 2), 16);
            byteArray[i / 2] = (byte) byteValue;
        }
        return byteArray;
    }
}
```
Note: modify the paths according to your needs.

Repoduce:
```
>>> path_to_jdk/Hotspot_1.8.0_441/bin/java -cp . P0.C3

>>> path_to_jdk/Hotspot_11.0.26/bin/java -cp . P0.C3
```

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
According to this interesting result, we first decompiled P0.C3 using javap. The results are as follows: 

```java
Classfile /D:/Lab/TestJDoc/JSmith-main/your_dir/P0/C3.class
  Last modified May 12, 2025; size 539 bytes
  MD5 checksum dbff33781d5155f4f302757476bf08e2
public class P0.C3 implements P0.I0
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               P0/C3
   #2 = Class              #1             // P0/C3
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               P0/I0
   #6 = Class              #5             // P0/I0
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = NameAndType        #7:#8          // "<init>":()V
  #10 = Methodref          #4.#9          // java/lang/Object."<init>":()V
  #11 = Utf8               test
  #12 = Utf8               ()Ljava/lang/Integer;
  #13 = Utf8               P0/Helper
  #14 = Class              #13            // P0/Helper
  #15 = Utf8               getC5
  #16 = Utf8               ()LP0/C5;
  #17 = NameAndType        #15:#16        // getC5:()LP0/C5;
  #18 = Methodref          #14.#17        // P0/Helper.getC5:()LP0/C5;
  #19 = Utf8               m
  #20 = NameAndType        #19:#12        // m:()Ljava/lang/Integer;
  #21 = InterfaceMethodref #6.#20         // P0/I0.m:()Ljava/lang/Integer;
  #22 = Utf8               main
  #23 = Utf8               ([Ljava/lang/String;)V
  #24 = NameAndType        #11:#12        // test:()Ljava/lang/Integer;
  #25 = Methodref          #2.#24         // P0/C3.test:()Ljava/lang/Integer;
  #26 = Utf8               java/lang/System
  #27 = Class              #26            // java/lang/System
  #28 = Utf8               out
  #29 = Utf8               Ljava/io/PrintStream;
  #30 = NameAndType        #28:#29        // out:Ljava/io/PrintStream;
  #31 = Fieldref           #27.#30        // java/lang/System.out:Ljava/io/PrintStream;
  #32 = Utf8               Return value:
  #33 = String             #32            // Return value:
  #34 = Utf8               java/io/PrintStream
  #35 = Class              #34            // java/io/PrintStream
  #36 = Utf8               print
  #37 = Utf8               (Ljava/lang/String;)V
  #38 = NameAndType        #36:#37        // print:(Ljava/lang/String;)V
  #39 = Methodref          #35.#38        // java/io/PrintStream.print:(Ljava/lang/String;)V
  #40 = Utf8               println
  #41 = Utf8               (Ljava/lang/Object;)V
  #42 = NameAndType        #40:#41        // println:(Ljava/lang/Object;)V
  #43 = Methodref          #35.#42        // java/io/PrintStream.println:(Ljava/lang/Object;)V
  #44 = Utf8               Code
{
  public P0.C3();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>":()V
         4: return

  public static java.lang.Integer test();
    descriptor: ()Ljava/lang/Integer;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=0
         0: invokestatic  #18                 // Method P0/Helper.getC5:()LP0/C5;
         3: astore_0
         4: aload_0
         5: invokeinterface #21,  1           // InterfaceMethod P0/I0.m:()Ljava/lang/Integer;
        10: areturn

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: invokestatic  #25                 // Method test:()Ljava/lang/Integer;
         3: astore_1
         4: getstatic     #31                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: dup
         8: ldc           #33                 // String Return value:
        10: invokevirtual #39                 // Method java/io/PrintStream.print:(Ljava/lang/String;)V
        13: aload_1
        14: invokevirtual #43                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        17: return
}
```

We observed that the call to `var0.m()` in `P0\C3.test()` uses `invokeinterface`. As a result, we reviewed the relevant sections on `invokeinterface` in both JVM SE8 and SE11.

In SE8, the Method Selection rule states, "Otherwise, if C has a superclass, a search for a declaration of an instance method with the same name and descriptor as the resolved method is performed, starting with the direct superclass of C and continuing with the direct superclass of that class, and so forth, until a match is found or no further superclasses exist. If a match is found, then it is the method to be invoked." Therefore, the selected method should be `P0\C4.m()`(flags: private). According to the [SE8 invokeinterface specification](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokeinterface), "Otherwise, if step 1 or step 2 of the lookup procedure selects a method that is not `public`, *invokeinterface* throws an `IllegalAccessError`." Therefore, the expected behavior in Hotspot (1.8.0_441) should be an `IllegalAccessError`rather than an `AbstractMethodError`.
ACTUAL -
The output is as follows:

Hotspot(1.8.0_441):

```

Exception in thread "main" java.lang.IllegalAccessError: P0.C5.m()Ljava/lang/Integer;
at P0.C3.test(Unknown Source)
at P0.C3.main(Unknown Source)

```

Hotspot(11.0.26):

```

Exception in thread "main" java.lang.AbstractMethodError: Receiver class P0.C5 does not define or inherit an implementation of the resolved method 'java.lang.Integer m()' of interface P0.I0.
at P0.C3.test(Unknown Source)
at P0.C3.main(Unknown Source)

```

---------- BEGIN SOURCE ----------
After obtaining the test cases, you can derive the following test cases through decompilation:

```java
package P0;

import java.io.PrintStream;

public class C3 implements I0 {
    public C3() {
    }

    public static Integer test() {
        C5 var0 = Helper.getC5();
        return var0.m();
    }

    public static void main(String[] var0) {
        Integer var1 = test();
        PrintStream var10000 = System.out;
        var10000.print("Return value: ");
        var10000.println(var1);
    }
}
```

```java
package P0;

public class C5 extends C4 {
    public C5() {
    }
}
```

```java
package P0;

public class C4 implements I0 {
    public C4() {
    }

    private Integer m() {
        return new Integer(4);
    }
}
```

```java
package P0;

public interface I0 {
    default Integer m() {
        return new Integer(0);
    }
}
```
---------- END SOURCE ----------


Comments
Here are some examples of the extended logging that I added when trying to track down where/why the default method slot was not being processed correctly: [0.067s][debug][defaultmethods] Interface P0.I0 requires default method processing [0.067s][debug][defaultmethods] P0/I0 [0.067s][debug][defaultmethods] java/lang/Object [0.067s][debug][defaultmethods] Checking superclass: java/lang/Object [0.067s][debug][defaultmethods] No super defaults found [0.067s][debug][defaultmethods] Slots that need filling: [0.067s][debug][defaultmethods] No empty slots found [0.067s][debug][defaultmethods] Default method processing complete [0.067s][debug][defaultmethods] P0/C3 [0.067s][debug][defaultmethods] java/lang/Object [0.067s][debug][defaultmethods] P0/I0 [0.067s][debug][defaultmethods] Checking superclass: java/lang/Object [0.067s][debug][defaultmethods] No super defaults found [0.067s][debug][defaultmethods] Slots that need filling: [0.067s][debug][defaultmethods] m()Ljava/lang/Integer; [0.067s][debug][defaultmethods] Looking for default methods for slot m()Ljava/lang/Integer; [0.067s][debug][defaultmethods] Found candidate: P0.I0.m()Ljava/lang/Integer; [0.067s][debug][defaultmethods] Creating defaults and overpasses... [0.067s][debug][defaultmethods] for slot: m()Ljava/lang/Integer; [0.067s][debug][defaultmethods] Selected method: P0/I0.m()Ljava/lang/Integer; [0.067s][debug][defaultmethods] Created 0 overpass methods [0.067s][debug][defaultmethods] Created 1 default methods [0.067s][debug][defaultmethods] Default method processing complete Unfortunately JBS loses the indentation - <sigh>
09-07-2025

> Interestingly, if I change the test so that C5, not C4, implements I0, everything works fine. In theory, it's the same selection algorithm either way. The bug is in the processing of superclass default methods, so if there is no superclass default method, we bypass the bug.
08-07-2025

Interestingly, if I change the test so that C5, not C4, implements I0, everything works fine. In theory, it's the same selection algorithm either way.
07-07-2025

The spec here was most recently changed with JEP 181 (JDK-8177020), which specifically ruled out selection of 'private' methods, aside from the resolved method, by an 'invokeinterface'. The specified behavior of selection is to select the interface method.
07-07-2025

When we are filling in the vtable/itable for a class and we process the superclass default methods, we look for an implementation in the superclass that would satisfy the current class. However that lookup selects private methods in the superclass, which is not correct as these are not accessible to the subclass. If we elide the private method and leave the vtable slot empty, we then trigger the logic that searches for an implementation, which will correctly find the actual Interface default method.
07-07-2025

The failing test case can be distilled down to the following: public interface I0 { default Integer m() { return new Integer(0); } } public class C4 implements I0 { private Integer m() { return new Integer(4); } } public class C5 extends C4 { } Note that this source won't compile as we have a definition of m() in C4 that attempts to restrict the access of the inherited public I0.m() default method. Then we have an invocation in a main class: I0 var0 = new C5(); var0.m(); I think we can skip the detailed analysis of method resolution as we agree this will resolve to invoking I0.m() using invokeinterface. I also agree with this reasoning above regarding method selection that concludes: > According to §5.4.3.3, the maximally-specific superinterface method of `C5` is solely `I0.m()`, which is non-abstract. Therefore, the selected method is `I0.m()`. but then it is stated: > Returning to the `invokeinterface` instruction, it states: "Otherwise, if the selected method is neither `public` nor `private`, `invokeinterface` throws an `IllegalAccessError`." Consequently, the result should be an `IllegalAccessError` rather than an `AbstractMethodError`. But the selected method I0.m is public so this does not apply. So based on the previous analysis the method invocation should simply succeed, but what we get is: java.lang.AbstractMethodError: Receiver class P0.C5 does not define or inherit an implementation of the resolved method 'java.lang.Integer m()' of interface P0.I0 This seems absurd on the surface as C5 extends C4 which implements I0 which has a default method m(). If we change the example so that we invoke I0.m on an instance of C4 (which has the private m()) then the call succeeds and we do invoke the I0.m default method. So does something change when we use C5 over C4 in terms of the specification, or is this simply a bug in the VM's implementation? My conclusion is that it is a bug in the default method handling in the VM. Class C4 correctly gets a default method entry for I0.m when it is processed, but C5 does not because of the presence of the private C4.m method.
07-07-2025

Note using invokeinterface for invoking C5.m is again the key to seeing the incorrect behaviour.
02-07-2025

So the title of this bug is: IllegalAccessError in HotSpot Due to Incorrect Handling of Private Method but based on the above it sounds like it should be AbstractMethodError in HotSpot Due to Incorrect Handling of Private Method and the AffectsVersion should be 11. Is that correct? The occurrence of the AbstractMethodError is very similar to what we see in JDK-8356942.
02-07-2025

Bug title and Affects Version updated. I suspect this bug and JDK-8356942 have the same underlying cause - which was introduced in JDK 10. UPDATE: No these are distinct bugs with different causes. JDK-8356942 was introduced in JDK 10, but this issue is specific to JDK 11.
02-07-2025

Additional Information from Submitter: ============================================ > So the title of this bug is: > IllegalAccessError in HotSpot Due to Incorrect Handling of Private Method > but based on the above it sounds like it should be > AbstractMethodError in HotSpot Due to Incorrect Handling of Private Interface Method > and the AffectsVersion should be 11. Is that correct? > The occurrence of the AbstractMethodError is very similar to what we see in JDK-8356942. Yes, AbstractMethodError is not what we expected, and the affected version, in my opinion, is 11. At the same time, JDK-8356941 and JDK-8356942 are indeed both related to invokeinterface, but I believe they reflect different execution branches.
19-05-2025

Additional Information from submitter: ========================================= The version I was referring to might have been a mistake due to a typo, and the version I am actually discussing is JDK 11. According to the Java SE 11 JVM Specification, the `invokeinterface` instruction states that "the named interface method is resolved ([§5.4.3.4](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.3.4))." Furthermore, §5.4.3.4 specifies: "Otherwise, if `C` declares a method with the name and descriptor specified by the interface method reference, method lookup succeeds." Based on this, the resolved interface method is `I0.m()`. Proceeding to the Method Selection phase (§5.4.6), the resolved method `mR` is `I0.m()`, and the class `C` is `C5`. According to §5.4.6, the rule states: "If `C` contains a declaration of an instance method `m` that can override `mR` ([§5.4.5](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.5)), then `m` is the selected method." Since `C5` does not declare such a method, the process moves to the next rule: "Otherwise, if `C` has a superclass, a search for a declaration of an instance method that can override `mR` is performed, starting with the direct superclass of `C` and continuing with the direct superclass of that class, and so forth, until a method is found or no further superclasses exist. If a method is found, it is the selected method." However, the method in `C5`'s superclass `C4` is `private` and cannot override `I0.m()`, so this step fails. Thus, the process proceeds to the final rule: "Otherwise, the maximally-specific superinterface methods of `C` are determined ([§5.4.3.3](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-5.html#jvms-5.4.3.3)). If exactly one matches `mR`'s name and descriptor and is not `abstract`, then it is the selected method." According to §5.4.3.3, the maximally-specific superinterface method of `C5` is solely `I0.m()`, which is non-abstract. Therefore, the selected method is `I0.m()`. Returning to the `invokeinterface` instruction, it states: "Otherwise, if the selected method is neither `public` nor `private`, `invokeinterface` throws an `IllegalAccessError`." Consequently, the result should be an `IllegalAccessError` rather than an `AbstractMethodError`.
16-05-2025

Closing as "Not an Issue". If I have misunderstood the issue being reported and the submitter can better explain what they think is the issue, then please reopen.
16-05-2025

The submitter is referencing JVMS 8 but then complaining about the behaviour of JDK 11. The handling of private interface methods changed in JDK 11 with the introduction of "NestMates" - JEP-181 https://openjdk.org/jeps/181. You can find the changes to JVMS 11 here https://bugs.openjdk.org/secure/attachment/76344/nestmates.html Of particular note is the addition of JVMS 5.4.6 "Method Selection": During execution of an invokeinterface or invokevirtual instruction, a method is selected with respect to (i) the run-time type of the object on the stack, and (ii) a method that was previously resolved by the instruction. The rules to select a method with respect to a class or interface C and a method mR are as follows: 1. If mR is marked ACC_PRIVATE, then it is the selected method. I have not gone through the current scenario in detail, but if the resolved method is private then it will be the selected method, but no such method exists in class C5 - hence the AbstractMethodError.
14-05-2025