第十章 内部类 内部类和嵌套类

1.内部类访问外围类的成员方法

  • 内部类可以访问其外围类的方法和字段,就像他们自己的一样。
  • 当某个外围类的对象创建一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。
    在访问此外围类成员的时候,就用那个引用去访问外围类的成员,内部类对象只能在与其外围类的对象相关联
    的时候才能被创建。编译器会处理这些细节。

2.使用.this和.new

  • .this生成一个外部类对象的引用。
    public class DotThis {
    	void f(){System.out.println("DotThis.f()");}
    	public class Inner{
    		public DotThis outer(){
    			//.this 返回外部类对象
    			return DotThis.this;
    		}
    	}
    	public Inner inner(){return new Inner();}
    	public static void main(String[] args) {
    		DotThis dt = new DotThis();
    		Inner dti = dt.inner();
    		dti.outer().f();
    	}
    }
    
  • .new 生成内部类的对象。
    public class DotNew {
    	public class Inner{}
    	public static void main(String[] args) {
    		DotNew dn = new DotNew();
    		//注意这里 你不能new DotNew.Inner();
    		Inner dni = dn.new Inner();
    	}
    }
    可以看到上面的代码必须生成一个外部类对象,然后才能生成内部类对象。
    因为在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会隐式的连接到创建它的外部类对象上。

3.内部类和向上转型

  • 当内部类向上转型为其父类的时候,得到的只是指向父类或接口的引用,所以只能调用父类或接口中所声明的方法(子类会重写这些方法),所以就隐藏了实现细节
    而声明private或protected(除非它的子类或同一包下的或外部类能访问)的内部类可以实现外部类外的类不能声明这个内部类的具体引用,所以内部类就实现了细节的隐藏。
    interface Destination{
    	String readLabel();
    }
    interface Contents{
    	int value();
    }
    class Parcel{
    	//内部类
    	private class PContents implements Contents{
    		private int i = 11;
    		public int value() {return i;}
    	}
    	//内部类
    	protected class PDestination implements Destination{
    		private String label;
    		private PDestination(String whereTo){label = whereTo;}
    		public String readLabel() {return null;}
    	}
    	public Destination destination(String s){return new PDestination(s);}
    	public Contents contents(){return new PContents();}
    }
    public class TestParcel {
    
    	public static void main(String[] args) {
    		Parcel p = new Parcel();
    		//通过p的方法获得,进行了向上转型
    		Contents c = p.contents();
    //		c = p.new PContents();这种是错误的行为,因为PContents是Parcel的私有内部类
    		Destination d = p.destination("哈哈");
    	}
    }
    

4.内部类的复杂使用

  • 内部类语法 覆盖了大量其他的更加难以理解的技术。
  1. 创建一个类,但又不希望这个类是公共可用的。像3一样,private的内部类。
  2. 一个定义在方法中的类。
  3. 一个定义在作用域的类,此作用域在方法的内部。
  4. 一个实现了接口的匿名类。
  5. 一个匿名类,它扩展了有非默认构造器的类。
  6. 一个匿名类,他执行字段初始化。
  7. 一个匿名类,他通过实例化实现构造器(匿名类不可能有构造器)。

4.1.一个定义在方法(域)中的内部类

  • 定义在方法中的内部类在方法外是不可以访问这个内部类的
    interface Destination{
    	String readLabel();
    }
    class Parcel{
    	//方法
    	public Destination destination(String s){
    		//内部类
    		class PDestination implements Destination{
    			private String label;
    			private PDestination(String whereTo){label = whereTo;}
    			public String readLabel() {return label;}
    		}
    		//返回这个对象,可以写一个引用获得这个对象
    		return new PDestination(s);
    	}
    }
    public class TestParcel {
    	public static void main(String[] args) {
    		Parcel p = new Parcel();
    		Destination d = p.destination("呵呵");
    	}
    } 
    

4.2.定义在作用域内的类

  • 定义在作用域内的类,在作用域外是不能够访问这个类的。
    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("x");
    			String s = ts.getSlip();
    		}
    	}
    	public void track(){internalTracking(true);}
    	public static void main(String[] args) {
    		Parcel6 p = new Parcel6();
    		p.track();
    	}
    }


