内部类

SOBER大约 6 分钟

内部类

基本介绍

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为**内部类(inner class)**嵌套其他类的类称为外部类 (outer class) 。是我们类的第五大成员,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系

思考: 类的五大成员是哪些?

属性、方法、构造器、代码块、内部类,

基本语法

/** 外部类 */
class Outer{
    /** 内部类 */
    class Inner{}
}
class Other {} /** 外部其他类 */

内部类的分类

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

  1. 局部内部类(有类名)
  2. 匿名内部类(没有类名,重)

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

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

局部内部类的使用

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

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用 final 修饰,因为局部变量也可以使用final
  3. 作用域: 仅仅在定义它的方法或代码块中。
  4. 局部内部类---访问---->外部类的成员【访问方式: 直接访问】
  5. 外部类---访问---->局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】
    public class LocalInnerClass01 {
        public static void main(String[] args) {
            Outer02 outer02 = new Outer02();
            outer02.m1();
        }
    }
    
    class Outer02 {
        /** 私有属性和方法 */
        private int n1 = 100;
        private void m2() {
            System.out.println("Outer + m2方法");
        }
        public void m1(){
            /** 内部类通常在方法里面,他本身也是一个类 */
            class Inner02 {
                public void f1(){
                    /** 内部类可以直接访问外部类的所有成员 */
                    System.out.println("n1= " + n1);
                    m2();
                }
            }
            /** 可以家加 final 修饰符 */
            final class Inner03 {}
            class Inner04 extends Inner02 {
                public void f2(){}
            }
            /** 外部类在方法中,可以创建对象,然后调用方法即可 */
            Inner03 inner03 = new Inner03();
            Inner02 inner02 = new Inner02();
            Inner04 inner04 = new Inner04();
            inner02.f1();
            inner04.f2();
        }
        /** 代码块中的内部类 */
        {
            class Inner05 {}
        }
    }
    
  6. 外部其他类不能访问局部内部类( 局部内部类地位是一个局部变量)
  7. 外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问[演示]
    public class LocalInnerClass01 {
        public static void main(String[] args) {
            Outer02 outer02 = new Outer02();
            outer02.m1();
        }
    }
    
    class Outer02 {
        private int n1 = 100;
        public void m1(){
            class Inner02 {
                private int n1 = 800;
                public void f1(){
                    System.out.println("内部类 " + n1 + " 外部类" + Outer02.this.n1);
                }
            }
    }
    

匿名内部类的使用(重要!!!!!!!)

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

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

基本语法

new 类或接口(参数列表){
    类体
}

演示(基于接口)

需求(为什么使用匿名类):想使用接口 PP 并创建对象

传统方式

写一个类,实现接口, 并创建对象

public class Anonymous {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 {
    private int n1 = 10;
    public void method(){
        /**
         * 需求是 Tiger 只使用一次,后面不适用
         * 所以使用内部类来简化
         **/
        Tiger tiger = new Tiger();
        Dog dog = new Dog();
        tiger.cry();
        dog.cry();
    }
}

/** 接口 */
interface PP{
    public void cry();
}
/** 实现接口 */
class Tiger implements PP{
    @Override
    public void cry() {
        System.out.println("传统方式实现接口 Tiger");
    }
}

class Dog implements PP{
    @Override
    public void cry() {
        System.out.println("传统方式实现接口 Dog");
    }
}

匿名类实现

public class Anonymous {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 {
    private int n1 = 10;
    public void method(){
        /**
         * 1. 需求是 Tiger 只使用一次,后面不适用
         * 2. 所以使用内部类来简化
         * 3. taiger 的编译类型?
         * 4. taiger 的运行类型? 匿名类(Outer04$1)【匿名类名字是:类名+$1】
         * 5. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 outer04S1实例,并且把地址返回给 tiger
         * 6. 匿名内部类使用一次,就不能再使用
         **/
        PP taiger =  new PP() {
            @Override
            public void cry() {
                System.out.println("老虎交换");
            }
        };
        System.out.println("taiger的运行类型=" + taiger.getClass());
        taiger.cry();
    }
}

/** 接口 */
interface PP{
    public void cry();
}

演示(基于类)

public class Anonymous {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 {
    private int n1 = 10;
    public void method(){
        /**
         * 1. father 的编译类型? Father
         * 2. father 的运行类型? 匿名类(Outer04$1)【匿名类名字是:类名+$1】
         * 3. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 outer04S1实例,并且把地址返回给 father
         **/
        Father father = new Father("JACK"){};
        System.out.println("father的运行类型=" + father.getClass());
        father.test01();

        /** 匿名类也可以直接调用 */
        new Father("JACK"){}.test01();
    }
}

class Father{
    public Father(String name){
        super();
    }
    public void test01(){
        System.out.println("老虎交换");
    }
}

实践简化

public class Anonymous {
    public static void main(String[] args) {
        f1(new PP() {
            @Override
            public void cry() {
                System.out.println("实践简化");
            }
        });
    }
    public static void f1(PP pp){
        pp.cry();
    }
}

/** 接口 */
interface PP{
    void cry();
}
public class Anonymous {
    public static void main(String[] args) {
        f1(new Picrure());
    }
}
/** 接口 */
interface PP{
    void cry();
}

class Picrure implements PP {
    @Override
    public void cry() {
        System.out.println("实现接口传参");
    }
}

成员内部类

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

  1. 1.可以直接访问外部类的所有成员,包含私有的
  2. 可以添加任意访问修饰符( public、protected 、默认、private),因为它的地位就是一个成员。
  3. 作用:和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法
  4. 成员内部类---访问---->外部类(比如: 属性)[访问方式:直接访间]
  5. 外部类---访问------>内部类 访问方式: 创建对象,再访问
  6. 外部其他类---访问---->成员内部类
  7. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

演示

public class Outer08 {
    public static void main(String[] args) {
        // 1.使用外部类,调用内部类方法
        Inner08 inner08 = new Inner08();
        inner08.says();
        // 2.直接实例化内部类
        Inner08.InnerClass innerClass = inner08.new InnerClass();
        innerClass.say();
        // 3.直接使用方法返回的实例
        Inner08.InnerClass innerClass1 = inner08.getInnerClass();
        innerClass1.say();
    }
}

class Inner08 {
    private int n2 = 10;
    public String name = "账单";
    class InnerClass {
        public void say(){
            System.out.println(n2 + name);
        }
    }
    public void says(){
        // 外部类方法实例化内部类
        InnerClass innerClass = new InnerClass();
        innerClass.say();
    }
    // 该方法返回内部类实例
    public InnerClass getInnerClass(){
        return new InnerClass();
    }

}

静态内部类

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

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  2. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是个成员。
  3. 作用域: 同其他的成员,为整个类体
  4. 静态内部类---访问---->外部类(比如: 静态属性)[访问方式: 直接访问所有静态成员]
  5. 外部类---访问--->静态内部类 访问方式:创建对象,再访问

演示

public class Outher10 {
    public static void main(String[] args) {
        InnerClass10.Inner10 inner10 = new InnerClass10.Inner10();
        inner10.scy();
    }
}

class InnerClass10 {
    private int n1 = 10;
    private static String name = "JJJJ";
    static class Inner10 {
        public void scy(){
            System.out.println(name);
        }
    }
}

小结

内部类有四种

  1. 局部内部类
  2. 匿名内部类
  3. 成员内部类
  4. 静态内部类

注意

成员内部类,静态内部类,是放在外部类的成员位置,本质就是一个成