扫码关注微信公众号

回复“面试手册”,获取本站PDF版

回复“简历”,获取高质量简历模板

回复“加群”,加入程序员交流群

回复“电子书”,获取程序员类电子书

当前位置: Java > Java基础高频面试题 > 32. Java的内部类

内部类包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类

  • 成员内部类

1.成员内部类定义为位于另一个类的内部,成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

class Outer{
    private double a = 0;
    public static int b =1;
    public Outer(double a) {
        this.a = a;
    }

    class Inner {     //内部类
        public void fun() {
            System.out.println(a);
            System.out.println(b);
        }
    }
}

2.当成员内部类拥有和外部类同名的成员变量或者方法时,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:外部类.this.成员变量

3.在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。

4.成员内部类是依附外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:

class Outter{
    private double a = 0;
    public static int b =1;
    public Outter(){}
    public Outter(double a) {
        this.a = a;
        Inner inner = new Inner();
        inner.fun();     //调用内部类的方法
    }


    class Inner {     //内部类
        int b = 2;
        public void fun() {
            System.out.println(a);
            System.out.println(b);            //访问内部类的b
            System.out.println(Outter.this.b);//访问外部类的b
        }
    }
}
public class Main{
    public static void main(String[] args) {
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner(); //创建内部类的对象
    }
}
  • 局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。

class Outter {

    private int outter_a = 1;
    private static int static_b = 2;

    public void test1(){
        int inner_c =3;
        class Inner {
            private void fun(){
                System.out.println(outter_a);
                System.out.println(static_b);
                System.out.println(inner_c);
            }
        }
        Inner  inner = new Inner(); //创建局部内部类
        inner.fun();
    }
    public static void test2(){
        int inner_d =3;
        class Inner {
            private void fun(){
                 System.out.println(outter_a); //编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
                System.out.println(static_b);
                System.out.println(inner_d);
            }
        }
        Inner  inner = new Inner();
        inner.fun();
    }
}
  • 匿名内部类

匿名内部类只没有名字的内部类,在日常开发中使用较多。使用匿名内部类的前提条件:必须继承一个父类或实现一个接口。

interface Person {
    public void fun();
}
class Demo {
    public static void main(String[] args) {
         new Person() {
            public void fun() {
                System.out.println("hello,word");
            }
        }.fun();
    }
}
  • 静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

class Outter {
    int a = 1;
    static int b = 2;
    public Outter() {

    }

    static class Inner {
        public Inner() {
            System.out.println(a);//报错,静态内部类不能访问非静态变量
            System.out.println(b);
        }
    }

}
public class Main{
    public static void main(String[] args) {
        Outter.Inner inner = new Outter.Inner();
    }
}
  • 内部类的优点:
    1. 内部类不为同一包的其他类所见,具有很好的封装性;
    2. 匿名内部类可以很方便的定义回调。
    3. 每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
    4. 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
  • 局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final
public class Main {
    public static void main(String[] args)  {
         
    }
     
    public void fun(final int b) {
        final int a = 10;
        new Thread(){
            public void run() {
                System.out.println(a);
                System.out.println(b);
            };
        }.start();
    }
}

对于变量a可以从生命周期的角度理解,局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁,而局部内部类对局部变量的引用依然存在,如果局部内部类要调用没有final修饰的局部变量时,就会造成生命周期不一致出错。

对于变量b,其实是将fun方法中的变量b以参数的形式对匿名内部类中的拷贝(变量b的拷贝)进行赋值初始化。在run方法中访问的变量b根本就不是test方法中的局部变量b,而是一个拷贝值,所以不存在生命周期不一致的问题,但如果在run方法中修改变量b的值会导致数据不一致,所以需要加final修饰。


点击面试手册,获取本站面试手册PDF完整版