到底什么是“内部类”?到底如何使用“匿名内部类”?

1.内部类

/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 14:27
 *
 * 如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
 * 例如:身体包含心脏,汽车包含发动机。。。
 * 内部类必须在外部类内部才能正常使用
 *--------------------------------------------------------------------
 * 分类:
 * 1.成员局部类
 * 2.局部内部类(包含匿名内部类)
 *=====================================================================
 * a.
 * 成员内部类定义格式:
 * 修饰符 class 外部类名称 {
 *     修饰符 class 内部类名称 {
 *         // TODO
 *     }
 *     // TODO
 * }
 * 注意事项:
 * 内用外,随意访问;外用内,需要内部类对象。
 * 使用方式:
 * 1.间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法
 * 2.直接方式,公式:
 *------>外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
 * ======================================================================
 * b.
 * 局部内部类定义格式:
 * 修饰符 class 外部类名称(参数列表){
 *     修饰符 返回值类型 外部方法名称(参数列表){
 *         class 局部内部类名称{
 *             // TODO
 *         }
 *     }
 * }
 * “局部”的意思是只有所属的方法可以使用,方法外不可用。
 * 局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final】的
 * 备注:
 * 从Java8开始,只要局部变量事实不变,那么final关键字可以shenglue。
 * 原因:
 * 1.new出来的对象在堆中
 * 2.局部变量是跟着方法走的,在栈内存中
 * 3.方法结束后,立刻出栈,局部变量就会消失
 * 4.new出来的对象还会在堆中持续存在,直到垃圾回收为止
 * ------------------------------------------------------------------------
 * 修饰符使用范围:
 * 1.外部类:public / (default)
 * 2.成员内部类:public / protected / (default) / private
 * 3.局部内部类:什么都不写
 */
public class InnerClass {

    public static void main(String[] args) {
        Body body = new Body();
        // 通过外部类的对象,调用外部类的方法,外部类的方法间接使用内部类
        body.methodBody();
        System.out.println("=========================");
        Body.Heart heart = new Body().new Heart();
        heart.beat();

        Outer.Inner obj = new Outer().new Inner();
        obj.methodInner();

        Outer2 outer2 = new Outer2();
        outer2.methodOuter();
    }
}
/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 14:33
 *
 * 编译完输出文件:
 * Body.class        外部类输出
 * Body$Heart.class  内部类输出
 */
public class Body {

    public class Heart {// 成员内部类

        public void beat(){
            System.out.println("心脏跳动");
            System.out.println("我叫," + name);
        }
    }

    // 外部类成员变量
    private String name;

    public void methodBody(){
        System.out.println("外部类方法");
        Heart heart = new Heart();
        heart.beat();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 14:49
 *
 * 如果出现了重名现象,那么格式是:---> 外部类名称.this.外部类成员变量名
 */
public class Outer {

    int num = 10;

    public class Inner{
        int num = 20;
        public void methodInner(){
            int num = 30;
            System.out.println(num);
            System.out.println(this.num);
            System.out.println(Outer.this.num);
        }
    }
}
/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 14:56
 */
public class Outer2 {

    public void methodOuter(){
        int num = 50;
//        num = 20; // 错误写法

        // 局部内部类任何修饰符都不能写
        class Inner { // 局部内部类
//            int num = 100;
            public void methodInner(){
                System.out.println(num);
            }
        }

        Inner inner = new Inner();
        inner.methodInner();
    }
}

2.匿名内部类

/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 15:58
 *
 * 如果接口的实现类(或者父类的子类),只需要使用唯一一次,
 * 就可以省略类的定义,改为直接使用【匿名内部类】
 *
 * 匿名内部类格式:
 * 接口名称 对象名 = new 接口名称(){
 *     // 覆盖重写接口中所有抽象方法
 * };
 * 格式中,大括号之间的是一个类,它没有名字,并且实现了接口中的抽象方法
 * 好处:
 * 为了使用接口,不得不针对接口做一个实现类,如果只使用一次,不想单独定义一个类---
 * ---> 可以直接 new 接口(){}; 补充一个大括号,在大括号中实现一个没有名字的类,随用随定义
 *
 * 对格式 “new 接口名称() {...} 进行解析:
 * 1.new 代表创建对象的动作
 * 2.接口名称就是匿名内部类需要实现哪个接口的抽象方法
 * 3.{...} 大括号之间的内容是匿名内部类的内容
 *
 * 注意几点问题:
 * 1.匿名内部类在创建对象时,只能使用唯一一次,如果希望多次使用,需要单独定义实现类
 * 2.匿名对象,在【调用方法】的时候,只能调用唯一一次
 * 如果希望同一个对象,调用多次方法,那么必须给对象起一个名字
 * 3.匿名内部类是省略了【实现类(或子类)】的名称
 *   匿名对象是省略了【对象名称】
 * 强调:二者不是同一回事
 */
public class MainTest {

    public static void main(String[] args) {
        MyInterfaceImpl impl = new MyInterfaceImpl();
        impl.method1();
        impl.method2();
        System.out.println("=============");
        MyInterface obj = new MyInterfaceImpl();
        obj.method1();
        obj.method2();
        System.out.println("==============");

        // 使用匿名内部类
        // 匿名内部类,不是匿名对象,对象名字叫做 niMing
        MyInterface niMing = new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现的方法111-A");
            }

            @Override
            public void method2() {
                System.out.println("匿名内部类实现的方法222-A");
            }
        };
        niMing.method1();
        niMing.method2();
        System.out.println("==============");

        // 匿名内部类,同时是匿名对象
        new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现的方法111-B");
            }

            @Override
            public void method2() {
                System.out.println("匿名内部类实现的方法222-B");
            }
        }.method1();

        new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现的方法111-B");
            }

            @Override
            public void method2() {
                System.out.println("匿名内部类实现的方法222-B");
            }
        }.method2();
    }
}
/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 15:55
 */
public interface MyInterface {

    void method1();
    void method2();
}
/**
 * @author : sunkepeng E-mail:[email protected]
 * @date : 2020/7/22 15:56
 */
public class MyInterfaceImpl implements MyInterface{

    @Override
    public void method1() {
        System.out.println("实现类覆盖重写了方法111");
    }

    @Override
    public void method2() {
        System.out.println("实现类覆盖重写了方法222");
    }
}

猜你喜欢

转载自blog.csdn.net/kepengs/article/details/107514477
今日推荐