Variables having same name but different type

后端 未结 4 1359
无人及你
无人及你 2020-12-09 23:32

I have read here that in Java it is possible for two variables having same name but different type to co-exist in the same scope. What I mean is this

class te         


        
相关标签:
4条回答
  • 2020-12-10 00:15

    You cannot have variables having same name (but different type) to exist in the same scope. Consider if it was possible then how would the java compiler determine which one you meant.

    Consider this code snippet

    class test
    {
        private int x;
        private double x;
    
        test() //constructor
        {
            System.out.println(x); //Error cannot determine which x you meant
        } 
    }
    

    The java compiler cannot understand which x you are actually referring to. So such a code is not syntactically correct and not compilable.

    However there exists tools such as ClassEditor which can modify the generated class file after it is created. There it is possible to change the name two variables to same.

    However such a class is not necessarily runnable by the java jvm.

    The software which you have quoted i.e JAD can rename such duplicate named variables in the class file so that the source code which you will be getting will actually be syntactically correct

    0 讨论(0)
  • 2020-12-10 00:18

    According to the specification of the language (JLS 8.3):

    It is a compile-time error for the body of a class declaration to declare two fields with the same name.

    The statement that you've quoted is about a class file (i.e. a compiled file, not the source code).

    0 讨论(0)
  • 2020-12-10 00:26

    Of course you cannot have int x and long x fields in the same class, just as you cannot have two methods with the same name and parameter list. But this is at the source level. JVM and bytecode have different rules. Consider this:

    package test;

    public class Test {
        static int x;
    
        @Override
        protected Test clone() throws CloneNotSupportedException {
            return this;
        }
    
        public static void main(String[] args) {
            int y = x;
        }
    }
    

    If you use a bytecode outline tool (I've used Andrey Loskutov's plugin for Eclipse) you will see in this line int Test.main()

    GETSTATIC test/Test.x : I
    

    This is how JVM loads value from field x, its full name is "test/Test.x : I". That gives you a hint that the field value is present in the field full name.

    It's no secret that javac is not the only means to create a class, there are tools/libraries to create bytecode directly, and they are free to create classes with fields with the same name but different type. Same goes for JNI.

    It's hard to show a working example of what I am trying to prove. But let's consider methods, a similar issue. Bytecode analisys shows that there are two methods in Test class with the same name and parameters which is not allowed by JLS:

    protected clone()Ltest/Test; throws java/lang/CloneNotSupportedException 
    
    protected volatile bridge clone()Ljava/lang/Object; throws java/lang/CloneNotSupportedException 
    

    The "bridge" method was added by javac because Test.clone() returns Test and this means it does not override Object.clone() which returns Object and this is because JVM thinks these two are different methods

    1 clone()Ltest/Test;
    2 clone()Ljava/lang/Object;
    
    0 讨论(0)
  • 2020-12-10 00:30

    As others said, illegal in Java, but legal in bytecode.

    javac assert

    assert is a Java example which in Oracle JDK 1.8.0_45 generates multiple fields with the same name but different types. E.g.:

    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;
        }
    }
    

    The presence of assert generates an bool $assertionsDisable a synthetic field to cache a method call, see: https://stackoverflow.com/a/29439538/895245 for the details.

    Then:

    javac Assert.java
    javap -c -constants -private -verbose Assert.class
    

    contains the lines:

     #3 = Fieldref           #9.#28         // Assert.$assertionsDisabled:[I
     #5 = Fieldref           #9.#31         // Assert.$assertionsDisabled:Z
    #12 = Utf8               $assertionsDisabled
    #28 = NameAndType        #12:#13        // $assertionsDisabled:[I
    #31 = NameAndType        #12:#14        // $assertionsDisabled:Z
    
    public static void main(java.lang.String[]);
     3: getstatic     #3                  // Field $assertionsDisabled:[I
    10: getstatic     #5                  // Field $assertionsDisabled:Z
    

    Note how the constant table even reuses #12 as the variable name.

    If we had declared another boolean however, it would not compile:

    static final boolean $assertionsDisabled = false;
    

    with error:

    the symbol $assertionsDisabled conflicts with a compile synthesized symbol
    

    This is also why it is a very bad idea to use field names with dollar signs: When should I use the dollar symbol ($) in a variable name?

    jasmin

    Of course, we can also try it out with Jasmin:

    .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
    

    Which contains two static fields, one int (I) and one float (F), and outputs:

    1
    1.5
    

    If works because:

    • getstatic points to a Fieldref structure on the constant table
    • Fieldref points to to a NameAndType
    • NameAndType points to the type, obviously

    So to differentiate them, Jasmin simply uses two different Fieldref with different types.

    0 讨论(0)
提交回复
热议问题