ThinkInJava_10_内部类

本文详细探讨了Java内部类的创建、链接外部类的方式、使用`.this`与`.new`,以及内部类与向上转型的关系。讲解了在方法和作用域中的内部类,匿名内部类的实现,嵌套类的概念和用途,以及为何需要内部类来解决多重继承问题。同时,讨论了内部类的继承和局部内部类的特点。
摘要由CSDN通过智能技术生成

10.1 创建内部类

public class Parcel2 {
	class Contents {}
	class Destination {}
	public Destination to() {
		return new Destination();
	}
	public Contents contents() {
		return new Contents();
	}
	public static void main(String[] args) {
		Parcel2 p = new Parcel2();
		Parcel2.Contents c = p.contents(); //外部类名.内部类名
		Parcel2.Destination d = p.to(); //Outer.Inner
	}
}
//从外部类的非静态方法之外的任意地方创建内部类对象
//外部类名.内部类名
//Outer.Inner

10.2 链接到外部类

  • 生成一个内部类对象时,此对象与制造它的外部类对象就有了一种联系,它能访问外部类对象的所有成员
  • 下面这个类使用了迭代器设计模式
    将一个迭代器作为一个固定长度数组类的迭代器
interface Selector {
	boolean end();
	Object current();
	void next();
}
public class Sequence {
	private Object[] items;
	private int next = 0;
	public Sequence(int size) { items = new Object[size]; }
	public void add(Object x) {
		if(next < item.length)
			item[next++] = x;
	}
	//内部类 SequenceSelector
	private class SequenceSelector implements Selector {
		private int i = 0;
		public boolean end() { return i == items.length; }
		public Object current() { return items[i]; }
		public void next() { if(i < items.length) i++; }
	}
	public SequenceSelector selector() {
		return new SequenceSelector();
	}
	public static void main(String[] args) {
		Sequence sequence = new Sequence(10);
		for(int i = 0;i < 10;i++)
			sequence.add(Integer.toString(i));
		Selector selector = sequence.selector();
		while(!selector.end())
			selector.next();
	}
}
  • 当某个外围类的对象创建了一个内部类对象时,该内部类对象会秘密地捕获一个指向那个外围类对象的引用
  • 内部类对象只有在和外部类对象相关联的时候才能被创建

10.3 使用 .this 与 .new

//内部类引用外部类对象
外部类名.this
public class Outer {
	void f() {}
	public class Inner {
		public Outer outer() {
			return Outer.this;
		}
	}
}
//外部类创建内部类对象
由某个外部类对象创建一个内部类对象,必须用
外部类名.内部类名 内部类对象名 = 外部类对象名.new 内部类名();
Outer.Inner in = out.new Inner();

10.4 内部类与向上转型

  • 内部类可以向上转型为一个 interface ,作为它的一个实现
interface Contents {
	int value();
}
public class Outter {
	private class MyContents implements Contents {
		int value() {}
	}
}
  • private 的内部类仅外部类能够访问,protected 的内部类仅外部类及其子类能访问,甚至不能向下转型成 private 的

在方法和作用域中的内部类

  • 1)你实现了某种接口,于是可以创建并返回对其的引用
  • 2)你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但又不希望这个类是公共可用的
//在方法里返回一个内部类对象,内部类直接在方法内部定一个
public class Parcel {
	public Destination destination(String s) {
		class MyDestiation implements Destination {
			private String label;
			private MyDestination(String whereTo) {
				label = whereTo;
			}
		}
		return new MyDestination(s);
	}
	//内部类 MyDestination 是方法 destination 的一部分,因此只能在方法内部访问
	//返回对象是 MyDestination ,引用是向上转型的基类引用 Destination
}
//在域中的类
class Outter {
	public void f(boolean b) {
		if(b) {
			class Inner {}
		}
		Inner in = new Inner(); //在域中创建的内部类不能在域外访问
}

10.6 匿名内部类

public class Outter {
	public Contents contents(int x) { //将返回值与类的定义绑定在一起
		return new Contents(x) { //传递构造器参数
			private int i = 1;
		}; //这个;表示 return 这个语句的结束
	}
}
//Contents 是一个接口,这里创建的是一个匿名的Contents类的实现类的对象
  • 内部类作为接口的实现类
interface Service {
	public void method1();
	public void method2();
}
//制造不同Service对象的工厂
interface ServiceFactory {
	Service getService();
}
class Implementation1 implements Service {
	private Implementation1() {}
	public void method1() {}
	public void method2() {}
	public static ServiceFactory factory = 
		new ServiceFactory() {
			public Service ServiceFactory() {
				return new Implementation1();
			}
		}
	}
}
class Implementation2 implements Service {
	private Implementation2() {}
	public void method1() {}
	public void method2() {}
	public static ServiceFactory factory = 
		new ServiceFactory() {  //接口的一个实现,内部类
			public Service ServiceFactory() {
				return new Implementation2();
			}
		}
	}
}
pubic class Factories {
	public static void serviceConsumer(ServiceFactory fact) {
		Service s = fact.getService();
		s.method1();
		s.method2();
	}
	public static void main(String[] args) {
		serviceConsumer(Implementation1.factory);
		serviceConsumer(Implementation2.factory);
	}
}
//工厂设计模式
interface Iphone {}
interface IphoneFactory {
	Iphone getIphone();
}
class Iphone11 implements Iphone {}

