• java中的内部类


    概述

    将一个类定义在另一个类的里面,里面的那个类就称为内部类(内置类,嵌套类)

    分析事物A时,发现该事物A描述中还有事物B,而且这个事物B还在访问被描述事物A的内容,将事物B定义成内部类来描述。

    特点

    1. 内部类可以直接访问外部类中的成员;
    2. 外部类要访问内部类,必须建立内部类的对象;

    举例:

    package innerdemo;
    
    public class InnerDemo1 {
        public static void main(String[] args) {
            Outer.Inner in = new Outer().new Inner(); // 直接访问内部类的方法
            in.show();
    
            Outer o = new Outer();//
            o.method();
        }
    }
    class Outer{
    
        private int num = 3;
        // 内部类
        class Inner{
            void show(){
                num = 100;
                System.out.println("内部类run..."+num);
            }
        }
    
        public void method(){
            Inner in = new Inner(); //外部类要访问内部类,必须建立内部类的对象;
            in.show();
        }
    }
    

    修饰符

    1. 直接访问外部类中的内部类中的成员:(不多见)

      外部类名.内部类名 变量名 = new 外部类名(). new 内部类名();

      Outer.Inner in = new Outer().new Inner();

      in.show();

    2. 内部类是静态的类,相当于一个外部类。外部类只要一加载,内部类就存在了,所以直接new一个内部类对象出来;

      Outer.Inner in1 = new Outer.Inner();

      public class InnerClassDemo {
          public static void main(String[] args) {
              // 内部类是静态的。相当于一个外部类
              Outer.Inner in1 = new Outer.Inner();
              in1.show();
          }
      }
      class Outer{
          private static int num = 3;
          // 内部类
          static class Inner{
              void show(){
                  System.out.println("内部类run..."+num);
              }
          }
      }
      
    3. 如果内部类是静态的,成员是静态的,就不需要对象了。如果内部类中定义了静态成员,该内部类也必须是静态的。

      package java_demo_2;
      
      public class InnerClassDemo {
          public static void main(String[] args) {
              Outer.Inner.function();
          }
      }
      class Outer{
          private static int num = 3;
          // 内部类
          static class Inner{
              void show(){
                  System.out.println("内部类run..."+num);
              }
              public static void function(){
                  System.out.println("内部类是静态的,成员也是静态的,不需要创建对象"+num);
              }
          }
      }
      

    细节

    package java_demo_2;
    
    public class InnerClassDemo {
        public static void main(String[] args) {
            new Outer().method();
        }
    
    class Outer{
        int num = 3;
        // 内部类
        class Inner{
            int num = 4;
            void show(){
                int num = 5;
                System.out.println(num); // num 5
                System.out.println(this.num); // 4 局部和成员变量重名
                System.out.println(Outer.this.num); // 3
            }
        }
        void method(){
            new Inner().show();
        }
    }
    

    为什么内部类能直接访问外部类中成员呢?

    那是因为内部类持有了外部类的引用。外部类名.this

    局部内部类

    内部类可以存放在局部位置上,可以放在方法中,放在代码块中。

    class Outer1{
    
        int num = 3;
    
        void method(){
            // 内部类在方法中
    
            class Inner{
                void show(){
                    System.out.println("方法中的内部类:"+num);
                }
            }
            // 创建对象
            Inner in = new Inner();
            in.show();
        }
    
        {
            // 内部类在代码块中
            class Inner2{
                void show(){
                    System.out.println("代码块中的内部类:" + num);
                }
            }
            Inner2 in2 = new Inner2();
            in2.show();
        }
    }
    

    内部类在局部位置上只能访问局部中被final修饰的局部变量;

    class Outer{
        int num = 3;
        void method(){
    
            final int x  = 9; // 这个好像都行 int x = 9 不报错;
            class Inner{
                void show(){
                    System.out.println("show..."+x); // 内部类在局部位置上只能访问局部中被final修饰的局部变量;
                }
            }
            // 创建对象
            Inner in = new Inner();
            in.show();
        }
    }
    

    匿名内部类

    概述

    内部类的简写格式。要简写,必须和外部类有关系。必须有前提:内部类必须继承或者实现一个外部类或者接口。

    格式: new 父类or接口(){子类内容};

    匿名内部类,其实就是一个匿名子类对象;这个对象比较胖。

    按道理要先继承父类,重构方法,再创建对象调用方法如:

    class Inner extends InnerDemo{
        void show() {
            System.out.println("内部类run..." + num);
        }
    }
    public void method() {
       new Inner().show();
    }
    

    现在直接在方法里,进行new 父类(){重构方法;}

    new InnerDemo(){ // 匿名内部类,new 他爹(){把方法重写;}
        void show(){
            System.out.println("show..."+num);
        }
    }
    

    具体代码如下:

    public class InnerClassDemo {
        public static void main(String[] args) {
            new Outer().method();
        }
    }
    
    // 抽象类
    abstract class InnerDemo{
        abstract void show();
    }
    class Outer {
    
        private int num = 3;
    
        // 内部类
    //    class Inner {
    //        void show() {
    //            System.out.println("内部类run..." + num);
    //        }
    //
    //    }
    
        public void method() {
    //        new Inner().show();
            new InnerDemo(){ // 匿名内部类,new 他爹(){把方法重写;}
                void show(){
                    System.out.println("show..."+num);
                }
            }.show();
        }
    }
    

    应用

    注释部分:普通内部类继承外部接口时代码:

    interface Inter{
        void show1();
        void show2();
    }
    class Outer {
        private int num = 3;
    
        // 内部类
        /*
        class Inner implements Inter {
            public void show1(){
    
            }
            public void show2(){
    
            }
        }
        */
        public void method(){
    
    //        Inner in = new Inner();
    //        in.show1();
    //        in.show2();
            Inter in = new Inter(){
                public void show1(){
    
                }
                public void show2(){
    
                }
    
            };
            in.show1();
            in.show2();
        }
    }
    

    通常的使用场景之一:当函数参数是接口类型时,而且接口中的方法不超过三个,可以用匿名内部类作为实际参数进行传递。

    // 正常写
    public class InnerClassDemo {
        public static void main(String[] args) {
        
        show(new InterImpl());
    }
        public static void show(Inter in){
            in.show1();
            in.show2();
        }
    }
    interface Inter{
        void show1();
        void show2();
    }
    
    class InterImpl implements Inter{
        public void show1(){}
        public void show2(){}
    }
    
    // 简写,将匿名内作为实际参数传递
    public class InnerClassDemo {
        public static void main(String[] args) {
        
        show(new Inter(){
            public void show1(){}
            public void show2(){}
        });
    }   
        public static void show(Inter in){
            in.show1();
            in.show2();
        }
    }
    //接口
    interface Inter{
        void show1();
        void show2();
    }
    

    分类

    • 成员内部类(静态内部类和非静态内部类)
    • 局部内部类
    • 匿名内部类

    成员内部类

    • 静态内部类:直接通过外部类调用静态内部类的构造器
    • 非静态内部类:先创建外部类的对象,再通过外部类的对象调用内部类的构造器或者
      外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
    package innerdemo;
    
    /**
     * @ClassName: InnerClassDemo
     * @author: benjamin
     * @version: 1.0
     * @description: TODO
     * @createTime: 2019/06/11/10:11
     */
    
    public class InnerClassDemo {
        public static void main(String[] args) {
            // 创建静态内部类的对象
            Person.Dog d = new Person.Dog();// 直接通过外部类调用静态内部类的构造器
            //创建非静态内部类的对象
    //        Person.Bird b = new Person().new Bird();
            Person p = new Person();
            Person.Bird b = p.new Bird();// 通过外部类的对象调用内部类的构造器
            b.info();
    
        }
    }
    
    class Person{
    
        String name;
        int age;
    
        // 非静态成员内部类
        class Bird{
            String name;
            int id;
            public Bird(){
    
            }
    
            public void setName(String name){
                this.name = name;
            }
            public void info(){
                show();
            }
        }
    
        // 静态成员内部类
        static class Dog{
            String name;
            int id;
            public Dog(){
    
            }
    
            public void setName(String name){
                this.name = name;
            }
            public void info(){
    
            }
        }
    
    
        // 外部类的成员方法
        public void show(){
            System.out.println("我是外部类的show()方法");
        }
    }
    

    局部内部类:常常使用一个方法,使其返回值为某个类或接口的对象,而这个类或接口在方法内部创建。举例:

    匿名内部类:

    举例:

    class OuterJu{
    
        // 局部内部类的使用
        public Comparable getComparable(){
            //1.创建一个实现Comparable接口的类:局部内部类
            class MyComparable implements Comparable{
                @Override
                public int compareTo(Object o) {
                    return 0;
                }
            }
            // 2. 返回一个实现类的对象
            return new MyComparable();
        }
    
        // 匿名内部类的使用
        public Comparable getComparable1(){
            //返回一个实现Comparable接口的匿名内部类的对象
            return new Comparable() {
                @Override
                public int compareTo(Object o) {
                    return 0;
                }
            };
        }
    }
    

    细节

    细节1

    主函数会报错,因为无法访问非静态类,而且由于是静态不能采用this.new Inner()

    方法:需要将Inner定义成静态类;

    package java_demo_2;
    
    /**
     * @ClassName: InnerClassDemo5
     * @author: benjamin
     * @version: 1.0
     * @description: TODO
     * @createTime: 2019/04/13/22:28
     */
    
    public class InnerClassDemo5 {
        class Inner{// 如果不定义成静态,主函数会报错;
    
        }
    
        public static void main(String[] args) {
    
            new Inner(); //无法从静态上下文中引用非静态 变量 this
            // 因为主函数是静态的;
        }
    
        public void method(){
            
            new Inner(); // 正确
        }
    
        public static void show(Inter in){
            in.show1();
            in.show2();
        }
    }
    
    interface Inter{
        void show1();
        void show2();
    }
    

    细节2:

    // 正确的
    package java_demo_2;
    
    public class InnerClassDemo6 {
        public static void main(String[] args) {
    
            new Outer6().method();
        }
    
    }
    
    class Outer6{
    
        // 创建的匿名内部类相当于
    //    class Inner6 extends Object{
    //        public void show(){
    //            System.out.println("show run");
    //        }
    //    }
    //    new Inner6.show();
        void method(){
    
            new Object(){
                public void show(){
                    System.out.println("show run");
                }
            }.show();
        }
    }
    

    编译看左边

    package java_demo_2;
    
    public class InnerClassDemo6 {
        public static void main(String[] args) {
    
            new Outer6().method();
        }
    }
    
    class Outer6{
    
        void method(){
    
             Object obj = new Object(){
                public void show(){
                    System.out.println("show run");
                }
             };
             obj.show();
    //         Error:(35, 13) java: 找不到符号
            // 因为匿名内部类这个子类对象被向上转型为Object类型,
            // 这样就不再使用子类特有的方法了;
        }
    }
    
  • 相关阅读:
    ios 手势加变形
    ios 懒加载
    [leetCode]1111. 有效括号的嵌套深度
    [leetCode]面试题 08.07. 无重复字符串的排列组合
    [leetCode]46. 全排列
    [leetCode]37. 解数独
    [leetCode]面试题 08.09. 括号
    torch.Tensor 与 numpy.ndarray的相互转化
    [leetCode]93. 复原IP地址
    [leetCode]15. 三数之和
  • 原文地址:https://www.cnblogs.com/benjieqiang/p/11512813.html
Copyright © 2020-2023  润新知