What is the scope of the local variable/methods of an instance

后端 未结 4 2109
心在旅途
心在旅途 2021-01-21 14:56

I am testing the snippet below, I need to know how can I access t.x or t.hello? What is its scope? Do developers define variables in this way?

public class Test{         


        
相关标签:
4条回答
  • 2021-01-21 15:27

    Your code creates an anonymous inner class. It's (more-or-less) equivalent to doing this:

    public class Test {
        // ...
        private class TestAnonymousInner extends Test {
            int x = 0;
            //System.out.print("" + x);
            void hello(){
                System.out.print("inside hello\n");
            }
        }
    
        public static void main(String[] args) {
            Test t = new TestAnonymousInner();
            // invalid:
            // t.hello(); 
        }
    }
    

    If you look at the compiler output for that file, you'll notice a file named something like Test$1.class – that's the anonymous class you've defined.

    Since the variable you're storing the instance in is of type Test, the fields aren't accessible through it. They're accessible through reflection, or from the constructor expression. E.g. the following works, although it's not particularly useful:

    new Test() {
        void hello() {
            System.out.println("hello()");
        }
    }.hello(); // should print "hello()"
    

    Re: your edit. start() is a method of Thread. The variable tr is also of type Thread, so you can call its methods. Just not methods you add in an AIC.

    0 讨论(0)
  • 2021-01-21 15:27

    As written, neither x nor hello can be accessed outside the object referenced by t. The problem is that they are only declared in t's anonymous class. They are not defined in Test, and it is not possible to cast the t reference to the type in which they are declared, because it is anonymous.

    I have modified Test to make it abstract and add an abstract declaration of hello, allowing it to be called from outside the object referenced by t. I have also modified hello to add a use of x. Those changes illustrate the two ways of accessing anonymous class features - though the base class or internally.

    public abstract class Test {
    
      abstract void hello();
    
      public Test() {
        System.out.print("constructor\n");
      }
    
      public static void main(String[] args) {
    
        Test t = new Test() {
          int x = 0;
    
          // System.out.print("" + x);
          void hello() {
            System.out.print("inside hello\n");
            System.out.print("My value of x is "+x);
          }
        };
        t.hello();
    
      }
    }
    
    0 讨论(0)
  • 2021-01-21 15:35

    You should distinguish declaration and definition.

    In your case you declare a variable of class Test and assign it to an object of some class derived from Test (it's an anonymous class) which has some additional stuff in it.

    The code after this definition sees t of class Test only, it knows nothing about x and hello because Test doesn't have them.

    So, apart from reflection, you cannot use x and hello after definition of an anonymous class. And yes, developers use such variables when they need these variables inside of definition.

    It was mentioned that you can call methods and access variables that are not part of Test immediately after definition:

    int y = new Test(){
        int x = 0;
        //System.out.print("" + x);
        void hello(){
            System.out.print("inside hello\n");
        }
    }.x;
    

    This can be done because at this point the type of an object is know (it's the anonymous class). As soon as you assign this object to Test t, you lose this information.

    0 讨论(0)
  • 2021-01-21 15:51

    It creates an anonymous inner class. In this case it has little use. Anonymous classes are generally used to implement an interface without creating a whole new class. When you do that, you can add as many members as you want. For example:

    Runnable r = new Runnable() {
        int i = 0;
        public void run() {
            System.out.println(i++);
        }
    };
    

    By doing that, you have added a counter to your implementation of the Runnable interface (which does not have such a field) and every time you call r.run(); an incremented value gets printed.

    A less contrived example that uses a similar pattern:

    private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
        private final AtomicInteger threadId = new AtomicInteger();
    
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "Thread #" + threadId.incrementAndGet());
        }
    });
    

    Here, a basic implementation of ThreadFactory is provided which names each new Thread Thread #i.

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