10.7 嵌套类

  • 如果不需要内部类和外部类之间连结的关系,可以将内部类声明为 static 的,这称为嵌套类
    1)创建嵌套类对象,不需要外部类对象
    2)嵌套类不能访问外部类非静态成员
class Parcel {
	private static class ParcelContents implements Contents {}
	public static Contents contents() {
		return new ParcelContents();
	}
}
  • 接口中放入嵌套类,接口中的任何类都自动是 public 和 static 的
  • 为接口创建一些公共代码,为所有实现类所公用
public interface ClassInInterface {
	void howdy() {}
	class Test implements ClasInInterface {
		public void howdy() {}
	}
	public static void main(String[] args) {
		new Test();
	}
}
  • 用嵌套类对类代码进行测试
public class TestBed {
	public void f() {}
	public static class Tester {
		public static void main(String[] args) {
			TestBed t = new TestBed();
			t.f();
		}
	}
}
//执行 java TestBed$Tester

10.8 为什么需要内部类

  • 内部类提供了某种进入外部类的窗口
  • 每个内部类能够独立地继承一个接口的实现,所以无论外部类是否已经继承了接口,对内部类都没有影响
  • 内部类可以解决多重继承的问题,在一个类内部实现多个接口,如果单单是继承,一个类只能继承自一个基类
    1)内部类可以有多个实例,每个实例有自己的状态信息,并且与外部类的信息相互独立
    2)单个外围类中,可以让多个内部类实现同一个接口
    3)创建内部类对象的时刻并不依赖于外围类对象的创建
    4)没有令人疑惑的 is-a 关系
  • 内部类是面向对象的一种闭包,它拥有外部类对象的引用,可以访问外部类对象的任何成员
public class GreenHouseControls extends Controller {
	private boolean light = false;
	public class LightOn extends Event {
		public LightOn(long delayTime) { super(delayTime); }
		public void action() {
			light = true;
		}
	}
	public class LightOff extends Event {
		public LightOff(long delayTime) { super(delayTime); }
		public void action() {
			light = false;
		}
	}
	private boolean water = false;
	public class WaterOn extends Event {
		public WaterOn(long delayTime) { super(delayTime); }
		public void action() {
			water = true;
		}
	}
	public class WaterOff extends Event {
		public WaterOff(long delayTime) { super(delayTime); }
		public void action() {
			water = false;
		}
	}
}

10.9 内部类的继承

  • 内部类继承类必须初始化外部类,调用外部类构造器,这一语句应在内部类继承类中显式调用
class Outter {
	class Inner {}
}
public class InheritInner extends Outter.Inner {
	InheritInner(Outter wi) {
		wi.super(); //必须要有这个初始化,否则无法编译
	}
	public static void main(String[] args) {
		Outter wi = new Outter();
		InheritInner ii = new InheritInner(wi);
	}
}

10.10 内部类可以被覆盖吗

class Egg {
	private Yolk y;
	protected class Yolk {
		public Yolk() { System.out.println("Egg.Yolk()"); }
	}
	public Egg() {
		System.out.println("new Egg()");
		y = new Yolk();
	}
}
public class BigEgg extends Egg {
	public class Yolk {
		public Yolk() { System.out.println("BigEgg.Yolk()"); } //并不会调用这个版本的构造器,因为两个 Yolk 类本质上是两个独立的类,没有关联
	}
	public static void main(String[] args) {
		new BigEgg();
	}
}
/*
new Egg()
Egg.Yolk()
*/

10.11 局部内部类



interface Counter {
	int next();
}
public class LocalInnerClass {
	private int counter = 0;
	Counter getCounter(final String name) {
		class LocalCounter implements Counter {
			public LocalCounter() {
				System.out.println("LocalCounter");
			}
			public int next() {
				System.out.println(name);
				return counter++;
			}
		}
		return new LocalCounter();
	}
	Counter getCounter2(final String name) {
		return new Counter() {
			{
				System.out.println("Counter");
			}
			public int next() {
				System.out.println(name);
				return counter++;
			}
		};
	}
	public static void main(String[] args) {
		LocalInnerClass lic = new LocalInnerClass();
		Counter c1 = lic.getCounter("Local Inner");
		Counter c2 = lic.getCounter2("Anonymous inner ");
		for(int i = 0;i < 5;i++)
			System.out.println(c1.next());
		for(int i = 0;i < 5;i++)
			System.out.println(c2.next());
	}
}
/*
LocalCounter
Counter
Local Inner
0
Local Inner
1
Local Inner
2
Local Inner
3
Local Inner
4
Anonymous inner 
5
Anonymous inner 
6
Anonymous inner 
7
Anonymous inner 
8
Anonymous inner 
9
*/
  • 已命名的局部内部类可以使用已命名的构造器,而匿名的内部类只能用于实例初始化

10.12 内部类标识符

Counter.class
LocalInnerClass$1.class
LocalInnerClass$1LocalCounter.class
LocalInnerClass.class
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值