Java 内部类 匿名类 匿名内部类

 

以下均来源于网络整理

 

一、内部类

https://www.cnblogs.com/wfq9330/p/8760031.html 

定义:根据创建位置的不同,分为成员的、方法的、匿名的。接口中的内部类叫做接口内部类。 
理解:在类的内部创建,那就是类的一部分,跟属性、方法同级。这也就解释了为何能访问外部私有成员,我是你的一部分,我当然可以访问了

1、成员内部类

class Outer {
    private int i = 1; 

    class Inner { 
        public void fun() {System.out.println("Outer I=" + i)} 
    } 
} 

2、方法内部类

class Outer{

    private String test;

    public void fun() {
        final int i = 1; // 被方法内部类访问的局部变量必须被final修饰

        class Inner { // 方法内部类 不能有访问修饰符,比如public
            public void print() {
                System.out.println("Method I=" + i + test);
            }
        }
    }
}

 

3、匿名内部类

interface USB {
    public abstract void start()
}

class Outer{

    public void fun() {
        final int i = 1; // 被匿名内部类访问的局部变量必须被final修饰
        new USB(){
            @Override
            public void start(){
                    System.out.println("local_var_i=" + i);
            }
        }.start();
    }
}        

4、静态内部类

class Outer{ 
    private int i = 1; 

    static class Inner{ // 不能访问外部类的非静态成员
        public void fun() {

         } 
    } 
}        

5、接口内部类

interface USB { 
    class Inner { // 默认是public static,即可以直接new USB.Inner();
    } 
} 

 

二、匿名内部类

https://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html

匿名内部类也就是没有名字的内部类

正因为没有名字,所以匿名内部类只能使用一次,当然也就不能有构造器

但使用匿名内部类:必须继承一个父类或实现一个接口

使用匿名内部类课使代码更加简洁、紧凑,模块化程度更高。

内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到,所以匿名内部类作用大

1、匿名内部类的基本实现

abstract class Person {
    public abstract void eat();
}
 
public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

运行结果:eat something

红色加粗的代码,就是匿名内部类,继承了 Person 类,却没有给出这个类的名字,直接实例化它并赋值给 p

如果不用匿名内部类,我们会这样写

abstract class Person {
    public abstract void eat();
}
 
class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}
 
public class Demo {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}
运行结果:eat something

先定义一个类,名字叫Child,用到的时候,Person p = new Child(); 用它的名字实例化它,然后赋值给 p,对比发现,定义匿名内部类,后面有大括号接类的方法,普通的实例化,没有大括号的内容

2、在接口上使用匿名内部类

interface Person {
    public void eat();
}
 
public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

运行结果:eat something

3、Thread类的匿名内部类实现

public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}
运行结果:1 2 3 4 5

4、Runnable接口的匿名内部类实现

public class Demo {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}
运行结果:1 2 3 4 5

三、匿名类

  我个人理解,一个没有名字的类--匿名类,必须依赖于一个现有的类中,才能存在,你在类外部定义一个匿名类,语法是通不过的,所以匿名类就是匿名内部类

四、特殊点

链接:https://www.zhihu.com/question/49330534/answer/115478102
除了只能使用一次,其实还有其他用处(在看spring-boot源码时发现的)
当你想使用一个类的protected 方法时,但是又不和这个类在同一个包下,你是没办法调用的。
这时候匿名类就派上用场了,你可以声明一个匿名类继承该类,并定义一个方法,在这个方法内使用super调用你想调用的那个方法(其实你也可以写个类继承这个类,就能调用父类的protected方法了,但是匿名类更简洁,因为你只想调用这个方法而已)

 

五、匿名对象与匿名内部类

匿名对象:没有名字的对象。

非匿名对象:

ClassName c=new ClassName();

c.run();

匿名对象:

new ClassName().run();

注意事项:

1、当对象对方法仅进行一次调用的时候,就可以简化成匿名对象。

2、两个匿名对象不可能是同一个对象。

3、一般不给匿名对象赋予属性值,因为永远无法获取到。

4、运行一次,直接就被回收掉了,节省内存空间。

 

posted @ 2020-06-05 15:53  老凯瑞  阅读(531)  评论(0编辑  收藏  举报