Java基础篇(1)---内部类

一直都在瞎用,也没有系统整理过,处在会用不会说的阶段,现在开始整理资料
内部类,顾名思义它就是在一个类内部继续定义一个类

//代码片段1
//Outer类
public class Outer {
    private String age;
    //内部再定义一个Inner类
    private class Inner {
        private String name;

        private void setName() {
            ge = "19";
        }
    }
}

看到其外型,先思考思考,来个疑问三连
1、为什么要用内部类?
在《 think in Java》中,有一句话非常有意思,内部类最吸引人的地方在于,每个内部类都可以独立的继承一个(接口)的实现,无论外部类是否继承了某个(接口的实现),对于内部类都没有影响。其实说了这么多总结起来就一句话:内部类可以完美实现多重继承!
2、内部类的特点?

//代码片段2
public class Outer {
    private String age;

    private String setCode() {
        Inner inner = new Inner();
        inner.setName();
        inner.name = "code";
        return age;
    }

    private class Inner {
        private String name;

        private void setName() {
            age = "19";
            setCode();//Outer.this.setCode();
        }
    }

不知道大家发现没有,内部类是可以直接使用外部类的成员变量和方法的,即便是外部类的私有方法和变量,这就是在优化性能时大家说的,内部类默认持有外部类的引用,所以我们无需new对象的实例,也可以像使用局部方法和变量来使用外部类的!!!
到这里了我们需要明确一点,内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。

JAVA的内部类主要有四种:成员内部类、局部内部类、匿名内部类、静态内部类
一、成员内部类:成员内部类也是最普通的内部类,这个内部类可以无限制的访问外部类的所有成员属性和方法,包括私有的,但是反过来外部类访问内部类是需要实例化的
需要注意的是,成员内部类不能存在任何static的变量和方法;—代码片段2可以说明问题
二、局部内部类:这种内部类是嵌套在方法上的,它和成员内部类的主要区别就是作用域的不同,和匿名内部类的不同主要就是有没有名字。。。
三、匿名内部类:就是没有名的内部类,作为一个参数来传给函数,在使用匿名内部类的时候,我们需要注意如下几点:
1、使用匿名内部类只能继承一个类或者实现一个接口,两者不可兼得,同继承和实现的数量也只能是一个;
2、匿名内部类是不能定义构造器的;//因为这个类根本没有名字
3、匿名内部类中不能存在任何静态成员变量和静态方法;
4、匿名内部类就是没有名字的局部内部类
5、匿名内部类不能抽象,必须实现继承的类,或者实现的接口中所有的方法

《Java基础篇(1)---内部类》
这里我们能看出来几个问题,
1、匿名内部类都是在调用方法的时候使用的
2、在内部类中可以使用私有的外部类成员方法show,这个就印证了内部类的特点,内部类默认持有外部类的引用,
3、在内部类中使用外部类的局部变量,或者匿名内部类中使用了的参数,在方法的形参上必须加final,那么为什么一定要加个final?
3、解答:在直观的表象看来,匿名内部类中使用的局部变量也好,使用方法的形参也好,貌似是直接拿过来使用的,其实不是,当程序代码经过编译以后,匿名内部类和外部类是会分成两个类的,只是内部类持有外部类的引用,那么,匿名内部类中该怎么使用外部类的局部变量或者方法形参,


public class OuterClass$InnerClass {
    public InnerClass(String name,String age){
        this.InnerClass$name = name;
        this.InnerClass$age = age;
    }
    
    
    public void display(){
        System.out.println(this.InnerClass$name + "----" + this.InnerClass$age );
    }
}

就像这个例子,实则是将匿名内部类中用到的形参或者局部变量通过内部类的构造器传递进来,这就产生了一个问题,如果我们在内部类中将这个形参值改了,出现了偏差,程序就会出bug,而且非常的难以排查,为了保证传送过程中的形参值唯一性,索性用final修饰。
四、静态内部类:
static关键字是可以修饰成员变量、成员方法和代码块的,也可以修饰内部类,那么静态内部类和其他内部类最大的一个区别是:普通的内部类是默认持有外部类的引用的,所以它可以使用外部类的变量和方法(包括私有的),但是静态内部类是没有这个引用的,这就意味着:

  1. 静态内部类的创建不需要依赖外部类
  2. 静态内部类不能使用外部类的非static成员变量和方法

参考资料:
https://www.cnblogs.com/chenssy/p/3388487.html

点赞