Home > Mobile >  Does final keyword on method parameter get compiled to bytecode?
Does final keyword on method parameter get compiled to bytecode?

Time:11-03

I have the following class:

public class Test {
  private int a;

  public Test(final int a) {
    this.a = a;
  }
}

I tried compiling (using javac Test.java) with and without the final keyword on a. In both cases, when I decompile (using javap -v -c Test.class) I get the following bytecode (java 11, open jdk):

Classfile /home/sadeep/repos/podium.cubs-cnt-svc-modelruntime/src/main/java/podium/cubs/cnt/svc/modelruntime/Test.class
  Last modified Nov 3, 2021; size 261 bytes
  MD5 checksum aa55c5cbaad8a25b1ebf28a572fa72e3
  Compiled from "Test.java"
public class podium.cubs.cnt.svc.modelruntime.Test
  minor version: 0
  major version: 55
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #3                          // podium/cubs/cnt/svc/modelruntime/Test
  super_class: #4                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 1, attributes: 1
Constant pool:
   #1 = Methodref          #4.#13         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#14         // podium/cubs/cnt/svc/modelruntime/Test.a:I
   #3 = Class              #15            // podium/cubs/cnt/svc/modelruntime/Test
   #4 = Class              #16            // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               (I)V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               SourceFile
  #12 = Utf8               Test.java
  #13 = NameAndType        #7:#17         // "<init>":()V
  #14 = NameAndType        #5:#6          // a:I
  #15 = Utf8               podium/cubs/cnt/svc/modelruntime/Test
  #16 = Utf8               java/lang/Object
  #17 = Utf8               ()V
{
  public podium.cubs.cnt.svc.modelruntime.Test(int);
    descriptor: (I)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iload_1
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 6: 0
        line 7: 4
        line 8: 9
}
SourceFile: "Test.java"

Is final on method parameters not a jvm construct?

EDIT:

javap -p -c -v:

Classfile /home/sadeep/Test.class
  Last modified Nov 3, 2021; size 228 bytes
  MD5 checksum 2f3a79a3c91a62a2d7831651be24168b
  Compiled from "test.java"
class Test
  minor version: 0
  major version: 55
  flags: (0x0020) ACC_SUPER
  this_class: #3                          // Test
  super_class: #4                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 1, attributes: 1
Constant pool:
   #1 = Methodref          #4.#13         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#14         // Test.a:I
   #3 = Class              #15            // Test
   #4 = Class              #16            // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               (I)V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               SourceFile
  #12 = Utf8               test.java
  #13 = NameAndType        #7:#17         // "<init>":()V
  #14 = NameAndType        #5:#6          // a:I
  #15 = Utf8               Test
  #16 = Utf8               java/lang/Object
  #17 = Utf8               ()V
{
  private final int a;
    descriptor: I
    flags: (0x0012) ACC_PRIVATE, ACC_FINAL

  public Test(int);
    descriptor: (I)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iload_1
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 9
}
SourceFile: "test.java"

Looks like even with -p, the final indicator is only set for the field.

CodePudding user response:

TL;DR: You don’t need that information in the bytecode

The final keyword on a parameter means that you cannot assign a value to that parameter inside your method or constructor. It’s the compiler’s job to check that you are not doing this (and the compiler will issue an error message if you do). Once the compiler has done its job, we can be assured that the parameter indeed keeps its initial value throughout. There is no need to have the information in the bytecode that the parameter is declared final. Which is why the information is not there.

From a comment by Link182:

Then how do we know the parameter is final in a compiled library?

You don’t. You don’t need to. What would you use that information for? It’s only relevant for the implementor of the method.

CodePudding user response:

The MethodParameters attribute is used to indicate that parameters are final. https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.24

In order for javac to add this attribute, you need to pass the -parameters option.

  • Related