Are all final variables captured by anonymous classes?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite
1












I thought I knew the answer to this, but I can't find any confirmation after an hour or so of searching.



In this code:



public class Outer 

// other code

private void method1()
final SomeObject obj1 = new SomeObject(...);
final SomeObject obj2 = new SomeObject(...);
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.getName());

);




Assume that registerCallback saves its parameter somewhere, so that the object of the anonymous subclass will live for a while. Obviously this object has to maintain a reference to obj1 so that onEvent will work if it is called.



But given that the object doesn't use obj2, does it still maintain a reference to obj2, so that obj2 can't be garbage-collected while the object lives? I was under the impression that all visible final (or effectively final) local variables and parameters were captured and thus couldn't be GC'ed as long as the object was alive, but I can't find anything that says one way or the other.



Is it implementation-dependent?



Is there a section in the JLS that answers this? I wasn't able to find the answer there.










share|improve this question





















  • How do you know that obj2 is bound to callback$x? You have seen it in bytecode?
    – Antoniossss
    32 mins ago






  • 1




    "Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture obj2, but there is no reason it can't.
    – Andy Turner
    26 mins ago










  • I think a good reason it would not capture obj2 as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1 only, whilst another might refer to obj2 only. It wouldn't be sensible for both classes to capture both variables.
    – Andy Turner
    8 mins ago















up vote
6
down vote

favorite
1












I thought I knew the answer to this, but I can't find any confirmation after an hour or so of searching.



In this code:



public class Outer 

// other code

private void method1()
final SomeObject obj1 = new SomeObject(...);
final SomeObject obj2 = new SomeObject(...);
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.getName());

);




Assume that registerCallback saves its parameter somewhere, so that the object of the anonymous subclass will live for a while. Obviously this object has to maintain a reference to obj1 so that onEvent will work if it is called.



But given that the object doesn't use obj2, does it still maintain a reference to obj2, so that obj2 can't be garbage-collected while the object lives? I was under the impression that all visible final (or effectively final) local variables and parameters were captured and thus couldn't be GC'ed as long as the object was alive, but I can't find anything that says one way or the other.



Is it implementation-dependent?



Is there a section in the JLS that answers this? I wasn't able to find the answer there.










share|improve this question





















  • How do you know that obj2 is bound to callback$x? You have seen it in bytecode?
    – Antoniossss
    32 mins ago






  • 1




    "Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture obj2, but there is no reason it can't.
    – Andy Turner
    26 mins ago










  • I think a good reason it would not capture obj2 as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1 only, whilst another might refer to obj2 only. It wouldn't be sensible for both classes to capture both variables.
    – Andy Turner
    8 mins ago













up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





I thought I knew the answer to this, but I can't find any confirmation after an hour or so of searching.



In this code:



public class Outer 

// other code

private void method1()
final SomeObject obj1 = new SomeObject(...);
final SomeObject obj2 = new SomeObject(...);
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.getName());

);




Assume that registerCallback saves its parameter somewhere, so that the object of the anonymous subclass will live for a while. Obviously this object has to maintain a reference to obj1 so that onEvent will work if it is called.



But given that the object doesn't use obj2, does it still maintain a reference to obj2, so that obj2 can't be garbage-collected while the object lives? I was under the impression that all visible final (or effectively final) local variables and parameters were captured and thus couldn't be GC'ed as long as the object was alive, but I can't find anything that says one way or the other.



Is it implementation-dependent?



Is there a section in the JLS that answers this? I wasn't able to find the answer there.










share|improve this question













I thought I knew the answer to this, but I can't find any confirmation after an hour or so of searching.



In this code:



public class Outer 

// other code

private void method1()
final SomeObject obj1 = new SomeObject(...);
final SomeObject obj2 = new SomeObject(...);
someManager.registerCallback(new SomeCallbackClass()
@Override
public void onEvent()
System.out.println(obj1.getName());

);




Assume that registerCallback saves its parameter somewhere, so that the object of the anonymous subclass will live for a while. Obviously this object has to maintain a reference to obj1 so that onEvent will work if it is called.



