Java之内部类

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编程思想》


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值