在java中允许在类的内部再定义一个类,这个定义在类内部的类称之为内部类,包含内部类的类称之为外部类。内部类可以方便的访问外部类的私有属性和方法,可以把内部类定义为private以实现对外部的完全封装,同时内部类也可以让类的结构层次更加的清晰,代码也比较的简洁。
java中的内部类只是java编译器的概念,对于java的虚拟机而言,它是没有java内部类的概念的,也就是说java中的内部类最后也会被编译成一个独立的class文件。在java中有四中常见的内部类,它们分别是:静态内部类、成员内部类、方法内部类、匿名内部类。
1.静态内部类
静态内部类的定义方式和定义静态方法的方式一样只是把关键字换成class即可。
public class StaticOutter { private static Integer outterNum = 1; private static void outStatic(){ System.out.println("run out static"); } public static class StaticInner{ public void testStaticInner(){ System.out.println("调用外部类的静态方法"); outStatic(); System.out.println("调用外部类的静态属性"); System.out.println(outterNum); } } }
静态内部类可以直接访问外部的静态属性和方法,但是不可访问外部类的实例属性和方法。上面我们介绍其实内部类只是java编译器的概念真正在java执行时会产生两个class文件,可是我们知道类的私有属性在类外是无法访问的那么java是怎么实现内部类访问外部类的私有属性和方法的呢?查看编译后的代码发现,java生成了两个class文件,一个叫StaticOutter.class,一个叫StaticOutter$StaticInner.class,反编译class文件发现内部类访问外部类的私有静态属性,java编译器会自动为StaticOutter生成一个非私有的访问方法access$0,它返回StaticOutter类的私有属性。
public class StaticOutter$StaticInner { public void testStaticInner() { System.out.println("调用外部类的静态方法"); StaticOutter.access$0(); System.out.println("调用外部类的静态属性"); System.out.println(StaticOutter.access$1()); } }
2.成员内部类
成员内部类的定义方式基本与静态内部类相同只是去掉static修饰符即可。
public class Outter { private Integer outterNum = 1; private void outterMethod(){ System.out.println("运行外部方法......"); } public class Inner{ public void innerMethod(){ System.out.println("outterNum:"+outterNum); System.out.println("运行outter的方法"); outterMethod(); } } }
在内部类Inner中除了可以访问外部类的静态方法和属性还可以访问外部类的实例属性和方法。其中在内部类还可以通过Outter.this.xxx来调用Outter类中的实例属性,这样调用主要是在重名的情况下使用,一般情况下可以省略Outter.this。成员内部类和静态内部类不同,在成员内部类中不可以定义静态变量和静态方法。这个我的理解就是因为成员内部类依托于与外部类的实例,正如在实例方法中无法定义静态变量,这里可以把成员内部类看成一个比较特殊的”实例方法“。
3.方法内部类
在方法的内部定义一个类称之为方法内部类。
public class MethodOutter { private Integer outter = 10; public void testMethod(Integer param){ String local = "hello"; class MethodInner{ public void innerMethod(){ System.out.println("MethodOutter outter:"+outter); System.out.println("param:"+param); System.out.println("local:"+local); } } MethodInner inner = new MethodInner(); inner.innerMethod(); } public static void main(String[] args) { MethodOutter out = new MethodOutter(); out.testMethod(1); } }
方法内部类只能在定义的方法中使用,其中在实例方法中定义的内部类可以直接访问外部类的实例方法和属性但是不能访问外部类定义的静态方法和静态属性。如果在静态方法中定义则只可以访问外部类的静态方法和静态属性。在方法内部类中可以调用方法的形式参数和局部变量,但是注意这些变量具有final的语义,如果在内部类中修改导致编译异常。
4.匿名内部类
匿名内部类和前面介绍的内部类不同,匿名内部类没有单独定义类而是通过new后面是父类或者接口时创建的。
public interface TestInteface { public void show(String param); } public class AnonymousTest { public void test(){ new TestInteface() { @Override public void show(String param) { System.out.println(param); } }; } }
匿名内部类只能使用一次,它没有名字,没有构造方法但是它可以根据参数调用父类的构造方法。和方法内部类一样,匿名内部类可以访问外部类的变量和方法,也可以访问方法中的局部变量和参数,但是这些变量依然具有final的语义。
内部类的使用可以让我们的代码具有良好的封装性,代码的结构也会变得更加的清晰。