内部类的好处:提供更好地封装和方便访问外部类的私有成员。
1. 非静态内部类
public class Temp {
public static void main (String args[]) {
Outer outer = new Outer();
outer.print();
}
}
class Outer{
private String name = "Outer class";
public String getName() {
return this.name;
}
public void print() {
new Inner().printInfo();
}
private class Inner{
private String name = "Inner class";
public void printInfo(){
System.out.println(this.name); //访问本类成员
System.out.println(Outer.this.name); //访问外部类成员
System.out.println(Outer.this.getName()); //访问外部类方法
}
}
}
1.1 编译Outer类会生成两个class文件:Outer.class和Outer$Inner.class。
1.2 非静态内部类中可以任意访问外部类的非静态成员和方法。
1.3 在非静态内部类中访问一个变量时,系统会优先在方法内部查找该变量,其次在内部类中,再在外部类中。如果内部类和外部类中存在相同名字的成员,则使用this.name代表内部类成员,使用Outer.this.name代表外部类成员。
1.4 外部类必须先显示创建内部类实例才能调用内部类的成员和方法。因为创建外部类实例并不代表着内部类实例也创建了。但是如果一个内部类实例创建了,那包裹它的外部类实例一定已经被创建了。
1.5 在非静态内部类中不能定义静态的成员,代码块和方法。如果非要定义,只能使用static final的。
1.6 根据静态成员不能访问非静态成员的规则,外部类中的静态成员不能访问非静态内部类的成员。除了非静态内部类中的static final成员。
1.7 在外部类以外的地方创建内部类实例的格式:外部类实例.new 内部类实例。前提是内部类的访问权限可以让外部类之外的环境访问。例如:
public class Temp {
public static void main (String args[]) {
Outer.Inner inner = new Outer().new Inner();
inner.printInfo();
}
}
class Outer{
private String name = "Outer class";
public String getName() {
return this.name;
}
public void print() {
new Inner().printInfo();
}
public class Inner{
private String name = "Inner class";
public void printInfo(){
System.out.println(this.name); //访问本类成员
System.out.println(Outer.this.name); //访问外部类成员
System.out.println(Outer.this.getName()); //访问外部类方法
}
}
}
1.8 子类继承非静态内部类:注意子类的构造方法中一定要有被继承的内部类的外部类的实例。
public class Temp {
public static void main (String args[]) {
SubInner subInner = new SubInner(new Outer("外部类"));
System.out.println(subInner.name); //输出"子类",因为SubInner构造方法中调用的是Inner类的构造器,将"子类"字符串赋值到了Inner类中的name变量。
}
}
class Outer{ //外部类
public String name;
public Outer(String name) { //外部类构造方法
this.name = name;
System.out.println(this.name); //输出"外部类",main方法中调用Outer类构造器的时候传入。
}
public class Inner{ //非静态内部类
public String name;
public Inner (String name) { //非静态内部类构造方法
this.name = name;
}
}
}
class SubInner extends Outer.Inner {
public SubInner(Outer outer) {
outer.super("子类"); //通过传入out的对象显示调用Inner类的构造器。注意:这里调的是Inner的构造器,不是Outer的。
}
}
2. 静态内部类
public class Temp {
public static void main (String args[]) {
Outer outer = new Outer();
outer.print();
}
}
class Outer{
private static String name = "Outer class";
public static String getName() {
return name;
}
public void print() {
System.out.println(Inner.name);
new Inner().printInfo();
}
private static class Inner{
private static String name = "Inner class";
public void printInfo(){
System.out.println(Inner.name); //访问本类成员
System.out.println(Outer.name); //访问外部类成员
System.out.println(Outer.getName()); //访问外部类方法
}
}
}
2.1 只有静态内部类中才可以包含静态成员。静态内部类中的静态成员不能访问外部类的非静态成员。
2.2 在外部类以外的地方创建静态内部类实例的格式:new 外部类类名.内部类实例。因为静态内部类是其外部类类相关的,因此创建静态内部类实例的时候不需要外部类的实例。
public class Temp {
public static void main (String args[]) {
Outer.Inner inner = new Outer.Inner();
inner.print();
}
}
class Outer{
private String name = "Outer class";
public String getName() {
return this.name;
}
public static class Inner{
private String name = "Inner class";
public void print() {
System.out.println("内部类方法");
}
}
}
2.3 子类继承静态内部类:不需要外部类的实例。
public class Temp {
public static void main (String args[]) {
SubInner subInner = new SubInner();
System.out.println(subInner.name); //输出"子类"。
}
}
class Outer{ //外部类
public String name;
public Outer(String name) { //外部类构造方法
this.name = name;
System.out.println(this.name); //不会执行,因为实例化静态内部类的时候不需要调用外部类的构造器。
}
public static class Inner{ //静态内部类
public String name;
public Inner (String name) { //静态内部类构造方法
this.name = name;
}
}
}
class SubInner extends Outer.Inner {
public SubInner() {
super("子类"); //不需要传入out的对象。很显然,这里调的是Inner的构造器。
}
}
3. 局部内部类:将内部类放在方法定义里。
public class Temp {
public static void main (String args[]) {
class Inner { //局部内部类
int a = 1;
}
class SubInner extends Inner { //第二个局部内部类,继承第一个局部内部类
int b = 2;
}
Inner inner = new Inner(); //创建局部内部类实例
System.out.println(inner.a);
SubInner subInner = new SubInner();
System.out.println(subInner.a + " " + subInner.b);
}
}
3.1 因为局部内部类定义在方法内,因此局部内部类的适用范围仅在该方法里。根据所有局部成员都不存在访问控制符和static的原则:局部内部类不可能被外部类以外的地方使用,因此也无需使用访问控制符和static。
3.2 编译上面程序后会生成三个class文件:Temp.class,Temp$1Inner.class,Temp$1SubInner.class。注意到局部内部类的class文件名比内部类多了一个"1"。这是因为在一个类中不可能有重名的内部类,但是有可能有重名的局部内部类(在不同方法中定义)。这个数字便用于区分同名的局部内部类。
4. 匿名内部类:只是用一次的类。
4.1 匿名内部类创建后会立即生成该类实例,然后类定义消失。因此该类只能使用一次。定义匿名内部类的格式是:new 父类构造器 (参数列表|实现接口)。
4.2 匿名内部类必须且只能继承一个父类或实现一个接口。
4.3 匿名内部类不可能是抽象类,因为要生成类实例。
4.4 匿名内部类不能定义构造方法,但是可以有构造块。一般都是通过构造块完成构造方法的事情。
4.5 创建实现接口的匿名内部类的例子:
public class Temp {
public void testWork(Workable workable) { //该方法需要传入一个实现Workable接口的实例
System.out.println(workable.work());
}
public static void main (String args[]) {
new Temp().testWork(new Workable() { //定义匿名内部类,实现Workable接口
public String work() {
return ("工作");
}
});
}
}
interface Workable { //定义一个接口,匿名内部类实现的便是这个接口
public String work();
}
4.6 创建继承父类的匿名内部类的例子:
public class Temp {
public void testWork(Father father) { //该方法需要传入一个继承Father类的实例
System.out.println(father.work());
}
public static void main (String args[]) {
new Temp().testWork(new Father("继承父类的匿名内部类") { //继承父类的匿名内部类
public String work() { //重写父类的work方法
return this.name + "在新地方工作";
}
});
}
}
class Father { //定义一个父类
public String name;
public Father(String name) { //定义父类的构造方法,需要传入一个String参数
this.name = name;
}
public String work() {
return this.name + "在工作";
}
}
4.7 匿名内部类访问类外部的局部变量,该局部变量必须是final的,否则不能访问。
public class Temp {
public void testWork(Father father) { //该方法需要传入一个继承Father类的实例
System.out.println(father.work());
}
public static void main (String args[]) {
final String newName = "类外部的局部变量"; //必须定义成final的
new Temp().testWork(new Father() { //继承父类的匿名内部类
public String work() { //重写父类的work方法
return newName + "在工作"; //newName必须是final的,否则编译报错
}
});
}
}
class Father { //定义一个父类
public String name = "父类";
public String work() {
return this.name + "在工作";
}
}