8. 面向对象编程 8.9 內部类

8. 面向对象编程

8.9 內部类

如果定义类在局部位置(方法中/代码块):(1) 局部内部类 (2) 匿名内部类

定义在成员位置 (1) 成员内部类 (2) 静态内部类

8.9.1基本介绍

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为內部类,嵌套其他类的类称为外部类。是类的第五大成员。【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类] 】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系,注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。

8.9.2 基本语法

class Outer{  //外部类
    class Inner{  //内部类
    }
}
class Other{  //外部其他类
}
//InnerClass01.java

8.9.3快速入门案例

代码

package com.ming.innerclass;

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

    }
}
class Outer{//外部类
    private int n1 = 100;//属性
    public Outer(int n1){//构造器
        this.n1 = n1;
    }
    {//代码块
        System.out.println("代码块");
    }
    class Inner{//內部类,在Outer类的内部

    }
}

8.9.4 内部类的分类

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

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

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

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

8.9.5 局部内部类的使用 LocalInnerClass.java

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

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

  2. 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final

  3. 作用域:仅仅在定义它的方法或代码块中。

  4. 局部内部类----访问----->外部类的成员 [访问方式:直接访问]

  5. 外部类----访问----->局部内部类的成员
    访问方式:创建对象,再访问(注意:必须在作用域内)

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

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

System.out.println("外部类的n2=" + 外部类名.this.n2);

package com.ming.innerclass;
/*
* 演示局部内部类的使用
* */
public class LocalInnerClass {
    public static void main(String[] args) {
        Outer02 outer02 = new Outer02();
        outer02.m1();
        System.out.println("outer02的hashCode值"+outer02);
    }
}

class Outer02{//外部类
    private int n1 = 100;
    private  void m2() {
        System.out.println("Outer02 m2()");
    }
    public void m1(){
        //1.局部内部类是定义在外部类的局部位置,通常在方法中
        //3.不能添加访问修饰符,但是可以使用final修饰
        //4.作用域:仅仅在定义它的方法或代码块中
        final class Inner02{//局部內部类
            //2.可以直接访问外部类的所有成员,包含私有的
            //7.如果外部类和局部內部类的成员重名是,默认遵循就近原则
            //如果想访问外部类的成员,使用外部类名.this.成员去访问
            private int n1 = 800;
            public void f1(){
                System.out.println("n1=" + Outer02.this.n1);
                System.out.println("Outer02.this)" + Outer02.this);
                m2();
            }
        }
        //5.外部类在方法中,可以创建Inner02对象,然后调用方法即可
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }

    {//代码块
        class Inner03 {

        }
    }
}

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

(1)本质是类、(2)内部类(3)无名字(4)同时是一个对象

