具有相同名称但类型不同的变量

14 浏览
0 Comments

具有相同名称但类型不同的变量

我在这里读到,在Java中,同一作用域中可以存在两个具有相同名称但不同类型的变量。我的意思是这样的:\n

class test
{
    private int x;
    private double x;
}

\n但是所有的Java IDE都不允许这样的代码。我想知道这样的代码是否真的在语法上是正确的,还是简单地IDE不允许这样的代码以防止歧义。\n无论如何,这是从网站上摘录的内容:\n

\n\"如果你幸运的话,你可能能够重新编译Jad的输出。然而,Java虚拟机对变量命名的规则比Java语言本身更宽松。例如,一个有效的类文件可以有几个名为\'a\'的变量,只要它们具有不同的类型。如果你反编译这样的类,你得到的源代码将不是有效的。\nJAD通常会重命名这些有问题的字段,并生成一个可重新编译的文件...唯一的问题是重新编译后的文件与原始类不兼容。\"\n

0
0 Comments

问题的出现原因是根据语言规范,在一个类声明的主体中,声明两个具有相同名称的字段是编译时错误。然而,这个规则是针对类文件而不是源代码的。

解决方法是,如果类型不同,NetBeans可以接受具有相同名称的两个变量,但是Eclipse不接受。通过实验证实,当在NetBeans 7.2.1中尝试声明具有相同名称但类型不同的变量时,第二个变量会被标记为错误(已在类中定义了变量)。

关于如何在源代码无法编译的情况下生成类文件,一种可能的解释是,编译后的类文件可能包含多个具有相同名称的变量。因此,当反编译工具需要将类文件转换为Java源代码文件时,会将这些重复变量重命名,以确保生成的代码可以编译。

另外,编译后的类文件不存储方法作用域的变量名,因此反编译器会将每个方法体的局部字段都应用一些无意义的“a”名称。

0
0 Comments

在同一作用域中,不允许存在变量名称相同但类型不同的变量。如果允许存在这种情况,Java编译器将无法确定你想引用哪个变量。

考虑以下代码片段:

class test {
    private int x;
    private double x;
    test() { //构造函数
        System.out.println(x); //错误,无法确定引用的是哪个x
    } 
}

Java编译器无法理解你实际上引用的是哪个x。因此,这样的代码在语法上是错误的,无法编译通过。

然而,存在一些工具(例如ClassEditor)可以在生成的类文件创建之后修改它。在这里,可以将两个变量的名称更改为相同。然而,这样的类不一定可以在Java虚拟机中运行。

你提到的软件JAD可以重命名类文件中重复命名的变量,以便你获得的源代码实际上是符合语法规范的。

0
0 Comments

在Java中,变量不能具有相同的名称但不同的类型,这是非法的。然而,在字节码中是合法的。

问题的出现原因是由于使用了Java中的assert关键字,该关键字在Oracle JDK 1.8.0_45中会生成多个具有相同名称但不同类型的字段。例如,在下面的示例中,Assert类中使用了assert关键字:

public class Assert {
    // We can't use a primitive like int here or it would get inlined.
    static final int[] $assertionsDisabled = new int[0];
    public static void main(String[] args) {
        System.out.println($assertionsDisabled.length);
        // currentTimeMillis so it won't get optimized away.
        assert System.currentTimeMillis() == 0L;
    }
}

assert关键字会生成一个合成字段bool $assertionsDisable来缓存一个方法调用。通过观察生成的字节码,可以看到常量表中复用了变量名#12

如果我们声明了另一个布尔变量,将无法编译通过,报错信息如下:

the symbol $assertionsDisabled conflicts with a compile synthesized symbol

这也是为什么在变量名中使用美元符号($)是一个非常糟糕的主意。

我们还可以使用Jasmin来验证这个问题。在下面的示例中,我们使用Jasmin语言编写了一个包含两个静态字段的类,一个是整型(I),一个是浮点型(F):

.class public FieldOverload
.super java/lang/Object
.field static f I
.field static f F
.method public static main([Ljava/lang/String;)V
    .limit stack 2
    ldc 1
    putstatic FieldOverload/f I
    ldc 1.5
    putstatic FieldOverload/f F
    getstatic java/lang/System/out Ljava/io/PrintStream;
    getstatic FieldOverload/f I
    invokevirtual java/io/PrintStream/println(I)V
    getstatic java/lang/System/out Ljava/io/PrintStream;
    getstatic FieldOverload/f F
    invokevirtual java/io/PrintStream/println(F)V
    return
.end method

这个示例中的两个静态字段分别是一个整型和一个浮点型。运行这段代码会输出:

1
1.5

这是因为Jasmin使用了两个不同类型的Fieldref来区分它们。

变量具有相同名称但不同类型的问题在Java中是非法的,但在字节码中是合法的。要解决这个问题,可以避免使用具有相同名称的不同类型的变量,或者使用Jasmin等编译器来生成字节码时,确保使用不同类型的Fieldref来区分它们。

0