java 四种内部类

四种内部类

基本介绍:一个类的内部又完整嵌套了了另一个类结构,被嵌套的类称为内部类

属性,方法,构造器,代码块,内部类 类的五大成员

内部类是学习的难点,同事也是重点,后面看底层源码时,有大量得到内部类

1.定义在外部类的局部位置上(比如方法内) :

  1. 局部内部类(有类名)
  2. 匿名内部类(没有类名,重点!!!!!一把梭哈

2.定义在外部类的成员位置上

  1. 成员内部类(没用 static 修饰)
  2. 静态内部类(static 修饰)

局部内部类(有类名)

说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为它的位置就是一个局部变量,局部变量是不能使用访问修饰符的。但是可以使用 final 修饰,因为局部变量可以使用 final
  3. 作用域:仅仅在定义它的方法或代码块中。
  4. 局部内部类----访问----> 外部类的成员[访问方式:直接访问]
  5. 外部类 ---- 访问 ----- > 局部内部类成员 访问方式 : 创建对象,在访问(注意:必须在作用域内)
package com.wxledu.innercass;

/**
 * 演示局部内部类的使用
 */
public class LocalInnerClass {
    public static void main(String[] args) {
        //演示一下
        Outer02 outer02 = new Outer02();
        outer02.m1();
    }
}

class Outer02{//外部类
    private int n1 = 100;

    private void m2(){}//私有方法
    public void m1(){//方法
        // 1. 局部内部类是定义在外部类的局部位置,通常在 方法
        // 2. 不能添加访问修饰符,但是可以使用 final 修饰,因为局部变量可以使用 final 修饰
        // 3. 作用域 : 仅仅在定义它的方法 和 代码块中
        class Inner02{//局部内部类(本质还是一个类)
            // 4. 可以直接访问外部类的所有成员,包含私有的
            public void f1(){
                // 5. 局部内部类直接访问外部类的成员。 比如下面  n1  m2()
                System.out.println("n1 = " + n1);
                m2();
            }
        }
        // 6. 外部类可以在这个方法中创建 Inner02 对象,然后调用方法即可
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }
}

记住 (1) 局部内部类是定义在方法中 / 代码块. (2) 作用域在方法体或者代码块 (3) 本质仍然是一个类

  1. 外部其他类 --- 不能访问 ----> 局部内部类(因为局部内部类的地位是一个局部变量)
  2. 如果外部类和局部内部类的成员重名时,默认遵循就进原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员) 去访问

匿名内部类

  1. 本质是类
  2. 内部类
  3. 该类没有名字 (匿名)
  4. 同时还是一个对象

说明: 匿名内部类是定义在外部类的局部位置,比如在方法中,并且没有类名

为什么要使用匿名内部类?

​ 很多时候是为了简化开发,或者基于一个类去创建一个新的类,有时候这个类只想使用一次

package com.wxledu.innercass;

/**
 * 演示匿名内部类的使用
 */
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}


class Outer04{
    private int n1 = 10; //属性

    public void method(){//方法
        //基于接口的匿名内部类
        // 1. 需求:想使用接口 IA, 并创建对象
        // 2. 传统方式:是写一个类,实现该接口,并创建对象
        // 3. 希望 tiger 这个类值使用一次,以后再也不使用了
        // 4. 可以使用匿名内部类简化开发
        // 5. tiger 的编译类型:IA (看等号左边)
        // 6. tiger 的运行类型:就是匿名内部类 XXX => Outer04$1

        /*
                我们看底层
                class XXXX implements IA{
                    @Override
                    public void cry() {
                        System.out.println("老虎叫唤......");
                    }
                }
         */

        // 7. jdk 底层,在创建了匿名内部类 Outer04$1 ,立即马上创建了 Outer04$1 实例, 并且把地址返回给 tiger

        IA tiger = new IA(){
            @Override
            public void cry() {
                System.out.println("老虎叫唤.....");
            }
        };
        System.out.println("tiger的运行类型 = " + tiger.getClass());
        tiger.cry();
        tiger.cry();

        // 演示基于类的匿名内部类
        // 分析
        // 1.  编译类型是 father
        // 2.  运行类型是  Outer04$2
        // 3.  底层会会创建一个匿名内部类
        /*
                class Outer04$2 extends father{}
         */
        // 4. 同事也直接返回了 匿名内部类 Outer04$2 这个对象
        // 5. 注意 : 参数列表会传递给 构造器
        father jack = new father("jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了 test() 方法");
            }
        };
        System.out.println("father对象的运行类型 = " + jack.getClass());
        jack.test();

        //基于抽象类的匿名内部类
        Animal animal = new Animal(){
            @Override
            void eat() {
                System.out.println("实现了 抽象类的 eat() 方法");
            }
        };
        animal.eat();
    }
}

interface IA{
    public void cry();
}

class father{//类

    public father(String name) {//构造器
        System.out.println("接受到" + name);
    }

    public void test(){}
}

