一、非静态内部类。
1、修饰符
非静态内部类有四个作用域,所以有四个修饰符。
private : 只能在外部类的内部使用。
protected : 可被与外部类处于同一个包中的其他类和外部类的子类所访问。
省略 : 只能被与外部类处于同一个包中的其他类访问。
public : 可以在任何地方被访问。
static:
2、特点
a) 非静态内部类成员可以直接访问外部类的私有成员(反过来是不成立的),外部类不能访问内部类的实现细节,例如内部类的成员变量。
b) 非静态内部类不可以拥有静态成员。
c) 局部内部类和匿名内部类不是类成员。
d) 在非静态内部类对象里,保存了一个它所寄生的外部类对象的引用。(当调用非静态内部类的实例方法时,必须有一个非静态内部类实例,非静态内部类实例必须寄生在外部类实例里)
public class Cow{private double weight;// 外部类的两个重载的构造器public Cow(){System.out.println("Cow.Cow()");}public Cow(double weight){System.out.println("Cow.Cow(double weight)");this.weight = weight;}// 定义一个非静态内部类class CowLeg{// 非静态内部类的两个实例变量private double length;private String color;// 非静态内部类的两个重载的构造器public CowLeg(){System.out.println("Cow.CowLeg.CowLeg()");}public CowLeg(double length , String color){this.length = length;this.color = color;System.out.println("Cow.CowLeg.CowLeg(double length , String color)");}// 下面省略length、color的setter和getter方法public void setLength(double length){this.length = length;}public double getLength(){return this.length;}public void setColor(String color){this.color = color;}public String getColor(){return this.color;}// 非静态内部类的实例方法public void info(){System.out.println("当前牛腿颜色是:"+ color + ", 高:" + length);// 直接访问外部类的private修饰的成员变量System.out.println("本牛腿所在奶牛重:" + weight); //①}}public void test(){CowLeg cl = new CowLeg(1.12 , "黑白相间");cl.info();}public static void main(String[] args){Cow cow = new Cow(378.9);cow.test();//CowLeg cowleg = new Cow().new CowLeg();}
}
e) 非静态内部类直接范围外部类的private访问权限的实例变量。
f) 在内部类方法中如何访问同名的变量
外部类类名.this.变量 访问的是外部类的成员变量
this.变量 访问内部类的成员变量
变量 方法里面定义的变量
public class DiscernVariable{private String prop = "外部类的实例变量";private class InClass{private String prop = "内部类的实例变量";public void info(){String prop = "局部变量";// 通过 外部类类名.this.varName 访问外部类实例变量System.out.println("外部类的实例变量值:"+ DiscernVariable.this.prop);// 通过 this.varName 访问内部类实例的变量System.out.println("内部类的实例变量值:" + this.prop);// 直接访问局部变量System.out.println("局部变量的值:" + prop);}}public void test(){InClass in = new InClass();in.info();}public static void main(String[] args){new DiscernVariable().test();}
}
public class Outer{private int outProp = 9;public class Inner{private int inProp = 5;public void acessOuterProp(){// 非静态内部类可以直接访问外部类的private成员变量System.out.println("外部类的outProp值:"+ outProp);}}public void accessInnerProp(){// 外部类不能直接访问非静态内部类的实例变量,// 下面代码出现编译错误// System.out.println("内部类的inProp值:" + inProp);// 如需访问内部类的实例变量,必须显式创建内部类对象System.out.println("内部类的inProp值:"+ new Inner().inProp);}public static void main(String[] args){// 执行下面代码,只创建了外部类对象,还未创建内部类对象Outer out = new Outer(); //①out.accessInnerProp();}
}
g) 如需访问内部类的实例变量,必须显式创建内部类对象
new Inner().inProp
h)非静态内部类对象必须寄生在外部类对象里,而外部类对象则不一定有非静态内部类对象寄生其中。
i) 静态成员不能访问非静态成员
外部类的静态方法,静态代码块不能访问非静态内部类(包括不能使用非静态内部类定义变量,创建实例等),总之,不允许在外部类的静态成员中直接使用非静态内部类。
public class StaticTest{// 定义一个非静态的内部类,是一个空类private class In{}// 外部类的静态方法 public static void main(String[] args){// 下面代码引发编译异常,因为静态成员(main()方法)// 无法访问非静态成员(In类)//new In();}
}
j) Java不允许在非静态内部类里定义静态成员
public class InnerNoStatic{private class InnerClass{/*下面三个静态声明都将引发如下编译错误:非静态内部类不能有静态声明*/static{System.out.println("==========");}private static int inProp;private static void test(){}}
}
非静态内部类里不能有静态方法,静态成员变量,静态初始化快(但可以包含普通初始化快,非静态内部类普通初始化快的作用与外部类初始化快的作用完全相同)。
二、静态内部类(类内部类)
1、特点
a) 静态内部类属于外部类本身,而不属于外部类的某个对象。
static关键字的作用是把类的成员变量变成类相关,而不是实例相关,即static修饰的成员属于整个类,而不属于单个对象。内部类的上一级程序单元是外部类,使用static修饰可以将内部类变成外部类相关,而不是外部类实例相关。
public class StaticInnerClassTest{private int prop1 = 5;private static int prop2 = 9;static class StaticInnerClass{// 静态内部类里可以包含静态成员private static int age;public void accessOuterProp(){// 下面代码出现错误:// 静态内部类无法访问外部类的实例变量// System.out.println(prop1);// 下面代码正常System.out.println(prop2);}}
}
b) 外部类依然不能直接访问静态内部类的成员。
c) 使用静态内部类的类名作为调用者来访问静态内部类的类成员。
d) 使用静态内部类对象作为调用者来访问静态内部类的实例成员。
public class AccessStaticInnerClass{static class StaticInnerClass{private static int prop1 = 5;private int prop2 = 9;}public void accessInnerProp(){// System.out.println(prop1);// 上面代码出现错误,应改为如下形式:// 通过类名访问静态内部类的类成员System.out.println(StaticInnerClass.prop1);// System.out.println(prop2);// 上面代码出现错误,应改为如下形式:// 通过实例访问静态内部类的实例成员System.out.println(new StaticInnerClass().prop2);}
}
三、接口里定义内部类
接口里定义的内部类默认使用public static 修饰(写不写都是,也只能这样写),也就是说,接口内部类只能是静态内部类。
四、使用内部类
1、在外部类以外使用非静态内部类
a) 非静态内部类的构造器必须使用外部类对象来调用。
class Out{// 定义一个内部类,不使用访问控制符,// 即只有同一个包中其他类可访问该内部类class In{public In(String msg){System.out.println(msg);}}
}
public class CreateInnerInstance{public static void main(String[] args){Out.In in = new Out().new In("测试信息");/*上面代码可改为如下三行代码:使用OutterClass.InnerClass的形式定义内部类变量Out.In in;创建外部类实例,非静态内部类实例将寄存在该实例中Out out = new Out();通过外部类实例和new来调用内部类构造器创建非静态内部类实例in = out.new In("测试信息");*/}
}
在外部类以外的地方创建非静态内部类的子类。
public class SubClass extends Out.In{//显示定义SubClass的构造器public SubClass(Out out){//通过传入的Out对象显式调用In的构造器out.super("hello");}
}
2、在外部类以外使用静态内部类
class StaticOut{// 定义一个静态内部类,不使用访问控制符,// 即同一个包中其他类可访问该内部类static class StaticIn{public StaticIn(){System.out.println("静态内部类的构造器");}}
}
public class CreateStaticInnerInstance{public static void main(String[] args){StaticOut.StaticIn in = new StaticOut.StaticIn();/*上面代码可改为如下两行代码:使用OutterClass.InnerClass的形式定义内部类变量StaticOut.StaticIn in;通过new来调用内部类构造器创建静态内部类实例in = new StaticOut.StaticIn();*/}
}
从上面代码可以看出,不管是静态内部类还是非静态内部类,它们声明变量的语法完全一样。区别只是在创建内部类对象时,静态内部类只需使用外部类即可调用构造器,而非静态内部类必须使用外部类对象来调用构造器。
因为调用静态内部类的构造器时无需使用外部类对象,所以创建静态内部类的子类也比较简单。
public class StaticSubClass extends StaticOut.StaticIn{public static void main(String[] args) {new StaticSubClass();}
}
使用静态内部类比使用非静态内部类要简单很多,使用静态内部类时,只要把外部类当成静态内部类的包空间即可。