定义在外部类的局部位置(如方法中 )

  1. 基本语法:`new 类或接口(参数列表){ 类体 };

案例演示关联文件:AnonymousInnerClass.java

package com.ming.innerclass;



public class AnonymousInnerClass {
    public static void main(String[] args) {
        new Outer04().method();
    }
}
class Outer04{//外部类
    private int n1 = 10;
    public void method() {
        //基于接口的匿名内部类
        //1.需求:想使用IA接口
        //2.传统方式,是写一个类实现接口并创建对象
        //3.现在需求是Tiger类只使用一次,后面不再使用
        //4.可以使用匿名內部类来简化开发
        //5.tiger 的编译类型 是 IA
        //6.tiger 的运行类型 是 匿名內部类
        /*
            我们看底层 会分配类名 Outer04$1
            class Outer04$1 implements IA{
                @Override
                public void cry() {
                    System.out.println("老虎叫~~");
                }
            }
        */
        //7.jdk在创建匿名內部类 Outer04$1,立即马上就创建了Outer04$1实例,
        //并且马上把地址返回给tiger
        //8.匿名内部类使用一次,就不能再使用了
        IA tiger = new IA(){
            @Override
            public void cry() {
                System.out.println("老虎叫~");
            }
        };
        System.out.println("tiger的运行类型:"+tiger.getClass());
        tiger.cry();
//        Tiger tiger = new Tiger();
//        tiger.cry();

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

        //基于抽象类的匿名內部类
        Animal animal =new Animal(){
            @Override
            void eat() {
                System.out.println("小狗吃骨头~");
            }
        };
        animal.eat();
    }
}
interface  IA{
    public void cry();
}
//class Tiger implements IA{
//    @Override
//    public void cry() {
//        System.out.println("老虎叫~~");
//    }
//}
class Father{
    public Father(String name){
        System.out.println("接受的name = " + name);
    }
    public void test(){
        System.out.println("我是父类的test()");
    }
}

abstract class Animal{
    abstract void eat();
}

AnonymousInnerClassDetail.java
2. 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。

  1. 可以直接访问外部类的所有成员,包含私有的 [案例演示]

  2. 不能添加访问修饰符,因为它的地位就是一个局部变量。[过]

  3. 作用域:仅仅在定义它的方法或代码块中。[过]

  4. 匿名内部类----访问----->外部类成员 [访问方式:直接访问]

  5. 外部其他类---不能访问----->匿名内部类(因为 匿名内部类地位是一个局部变量)

  6. 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

package com.ming.innerclass;

public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.f1();
        System.out.println("outer05 的hashCode值" + outer05);
    }
}
class Outer05 {
    private int n1  = 99;
    public  void f1(){
        //创建一个基于类的匿名內部类
        Person p = new Person(){
            private int n1 = 666;
            //可以直接访问外部类的所有成员,包含私有的
            //不能添加访问修饰符,因为作用就是一个局部变量
            //作用域仅在定义它的代码块和方法体中
            //如果外部类和局部內部类的成员重名是,默认遵循就近原则
            //如果想访问外部类的成员,使用外部类名.this.成员去访问
            @Override
            public void hi() {
                System.out.println("匿名內部类重写了hi方法  n1 = " + Outer05.this.n1);
                //Outer05.this就是调用f1的对象
                System.out.println("Outer05.this 的hashCode值" + Outer05.this);
            }


        };
        p.hi();//动态绑定,运行类型是 Ourer05$1

        //也可以直接调用 匿名內部类.方法
        //class 匿名內部类 extends Person{}
        new Person(){
            @Override
            public void hi() {
                System.out.println("匿名內部类重写了hi方法");
            }

            @Override
            public void ok(String str) {
                super.ok(str);
            }
        }.ok("45646");
    }

}
class Person {//类
    public void hi(){
        System.out.println("Person hi()");
    }
    public void ok(String str){
        System.out.println("Person ok()" + str);
    }
}

8.9.7匿名内部类的最佳实践

当做实参直接传递,简洁高效。InnerClassExercise02.java

package com.ming.innerclass;

public class InnerClassExercise02 {
    public static void main(String[] args) {
        CellPhone cellPhone = new CellPhone();
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒人起床了");
            }
        });
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("同学们上课了");
            }
        });
    }
}
interface Bell{
    void ring();
}
class CellPhone{
    public void alarmClock(Bell bell){
        bell.ring();
    }
}

8.9.9 成员内部类的使用

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

  1. 可以直接访问外部类的所有成员,包含私有的
class Outer01{//外部类
    private int n1 = 10;
    public String name = "张三";
    class Inner01{
        public void say(){
        	System.out.println("Outer01 的 n1 = " + n1 + " outer01 的 name = " + name );
		}
    }
}
  1. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。

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

  3. 成员内部类----访问----->外部类成员(比如:属性) [访问方式: 直接访问] (说明)

  4. 外部类----访问------->成员内部类 (说明)
    访问方式: 创建对象,再访问

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

  6. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员) 去访问

package com.ming.innerclass;

public class MemberInnerClass01 {
    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.getInner08();
        inner08Instance.say();
        //第三种
        new Outer08().new Inner08();
    }
}

class Outer08{
    private int n1 = 10;
    public String name = "张三";
    public void hi(){
        System.out.println("hi()方法...");
    }
    //1.注意:成员內部类,是定义在外部类的成员位置上
    //2.可以添加任意访问修饰符(public,protected,默认,private)
    class Inner08{//成员內部类
        //如果外部类和局部內部类的成员重名是,默认遵循就近原则
        //如果想访问外部类的成员,使用外部类名.this.成员去访问
        private int n1 = 66;
        private double sal = 99.8;
        public  void say(){
            System.out.println("n1=" + Outer08.this.n1+"     name="+name);
            hi();
        }
    }
    //方法返回一个Inner08的实例
    public Inner08 getInner08(){
        return new Inner08();
    }
    //写方法
    public void t1(){
        //使用成员内部类
        //创建成员内部类对象,然后使用相关方法
        Inner08 inner08 = new Inner08();
        inner08.say();
        System.out.println("inner08.sal="+inner08.sal);
    }
}

8.9.10 静态内部类的使用 StaticInnerClass01.java

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

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  2. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
  3. 作用域:同其他的成员,为整个类体
  4. 静态内部类----访问---->外部类(比如:静态属性) [访问方式:直接访问所有静态成员]
  5. 外部类----访问------>静态内部类 访问方式:创建对象,再访问
  6. 外部其他类----访问----->静态内部类
  7. 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
package com.ming.innerclass;

public class StaticnnerClass01 {
        public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.m1();

        //外部其他类使用 静态内部类
        //方式一
        //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //方式二
        // 在外部类中编写一个方法,可以返回Inner10对象实例
        Outer10.Inner10 inner11 = outer10.getInner10();
        inner11.say();

        Outer10.Inner10 inner10static = Outer10.getInner10static();
        inner10static.say();
    }
}

class Outer10{
        private int n1 = 10;
        private static  String name = "张三";
        //Inner10就是静态内部类
        //1.放在外部类的成员位置
        //2.使用static修饰
        //3.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非私有的
        //4.可以添加任意访问修饰符
        //5.作用域 :同其他的成员,为整个类体
        static class Inner10{
            private static  String name = "李四";
            public void say(){
                //如果外部类和局部內部类的成员重名是,默认遵循就近原则
                //如果想访问外部类的成员,使用外部类名.成员去访问
                System.out.println(name);
                System.out.println(Outer10.name);
            }
        }

        public void m1(){
            Inner10 inner10 = new Inner10();
            inner10.say();
        }
        public Inner10 getInner10(){
            return new Inner10();
        }

        public static Inner10 getInner10static(){
            return new Inner10();
        }
}
posted @ 2025-08-13 17:20  *珍惜当下*  阅读(7)  评论(0)    收藏  举报