this post was submitted on 15 Jun 2023
18 points (100.0% liked)

Java

1388 readers
1 users here now

For discussing Java, the JVM, languages that run on the JVM, and other related technologies.

founded 1 year ago
MODERATORS
 

Though it is not possible in Java, the JVM can have multiple methods with the same name and parameter types so long as they have different return types. The JVM spec seems to call it "method descriptor" but I called it signature as I think that's more attention grabbing (and I'm showing how the JVM spec and Java spec differ).

No two methods in one class file may have the same name and descriptor

You can experimentally test this yourself with the Jasmin project. Jasmin is a tool that lets you write assembly code to assemble to JVM byte code. I also used this classfileanalyzer project to get some base Jasmin assembly.

For the lazy, here is the Java code I started with,

public class Example {
  public static void main(String[] args) {
    System.out.println(foo());
    System.out.println(fooInt());
  }
  static String foo() {
    return "1";
  }
  static int fooInt() {
    return 1;
  }
}

Then I got this Jasmin code and replaced each fooInt with foo

; Example.j

; Generated by ClassFileAnalyzer (Can)
; Analyzer and Disassembler for Java class files
; (Jasmin syntax 2, http://jasmin.sourceforge.net)
;
; ClassFileAnalyzer, version 0.7.0


.bytecode 63.0
.source Example.java
.class public Example
.super java/lang/Object

.method public <init>()V
  .limit stack 1
  .limit locals 1
  .line 1
  0: aload_0
  1: invokespecial java/lang/Object/<init>()V
  4: return
.end method

.method public static main([Ljava/lang/String;)V
  .limit stack 2
  .limit locals 1
  .line 3
  0: getstatic java/lang/System/out Ljava/io/PrintStream;
  3: invokestatic Example/foo()Ljava/lang/String;
  6: invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
  .line 4
  9: getstatic java/lang/System/out Ljava/io/PrintStream;
  12: invokestatic Example/foo()I
  15: invokevirtual java/io/PrintStream/println(I)V
  .line 5
  18: return
.end method

.method static foo()Ljava/lang/String;
  .limit stack 1
  .limit locals 0
  .line 7
  0: ldc "1"
  2: areturn
.end method

.method static foo()I
  .limit stack 1
  .limit locals 0
  .line 10
  0: iconst_1
  1: ireturn
.end method

After assembling Example.class with Jasmin and running javap -c Example I get this output,

Compiled from "Example.java"
public class Example {
  public Example();
    Code:
       0: aload_0
       1: invokespecial #28                 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #33                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: invokestatic  #32                 // Method foo:()Ljava/lang/String;
       6: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       9: getstatic     #33                 // Field java/lang/System.out:Ljava/io/PrintStream;
      12: invokestatic  #11                 // Method foo:()I
      15: invokevirtual #24                 // Method java/io/PrintStream.println:(I)V
      18: return

  static java.lang.String foo();
    Code:
       0: ldc           #27                 // String 1
       2: areturn

  static int foo();
    Code:
       0: iconst_1
       1: ireturn
}

And of course, running Example.class outputs

1
1

I hope you've enjoyed this interesting quirk of the JVM. It is a good reminder that while the JVM is primarily for Java, there are other languages that use it and some might even use this in a meaningful way somehow.

top 7 comments
sorted by: hot top controversial new old
[–] [email protected] 4 points 1 year ago (1 children)

The JVM is just very strange and quirky. Good write up!

[–] JackbyDev 2 points 1 year ago

Thanks! I'm trying to post something here everyday to keep the community growing. I remembered this fact from ages ago (don't recall where I heard it) and set out to reproduce it.

[–] doowkcin 3 points 1 year ago (1 children)

Has there ever been official discussion regarding why you can't do this in Java, if it's a thing the JVM allows? Maybe there are performance issues with code analysis and/or compilation?

[–] JackbyDev 4 points 1 year ago

My gut feeling is the answer will probably be "because C does it like that" but I doubt there's a primary source saying that anywhere.

I suppose one tricky thing with object oriented code might be deciding which method to use. The naive solution is just use the most specific but what if there are equally specific ones? Say in the example above I used Integer instead of int and ran this,

Object o = foo();

Both String and Integer are as "specific" as each other.

[–] Sheldan 1 points 1 year ago* (last edited 1 year ago) (1 children)

Something which I realized and made me understand why the return type is not part of the sigure, is the question "what happens if you just call a method, but not assign the return value to a variable?" If you have two methods with the same name, and parameters, and the only difference is the return type, how would you decide what method to call, if you have not the slightest idea which one of them is meant? As you are not required to assign the return value to anything, you have no indication.

[–] JackbyDev 1 points 1 year ago

In theory you could have void methods be called instead of ones returning a type when you explicitly don't assign anything, but yeah, it's just weird to think about.

[–] [email protected] 1 points 1 year ago

Same in C#.