4.3实现了接口匿名内部类

  • 匿名内部类一定伴随着抽象类或接口的继承。
  • interface Contents{
    	int value();
    }
    public class TestParcel {
    
    	public Contents contents(){
    		//可以看到下面这个实现了Contents接口的类并没有名字,它看起来像是创建了一个Contents对象。
    		return new Contents() {
    			private int i = 11;
    			public int value() {return i;}
    		};
    	}
    	public static void main(String[] args) {
    		TestParcel p = new TestParcel();
    		Contents c = p.contents();
    	}
    }
    上面是下面简化形式:??有问题
    interface Contents{
    	int value();
    }
    public class TestParcel {
    
    	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) {
    		TestParcel p = new TestParcel();
    		Contents c = p.contents();
    	}
    }
    

4.4扩展了非默认构造器的匿名内部类

  • class Wrapping{//这是一个普通的类
    	private int i;
    	public Wrapping(int x){i = x;}
    	public int value(){return i;}
    }
    public class Parcel7 {
    
    	public Wrapping wrapping(int x){
    		//也可以这样
    		return new Wrapping(x){
    			public int value() {
    				return super.value()*47;
    			}
    		};//此分号和其他return表达式的分号一样,代表表达式结束。
    	}
    }
    

4.5执行字段初始化的内部类

  • 如果一个匿名内部类希望使用一个在其外定义的对象,那么编译器会要求其参数引用是final的。
    interface Destination{
    	String readLabel();
    }
    public class TestParcel {
    
    	//final的参数
    	public Destination destination(final String dest){
    		return new Destination() {
    			//初始化
    			private String label = dest;
    			public String readLabel() {return label;}
    		};
    	}
    	public static void main(String[] args) {
    		TestParcel p = new TestParcel();
    		Destination d = p.destination("哈哈");
    	}
    }
    

4.6实例化实现构造的匿名内部类

  • 匿名内部类中不可能有命名构造器(因为它们根本就没有名字),但可以通过实力初始化,就能够达到为匿名内部类创建一个构造器的效果,但并不是一个构造器,只是达到效果。
  • abstract class Base{
    	public Base(int i){
    		System.out.println("Base constructor, i = " + i);
    	}
    	public abstract void f();
    }
    public class AnonymousConstructor {
            //参数i不必为final ,因为没有在匿名内部类中使用
    	public static Base getBase(int i){
    		return new Base(i) {
    			//使用这种方式实现实例化构造,  实例初始化
    			{System.out.println("Inside instance initializer");}
    			public void f() {
    				System.out.println("In anonymous f()");
    			}
    		};
    	}
    	public static void main(String[] args) {
    		Base base = getBase(47);
    		base.f();
    	}
    }
  • 实例初始化的实际效果就是构造器。但它受到了限——你不能重载实例初始化方法,所以你仅有一个这样的构造器。

4.7匿名内部类的限制

  • 匿名内部类既可以扩展类,也可以实现接口,但不能两者兼备。而且如果是实现接口,也只能实现一个。
  • 匿名内部类可以实现工厂模式。

5.嵌套类

  • 如果不需要内部类对象与外部类对象之间有联系,就将内部类声明为static。通常被称为嵌套类。
  • 普通的内部类对象是隐式的保存了一个指向外围类对象的引用。当内部类是static意味着
    要创建嵌套类的对象,并不需要依赖其外围类的对象
    不能从嵌套类的对象中访问非静态的外围类对象。
  • 普通内部类的字段和方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。但嵌套类可以
  • interface Destination{
    	String readLabel();
    }
    interface Contents{
    	int value();
    }
    public class TestParcel {
    
    	//嵌套类
    	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的构造方法 这表示外面是无法初始化的
    		private ParcelDestination(String whereTo){
    			label = whereTo;
    		}
    		public String readLabel() {return label;}
    		//定义一些静态方法
    		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("呵呵");
    	}
    }


6.接口内部的类

  • 放到接口中的任何类都是public和static的。因为是static的,只是将嵌套类置于接口的命名空间内。
    public interface ClassInInterface {
    	void howdy();
    	//内部类中实现外围接口。
    	class Test implements ClassInInterface{
    		public void howdy() {
    			System.out.println("Howdy!");
    		}
    		public static void main(String[] args) {
    			new Test().howdy();
    		}
    	}
    }
  • 如果你想要创建某些公共方法,使得他们能够被某个接口的所有不同实现公用,那么使用接口嵌套类会更方便。

7.从多层嵌套类中访问外部类的成员

  • 一个内部类被嵌套多少层并不重要——它能够透明的访问所有它嵌入的外围类的所有成员。
    class MNA{
    	private void f(){}
    	//一层嵌套
    	class A{
    		private void g(){}
    		//二层嵌套
    		public class B{
    			void h(){
    				//调用外部类的方法,不需要任何条件
    				g();
    				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();
    	}
    }
    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值