内部类
可以将一个类的定义定义在另一个类的定义中,这个类就叫做内部类。
让我们看下关于定义一个内部类的简单示例。
public class TestOne { /* * 定义一个内部类 * */ public class InnerClass{}}
上述代码我们在TestOne类中定义了一个InnerClass内部类。
关于使用内部类的好处,我将在下面的代码中一一介绍。
1、静态内部类:
静态内部类的定义和定义一个静态方法一样很简单,只需要在定义它的时候给它一个static修饰符。
public class TestOne { /* * 定义一个非静态内部类 * */ public class InnerClass{} /* * 定义一个静态内部类 * */ public static class StaticInnerClass{} public static void main(String[] args) { /* * 实例化一个非静态内部类 * */ TestOne testOne = new TestOne(); TestOne.InnerClass innerClass = testOne.new InnerClass(); /* * 实例化一个静态内部类 * */ TestOne.StaticInnerClass staticInnerClass = new TestOne.StaticInnerClass(); }}
像上述代码,定义了一个静态内部类和非静态内部类,他们有几个不同点。
- 静态内部类由static修饰。
- 静态类和静态方法一样是相对于类的,所以在实例化时不需要实例化外部类。而是直接通过外部类类名寻找内部类实例化。
2.局部内部类:
局部内部类就是定义在一个方法的内部,使用的范围也局限于这个方法的作用域。
public class TestOne { /* * 为TestOne类定义一个成员方法 * */ public void function(){ /* * 在成员方法中定义一个内部类 * 相对于外部类来讲,这个类叫做局部内部类 * 因为它的作用域仅在这个方法有效 * */ class InnerClass{} /* * 只能在方法内部实例化和使用这个类 * */ InnerClass innerClass = new InnerClass(); }}
3.成员内部类:
定义在成员变量和成员方法同等区域的非静态内部类就叫做成员内部类,开头的那个例子就是一个公共的成员内部类。
public class TestOne { /* * 定义一个内部类 * */ public class InnerClass{}}
4.匿名内部类:
/** 定义匿名内部类的父接口* */interface InnerInterface{ void saying();}/* * 定义匿名内部类的父类 * */abstract class InnerAbstractClass{ abstract void saying();}public class TestOne { private int a = 10; public InnerInterface getInnerInterface(){ /* * 定义匿名内部类。 * */ return new InnerInterface() { public void saying(){ System.out.println("InnerInterface"); } }; } public InnerAbstractClass getInnerAbstractClass(){ /* * 定义匿名内部类。 * */ return new InnerAbstractClass() { void saying() { System.out.println("InnerAbstractClass"); } }; } }
对于匿名内部类,我们在定义它时需要先定义它的外部父接口或父类(一组规范),其实内部类本身是一个子类,他在定义时重写父接口或父类中的方法。但是它不能有构造函数,因为它是匿名的所以没有构造器能提供给它使用。
但是匿名内部类我们只能使用一次,那是因为我们是在使用的时候才定义它的,如果需要重复使用,那我们应该定义局部内部类而不是匿名内部类。
在匿名内部类中给父类有参构造器传参:
/**父类*/abstract class InnerAbstractClass{ private int a; public InnerAbstractClass(int a){ this.a = a; } abstract void saying();}public InnerAbstractClass getInnerAbstractClass(final int a){ /* * 定义匿名内部类。 * */ return new InnerAbstractClass(a) { void saying() { System.out.println("InnerAbstractClass "+a); } }; } public static void main(String[] args) { TestOne testOne = new TestOne(); InnerAbstractClass a = testOne.getInnerAbstractClass(15); a.saying(); }}/**output:*15*/
当我们需要对匿名内部类传递外部参数时,需要将形参修饰成final的,这个道很容易理解,因为绝大多数时候你也不想自己传进去的变量重新调用时值发生改变或者引用指向另一个对象。
而虽然匿名内部类没有构造器,但是可以通过如图过程在父类中定义构造函数然后通过匿名内部类对父类构造器进行传参。
内部类的特性:
1.始终包含一个指向外部类的引用:
因为内部类是定义在外部类里面的,所以无论外部类和外部类的成员变量、成员方法被怎样修饰,内部类都可以通过外部类的引用调用他们。
public class TestOne { private int a =10; public class Inner{ public void fun(){ /* *外部类对象引用:TestOne.this * */ System.out.println(TestOne.this.a); } } public static void main(String[] args) { TestOne testOne = new TestOne(); TestOne.Inner inner = testOne.new Inner(); inner.fun(); }}/** output:* 10* */
2.继承类和实现接口:
因为在Java的继承结构中是单根继承的,所以一个类只能继承一个接口,虽然可以继承任意数量的接口,但是在一个类中实现太多的接口本身就不符合Java的编程规范,内部类很好的解决了这一点。
我们可以定义许多我们需要的内部类,通过合理的分配让它们去继承和实现我们想要的类和接口,这样写出来的代码会具有良好的可阅读性。