浅谈Java系列之内部类介绍(Nested Classes)

浅谈Java系列之内部类介绍(Nested Classes)

Tans 833 2023-02-15

Java中的内部类(Nested Classes)

一、概念

前几天面试过程中遇到了一个关于匿名内部类的问题,当时不太明白,现在着重理解一下。甲骨文官方释意:

Nested classes are divided into two categories: non-static and static. Non-static nested classes are called inner classes. Nested classes that are declared static are called static nested classes.

1. 普通内部类(Inner Class)

内部类(Inner)就是放在另外一个类的内部定义的类。通常它这样写

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}
  1. 内部类可以访问并且修改外部类的private字段,例如
class Outer{
    private String info = "hello, i'm info";
    class Inner{
        public void run(){
            System.out.println("hello, i'm inner");
             //修改外部类的private字段
            info = "hello, i have changed by inner class method";
             //Outer.this.info = "hello, i have changed by inner class method";
            System.out.println(info);

        }
    }
}
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.run();
    }
}

// Result:
/**
hello, i'm inner
hello, i have changed by inner class method
**/
  1. 在内部类中,由于内部类实例依附于外部类实例,为了区分两者的同名属性,通常用this指代当前内部类实例本身,而通过Outer.this指代外部类实例,例如:
class Outer{
    private String info = "hello, i'm out";
    class Inner{
        private String info = "hello i'm inner";
        public void run(){
            System.out.println(this.info); //this 指向
            Outer.this.info = "hello, i have changed by inner class method";
            System.out.println(Outer.this.info);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.run();
    }
}
// result:
/**
hello i'm inner
hello, i have changed by inner class method
**/


另外,有两种特殊的Inner classed ,分别为local classesanonymous classes 具体可看special inner class

2. 静态嵌套类(Static Nested Class)

在内部类中,也可以用static修饰内部类,我们称之为Static Nested Class静态内部类, 例如ThreadLocal中:

public class ThreadLocal<T> {
     //....
     static class ThreadLocalMap {
     }
}

一个有趣的事情是:Oracle官方将普通内部类称作Inner Classes, 而将静态嵌套类称作Nested Class, 嵌套就是你我毫不相干,所以静态内部类不依附于外部类实例,所以可以作为一个独立的类存在,而且它可以访问外部类private修饰过的静态字段和静态方法,如果将其移动到外部,那么就失去了这种效果

class A {
    static private int a1 = 1;
    private int a2 = 2;
    static class B{
        public static void say(){
            System.out.println(a1); //right result : 1
            System.out.println(a2); //wrong 不可访问外部非静态对象
        }
    }

    public static void main(String[] args) {

    }
}
public class Test{
    public static void main(String[] args) {
        A.B.say(); //调用正确
        new A.B().say(); //调用正确
    }
}

二、作用

1. 实现多继承

由于Java支持单继承,但是我们可以通过匿名内部类来实现多继承,例如:

class dad {
    public String body(){
        return "I have strong body";
    }
}
class mom {
    public String hair(){
        return "I have black hair";
    }
}
//实现了多重继承
class Son{
    private class test1 extends dad {
        @Override
        public String body() {
            return "I have stronger body";
        }
    }
    private class test2 extends mom {
        @Override
        public String hair() {
            return "I have more black hair";
        }
    }
    public String getInfo(){
        return new test1().body() + " and " +  new test2().hair();
    }
}
//Result
/**
	I have stronger body and I have more black hair
**/ 

三、总结

  • 嵌套类包括Inner classes (内部类)和 static nested classes(静态内部类)
  • 其中Inner classes又包括simple inner classlocal classes and anonymous classes
  • 内部类优点:
    • 如果一个子类只被外部类自己使用,那么就没有必要将内部类变成top-level classes, 通过添加这样的“辅助类”可以使包结构变得简洁干练
    • 增加了封装,考虑两个顶级类A和B,其中B需要访问A的成员,通过将类B隐藏在类A中,可以将A的成员声明为私有,B可以访问它们。此外,B本身可以对外界隐藏。
    • 代码可读性和可维护性增加:嵌套类的代码和外部类的代码距离变得更近。

四、参考资料

  1. Oracle Nested Classes
  2. 为什么Java内部类要设计成静态和非静态两种?