一、基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class)嵌套其他类的类称为外部类(outer class)。它是我们类的第五大成员,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
二、内部类的分类
2.1 定义在外部类局部位置上(比如方法内):
①局部内部类(有类名)
②匿名内部类(没有类名,重点)
2.2 定义在外部类的成员位置上:
①成员内部类(没用static修饰)
②静态内部类(使用static修饰)
三、内部类的使用细节
3.1 局部内部类
1.局部内部类是定义在外部类的局部位置,比如方法中或者代码块中,并且有类名。
class OuterClass {private int n1 = 10;public void m1() {class InnerClass {//内部类}}
}
2.可以直接访问外部类的所有成员,包含外部类私有的成员
class OuterClass {private int n1 = 10;public void m1() {class InnerClass {//内部类public void f1(){System.out.println("n1="+n1);}}}
}
3.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final 修饰(这样就不可被继承),因为局部变量也可以使用final
class OuterClass {private int n1 = 10;public void m1() {class InnerClass {//内部类public void f1(){System.out.println("n1="+n1);}}class InnerClass1 extends InnerClass{//继承上面的内部类}}
}
4.作用域:仅仅在定义它的方法或代码块中
5.局部内部类可以访问外部类的成员
6.外部类访问局部内部类的成员,访问方式: 创建对象,再访问(注意:必须在作用域[所定义内部类的方法中]内)
7.如果外部类和局部内部类的成员重名,那么调用遵循就近原则(即先找局部内部类的成员),如果想访问外部类的成员变量,则需使用
外部类名.this.成员
//很好理解,我们可以解读为,外部类的对象的成员
3.2 匿名内部类
匿名内部类是定义在外部类的局部位置,比如方法中或者代码块中,并且没有类名;
匿名内部类的使用是为了简化开发
①基于接口的匿名内部类
假如:我们有一个需求,“使用IA接口,并创建对象使用其方法”
按照传统方法:我们需要①编写实现类实现接口的方法②new实现类的实例
public class AnonymousInnerClass {public static void main(String[] args) {Animal animal = new Animal();animal.eat();}
}interface IA {void eat();
}class Animal implements IA {@Overridepublic void eat() {System.out.println("动物吃饭");}
}
现在,有了匿名内部类,我们就可以这样实现:
public class AnonymousInnerClass {public static void main(String[] args) {IA animal = new IA() {@Overridepublic void eat() {System.out.println("动物吃饭");}};animal.eat();}
}interface IA {void eat();
}
说是匿名,其实是有名字的,在底层,系统给它起了名字,底层实现类似(大概模拟)这样:
class XXXX implements IA {@Overridepublic void eat() {System.out.println("动物吃饭");} }
类名是由系统起的,我们可以通过.getClass( )方法获取其运行时类型,编译类型当然是IA这不用说。
注意:匿名内部类只能使用一次,也就是只能new一个实例对象,这不代表其引用就能用一次。匿名内部类需要把接口的抽象方法都实现。
②基于普通类的匿名内部类
public class AnonymousInnerClass {public static void main(String[] args) {Animal animal = new Animal("老虎") {@Overridevoid eat() {System.out.println(this.name+"要吃肉");}};System.out.println(animal.getClass());animal.eat();}
}class Animal {String name;void eat() {System.out.println(this.name + "要吃饭");}public Animal(String name) {this.name = name;}
}
底层实现(大概模拟)
class XXXX extends Animal{
@Override void eat() {System.out.println(this.name+"要吃肉");} }
我们可以通过.getClass( )方法获取其运行时类型
③基于抽象类的匿名内部类
public class AnonymousInnerClass {public static void main(String[] args) {Animal animal = new Animal("老虎") {@Overridevoid eat() {System.out.println(this.name + "吃肉");}};System.out.println(animal.getClass());animal.eat();}
}abstract class Animal {String name;abstract void eat();void shout() {System.out.println("动物大叫");}public Animal(String name) {this.name = name;}
}
必须把抽象类中的抽象方法都实现。
这里补充说明一下,父类的私有属性可以被子类继承,但是子类无法使用;父类的构造方法,子类无法继承,但是子类创建对象会先调用父类的构造方法(默认是无参构造方法),以上案例匿名内部类应该是调用了父类的有参构造方法。
3.3 成员内部类
成员内部类定义在外部类的成员位置,并且没有static修饰。
可以添加任意访问修饰符(public、protected、默认、private),因为它的地位是一个成员。
1.成员内部类可访问外部类所有成员,包括私有的
使用内部类方法一
public class ChengYuan {public static void main(String[] args) {OuterClass outerClass = new OuterClass();outerClass.shiYong();}
}class OuterClass {int n = 10;public void eat() {System.out.println("吃顿饭");}class innerClass {public void f1() {System.out.println(n);eat();}}public void shiYong() {innerClass innerClass = new innerClass();innerClass.f1();}
}
使用内部类方法二
OuterClass.innerClass innerClass = outerClass.new innerClass();innerClass.f1();
使用内部类方法三
外部类写方法,返回内部类对象
public InnerClass shiYong1(){return new InnerClass();}
3.4 静态内部类
静态内部类是定义在外部类的成员位置,并且有static修饰
可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
作用域:同其他的成员,为整个类体
静态内部类可通过类名直接访问
public class ChengYuan {public static void main(String[] args) {OuterClass.InnerClass innerClass = new OuterClass.InnerClass();innerClass.f1();}
}class OuterClass {static int n = 10;static class InnerClass {public void f1() {System.out.println(n);}}
}
如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问。