美文网首页
内部类-匿名内部类

内部类-匿名内部类

作者: ae12 | 来源:发表于2018-10-12 17:48 被阅读45次

    https://www.geeksforgeeks.org/anonymous-inner-class-java/
    Anonymous Inner Class in Java
    It is an inner class without a name and for which only a single object is created. An anonymous inner class can be useful when making an instance of an object with certain “extras” such as overloading methods of a class or interface, without having to actually subclass a class.
    一个没有名字的内部类,只创建一个实例。当创建具有某些“额外”的对象的实例(例如重载类或接口的方法)时,匿名内部类可能很有用,而不必实际对类进行子类化。
    匿名内部类的作用:
    Anonymous inner classes are useful in writing implementation classes for listener interfaces in graphics programming.
    匿名内部类在为图形编程中的监听器接口编写实现类时很有作用。
    匿名内部类,android 开发以及java 开发一般都会遇到“为View注册监听器的“
    代码如下:

          Button button =(Button)  findViewById(R.id. btn_main_download);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    
                }
            });
    
    

    可以看出,这个类 (new View.OnClickListener )没有名字,

    //Java program to demonstrate need for Anonymous Inner class 
    interface Age 
    { 
        int x = 21; 
        void getAge(); 
    } 
    class AnonymousDemo 
    { 
        public static void main(String[] args)  
        { 
            // Myclass is implementation class of Age interface 
            MyClass obj=new MyClass(); 
      
            // calling getage() method implemented at Myclass 
            obj.getAge();      
        } 
    } 
      
    // Myclass implement the methods of Age Interface 
    class MyClass implements Age 
    { 
        @Override
        public void getAge()  
        { 
            // printing the age 
            System.out.print("Age is "+x); 
        } 
    } 
    

    In the program, interface Age is created with getAge() method and x=21. Myclass is written as implementation class of Age interface. As done in Program, there is no need to write a separate class Myclass. Instead, directly copy the code of Myclass into this parameter, as shown here:
    其实没必要写MyClass ,而是把MyClass拷贝到参数里,如下:

    Age oj1 = new Age() {
                @Override
                public void getAge() {
                    System.out.print("Age is "+x);
                }
            };
    

    用匿名类的代码改写为
    Anonymous inner class version of the above Program

    
    //Java program to demonstrate Anonymous inner class 
    interface Age 
    { 
        int x = 21; 
        void getAge(); 
    } 
    class AnonymousDemo 
    { 
        public static void main(String[] args) { 
      
            // Myclass is hidden inner class of Age interface 
            // whose name is not written but an object to it  
            // is created. 
            Age oj1 = new Age() { 
                @Override
                public void getAge() { 
                     // printing  age 
                    System.out.print("Age is "+x); 
                } 
            }; 
            oj1.getAge(); 
        } 
    } 
    ```source-java
    
    匿名类的3种类型:
    
    1.Anonymous Inner class that extends a class : We can have an anonymous inner class that extends a class.For example,we know that we can create a thread by extending a Thread class. Suppose we need an immediate thread but we don’t want to create a class that extend Thread class all the time. By the help of this type of Anonymous Inner class we can define a ready thread as follows:
    继承一个类的匿名内部类:例如我们想要立即创建一个线程,但是又不想创建一个类 继承Thread,此时我们就可以定义一个匿名类如下:
    ```source-java
    //Java program to illustrate creating an immediate thread 
    //Using Anonymous Inner class that extends a Class 
    class MyThread  
    { 
        public static void main(String[] args) 
        { 
            //Here we are using Anonymous Inner class 
            //that extends a class i.e. Here a Thread class 
            Thread t = new Thread() 
            { 
                public void run() 
                { 
                    System.out.println("Child Thread"); 
                } 
            }; 
            t.start(); 
            System.out.println("Main Thread"); 
        } 
    } 
    

    Output:

    Main Thread
    Child Thread
    OR
    Child Thread
    Main Thread
    

    2.Anonymous Inner class that implements a interface : We can also have an anonymous inner class that implements an interface.For example, we also know that by implementing Runnable interface we can create a Thread. Here we use anonymous Inner class that implements an interface.
    实现接口的匿名内部类:例如我们可以实现Runnable接口去创建一个Thread.下面👇就是实现接口的匿名内部类:

    //Java program to illustrate defining a thread 
    //Using Anonymous Inner class that implements an interface 
    class MyThread  
    { 
        public static void main(String[] args) 
        { 
            //Here we are using Anonymous Inner class 
            //that implements a interface i.e. Here Runnable interface 
            Runnable r = new Runnable() 
            { 
                public void run() 
                { 
                    System.out.println("Child Thread"); 
                } 
            }; 
            Thread t = new Thread(r); 
            t.start(); 
            System.out.println("Main Thread"); 
        } 
    } 
    

    Output:

    
    Main Thread
    Child Thread
    OR
    Child Thread
    Main Thread
    

    3.Anonymous Inner class that defines inside method/constructor argument : Anonymous inner classes in method/constructor arguments are often used in graphical user interface (GUI) applications. To get you familiar with syntax lets have a look on the following program that creates a thread using this type of Anonymous Inner class :

    定义内部方法/构造函数参数的匿名内部类:
    方法/构造函数参数中的匿名内部类通常用于图形用户界面(GUI)应用程序。为了让您熟悉语法,让我们看一下使用这种Anonymous Inner类创建线程的以下程序:
    (我们开头举例子的那个监听器,就是定义在方法参数的匿名内部类,真的很常用,也很常见)
    //Java program to illustrate defining a thread
    //Using Anonymous Inner class that define inside argument

    class MyThread  
    { 
        public static void main(String[] args) 
        { 
            //Here we are using Anonymous Inner class 
            //that define inside argument, here constructor argument 
            Thread t = new Thread(new Runnable() 
            { 
                public void run() 
                { 
                    System.out.println("Child Thread"); 
                } 
            }); 
              
            t.start(); 
              
            System.out.println("Main Thread"); 
        } 
    } 
    
    

    output:

    Main Thread
    Child Thread
    OR
    Child Thread
    Main Thread
    

    再加一个例子,代码:

    public class OuterClass {
        public InnerClass getInnerClass(final int num,String str2){
            return new InnerClass(){
                int number = num + 3;
                public int getNumber(){
                    return number;
                }
            };        /* 注意:分号不能省 */
        }
        
        public static void main(String[] args) {
            OuterClass out = new OuterClass();
            InnerClass inner = out.getInnerClass(2, "chenssy");
            System.out.println(inner.getNumber());
        }
    }
    
    interface InnerClass {
        int getNumber();
    }
    
    
    Output:
    5
    

    这里我们就需要看清几个地方

        1、 匿名内部类是没有访问修饰符的。
    
         2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。
    
         3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
    
        4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。
    

    Difference between Normal/Regular class and Anonymous Inner class:
    匿名内部类和 一般类的区别:
    A normal class can implement any number of interfaces but anonymous inner class can implement only one interface at a time.
    A regular class can extend a class and implement any number of interface simultaneously. But anonymous Inner class can extend a class or can implement an interface but not both at a time.
    For regular/normal class, we can write any number of constructors but we cant write any constructor for anonymous Inner class because anonymous class does not have any name and while defining constructor class name and constructor name must be same.
    一般类可以实现几个接口,但是内部类只能实现一个
    一般类可以同时继承一个类并implement多个接口,但是匿名内部类只能一次做一件事,要么继承一个要么implement 一个接口,且仅一个。
    一般类可以有几个构造函数,但是匿名内部类没有构造函数,因为内部类没有名字,而在定义构造函数时构造函数名字必须和类名一样。

    /** 以下不是太理解
    Accessing Local Variables of the Enclosing Scope, and Declaring and Accessing Members of the Anonymous Class
    访问封闭范围的本地变量,以及声明和访问匿名类的成员

    Like local classes, anonymous classes can capture variables; they have the same access to local variables of the enclosing scope:

    An anonymous class has access to the members of its enclosing class.
    An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final.
    Like a nested class, a declaration of a type (such as a variable) in an anonymous class shadows any other declarations in the enclosing scope that have the same name.
    **/

    Anonymous classes also have the same restrictions as local classes with respect to their members:
    匿名类对其成员也具有与本地类相同的限制
    We cannot declare static initializers or member interfaces in an anonymous class.
    不可以在内部类里定义static (静态)成员变量和静态方法。
    An anonymous class can have static members provided that they are constant variables.

    匿名类可以具有静态成员,前提是它们是常量变量。
    Note that you can declare the following in anonymous classes:

    Fields
    Extra methods (even if they do not implement any methods of the supertype)
    Instance initializers
    Local classes

    其他“关于使用的形参是final修饰的“
    或是“# Why are only final variables accessible in anonymous class?
    “为什么在匿名类中只能访问最终变量?”
    https://blog.csdn.net/chenssy/article/details/13170015
    有一段回答:
    Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned before the body of the inner class.

    任何在内部类中使用但是没有声明的局部变量、形式方法参数、异常处理程序参数都必须声明为final.必须在内部类的主体之前明确地分配在内部类中使用但未声明的任何局部变量。
    How can I return the 5 * a when it clicked? I mean,
    //编译器相当于拷贝了外部自由变量x的一个副本到匿名内部类里

    用R大回答里的原话说就是:
    java编译器实现的只是capture-by-value,并没有实现capture-by-reference。
    而只有后者才能保持匿名内部类和外部环境局部变量保持同步

    当final修饰基本类型变量时,不可更改其值,当final修饰引用变量时,不可更改其指向,只能更改其对象的内容。

    试想,假设允许对外部局部变量不加final,那当你在匿名内部类里面尝试改变外部基本类型的变量的值的时候,或者改变外部引用变量的指向的时候,表面上看起来好像都成功了,但实际上并不会影响到外部的变量。所以,Java为了不让自己看起来那么奇怪,才加了这个final的限制。

    当然在JDK 1.8及以后,看起来似乎编译器取消了这种限制,没有被声明为final的变量或参数也可以在匿名内部类内部被访问了。但实际上是因为Java 8引入了effectively final的概念(A variable or parameter whose value is never changed after it is initialized is effectively final)。所以,实际上是诸如effectively final的变量或参数被Java默认为final类型,所以才不会报错(最简单的测试方式:将上述代码integer变量取消final修饰(effectively final),试一下,在下面对其重新赋值(not effectively final),再试一下),而上述的根本原因没有任何变化。

    private void f(Button b, final int a){
    b.addClickHandler(new ClickHandler() {

        @Override
        public void onClick(ClickEvent event) {
             int b = a*5;
             return b; // but return type is void 
        }
    });
    

    }

    使用的形参为何要为final
    。内部类(Inner Class)通过包含一个指向外部类的引用,做到自由访问外部环境类的所有字段,变相把环境中的自由变量封装到函数里,形成一个闭包。


    java内部类指向外部类的引用.png

    【闭包(Closure):
    什么是闭包,大白话不怎么严谨的说就是:
    1.一个依赖于外部环境自由变量的函数
    2.这个函数能够访问外部环境里的自由变量】

    https://blog.csdn.net/u011617742/article/details/51613519

    相关文章

      网友评论

          本文标题:内部类-匿名内部类

          本文链接:https://www.haomeiwen.com/subject/jhcgaftx.html