java 内部类
内部类就是在类的内部又定义一个类。
实例内部类
实例内部类就是没有static修饰的内部类。他有以下几点需要注意
- 在创建内部类的实例时,外部类必须已经创立。例如:
Outer.InnerTool tool = new Outer().newInnerTool();
这个语句相当于
Outer outer = new Outer();
Outer.InnerTool Tool = outer.new InnerTool();
内部类也是在外部类的内部,可以访问外部类的任何级别的成员方法和成员变量。这是因为想要创建内部类,首先要创建外部类,这个时候可以看成内部类有外部类的引用。
一个外部类可以对应多个内部类,一个内部类对应一个外部类。外部类不能直接访问内部类的成员,必须要通过实例去访问。例如
public class A |
- 在内部类中不能定义静态成员。
- 如果内部类和外部类A有同名的成员。那么this代表外部,A.this代表内部
- 如果有两个内部类且一个定义成private,那么另一个类不能访问。因为两个是同级的,可以把两个内部类看成继承于同一个父类的类。并且如果想在一个内部类中使用另一个内部类,则必须用完整类名
public class A |
静态内部类
静态内部类也是一种静态变量。但是这种类比较神奇,本来static是不能修饰类的,但是内部类的static和普通的静态变量有所不同。它可以创建实例,也就是说不局限于方法区,只是为了有特殊的权限而把static安上去而已。
静态变量可以直接创建,不必先创建外部类。例如A.B b = new A.B();
。
正因为如此,所以静态内部类想访问外部类实例变量需要先创建实例。但是静态变量可以直接访问。
静态类的特点就是可以定义静态成员。
局部内部类
局部内部类是在一个方法中定义的类,它的可见范围是这个方法。局部内部类不能使用访问权限修饰符(public等),其实本来就没有必要,只能在这个方法内了还要访问权限干什么。
局部类也不能包含静态成员。依我看这就是java中的struct(不知道java中有不)。
匿名类
这种类的特殊之处就是没有名字,这种类实际上是内部类的简写形式(虽然也简单不到哪去),如果只需要创建一个内部类实例,就可以考虑匿名类。例:
public class A |
匿名类本身没有构造方法,但是他会调用父类的构造方法。匿名类和内部类的访问权限相同,也可以访问外部所有变量。
传递参数时要注意,如果传递的是外部类的参数,必须要加final。因为内部类和外部类编译时生成的是两个文件,也就是说可能是值传递。但是内部类和外部类按道理应该是同一个类,内部类改变了参数,外部类也要跟着改变。为了避免这种矛盾,干脆直接定义成final不可改变了。
语法: new 类名/接口名(构造方法参数){内容}
匿名内部类实现接口(注意是实现),其实就是创造了一个类
内部类的继承
如果一个外部类继承了另一个外部类的内部类的实例,那么这个外部类会自动引用另一个外部类。例如
class Outer |
Sample必须要提供如上所述的构造函数。因为如果不提供,那么就不知道引用的是哪一个Outer。此外,Java虚拟机会自动使内部类的实例引用外部类的实例。例如上面inner实例会自动引用outer1实例。
内部类用途
第一个作用就是封装。例如顶层类只有public和默认级别,而内部类四种级别都可以有。
第二个作用是访问外部类的属性。这个访问不代表创建一个内部类的实例就可以直接访问外部类的属性了,那反而是对封装的破坏,这里指的是在定义的时候可以随意使用外部类的属性。
第三个作用是回调。这个的含义是可以实现类和接口中同名的方法。例如两个接口或一个类一个接口中定义了重名的方法,那么可以让内部类实现接口然后外部覆盖方法。例如
public class Sub extends Base//Base调节速度,Adjustable调节温度 |
注意这里内部类是通过调用外部类的方法来实现的,虽然应该也可以直接在内部类中实现,频繁的跳转反而会带来性能的降低。但是某些时候想使用外部类的private类型时可以使用这种方法。
文件名
对于每个内部类,java都会生成.class文件。
- 成员内部类 外部类名字$内部类名字. 例: A$B.class
- 局部内部类 外部类名字$数字加内部类名字
- 匿名类 外部类名字$数字