1、创建内部类
可以将一个类的定义放在另一个类的定义内部,这就是内部类。
public class OuterClass {
static InnerClass iClass1 = new OuterClass().new InnerClass();//静态变量
OuterClass.InnerClass iClass3 = new InnerClass();//非静态变量声明方法
InnerClass iClass4 = new InnerClass();//非静态变量声明方法
class InnerClass {//内部类
private int i = 11;
public int value() { return i; }
}
public void ship() {//调用非静态变量
System.out.println("iClass3="+iClass3.value());
System.out.println("iClass4="+iClass4.value());
}
public static void main(String[] args) {
System.out.println("iClass1="+iClass1.value());//调用静态变量
new OuterClass().ship();
}
}
2、链接到外部类
内部类很适合隐藏代码。但是最引人注目的还是在生成一个内部类的对象时,此对象与制造它的外围对象之间有一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外内部类还拥有其外围类所有元素的访问权,因为当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密的捕捉到一个指向那个外围类对象的引用。然后,在你访问此外围类的成员时,就是用那个引用来选择外围类的成员。幸运的是,编译器会帮你处理所有的细节。
interface InnerInterface {
boolean end();
}
public class OuterClass2 {
private int i = 0;
private class InnerClass implements InnerInterface {
private int j = 0;
public boolean end() { return i == j; }//可以直接访问外围类的私有变量i
}
public InnerClass innerClass() {
return new InnerClass();
}
public static void main(String[] args) {
OuterClass2 oClass = new OuterClass2();
InnerInterface iClass = oClass.innerClass();
System.out.print(iClass.end());
}
}
内部类可以通过外部类的名字后跟小圆点和this(eg:OutClass.this)来获取外部类对象的引用。这样产生的引用自动具有正确的类型,并且在编译器就被知晓并获得检查,因此没有任何时候的开销。
3、在方法和作用域里的内部类
在方法的作用域中创建一个内部类
interface Destination {
String readLabel();
}
public class Parcel5 {
public Destination destination(String s) {//在方法的作用域里的内部类,局部内部类
//该类是destination方法的一部分,而不是Parcel5的一部分,故在destination方法外不能访问PDestination
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() { return label; }
}
return new PDestination(s);//返回一个引用,其他地方也可以使用该内部类
}
public static void main(String[] args) {
Parcel5 p = new Parcel5();
Destination d = p.destination("Tasmania");
}
}
在任意的作用域中嵌套一个内部类
public class Parcel6 {
private void internalTracking(boolean b) {
if (b) {
class TrackingSlip {//定义了一个内部类,不用管,直接看后面代码
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() {
return id;
}
}
TrackingSlip ts = new TrackingSlip("slip");//此处再去调用内部类
String s = ts.getSlip();
}
// 出了方法题,不能再调用TrackingSlip ts = new TrackingSlip("x");
}
public void track() {
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 p = new Parcel6();
p.track();
}
}
4、匿名内部类
interface Contents {
int value();
}
public class Parcel7 {
public Contents contents() {
return new Contents() { //这个类是匿名的,没有名字,
private int i = 11;
public int value() {
return i;
}
};
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
这种语法是创建一个继承自Contents的匿名类的对象。通过new表达式返回引用被自动向上转型为对Contents的引用。上述匿名内部类的语法是下述的简化形式:
interface Contents {
int value();
}
public class Parcel7b {
class MyContents implements Contents {
private int i = 11;
public int value() {
return i;
}
}
public Contents contents() {
return new MyContents();//返回一个引用
}
public static void main(String[] args) {
Parcel7b p = new Parcel7b();
Contents c = p.contents();
}
}
上述是使用了默认的构造器来生成Contents。下面的代码展示的是,如果你的基类需要一个有参数构造器:
class Wrapping {
private int i;
public Wrapping(int x) {//构造器
i = x;
}
public int value() {
return i;
}
}
public class Parcel8 {
public Wrapping wrapping(int x) {
return new Wrapping(x) { //传入参数
public int value() {
return super.value() * 47;
}
};
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);//传参数
}
}
如果定义了一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的,就像在destination()的参数看到的那样。否则会获得一个编译时的错误消息。
interface Destination {
String readLabel();
}
public class Parcel9 {
public Destination destination(final String dest) {
return new Destination() {
private String label = dest;//此处匿名类内部直接引用了外部定义的对象,声明时必须是final
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
另外,匿名内部类既可以扩展类,也可以扩展接口,但是不能两者兼备。而且如果是扩展接口,也只能实现一个借口。
5、嵌套类
如果不需要内部类对象与外围类对象之间有联系,可以将内部类声明为static。这通常称为嵌套类。想要理解static应用于内部类的含义,就必须记住,普通内部类对象的隐式的保存了一个引用,指向创建它的外围类对象。然而当内部类是static的时候,就不是这样了,嵌套类意味着:
- 要创建嵌套类的对象,并不需要其外围类的对象
- 不能从嵌套类对象重访问非静态的外围类对象
嵌套类和普通内部类还有一个区别:普通内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可以包含这些东西。
interface Contents {
int value();
}
interface Destination {
String readLabel();
}
public class Parcel11 {
private static class ParcelContents implements Contents {
private int i = 11;
public int value() {
return i;
}
}
protected static class ParcelDestination implements Destination {
private String label;
private ParcelDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
// Nested classes can contain other static elements:
public static void f() {
}
static int x = 10;
static class AnotherLevel {
public static void f() {
}
static int x = 10;
}
}
public static Destination destination(String s) {
return new ParcelDestination(s);
}
public static Contents contents() {
return new ParcelContents();
}
public static void main(String[] args) {
Contents c = contents();
Destination d = destination("Tasmania");//直接调用static
}
}
6、从多层嵌套类中访问外部类的成员
一个内部类被嵌套多少层并不重要,它能透明地访问它所嵌入的外围类的所有成员:
class MNA {
private void f() {
}
class A {
private void g() {
}
public class B {
void h() {
g();//访问私有方法g()
f();//访问f()
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args) {
MNA mna = new MNA();
MNA.A mnaa = mna.new A();
MNA.A.B mnaab = mnaa.new B();
mnaab.h();
}
}
参考资料《Java编程思想》