内部类包括 成员内部类、方法内部类、*静态内部类、匿名内部类*。
内部类的作用
由于内部类的实现和外部类没有关系,内部类可自由继承其他类,所以在某一程度上实现了类的多重继承。
使得代码逻辑更紧凑,比如可以将一些相关性强的代码用内部类实现。
有些类往往只实例化一次,可以使用匿名内部类,这样也不会造成类的泛滥。
匿名内部类还能获取不在同一个包的 proteced 方法。
代码示例
成员内部类
IAnimal.java
publicinterfaceIAnimal{voidsleep(Stringname);voideat(Stringname);}
IProgrammer.java
publicinterfaceIProgrammer{voidcoding();}
Person.java
publicclassPersonimplementsIAnimal{privateintage;privateStringname;publicPerson(intage,Stringname){this.age=age;this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}@Overridepublicvoidsleep(Stringname){System.out.println(name+"睡觉");}@Overridepublicvoideat(Stringname){System.out.println(name+"吃东西");}publicvoidcoding(){newXiaoMing().coding();}classXiaoMingimplementsIProgrammer{publicvoidxiaoMingSleep(){sleep(name);// 访问外部类的成员变量及方法}publicvoidxiaoMingEat(){eat(name);// 访问外部类的成员变量及方法}@Overridepublicvoidcoding(){System.out.println(age+"岁开始写代码");}}publicstaticvoidmain(String[]args){Personp=newPerson(12,"小明");Person.XiaoMingming=p.newXiaoMing();p.coding();ming.xiaoMingSleep();ming.xiaoMingEat();}}
运行 main() 方法,控制台打印出
可以看出内部类使用了外部类的成员变量及方法。
外部类也实现了 coding(),间接实现了多重继承。
静态内部类
静态内部类在实现单例模式时候经常使用到,示例:SingletonTest.java
publicclassSingletonTest{privateSingletonTest(){}privatestaticclassSingletonTestHolder{privatestaticSingletonTestsingletonTest=newSingletonTest();}publicstaticSingletonTestgetInstance(){returnSingletonTestHolder.singletonTest;}}
通过静态初始化类来实现单例模式,是线程安全的,利用 ClassLoader 来确保只有一个单例。
匿名内部类
一般作为接口和抽象的一种实现,通常只实例化一次。
比较常见的是我们实现 Runnable 接口和继承 Thread 类,都会用到匿名内部类。ThreadTest.java
publicclassThreadTest{publicstaticvoidmain(String[]args){newThread(){@Overridepublicvoidrun(){System.out.println("Thread ...");}}.start();Runnablerunnable=newRunnable(){@Overridepublicvoidrun(){System.out.println("runnable ...");}};newThread(runnable).start();}}
如果要实现 Runnable 接口,那么我们需要定义一个类,而在上述代码中,我们并没有去指明 class XXX implentments Runnable 这样一个类,我们创建了一个匿名类,来实现接口或者实现抽象方法。这在安卓中会大量用到,Java 中的话,用得其实并没有很多。
匿名类还有一个作用,就是可以访问跨包类中的 protected 方法。这个有点意思。比如在我们包 com.yhx.javabasic 中有个 HelloWorld.java
publicclassHelloWorld{protectedvoidsay(){System.out.println("Hello ...");}publicvoidsing(){System.out.println("sing ...");}}
在另一个包 com.yhx.com.yhx.anonymous 中有个类AnonymousTest.java,我们现在要想访问 HelloWorld.java 中的 say() 方法,怎么办呢?AnonymousTest.java
publicclassAnonymousTest{publicstaticvoidmain(String[]args){HelloWorldhelloWorld=newHelloWorld();helloWorld.sing();helloWorld.say();// 错误,不能调用不同包之间的 protected 方法}}
可以看到,由于 protected 关键字限制了作用域为同一个包内,所以在包外调用 protected方法时,就会出错。这个时候可以用匿名类来实现。更改上述方法,改之后的代码如下:
publicclassAnonymousTest{publicstaticvoidmain(String[]args){HelloWorldhelloWorld=newHelloWorld();helloWorld.sing();newHelloWorld(){voidcallHelloWorldSay(){super.say();}}.callHelloWorldSay();}}
控制台打印出:
这样就可以实现调用跨包之间的 protected 方法。
注意事项
非 static 内部类,不能用 static 修饰属性或方法。因为非静态类只有在实例化之后才能加载到 jvm 内存中。