But given that the object doesn't use obj2, does it still maintain a reference to obj2, so that obj2 can't be garbage-collected while the object lives? I was under the impression that all visible final (or effectively final) local variables and parameters were captured and thus couldn't be GC'ed as long as the object was alive, but I can't find anything that says one way or the other.



Is it implementation-dependent?



Is there a section in the JLS that answers this? I wasn't able to find the answer there.







java anonymous-class






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 41 mins ago









ajb

26.5k33257




26.5k33257











  • How do you know that obj2 is bound to callback$x? You have seen it in bytecode?
    – Antoniossss
    32 mins ago






  • 1




    "Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture obj2, but there is no reason it can't.
    – Andy Turner
    26 mins ago










  • I think a good reason it would not capture obj2 as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1 only, whilst another might refer to obj2 only. It wouldn't be sensible for both classes to capture both variables.
    – Andy Turner
    8 mins ago

















  • How do you know that obj2 is bound to callback$x? You have seen it in bytecode?
    – Antoniossss
    32 mins ago






  • 1




    "Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture obj2, but there is no reason it can't.
    – Andy Turner
    26 mins ago










  • I think a good reason it would not capture obj2 as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1 only, whilst another might refer to obj2 only. It wouldn't be sensible for both classes to capture both variables.
    – Andy Turner
    8 mins ago
















How do you know that obj2 is bound to callback$x? You have seen it in bytecode?
– Antoniossss
32 mins ago




How do you know that obj2 is bound to callback$x? You have seen it in bytecode?
– Antoniossss
32 mins ago




1




1




"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture obj2, but there is no reason it can't.
– Andy Turner
26 mins ago




"Is it implementation-dependent?" Technically, yes. There is no reason for the anonymous class to capture obj2, but there is no reason it can't.
– Andy Turner
26 mins ago












I think a good reason it would not capture obj2 as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1 only, whilst another might refer to obj2 only. It wouldn't be sensible for both classes to capture both variables.
– Andy Turner
8 mins ago





I think a good reason it would not capture obj2 as a matter of course is that you can have multiple anonymous classes declared in a method: one of those classes might refer to obj1 only, whilst another might refer to obj2 only. It wouldn't be sensible for both classes to capture both variables.
– Andy Turner
8 mins ago













5 Answers
5






active

oldest

votes

















up vote
4
down vote













Only obj1 is captured.



Logically, the anonymous class is implemented as a normal class something like this:



class Anonymous1 extends SomeCallbackClass 
private final Outer _outer;
private final SomeObject obj1;
Anonymous1(Outer _outer, SomeObject obj1)
this._outer = _outer;
this.obj1 = obj1;

@Override
public void onEvent()
System.out.println(this.obj1.getName());

);


Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.



The use of it becomes:



someManager.registerCallback(new Anonymous1(this, obj1));


As you can see, the reference value of obj1 is copied (pass-by-value).



There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.






share|improve this answer


















  • 2




    Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
    – Boris the Spider
    28 mins ago










  • it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
    – Carlos Heuberger
    2 mins ago


















up vote
2
down vote













The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:




Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)




(Anonymous classes are inner classes)



It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.



I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.






