Cuando el archivo Java es una interfaz, como TestInterface.java :
public interface TestInterface { void method(String parameterName); } Compilo con javac -g TestInterface.java y luego desensamblo con javap -v TestInterface , el resultado es el siguiente:
Classfile /private/tmp/TestInterface.class Last modified Mar 17, 2022; size 148 bytes MD5 checksum da2f58afc0eaf77badc94c90de385198 Compiled from "TestInterface.java" public interface TestInterface minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT Constant pool: #1 = Class #7 // TestInterface #2 = Class #8 // java/lang/Object #3 = Utf8 method #4 = Utf8 (Ljava/lang/String;)V #5 = Utf8 SourceFile #6 = Utf8 TestInterface.java #7 = Utf8 TestInterface #8 = Utf8 java/lang/Object { public abstract void method(java.lang.String); descriptor: (Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_ABSTRACT } SourceFile: "TestInterface.java" Y cuando el archivo Java es una clase, como TestClass.java :
public class TestClass { public void method(String parameterName) { } } Compile con javac -g TestClass.java y luego desmonte con javap -v TestClass , el resultado es el siguiente:
Classfile /private/tmp/TestClass.class Last modified Mar 17, 2022; size 389 bytes MD5 checksum 8e124ecce6632ad6e1a5bb45888a3168 Compiled from "TestClass.java" public class TestClass minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#17 // java/lang/Object."<init>":()V #2 = Class #18 // TestClass #3 = Class #19 // java/lang/Object #4 = Utf8 <init> #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 LocalVariableTable #9 = Utf8 this #10 = Utf8 LTestClass; #11 = Utf8 method #12 = Utf8 (Ljava/lang/String;)V #13 = Utf8 parameterName #14 = Utf8 Ljava/lang/String; #15 = Utf8 SourceFile #16 = Utf8 TestClass.java #17 = NameAndType #4:#5 // "<init>":()V #18 = Utf8 TestClass #19 = Utf8 java/lang/Object { public TestClass(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LTestClass; public void method(java.lang.String); descriptor: (Ljava/lang/String;)V flags: ACC_PUBLIC Code: stack=0, locals=2, args_size=2 0: return LineNumberTable: line 5: 0 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LTestClass; 0 1 1 parameterName Ljava/lang/String; } SourceFile: "TestClass.java" ¿Por qué LocalVariableTable no está incluido en el archivo de clase de la interfaz?
Versión JDK: 1.8.0_311
LocalVariableTable describe el alcance de la variable: la parte del código de bytes en la que se puede acceder a la variable.
En una clase, el parámetro de un método no abstracto tiene un alcance: es accesible en todo el cuerpo del método. Incluso cuando el método está "vacío", el código de bytes aún consta de un solo comando de return .
(También está implícita this variable en un método de instancia, que también es accesible en todo el cuerpo del método).
En un método de interfaz abstracto (es decir, no es un método default o static ), no hay código de bytes en el que se pueda acceder a esa variable, porque el método no tiene cuerpo y, por lo tanto, no tiene código de bytes. Por lo tanto, no hay necesidad de LocalVariableTable .
Un método abstracto (ya sea en una interfaz o en una clase) es solo una especificación que dice "los implementadores deben proporcionar esto". No hay implementación, no hay cuerpo, etc.
Porque no es así como funciona la estructura de archivos de clase.
De acuerdo con la especificación JVM , LocalVariableTable es parte de un atributo Code :
El atributo
LocalVariableTablees un atributo opcional de longitud variable en la tabla deattributesde un atributoCode(§4.7.3). Los depuradores pueden utilizarlo para determinar el valor de una variable local determinada durante la ejecución de un método.
Sin embargo, los métodos de interfaz son abstractos (es decir, tienen el indicador ACC_ABSTRACT ), por lo que no pueden tener atributos de Code en primer lugar ( §4.7.3 ).
El atributo
Codees un atributo de longitud variable en la tabla deattributesde una estructuramethod_info(§4.6). Un atributo deCodecontiene las instrucciones de la Máquina Virtual Java e información auxiliar para un método [...]Si el método es
nativeoabstracty no es un método de inicialización de clase o interfaz, entonces su estructuramethod_infono debe tener un atributoCodeen su tabla deattributes.
Por lo tanto, no es posible que javac genere un LocalVariableTable para su método de interfaz abstracto, incluso si quisiera, porque eso no produciría un archivo de clase correcto.
Otra forma de verlo es que el parámetro del método en realidad no "existe" hasta que lo implementas concretamente. Después de todo, se supone que un método abstracto es solo un "requisito" sin "implementaciones". Realmente no veo por qué esperaría que haya variables locales, ya que son detalles de implementación.