简介
内部类可以分为四类:普通内部类、静态内部类、匿名内部类、局部内部类。
普通内部类
public class OuterClass {
public int outF1=1;
protected int outF2=2;
int outF3=3;
private int outF4=4;
public OuterClass(){
InnerClass innerClass=new InnerClass();
System.out.println("外部类访问内部类属性-innerF1:"+innerClass.innerF1);
System.out.println("外部类访问内部类属性-innerF2:"+innerClass.innerF2);
System.out.println("外部类访问内部类属性-innerF3:"+innerClass.innerF3);
System.out.println("外部类访问内部类属性-innerF4:"+innerClass.innerF4);
}
//普通内部类
class InnerClass{
public int innerF1=1;
protected int innerF2=2;
int innerF3=3;
private int innerF4=4;
public InnerClass(){
System.out.println("内部类访问外部类属性-outF1:"+outF1);
System.out.println("内部类访问外部类属性-outF2:"+outF2);
System.out.println("内部类访问外部类属性-outF3:"+outF3);
System.out.println("内部类访问外部类属性-outF4:"+outF4);
}
}
public static void main(String[] args) {
OuterClass outerClass=new OuterClass();
//InnerClass innerClass=outerClass.new InnerClass();
}
}
结果:
内部类访问外部类属性-outF1:1
内部类访问外部类属性-outF2:2
内部类访问外部类属性-outF3:3
内部类访问外部类属性-outF4:4
外部类访问内部类属性-innerF1:1
外部类访问内部类属性-innerF2:2
外部类访问内部类属性-innerF3:3
外部类访问内部类属性-innerF4:4
总结:内部类对象可以访问外部类对象中所有访问权限的属性,同时,外部类对象也可以通过内部类的对象引用来访问内部类中定义的所有访问权限的属性。
静态内部类
一个类的静态成员独立于这个类的任何一个对象存在,只要在具有访问权限的地方,我们就可以通过 类名.静态成员名
的形式来访问这个静态成员,同样的,静态内部类也是作为一个外部类的静态成员而存在,创建一个类的静态内部类对象不需要依赖其外部类对象。
public class OuterClass2 {
public int outF1=1;
protected int outF2=2;
int outF3=3;
private int outF4=4;
public static int outStaticF1=1;
protected static int outStaticF2=2;
static int outStaticF3=3;
private static int outStaticF4=4;
public OuterClass2(){
InnerClass innerClass=new InnerClass();
System.out.println("外部类访问--内部类属性-innerF1:"+innerClass.innerF1);
System.out.println("外部类访问--内部类属性-innerF2:"+innerClass.innerF2);
System.out.println("外部类访问--内部类属性-innerF3:"+innerClass.innerF3);
System.out.println("外部类访问--内部类属性-innerF4:"+innerClass.innerF4);
System.out.println("外部类访问--内部类静态属性-innerStaticF1:"+InnerClass.innerStaticF1);
System.out.println("外部类访问--内部类静态属性-innerStaticF2:"+InnerClass.innerStaticF2);
System.out.println("外部类访问--内部类静态属性-innerStaticF3:"+InnerClass.innerStaticF3);
System.out.println("外部类访问--内部类静态属性-innerStaticF4:"+InnerClass.innerStaticF4);
}
//普通内部类
static class InnerClass{
public int innerF1=1;
protected int innerF2=2;
int innerF3=3;
private int innerF4=4;
public static int innerStaticF1=1;
protected static int innerStaticF2=2;
static int innerStaticF3=3;
private static int innerStaticF4=4;
public InnerClass(){
System.out.println("内部类访问--外部类静态属性-outStaticF1:"+outStaticF1);
System.out.println("内部类访问--外部类静态属性-outStaticF2:"+outStaticF2);
System.out.println("内部类访问--外部类静态属性-outStaticF3:"+outStaticF3);
System.out.println("内部类访问--外部类静态属性-outStaticF4:"+outStaticF4);
}
}
public static void main(String[] args) {
OuterClass2 outerClass=new OuterClass2();
//InnerClass innerClass=outerClass.new InnerClass();
}
}
结果:
内部类访问--外部类静态属性-outStaticF1:1
内部类访问--外部类静态属性-outStaticF2:2
内部类访问--外部类静态属性-outStaticF3:3
内部类访问--外部类静态属性-outStaticF4:4
外部类访问--内部类属性-innerF1:1
外部类访问--内部类属性-innerF2:2
外部类访问--内部类属性-innerF3:3
外部类访问--内部类属性-innerF4:4
外部类访问--内部类静态属性-innerStaticF1:1
外部类访问--内部类静态属性-innerStaticF2:2
外部类访问--内部类静态属性-innerStaticF3:3
外部类访问--内部类静态属性-innerStaticF4:4
总结:外部类对象可以通过内部类的对象引用来访问内部类中定义的所有访问权限的成员,
静态内部类只能访问外部类的所有权限的静态成员,不能访问非静态成员。
匿名内部类
匿名内部类有多种形式,其中最常见的一种形式莫过于方法参数中新建一个接口对象/类对象,并且实现这个接口声明/类中原有的方法
public class OuterClass3 {
public int outF1=1;
protected int outF2=2;
int outF3=3;
private int outF4=4;
public OuterClass3(){
System.out.println("创建"+this.getClass().getSimpleName()+"对象");
}
//自定义接口
interface OnClickLister{
void onClick(Object object);
}
private void anonymousClassTest(){
//创建一个匿名内部类对象
//这个匿名内部类实现了OnClickLister 接口,并重写onClick方法
OnClickLister clickLister=new OnClickLister() {
//可以在匿名内部类中定义属性,但只能在当前内部类中使用
//无法在外部类中使用,因为外部类无法获得当前匿名内部类的类名
//也就无法创建匿名内部类的对象
int f1=1;
public void onClick(Object object) {
System.out.println("对象"+object+"被点击!");
System.out.println("其外部类的outF1 字段的值:"+outF1);
System.out.println("其外部类的outF2 字段的值:"+outF2);
System.out.println("其外部类的outF3 字段的值:"+outF3);
System.out.println("其外部类的outF4 字段的值:"+outF4);
}
};
clickLister.onClick(new Object());
System.out.println("---------------------------");
//new Object() 过程会新建一个匿名内部类,继承与Object类
//并重写了toString()方法
clickLister.onClick(new Object(){
public String toString(){
return "obj1";
}
});
}
public static void main(String[] args) {
OuterClass3 outerClass=new OuterClass3();
outerClass.anonymousClassTest();
//InnerClass innerClass=outerClass.new InnerClass();
}
}
结果:
创建OuterClass3对象
对象java.lang.Object@17550481被点击!
其外部类的outF1 字段的值:1
其外部类的outF2 字段的值:2
其外部类的outF3 字段的值:3
其外部类的outF4 字段的值:4
---------------------------
对象obj1被点击!
其外部类的outF1 字段的值:1
其外部类的outF2 字段的值:2
其外部类的outF3 字段的值:3
其外部类的outF4 字段的值:4
上面的代码中展示了常见的两种使用匿名内部类的情况:
1、直接 new 一个接口,并实现这个接口声明的方法,在这个过程其实会创建一个匿名内部类实现这个接口,并重写接口声明的方法,然后再创建一个这个匿名内部类的对象并赋值给前面的 OnClickListener 类型的引用;
2、new 一个已经存在的类 / 抽象类,并且选择性的实现这个类中的一个或者多个非 final 的方法,这个过程会创建一个匿名内部类对象继承对应的类 / 抽象类,并且重写对应的方法。
在匿名内部类中可以使用外部类的属性,但是外部类却不能使用匿名内部类中定义的属性,因为是匿名内部类,因此在外部类中无法获取这个类的类名,也就无法得到属性信息。
局部内部类
public class InnerClassTest {
public int field1 = 1;
protected int field2 = 2;
int field3 = 3;
private int field4 = 4;
public InnerClassTest() {
System.out.println("创建 " + this.getClass().getSimpleName() + " 对象");
}
private void localInnerClassTest() {
// 局部内部类 A,只能在当前方法中使用
class A {
// static int field = 1; // 编译错误!局部内部类中不能定义 static 字段
public A() {
System.out.println("创建 " + A.class.getSimpleName() + " 对象");
System.out.println("其外部类的 field1 字段的值为: " + field1);
System.out.println("其外部类的 field2 字段的值为: " + field2);
System.out.println("其外部类的 field3 字段的值为: " + field3);
System.out.println("其外部类的 field4 字段的值为: " + field4);
}
}
A a = new A();
if (true) {
// 局部内部类 B,只能在当前代码块中使用
class B {
public B() {
System.out.println("创建 " + B.class.getSimpleName() + " 对象");
System.out.println("其外部类的 field1 字段的值为: " + field1);
System.out.println("其外部类的 field2 字段的值为: " + field2);
System.out.println("其外部类的 field3 字段的值为: " + field3);
System.out.println("其外部类的 field4 字段的值为: " + field4);
}
}
B b = new B();
}
// B b1 = new B(); // 编译错误!不在类 B 的定义域内,找不到类 B,
}
public static void main(String[] args) {
InnerClassTest outObj = new InnerClassTest();
outObj.localInnerClassTest();
}
}
在局部内部类里面可以访问外部类对象的所有访问权限的字段,而外部类却不能访问局部内部类中定义的字段,因为局部内部类的定义只在其特定的方法体 / 代码块中有效,一旦出了这个定义域,那么其定义就失效了,就像代码注释中描述的那样,即外部类不能获取局部内部类的对象,因而无法访问局部内部类的字段。