**初识内部类
内部类就是一个类的声明不在顶层类(与Java文件名相同的类相同层级),而是被嵌套在其他类或者其他方法当中的类。相当于这个类被其他代码环绕。
一般来说,内部类就分四种:成员内部类局部内部类匿名内部类静态内部类

1、成员内部类

成员内部类:顾名思义,就是这个类(B)身处某一个类(A)的内部,且这个类(B)像其他成员(属性和方法)一样,可以自由调用外部类(A)的属性和方法。

这里涉及了两个类,两个类的属性和方法,身处外部的A类和身处内部的B类,那么A就是B的外部类,而B就是A的成员内部类。
示例:
public class Outer { //外部类
    public String name = "老王";
    private void print(){}
    //成员内部类
    class Inner11 {
        }
    }
}
  • 类比类中的其他成员,成员内部类可以用任意访问权限修饰符修饰:(public, protected, default, private)。
  • 成员内部类可以无条件访问外部类的属性和方法,包括私有域的属性和方法。

    //外部类Outer
    public class Outer {
        public String name = "老王";
        private double age = 99;
        static int id = 20210423;
        final String status = "loser";
    
        private void print(){
            System.out.println("外部类私有方法");
        }
    
        //成员内部类
        class Inner11 {
            public String name = "老王.11";
            private double weight = 200.11;
            //内部类方法
            public void getOuterFields(){
                //内部类直接拿外部类属性与方法,不需要创建外部类对象
                System.out.println("属性名相同,用`Outer.this.XX`拿到外部类属性:" + Outer.this.name); //Outer.this.XX 可以拿到外部类所有非static的属性
                System.out.println("属性名相同时,默认输出内部类属性:"+ weight);
                System.out.println("内部类直接访问外部类的私有属性:"+ age);
                System.out.println("内部类直接访问外部类的静态属性:"+ id);
                System.out.println("内部类直接访问外部类的常量:"+ status);
                print();
            }
        }
    
    }
    
    //测试类
    class Test {
        public static void main(String[] args) {
            Outer.Inner11 inner11= new Outer().new Inner11();
            inner11.getOuterFields(); //
        }
    }
    
    //输出:
    属性名相同,用`Outer.this.XX`拿到外部类属性:老王
    属性名相同时,默认输出内部类属性:200.11
    内部类直接访问外部类的私有属性:99.0
    内部类直接访问外部类的静态属性:20210423
    内部类直接访问外部类的常量:loser
    外部类私有方法
  • 当内部类属性名或方法名与外部类重叠(相同)时,程序默认调用内部类的属性和方法,这时若想访问外部类的属性方法,要用以下语法格式访问:

    Outer.this.成员变量
    Outer.this.成员方法   
  • 成员内部类是依附在外部类里面的,因此想创建内部类就得先创建外部类。创建内部类的语法格式:

    外部类.内部类 内部类名 = new 外部类().new 内部类() //必须先创建外部类 new Outer()
    Outer.Inner inner = new Outer().new Inner();
  • 成功创建内部类后就可以正常的访问内部类的属性和方法了。

    class Test {
        public static void main(String[] args) {
            Outer.Inner11 inner11= new Outer().new Inner11();
            System.out.println(inner11.name); //inner的属性
            inner11.getOuterFields(); //inner的方法
        }
    }
  • 外部类要访问内部类的属性和方法,必须先实例化内部类,再通过内内部类的引用间接访问其元素。

    //外部类访问内部类成员,
    public void test(){
        Inner11 in =  new Inner11();
        in.getOuterFields();
    }

2、局部内部类

