类都对应于一个独立的Java源文件,但一个类还可以放在另一个类的内部,称之为内部类,相对而言,包含它的类称之为外部类。
内部类与包含它的外部类有比较密切的关系,而与其他类关系不大,定义在类内部,可以实现对外部完全隐藏,可以有更好的封装性,代码实现上也往往更为简洁。
内部类只是Java编译器的概念,对于Java虚拟机而言,它是不知道内部类这回事的,每个内部类最后都会被编译为一个独立的类,生成一个独立的字节码文件。
在Java中,根据定义的位置和方式不同,主要有4种内部类。
▪静态内部类。
▪成员内部类。
▪方法内部类。
▪匿名内部类。
其中,方法内部类是在一个方法内定义和使用的;匿名内部类使用范围更小,它们都不能在外部使用;成员内部类和静态内部类可以被外部使用,不过它们都可以被声明为private,这样,外部就不能使用了。
静态内部类
public class Outer { private static int shared = 100; public static class StaticInner {//静态内部类 public void innerMethod() { System.out.println("inner " + shared); } } public void test() { StaticInner si = new StaticInner(); si.innerMethod(); } } class Test { public static void main(String[] args) { Outer.StaticInner si = new Outer.StaticInner();//通过“外部类.静态内部类”的方式使用 si.innerMethod(); } }
静态内部类与静态变量和静态方法定义的位置一样,也带有static关键字,只是它定义的是类
静态内部类的使用场景是很多的,如果它与外部类关系密切,且不依赖于外部类实例,则可以考虑定义为静态内部类。
也可以看一些在Java API中使用静态内部类的例子:
▪Integer类内部有一个私有静态内部类IntegerCache,用于支持整数的自动装箱。
▪表示链表的LinkedList类内部有一个私有静态内部类Node,表示链表中的每个节点。
▪Character类内部有一个public静态内部类UnicodeBlock,用于表示一个Unicode block。
成员内部类
与静态内部类相比,成员内部类没有static修饰符,少了一个static修饰符,含义有很大不同
public class Outer { private int a = 100; private void action() { System.out.println("action"); } public void test() { Inner inner = new Inner(); inner.innerMethod(); } public class Inner { public void innerMethod() { System.out.println("outer a " + a);//直接访问外部类私有实例变量a Outer.this.action();//通过“外部类.this.xxx”的方式引用外部类的实例变量和方法 } } } class Test { public static void main(String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();//创建内部类对象的语法是“外部类对象.new内部类()” inner.innerMethod(); } }
成员内部类有哪些应用场景呢?如果内部类与外部类关系密切,需要访问外部类的实例变量或方法,则可以考虑定义为成员内部类。外部类的一些方法的返回值可能是某个接口,为了返回这个接口,外部类方法可能使用内部类实现这个接口,这个内部类可以被设为private,对外完全隐藏。
比如,在Java API的类LinkedList中,它的两个方法listIterator和descendingIterator的返回值都是接口Iterator,调用者可以通过Iterator接口对链表遍历,listIterator和descend-ingIterator内部分别使用了成员内部类ListItr和DescendingIterator,这两个内部类都实现了接口Iterator。
方法内部类
内部类还可以定义在一个方法体中。
public class Outer { private int a = 100; public void test(final int param) { final String str = "hello"; final String[] str2 = new String[]{"hello"}; class Inner { public void innerMethod() { System.out.println("outer a " + a);//直接访问了外部私有实例变量a System.out.println("param " + param); System.out.println("local var " + str); str2[0] = "hello world"; } } Inner inner = new Inner(); inner.innerMethod(); System.out.println(str2[0]); } } class Test { public static void main(String[] args) { Outer outer = new Outer(); outer.test(1); } }
方法内部类可以用成员内部类代替,至于方法参数,也可以作为参数传递给成员内部类。不过,如果类只在某个方法内被使用,使用方法内部类,可以实现更好的封装。
匿名内部类
匿名内部类没有单独的类定义,它在创建对象的同时定义类,语法如下:
new 父类(参数列表) {
//匿名内部类实现部分
}
或者
new 父接口() {
//匿名内部类实现部分
}
匿名内部类是与new关联的,在创建对象的时候定义类,new后面是父类或者父接口,然后是圆括号(),里面可以是传递给父类构造方法的参数,最后是大括号{},里面是类的定义。
匿名内部类跟详细的介绍: https://www.cnblogs.com/ooo0/p/12582296.html
匿名内部类能做的,方法内部类都能做。但如果对象只会创建一次,且不需要构造方法来接受参数,则可以使用匿名内部类,这样代码书写上更为简洁。
文章参考来源:java编程的逻辑