share|improve this answer



























    up vote
    1
    down vote













    I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this



    public class test 
    private static Object holder;

    private void method1()
    final Object obj1 = new Object();
    final Object obj2 = new Object();
    holder = new ActionListener()
    @Override
    public void actionPerformed(ActionEvent e)
    System.out.println(obj1);

    ;




    And resulted with following bytecode for of method1



     private method1()V
    L0
    LINENUMBER 8 L0
    NEW java/lang/Object
    DUP
    INVOKESPECIAL java/lang/Object.<init> ()V
    ASTORE 1
    L1
    LINENUMBER 9 L1
    NEW java/lang/Object
    DUP
    INVOKESPECIAL java/lang/Object.<init> ()V
    ASTORE 2
    L2
    LINENUMBER 10 L2
    NEW test$1
    DUP
    ALOAD 0
    ALOAD 1
    INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
    PUTSTATIC test.holder : Ljava/lang/Object;


    Which means:



    • L0 - store first final with idx 1 (ASTORE 1)

    • L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)

    • L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)

    So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.






    share|improve this answer



























      up vote
      -1
      down vote













      Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:



      import java.lang.ref.Reference;
      import java.lang.ref.WeakReference;

      public class Outer

      // other code

      private Reference<Object> obj1Ref;
      private Reference<Object> obj2Ref;

      private void method1()
      final Object obj1 = new Object();
      final Object obj2 = new Object();

      obj1Ref = new WeakReference<Object>(obj1);
      obj2Ref = new WeakReference<Object>(obj2);

      Manager someManager = new Manager();
      someManager.registerCallback(new SomeCallbackClass()
      @Override
      public void onEvent()
      System.out.println(obj1.hashCode());

      );


      // To be called after method1() finishes but before onEvent() get's called.
      public void checkReferences ()

      Object object1 = obj1Ref.get();
      System.out.println("obj1 is still alive: " + object1 != null);

      Object object2 = obj1Ref.get();
      System.out.println("obj2 is still alive: " + object2 != null);










      share|improve this answer



























        up vote
        -2
        down vote













        This code displays 10, it's unaffected by garbage collector:



        public class HelloWorld

        public static void main(String args)
        Outer q = new Outer();

        System.gc();
        System.runFinalization();

        q.method1().ok(4,1);





        interface Ok

        public void ok(int a, int b);



        class Outer
        private final int obj1 = 5;
        public Ok method1()

        Ok justDoIt = new Ok()
        public void ok(int a, int b)

        System.out.println(obj1+a+b);



        ;

        return justDoIt;




        To be honest I don't exactly understand your question.



        But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.



        Think of a final variable this way:



        public class HelloWorld

        public static void main(String args)
        Final<Integer> q = new Final();
        q.set(5);
        System.out.println(q.get());

        q.set(10); // ERROR






        class Final <T>

        private T variable;
        private Boolean setted=false;

        public void set(T value) throws Error
        if(setted)
        throw new Error();


        variable=value;
        setted = true;


        public T get()return variable;




        And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it






        share|improve this answer




















        • If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
          – Rab
          9 mins ago










        • OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
          – Antoniossss
          9 mins ago











        • I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
          – Nertan Lucian
          6 mins ago










        • You are missing the point and if you answered base on title, it is still off topic IMHO.
          – Antoniossss
          5 mins ago











        Your Answer






        StackExchange.ifUsing("editor", function ()
        StackExchange.using("externalEditor", function ()
        StackExchange.using("snippets", function ()
        StackExchange.snippets.init();
        );
        );
        , "code-snippets");

        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "1"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













         

        draft saved


        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203529%2fare-all-final-variables-captured-by-anonymous-classes%23new-answer', 'question_page');

        );

        Post as a guest






























        5 Answers
        5






        active

        oldest

        votes








        5 Answers
        5






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        4
        down vote













        Only obj1 is captured.



        Logically, the anonymous class is implemented as a normal class something like this:



        class Anonymous1 extends SomeCallbackClass 
        private final Outer _outer;
        private final SomeObject obj1;
        Anonymous1(Outer _outer, SomeObject obj1)
        this._outer = _outer;
        this.obj1 = obj1;

        @Override
        public void onEvent()
        System.out.println(this.obj1.getName());

        );


        Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.



        The use of it becomes:



        someManager.registerCallback(new Anonymous1(this, obj1));


        As you can see, the reference value of obj1 is copied (pass-by-value).



        There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.






        share|improve this answer


















        • 2




          Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
          – Boris the Spider
          28 mins ago










        • it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
          – Carlos Heuberger
          2 mins ago















        up vote
        4
        down vote













        Only obj1 is captured.



        Logically, the anonymous class is implemented as a normal class something like this:



        class Anonymous1 extends SomeCallbackClass 
        private final Outer _outer;
        private final SomeObject obj1;
        Anonymous1(Outer _outer, SomeObject obj1)
        this._outer = _outer;
        this.obj1 = obj1;

        @Override
        public void onEvent()
        System.out.println(this.obj1.getName());

        );


        Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.



        The use of it becomes:



        someManager.registerCallback(new Anonymous1(this, obj1));


        As you can see, the reference value of obj1 is copied (pass-by-value).



        There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.






        share|improve this answer


















        • 2




          Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
          – Boris the Spider
          28 mins ago










        • it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
          – Carlos Heuberger
          2 mins ago













        up vote
        4
        down vote










        up vote
        4
        down vote









        Only obj1 is captured.



        Logically, the anonymous class is implemented as a normal class something like this:



        class Anonymous1 extends SomeCallbackClass 
        private final Outer _outer;
        private final SomeObject obj1;
        Anonymous1(Outer _outer, SomeObject obj1)
        this._outer = _outer;
        this.obj1 = obj1;

        @Override
        public void onEvent()
        System.out.println(this.obj1.getName());

        );


        Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.



        The use of it becomes:



        someManager.registerCallback(new Anonymous1(this, obj1));


        As you can see, the reference value of obj1 is copied (pass-by-value).



        There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.






        share|improve this answer














        Only obj1 is captured.



        Logically, the anonymous class is implemented as a normal class something like this:



        class Anonymous1 extends SomeCallbackClass 
        private final Outer _outer;
        private final SomeObject obj1;
        Anonymous1(Outer _outer, SomeObject obj1)
        this._outer = _outer;
        this.obj1 = obj1;

        @Override
        public void onEvent()
        System.out.println(this.obj1.getName());

        );


        Note that an anonymous class is always an inner class, so it will always maintain a reference to the outer class, even if it doesn't need it. I don't know if later versions of the compiler have optimized that away, but I don't think so. It is a potential cause of memory leaks.



        The use of it becomes:



        someManager.registerCallback(new Anonymous1(this, obj1));


        As you can see, the reference value of obj1 is copied (pass-by-value).



        There is technically no reason for obj1 to be final, whether declared final or effectively final (Java 8+), except that if it wasn't and you change the value, the copy wouldn't change, causing bugs because you expected the value to change, given that the copying is a hidden action. To prevent programmer confusion, they decided that obj1 must be final, so you can never become confused about that behavior.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 25 mins ago

























        answered 32 mins ago









        Andreas

        72.3k454115




        72.3k454115







        • 2




          Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
          – Boris the Spider
          28 mins ago










        • it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
          – Carlos Heuberger
          2 mins ago













        • 2




          Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
          – Boris the Spider
          28 mins ago










        • it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
          – Carlos Heuberger
          2 mins ago








        2




        2




        Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
        – Boris the Spider
        28 mins ago




        Worth mentioning that since Java 8 the restriction on having to explicitly declare final has been lifted. The JLS now talks about "effectively final" variables.
        – Boris the Spider
        28 mins ago












        it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
        – Carlos Heuberger
        2 mins ago





        it is not only logically, it is almost exactly that what the compiler does (Java 8 and 11), just the fields are named differently [:-)
        – Carlos Heuberger
        2 mins ago













        up vote
        2
        down vote













        The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:




        Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)




        (Anonymous classes are inner classes)



        It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.



        I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.






        share|improve this answer
























          up vote
          2
          down vote













          The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:




          Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)




          (Anonymous classes are inner classes)



          It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.



          I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.






          share|improve this answer






















            up vote
            2
            down vote










            up vote
            2
            down vote









            The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:




            Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)




            (Anonymous classes are inner classes)



            It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.



            I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.






            share|improve this answer












            The only especially relevant section of the language spec that I can find is JLS Sec 8.1.3:




            Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.)




            (Anonymous classes are inner classes)



            It does not specify anything about which variables the anonymous class should capture, or how that capturing should be implemented.



            I think it is reasonable to infer from this that implementations need not capture variables that aren't referenced in the inner class; but it doesn't say they can't.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 13 mins ago









            Andy Turner

            77.3k876124




            77.3k876124




















                up vote
                1
                down vote













                I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this



                public class test 
                private static Object holder;

                private void method1()
                final Object obj1 = new Object();
                final Object obj2 = new Object();
                holder = new ActionListener()
                @Override
                public void actionPerformed(ActionEvent e)
                System.out.println(obj1);

                ;




                And resulted with following bytecode for of method1



                 private method1()V
                L0
                LINENUMBER 8 L0
                NEW java/lang/Object
                DUP
                INVOKESPECIAL java/lang/Object.<init> ()V
                ASTORE 1
                L1
                LINENUMBER 9 L1
                NEW java/lang/Object
                DUP
                INVOKESPECIAL java/lang/Object.<init> ()V
                ASTORE 2
                L2
                LINENUMBER 10 L2
                NEW test$1
                DUP
                ALOAD 0
                ALOAD 1
                INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
                PUTSTATIC test.holder : Ljava/lang/Object;


                Which means:



                • L0 - store first final with idx 1 (ASTORE 1)

                • L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)

                • L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)

                So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.






                share|improve this answer
























                  up vote
                  1
                  down vote













                  I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this



                  public class test 
                  private static Object holder;

                  private void method1()
                  final Object obj1 = new Object();
                  final Object obj2 = new Object();
                  holder = new ActionListener()
                  @Override
                  public void actionPerformed(ActionEvent e)
                  System.out.println(obj1);

                  ;




                  And resulted with following bytecode for of method1



                   private method1()V
                  L0
                  LINENUMBER 8 L0
                  NEW java/lang/Object
                  DUP
                  INVOKESPECIAL java/lang/Object.<init> ()V
                  ASTORE 1
                  L1
                  LINENUMBER 9 L1
                  NEW java/lang/Object
                  DUP
                  INVOKESPECIAL java/lang/Object.<init> ()V
                  ASTORE 2
                  L2
                  LINENUMBER 10 L2
                  NEW test$1
                  DUP
                  ALOAD 0
                  ALOAD 1
                  INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
                  PUTSTATIC test.holder : Ljava/lang/Object;


                  Which means:



                  • L0 - store first final with idx 1 (ASTORE 1)

                  • L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)

                  • L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)

                  So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.






                  share|improve this answer






















                    up vote
                    1
                    down vote










                    up vote
                    1
                    down vote









                    I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this



                    public class test 
                    private static Object holder;

                    private void method1()
                    final Object obj1 = new Object();
                    final Object obj2 = new Object();
                    holder = new ActionListener()
                    @Override
                    public void actionPerformed(ActionEvent e)
                    System.out.println(obj1);

                    ;




                    And resulted with following bytecode for of method1



                     private method1()V
                    L0
                    LINENUMBER 8 L0
                    NEW java/lang/Object
                    DUP
                    INVOKESPECIAL java/lang/Object.<init> ()V
                    ASTORE 1
                    L1
                    LINENUMBER 9 L1
                    NEW java/lang/Object
                    DUP
                    INVOKESPECIAL java/lang/Object.<init> ()V
                    ASTORE 2
                    L2
                    LINENUMBER 10 L2
                    NEW test$1
                    DUP
                    ALOAD 0
                    ALOAD 1
                    INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
                    PUTSTATIC test.holder : Ljava/lang/Object;


                    Which means:



                    • L0 - store first final with idx 1 (ASTORE 1)

                    • L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)

                    • L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)

                    So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.






                    share|improve this answer












                    I was curious and surprised by your statement that much (why would compiler do such thing???), that I had to check it myself. So I made simple example like this



                    public class test 
                    private static Object holder;

                    private void method1()
                    final Object obj1 = new Object();
                    final Object obj2 = new Object();
                    holder = new ActionListener()
                    @Override
                    public void actionPerformed(ActionEvent e)
                    System.out.println(obj1);

                    ;




                    And resulted with following bytecode for of method1



                     private method1()V
                    L0
                    LINENUMBER 8 L0
                    NEW java/lang/Object
                    DUP
                    INVOKESPECIAL java/lang/Object.<init> ()V
                    ASTORE 1
                    L1
                    LINENUMBER 9 L1
                    NEW java/lang/Object
                    DUP
                    INVOKESPECIAL java/lang/Object.<init> ()V
                    ASTORE 2
                    L2
                    LINENUMBER 10 L2
                    NEW test$1
                    DUP
                    ALOAD 0
                    ALOAD 1
                    INVOKESPECIAL test$1.<init> (Ltest;Ljava/lang/Object;)V
                    PUTSTATIC test.holder : Ljava/lang/Object;


                    Which means:



                    • L0 - store first final with idx 1 (ASTORE 1)

                    • L1 - store second final with idx 2(that one is not used in anon class) (ASTORE 2)

                    • L2 - create new test$1 with argumets (ALOAD 0) this and obj1 (ALOAD 1)

                    So I have no idea, how did you get to the conclusion that obj2 is passed to anonymous class instance, but it was simply wrong. IDK if it is compiler dependent, but as for what other has stated, it is not impossible.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered 14 mins ago









                    Antoniossss

                    14.5k12149




                    14.5k12149




















                        up vote
                        -1
                        down vote













                        Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:



                        import java.lang.ref.Reference;
                        import java.lang.ref.WeakReference;

                        public class Outer

                        // other code

                        private Reference<Object> obj1Ref;
                        private Reference<Object> obj2Ref;

                        private void method1()
                        final Object obj1 = new Object();
                        final Object obj2 = new Object();

                        obj1Ref = new WeakReference<Object>(obj1);
                        obj2Ref = new WeakReference<Object>(obj2);

                        Manager someManager = new Manager();
                        someManager.registerCallback(new SomeCallbackClass()
                        @Override
                        public void onEvent()
                        System.out.println(obj1.hashCode());

                        );


                        // To be called after method1() finishes but before onEvent() get's called.
                        public void checkReferences ()

                        Object object1 = obj1Ref.get();
                        System.out.println("obj1 is still alive: " + object1 != null);

                        Object object2 = obj1Ref.get();
                        System.out.println("obj2 is still alive: " + object2 != null);










                        share|improve this answer
























                          up vote
                          -1
                          down vote













                          Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:



                          import java.lang.ref.Reference;
                          import java.lang.ref.WeakReference;

                          public class Outer

                          // other code

                          private Reference<Object> obj1Ref;
                          private Reference<Object> obj2Ref;

                          private void method1()
                          final Object obj1 = new Object();
                          final Object obj2 = new Object();

                          obj1Ref = new WeakReference<Object>(obj1);
                          obj2Ref = new WeakReference<Object>(obj2);

                          Manager someManager = new Manager();
                          someManager.registerCallback(new SomeCallbackClass()
                          @Override
                          public void onEvent()
                          System.out.println(obj1.hashCode());

                          );


                          // To be called after method1() finishes but before onEvent() get's called.
                          public void checkReferences ()

                          Object object1 = obj1Ref.get();
                          System.out.println("obj1 is still alive: " + object1 != null);

                          Object object2 = obj1Ref.get();
                          System.out.println("obj2 is still alive: " + object2 != null);










                          share|improve this answer






















                            up vote
                            -1
                            down vote










                            up vote
                            -1
                            down vote









                            Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:



                            import java.lang.ref.Reference;
                            import java.lang.ref.WeakReference;

                            public class Outer

                            // other code

                            private Reference<Object> obj1Ref;
                            private Reference<Object> obj2Ref;

                            private void method1()
                            final Object obj1 = new Object();
                            final Object obj2 = new Object();

                            obj1Ref = new WeakReference<Object>(obj1);
                            obj2Ref = new WeakReference<Object>(obj2);

                            Manager someManager = new Manager();
                            someManager.registerCallback(new SomeCallbackClass()
                            @Override
                            public void onEvent()
                            System.out.println(obj1.hashCode());

                            );


                            // To be called after method1() finishes but before onEvent() get's called.
                            public void checkReferences ()

                            Object object1 = obj1Ref.get();
                            System.out.println("obj1 is still alive: " + object1 != null);

                            Object object2 = obj1Ref.get();
                            System.out.println("obj2 is still alive: " + object2 != null);










                            share|improve this answer












                            Even though GC is not deterministic, I think this is testable using java.lang.ref.WeakReference:



                            import java.lang.ref.Reference;
                            import java.lang.ref.WeakReference;

                            public class Outer

                            // other code

                            private Reference<Object> obj1Ref;
                            private Reference<Object> obj2Ref;

                            private void method1()
                            final Object obj1 = new Object();
                            final Object obj2 = new Object();

                            obj1Ref = new WeakReference<Object>(obj1);
                            obj2Ref = new WeakReference<Object>(obj2);

                            Manager someManager = new Manager();
                            someManager.registerCallback(new SomeCallbackClass()
                            @Override
                            public void onEvent()
                            System.out.println(obj1.hashCode());

                            );


                            // To be called after method1() finishes but before onEvent() get's called.
                            public void checkReferences ()

                            Object object1 = obj1Ref.get();
                            System.out.println("obj1 is still alive: " + object1 != null);

                            Object object2 = obj1Ref.get();
                            System.out.println("obj2 is still alive: " + object2 != null);











                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered 13 mins ago









                            aka-one

                            1,05118




                            1,05118




















                                up vote
                                -2
                                down vote













                                This code displays 10, it's unaffected by garbage collector:



                                public class HelloWorld

                                public static void main(String args)
                                Outer q = new Outer();

                                System.gc();
                                System.runFinalization();

                                q.method1().ok(4,1);





                                interface Ok

                                public void ok(int a, int b);



                                class Outer
                                private final int obj1 = 5;
                                public Ok method1()

                                Ok justDoIt = new Ok()
                                public void ok(int a, int b)

                                System.out.println(obj1+a+b);



                                ;

                                return justDoIt;




                                To be honest I don't exactly understand your question.



                                But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.



                                Think of a final variable this way:



                                public class HelloWorld

                                public static void main(String args)
                                Final<Integer> q = new Final();
                                q.set(5);
                                System.out.println(q.get());

                                q.set(10); // ERROR






                                class Final <T>

                                private T variable;
                                private Boolean setted=false;

                                public void set(T value) throws Error
                                if(setted)
                                throw new Error();


                                variable=value;
                                setted = true;


                                public T get()return variable;




                                And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it






                                share|improve this answer




















                                • If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
                                  – Rab
                                  9 mins ago










                                • OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
                                  – Antoniossss
                                  9 mins ago











                                • I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
                                  – Nertan Lucian
                                  6 mins ago










                                • You are missing the point and if you answered base on title, it is still off topic IMHO.
                                  – Antoniossss
                                  5 mins ago















                                up vote
                                -2
                                down vote













                                This code displays 10, it's unaffected by garbage collector:



                                public class HelloWorld

                                public static void main(String args)
                                Outer q = new Outer();

                                System.gc();
                                System.runFinalization();

                                q.method1().ok(4,1);





                                interface Ok

                                public void ok(int a, int b);



                                class Outer
                                private final int obj1 = 5;
                                public Ok method1()

                                Ok justDoIt = new Ok()
                                public void ok(int a, int b)

                                System.out.println(obj1+a+b);



                                ;

                                return justDoIt;




                                To be honest I don't exactly understand your question.



                                But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.



                                Think of a final variable this way:



                                public class HelloWorld

                                public static void main(String args)
                                Final<Integer> q = new Final();
                                q.set(5);
                                System.out.println(q.get());

                                q.set(10); // ERROR






                                class Final <T>

                                private T variable;
                                private Boolean setted=false;

                                public void set(T value) throws Error
                                if(setted)
                                throw new Error();


                                variable=value;
                                setted = true;


                                public T get()return variable;




                                And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it






                                share|improve this answer




















                                • If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
                                  – Rab
                                  9 mins ago










                                • OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
                                  – Antoniossss
                                  9 mins ago











                                • I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
                                  – Nertan Lucian
                                  6 mins ago










                                • You are missing the point and if you answered base on title, it is still off topic IMHO.
                                  – Antoniossss
                                  5 mins ago













                                up vote
                                -2
                                down vote










                                up vote
                                -2
                                down vote









                                This code displays 10, it's unaffected by garbage collector:



                                public class HelloWorld

                                public static void main(String args)
                                Outer q = new Outer();

                                System.gc();
                                System.runFinalization();

                                q.method1().ok(4,1);





                                interface Ok

                                public void ok(int a, int b);



                                class Outer
                                private final int obj1 = 5;
                                public Ok method1()

                                Ok justDoIt = new Ok()
                                public void ok(int a, int b)

                                System.out.println(obj1+a+b);



                                ;

                                return justDoIt;




                                To be honest I don't exactly understand your question.



                                But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.



                                Think of a final variable this way:



                                public class HelloWorld

                                public static void main(String args)
                                Final<Integer> q = new Final();
                                q.set(5);
                                System.out.println(q.get());

                                q.set(10); // ERROR






                                class Final <T>

                                private T variable;
                                private Boolean setted=false;

                                public void set(T value) throws Error
                                if(setted)
                                throw new Error();


                                variable=value;
                                setted = true;


                                public T get()return variable;




                                And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it






                                share|improve this answer












                                This code displays 10, it's unaffected by garbage collector:



                                public class HelloWorld

                                public static void main(String args)
                                Outer q = new Outer();

                                System.gc();
                                System.runFinalization();

                                q.method1().ok(4,1);





                                interface Ok

                                public void ok(int a, int b);



                                class Outer
                                private final int obj1 = 5;
                                public Ok method1()

                                Ok justDoIt = new Ok()
                                public void ok(int a, int b)

                                System.out.println(obj1+a+b);



                                ;

                                return justDoIt;




                                To be honest I don't exactly understand your question.



                                But, a final variable or a "non-final" variable for GC are the same things. The only restriction is that when you try to set it again you are blocked.



                                Think of a final variable this way:



                                public class HelloWorld

                                public static void main(String args)
                                Final<Integer> q = new Final();
                                q.set(5);
                                System.out.println(q.get());

                                q.set(10); // ERROR






                                class Final <T>

                                private T variable;
                                private Boolean setted=false;

                                public void set(T value) throws Error
                                if(setted)
                                throw new Error();


                                variable=value;
                                setted = true;


                                public T get()return variable;




                                And since you are creating a reference of the variable in the anonymous class, as long as you have the parent class referenced somewhere, it will linger and not be touched by gc. Even if the method is anonymous (or not), you still created a reference (pointer) to it







                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered 10 mins ago









                                Nertan Lucian

                                9219




                                9219











                                • If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
                                  – Rab
                                  9 mins ago










                                • OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
                                  – Antoniossss
                                  9 mins ago











                                • I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
                                  – Nertan Lucian
                                  6 mins ago










                                • You are missing the point and if you answered base on title, it is still off topic IMHO.
                                  – Antoniossss
                                  5 mins ago

















                                • If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
                                  – Rab
                                  9 mins ago










                                • OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
                                  – Antoniossss
                                  9 mins ago











                                • I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
                                  – Nertan Lucian
                                  6 mins ago










                                • You are missing the point and if you answered base on title, it is still off topic IMHO.
                                  – Antoniossss
                                  5 mins ago
















                                If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
                                – Rab
                                9 mins ago




                                If you don't understand the OP why would you post an answer to this question when it is already answered by 4 different people.
                                – Rab
                                9 mins ago












                                OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
                                – Antoniossss
                                9 mins ago





                                OP meant that he thought that even obj2 is not used in anon class it still holds reference to it (which is false btw). Its not about final or not declarations.
                                – Antoniossss
                                9 mins ago













                                I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
                                – Nertan Lucian
                                6 mins ago




                                I answered base on title, obj2 in op post has no outside reference as long as Outer class is not instantiated
                                – Nertan Lucian
                                6 mins ago












                                You are missing the point and if you answered base on title, it is still off topic IMHO.
                                – Antoniossss
                                5 mins ago





                                You are missing the point and if you answered base on title, it is still off topic IMHO.
                                – Antoniossss
                                5 mins ago


















                                 

                                draft saved


                                draft discarded















































                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53203529%2fare-all-final-variables-captured-by-anonymous-classes%23new-answer', 'question_page');

                                );

                                Post as a guest













































































                                Comments

                                Popular posts from this blog

                                What does second last employer means? [closed]

                                List of Gilmore Girls characters

                                Confectionery