局部内部类,与方法相关,如果一个类定义在一个方法或者作用域里,那么这个类就是局部内部类。

  • 局部内部类的格式如下:

    class Outer{ 
        //属性
        //方法
        public void method() { //局部内部类
            class Innter{ //方法中再定义一个类
                //内部类的方法
                //内部类的属性
            } 
        }
    }
    因为局部内部类是在方法里,可以理解为是跟方法的局部变量一样,不能有public、protected、private、static等修饰符。
  • 与成员内部类不一样的是,局部内部类对外部类完全隐藏。除了包住这个类的方法或作用域外,其他地方都不能访问。
  • 因为方法可以有返回值,所以外部类可以通过方法的返回值得到内部类的引用。但方法的声明就要先确定返回值的类型,而局部内部类不能被方法外部识别。所以要拿到方法里面的类,这个返回值的类型一定只能是内部类的父类引用,而内部类一定为某个类的子类或者接口

    class Outer{ 
        public void method() { //局部内部类
            class Innter{ //方法中再定义一个类
                //内部类的方法
                //内部类的属性
            } 
        }
    }

    示例:

    public class Outer02 {
        //演示方法内部类
        //演示一: 没有返回值的局部内部类
        public void runInnerMethod() {
           class Inner{ //定义局部内部类
               int id = 10;
               public void prnt(){
                   System.out.println(id);
               }
           }
           //只能在该方法中创建并使用该类
           new Inner().prnt();
        }
    
        //演示二:有父类引用作为返回值的内部类
        public Dog getSubClass(){
            class subDog extends Dog{
                public void shout() { //重写了父类的方法
                    System.out.println("小狗重新叫了一下");
                }
                void eat(){
                    System.out.println("开吃");
                }
            }
            return new subDog();
        }
    }
    
    //定义一个父类
    class Dog {
        void shout(){
            System.out.println("狗叫了一声");
        }
    }
    
    class Outer02Test {
        public static void main(String[] args) {
            Outer02 outer02= new Outer02();
            outer02.runInnerMethod();;
            Dog dog = outer02.getSubClass();
            //dog.eat();报错,父类无法调用子类
            //(subDog)dog; 无法写强转,因为局部内部类只能被包裹它的方法访问,对外部隐藏
            dog.shout(); //只有重写父类的方法,父类才能访问局部类被重写过的方法。
        }
    }
    
    //输出:
    10
    小狗重新叫了一下

3、匿名内部类

匿名内部类,就是没有引用变量直接new出来的类的统称,说白了就是一种没有赋予名字的对实例化对象。匿名内部类没有构造方法,因为匿名内部类并没有声明(没有名字)。方法格式如下:

class Outer {
    //属性
    //方法
    public void method(){
        new Inner() {
        //匿名内部类具体实现
           }
    }
}

匿名内部类可以看作是一种特殊的局部内部类。一般来说,因为匿名内部类没有构造方法,匿名内部类只用于对继承方法的实现或是重写,用于继承其他类或是实现接口。和局部内部类相似,并不需要增加额外的方法,因为只有方法本身内能调用。
示例:

public class Outer03 {
    //匿名内部类演示
    public void dogRun() {
        new Animal() { //匿名内部类没方法名,必须继承一个抽象类或者实现一个接口
            @Override
            public void run() {
                System.out.println("小狗在跑");
            }
        }.run();
    }
}
interface Animal {
    void run();
}
class Outer03Test {
    public static void main(String[] args) {
        new Outer03().dogRun();
    }
}

4、静态内部类

静态内部类就是前面加上 static修饰的成员内部类,静态内部类并不依赖外部类,可以在没有外部类对象的时候直接就能创建静态内部类。与静态属性和方法类似,静态内部类也拿不到外部类的非静态属性和方法。

  • 静态内部类不能取得外部类所有元素,只能获取外部类的静态部份。
  • 静态内部类的创建不依赖外部类对象。语法格式如下:

    //外部类.内部类 内部类名 = new 外部类.内部类();
    Outer.Inner inner =  new Outer.Inner();
  • 示例:

    public class Outer04 {
        int i = 1;
        static double d = 2.2;
    
        static class Inner {
            public void getOuterFields(){
                System.out.println(d);
                //静态内部类,拿不到非静态属性
                //System.out.println(i); //Non-static field 'i' cannot be referenced from a static context
            }
        }
    }
    
    class Outer04Test {
        public static void main(String[] args) {
            Outer04.Inner inner =  new Outer04.Inner();
            inner.getOuterFields();
        }
    }
    //输出:
    2.2
文章目录