abstract class Animal{
    abstract void eat();
}
  • 匿名内部类的使用
  1. 匿名内部类的语法比较奇特,请大家注意,匿名内部类即是一个类的定义,同时他本身也是一个对象,因此从语法上看,他既有定义类的特征,也有创建对象特征,对代码分析可以看出这个特点,因此可以调用匿名内部类方法
  2. 可以直接访问外部类的所有成员,包括私有的
  3. 不能添加访问修饰符,因为他的地位就是一个局部变量
  4. 作用域:仅仅在定义它的代码块中
  5. 匿名内部类 ---- > 访问 ----> 外部类成员 [访问方式 直接访问]
  6. 外部其他类 ------ > 不能访问 -------> 匿名内部类
  7. 如果外部类和内部类的成员重名时,内部类访问的话,必须遵循就进原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问

匿名内部类的最佳实践

  • 当做实参世界传递,简介高效

匿名内部类

  1. 继承
  2. 多态
  3. 动态绑定
  4. 内部类

3.成员内部类

说明:定义在外部类的成员位置。并且没有static修饰

  1. 可以直接访问外部类的所有成员,包含私有的

  2. 可以添加任意访问修饰符(public, protected, 默认,private),因为它的地位就是一个成员

  3. 作用域和外部类的其他成员一样,为整个类体,比如前面的案例,在外部类的成员方法中创建成员和内部类对象,在调用方法

  4. 成员内部类 ------> 访问 --------> 外部类的成员(比如:属性) 【访问方式 直接访问】

  5. 外部类 ----> 访问 -----> 内部类 【访问方式 创建对象在访问】

  6. 外部其他类 ----> 访问 -----> 成员内部类

    package com.wxledu.innercass;
    
    public class MemberInnerClass {
        public static void main(String[] args) {
            Outer08 outer08 = new Outer08();
            outer08.t1();
    
            //外部其他类使用成员内部类的三种方式
    
            // 解读
            // 第一种方式
            // outer08.new Inner08()   相当与 把 new Inner08()  当做  outer08  的成员
            // 这就是一个语法,不用特别纠结
            Outer08.Inner08 inner08 = outer08.new Inner08();
            inner08.say();
    
            // 第二种方式,在外部类中,编写一个方法,返回 Inner08 的对象池
            Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
            inner08Instance.say();
    
            // 第三种方式
        }
    
    
    }
    
    
    class Outer08{//外部类
        private int n1 = 10;
        public String name = "张三";
    
        class Inner08{//成员内部类
            private int n2 = 99;
            private int n1 = 66;
            public void say(){
                //可以直接访问外部类的所有成员,包含私有的
                // 如果内部类的成员和外部类成员重名,则遵循就进原则
                System.out.println("Outer08 的 n1 = " + n1 + ",Outer08 的 name = " + name + "外部类 的 n1 = " + Outer08.this.n1);
            }
        }
    
        // 该方法返回一个  Inner08 实例
        public Inner08 getInner08Instance(){
            return new Inner08();
        }
    
        //写方法
        public void t1(){
            //使用成员内部类
            //创建成员内部类的对象,然后直接使用
            Inner08 inner08 = new Inner08();
            inner08.say();
            System.out.println(inner08.n2);
        }
    }
    

4.静态内部类

说明:静态内部类是定义在外部类的成员位置,并且有 static 修饰

  1. 可以访问外部类的所有成员,包含私有的,但不能访问非静态成员
  2. 可以添加任意访问修饰符(public, protected, 默认 , private), 因为他的地位就是一个成员
  3. 作用域: 同其他成员,为整个类体
  4. 如果外部类和静态内部类成员重名时,静态内部类重名时默认遵循就进原则,如果想访问外部类名,(外部类名.成员)
package com.wxledu.innercass;

public class StaticInnerClass {
    public static void main(String[] args) {

        Outer10 outer10 = new Outer10();
        outer10.show();


        //外部其他类----->  访问  ----->  内部静态类

        //方式一
        //因为静态内部类,是可以通过类名直接访问的,(前提是满足访问条件)
        Outer10.Inner02 inner02 = new Outer10.Inner02();
        inner02.say();
        //方式二
        //编写一个方法,可以返回静态类对象
        Outer10.Inner02 inner021 = outer10.getInner02();
        System.out.println("========");
        inner021.say();

        Outer10.Inner02 inner022 = Outer10.getInner02_();
        System.out.println("******");
        inner022.say();
    }
}

class Outer10{//外部类
    private int n1 = 10;
    private static String name = "张三";
    static class Inner02{//静态内部类
        public void say(){
            System.out.println(name);
            // 不能访问外部类的非静态成员
            //System.out.println(n1);
        }
    }

    public void show(){
        // 外部类使用内部类
        new Inner02().say();
    }

    public Inner02 getInner02(){
        return new Inner02();
    }

    public static Inner02 getInner02_(){
        return new Inner02();
    }
}

重点掌握匿名内部类的使用

posted @ 2023-10-11 22:20  TomLove  阅读(63)  评论(0)    收藏  举报