Java内部类最细详解

内部类(本质上还是一个类)

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

内部类有四种:局部内部类、匿名内部类 ||| 成员内部类、静态内部类

  1. 内部类的分类:

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

      1. 局部内部类(有类名)

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

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

          局部变量不能使用访问修饰符。但可以使用final修饰,因为局部变量也可以使用final

        • 作用域:仅仅在定义它的方法中或者代码块中

        • 局部内部类访问外部类成员----->直接访问

        • 外部类在方法中可以创建对象实例 然后调用方法即可

        • 外部其他类不能局部内部类

        • 如果外部类和局部内部类的成员重名时,默认遵循就近原则。

          如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

          外部类名.this 本质就是外部类对象 即哪个对象调用了m1,Outer.this就是哪个对象

          /**
           * @author caicai
           * 演示局部内部类的使用
           */
          public class LocalInnerClass {
              public static void main(String[] args) {
                  Outer outer = new Outer();
                  outer.m1();
                  System.out.println("外部outer hashcode" + outer.hashCode());
              }
          }
          
          /**
           * 外部类
           */
          class Outer {
              private int n1 = 100;
          
              private void m2() {
                  System.out.println("这是m2方法");
              }
          
              public void m1() {
                  /*
                   * 局部内部类是定义在外部类的局部位置上的 通常在方法
                   */
                  final class InnerOuter { // 局部内部类(本质仍是一个类)
                      // 可以直接访问外部类的所有成员 包括私有的
                      private int n1 = 800;
          
                      public void f1() {
                          // 局部内部类访问外部类成员----->直接访问
                          System.out.println("n1 = " + n1);
                          System.out.println("外部类的n1 = " + Outer.this.n1);
                          System.out.println("内部Outer.this hashcode" + Outer.this.hashCode());
          
                          m2();
                      }
                  }
                  InnerOuter innerOuter = new InnerOuter();
                  innerOuter.f1();
              }
          }

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

        (本质还是一个类、是内部类、没有名字的类、同时还是一个对象)

        /**
         * @author caicai
         * 基于接口、类、抽象类的匿名内部类
         */
        public class AnonymousInnerClass {
            public static void main(String[] args) {
                Outer01 outer01 = new Outer01();
                outer01.method();
            }
        }
        ​
        class Outer01 {
        ​
            private int n1 = 10;
        ​
            public void method() {
                /**
                 * 基于接口的匿名内部类
                 * tiger的编译类型是 接口A
                 * tiger的运行类型是 匿名内部类 ---?XXX  Outer01$1
                 * jdk底层在创建匿名内部类 Outer01$1 就立马创建了 Outer01$1 实例 并把地址返回给tiger
                 * 匿名内部类使用一次 就不能再使用 但是tiger可以重复使用 因为tiger是对象
                 *
                 * 看底层 系统会分配类型
                 * class XXX(匿名内部类) implements A{
                 *  @Override
                 *  public void cry() {
                 *      System.out.println("老虎叫唤....");
                 *  }
                 * }
                 */
                // 基于接口的匿名内部类
                A tiger = new A() {
                    @Override
                    public void cry() {
                        System.out.println("老虎叫唤....");
                    }
                };
                System.out.println("tiger的运行类型是:" + tiger.getClass());
                tiger.cry();
        ​
                // 基于类的匿名内部类
                /**
                 * 分析:
                 * father的编译类型是 Father
                 * father(需要带大括号)的运行类型是 匿名内部类 Outer01$2
                 * father如果不带大括号 就跟以前的一样
                 */
                Father father = new Father("Jack") {
                    @Override
                    public void fatherTest() {
                        System.out.println("匿名内部类father重写了fatherTest方法");
                    }
                };
                father.fatherTest();
                System.out.println("father的运行类型是:" + father.getClass());
        ​
                // 基于抽象类的匿名内部类
                Animal animal = new Animal() {
                    @Override
                    void eat() {
                        System.out.println("小狗吃骨头");
                    }
                };
                animal.eat();
                System.out.println("animal的运行类型是:" + father.getClass());
            }
        }
        ​
        interface A {
            public void cry();
        }
        ​
        class Tigher implements A {
        ​
            @Override
            public void cry() {
        ​
            }
        }
        ​
        class Father {
            public Father(String name) {
        ​
            }
        ​
            public void fatherTest() {
        ​
            }
        }
        ​
        abstract class Animal {
            abstract void eat();
        }
        1. 细节:匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征。

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

        3. 不能添加访问修饰符

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

        5. 外部其他类不能访问匿名内部类

        6. 如果外部类和匿名内部类重名时,匿名内部类访问时也遵循就近原则

        7. 匿名内部类实践:

        public class InnerClassTest02 {
            public static void main(String[] args) {
                CellPhone cellPhone = new CellPhone();
                // 传递实现了 Bell接口的匿名内部类
                // 重写了ring方法
                /**
                 * 相当于:
                 * Bell bell = new Bell() {
                 *             @Override
                 *             public void ring() {
                 *                 System.out.println("懒猪起床了");
                 *             }
                 *         }
                 */
                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();
            }
        }

    2. 定义在外部类的成员(属性、方法)位置上:

      • 成员内部类(没用static修饰)

        • 可以直接访问外部类的所有成员,包括私有成员

        • 可以添加任意的修饰符 因为它也是一个类的成员

        • 使用成员内部类直接在外部类中new就可以了

        • 外部类访问成员内部类:先创建成员内部类对象 再调用

        • 就近原则 外部类名.this.属性

          /**
           * @author caicai
           * 成员内部类(没用static修饰)
           */
          public class MemberInnerClass {
              public static void main(String[] args) {
                  Outer04 outer04 = new Outer04();
                  outer04.f1();
          ​
                  // 外部其他类使用成员内部类的三种方式
                  // outer04.new Inner04(); 相当于把 new Inner04() 当作是outer04的成员
                  Outer04.Inner04 inner04 = outer04.new Inner04();
          ​
                  // 第二种方式 在外部类中写一个方法 返回一个inner04的对象实例
                  Outer04.Inner04 inner041 = outer04.f2();
                  inner041.say();
                  
              }
          }
          class Outer04 { // 外部类
              private int n1 = 10;
              public String name = "张三";
          ​
              private void hi() {
                  System.out.println("这是Outer04的私有方法");
              }
              // 注意:成员内部类是定义在外部类的成员位置上
              class Inner04 { // 成员内部类 既没在方法中也没在代码块中
                  public void say() {
                      // 可以直接访问外部类的所有成员,包括私有成员
                      System.out.println("名字是:" + name + "  n1是:" + n1);
                      hi();
                  }
              }
              public void f1() {
                  // 使用成员内部类 直接在外部类中new就可以了
                  Inner04 inner04 = new Inner04();
                  inner04.say();
              }
              public Inner04 f2() {
                  return new Inner04();
              }
          }

      • 静态内部类(使用static修饰)

        • 可以访问外部类的所有静态成员 包含私有的 但不能直接访问非静态成员

        • 可以添加任意修饰符

        • 在外部类外部 创建静态内部类

          语法: 外部类.内部类 内部类对象 = new 外部类.内部类();
          举例: Outer.Inner in = new Outer.Inner();
          /**
           * 静态内部类
           *
           * @author caicai
           */
          public class StaticInnerClass {
              public static void main(String[] args) {
                  Outer05 outer05 = new Outer05();
                  outer05.mi();
          ​
                  Outer05.Inner05 inner05 = new Outer05.Inner05();
                  inner05.say();
          ​
                  outer05.getInner();
          ​
          ​
              }
          }
          ​
          class Outer05 { // 外部类
              private int n1 = 10;
              public static String name = "张三";
          ​
              private void hi() {
                  System.out.println("这是Outer05的私有方法");
              }
          ​
              /**
               * Inner05是静态内部类
               * 1. 放在外部类的成员位置
               * 2. 使用static修饰
               */
              static class Inner05 {
                  public void say() {
                      System.out.println(name);
                  }
              }
          ​
              public void mi() {
                  Outer05 outer05 = new Outer05();
                  System.out.println(outer05.n1);
              }
          ​
              public Inner05 getInner() {
                  return new Inner05();
              }
          }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔡霸霸i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值