java中的内部类

本文深入解析Java内部类的概念、分类及应用场景,包括成员内部类、局部内部类、匿名内部类和静态内部类的特点与用法,并通过实例演示如何利用内部类简化程序设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可将一个类定义置入另一个类定义中。这就叫作“内部类”。内部类对我们非常有用,因为利用它可对那些逻辑上相互联系的类进行分组,并可控制一个类在另一个类里的“可见性”。

为何要使用内部类,有以下比较基本的原因:

(1) 我们准备实现某种形式的接口,使自己能创建和返回一个句柄。

(2) 要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。(通过内部类隐藏实施细节)

基本注意点

1.普通类(指的是非内部类)不可设为private或 protected——只允许 public或者“友好的”,而内部类可以,这么做可将具体的实施细节完全隐藏起来。

2.对于局部内部类和匿名类(尤其是if语句内的局部内部类),并不意味着内部类是有条件创建的——它会随同其他所有东西得到编译。然而,在定义它的那个作用域之外,它是不可使用的。

3.对于局部内部类和匿名类,和局部变量一样,不能被public,protected,private和static修饰。局部内部类(含匿名类)只能访问局部方法中定义的final类型的局部变量。(注意:这里说的是所处方法作用域内的局部变量,如果是外部类中的局部变量,可直接使用)

4.非static内部类不能定义static变量,除非是final类型。

5.内部类拥有对封装类所有元素的访问权限。(当然,如果内部类是static的,必须变量也是static的。究其原因,静态内部类没有指向外部的引用)

6.一般来说,接口中不能有具体实现。但内部类可以作为接口的一部分。(通常是static内部类,否则可能没有实际意义。)

Java中的内部类共分为四种

成员内部类member inner class

局部内部类local inner class

匿名内部类anonymous inner class

静态内部类static inner class (also called nested class)

下面详细介绍:

成员内部类

成员内部类基本用法

abstract class Contents {
	abstract public int value();
}

interface Destination {
	String readLabel();
}

class Parcel3 {
	private class PContents extends 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 label; 
		}
	}
    public Destination dest(String s) {
    	return new PDestination(s);
	}
	public Contents cont() {
		return new PContents();
	}
}
 public static void Test2(){
    	Parcel3 p = new Parcel3();
    	Contents c = p.cont();
    	Destination d = p.dest("Tanzania");
    	// Illegal -- can't access private class:
    	//! Parcel3.PContents c = p.new PContents();
    }

局部内部类

在一个方法内定义内部类

class Parcel4 {
	public Destination dest(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 static void main(String[] args) {
		Parcel4 p = new Parcel4();
		Destination d = p.dest("Tanzania");
	}
}

在任意作用域内定义内部类

class Parcel5 {
	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) {
		Parcel5 p = new Parcel5();
		p.track();
	}
}

匿名内部类

匿名内部类就是没有名字的局部内部类,不使用关键字class, extends, implements, 没有构造方法。匿名内部类隐式地继承了一个父类或者实现了一个接口。也就是说,匿名类可以继承一个基础类,也可以实现一个接口,但不需要使用关键字,而是直接覆盖父类。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。如果匿名类实现了一个接口,该类是Object类的直接子类。

匿名内部类基本用法

class Wrapping {
	private int i;
	public Wrapping(int x) { 
		i = x; 
	}
	public int value() { 
		return i;
	}
} 

interface Wrapping2 {
	public int value();
}

//匿名类
class Parcel7 {
	public Wrapping wrap(int x) {
		// Base constructor call:
		return new Wrapping(x){
			public int value() {
				return super.value() * 47;
			}
		}; // Semicolon required
	}
	public Wrapping2 wrap2() {//既可以是一个基础类,也可以是一个接口
		return new Wrapping2(){
			public int value() {
				return 0;
			}
		};
	}
	public static void main(String[] args) {
		Parcel7 p = new Parcel7();
		Wrapping w = p.wrap(10);
		Wrapping2 w2=p.wrap2();
	}
}

匿名内部类不可以有构造方法,但还是可以对变量进行初始化的。

匿名类变量初始化

class Parcel8 {
	// Argument must be final to use inside
	// anonymous inner class:
	public Destination dest(final String dest) {
		return new Destination() {
			private String label = dest;
			public String readLabel() {
				return label;
			}
		};
	}
	public static void main(String[] args) {
		Parcel8 p = new Parcel8();
		Destination d = p.dest("Tanzania");
		System.out.println(d.readLabel());
	}
}
利用构造代码块初始化
class Parcel9 {
	public Destination dest(final String dest) {
		return new Destination() {
			{
			   System.out.println("代码块初始化!");
			}
			private String label = dest;
			public String readLabel() { 
				return label;
			}
		};
	}
	public static void main(String[] args) {
		Parcel9 p = new Parcel9();
		Destination d = p.dest("Tanzania");
	}
}
但构造代码块毕竟不是构造器,不能进行过载。

静态内部类

static内部类并不是说一个内部类是static 的。static内部类意味着:

(1) 创建一个 static内部类的对象,我们不需要一个外部类对象。

(2) 不能从 static内部类的一个对象中访问一个外部类对象。(除非该对象是static的)

静态内部类基本用法

class Parcel10 {
	//public int a=0;
	public static int a=0;
	private static class PContents extends Contents {
		private int i = 11;
		public int value() { return i; }
	}
	protected static class PDestination implements Destination {
		private String label;
		private PDestination(String whereTo) {
			label = whereTo;
		}
		public String readLabel() { 
			return label; 
		}
	}
	public static Destination dest(String s) {
		return new PDestination(s);
	}
	public static Contents cont() {
		return new PContents();
	}
	public static Parcel101 getP(){
		return new Parcel101();
	}
	public static int getA(){
		return a; //a也必须是static
	}
	public static void main(String[] args) {
		Contents c = cont();
		Destination d = dest("Tanzania");//这里没有显示调用static内部类,但方法是static,所以内部类必须是static的
		Parcel101 p= getP();//外部类没有static一说,可直接使用
		int b=getA();//变量同理,由于方法是static,因此变量必须是static
	}
}

接口中的静态内部类

以下为接口中内部类的一种用法,利用内部类编写公用测试方法。

class QuestionMain implements ITest{
    public static void main(String[] args) {
        ITest.TestInternal.test(new QuestionMain());
    }

    public void print() {
        System.out.println("QuestionMain.print");
    }
}

//接口中的内部类
interface ITest {

    void print();

    public static class TestInternal {
        public static void test(ITest test) {
            test.print();
        }
    }
}

除此之外,内部类还有一些其它特性


链接到外部类

interface Selector {
	boolean end();
	Object current();
	void next();
}

class Sequence {
	private Object[] o;
	private int next = 0;
	public Sequence(int size) {
		o = new Object[size];
	}
	public void add(Object x) {
		if(next < o.length) {
			o[next] = x;
			next++;
		}
	}
	private class SSelector implements Selector {
		int i = 0;
		public boolean end() {
			return i == o.length;
		}
		public Object current() {
			return o[i];
		}
		public void next() {
			if(i < o.length) i++;
		}
	}
	public Selector getSelector() {
		return new SSelector();
	}
	public static void main(String[] args) {
		Sequence s = new Sequence(10);
		for(int i = 0; i < 10; i++)
			s.add(Integer.toString(i));
		Selector sl = s.getSelector();
		while(!sl.end()) {
			System.out.println((String)sl.current());
			sl.next();
		}
	}
}

引用外部类对象

class Parcel11 {
	int a=1;
	int b=1;
	class Contents {
		private int i = 11;
		public int value() {
			return i; 
		}
	}
	class Destination {
		int a=2;
		private String label;
		Destination(String whereTo) {
			label = whereTo;
		}                       
		String readLabel() {
			return label; 
		}
		void getValue(){
			System.out.println(this.a);//this指向的是内部类
			//System.out.println(this.b); //内部类中无此值
		}
	}
	public static void main(String[] args) {
		Parcel11 p = new Parcel11();
		Parcel11.Contents c = p.new Contents();//非static的内部类必须通过外部类引用
		Parcel11.Destination d =p.new Destination("Tanzania");//不能绕过外部类直接为非static的开辟空间,所以采用这种写法
		d.getValue();
		//Parcel11.Contents c2 = new Parcel11.Contents(); //报错
	}
}

内部类继承

内部类继承比较特殊,子类必须有一个构造方法,且把外部类的一个对象作为参数。只有这样,才能保证内部类正常创建。

class WithInner {
	class Inner {}
}
class InheritInner extends WithInner.Inner {
	//! InheritInner() {} // Won't compile
	InheritInner(WithInner wi) {
		wi.super();
    }
	public static void main(String[] args) {
		WithInner wi = new WithInner();
		InheritInner ii = new InheritInner(wi);
	}
<strong>}</strong>

外部类被继承,内部类是否被覆盖

例子如下,被继承的只是外部类,子类中有一个和内部类同名的内部类,但这两个内部类并不存在继承关系

class Egg {
	protected class Yolk {
		public Yolk() {
			System.out.println("Egg.Yolk()");
		}
	}
	private Yolk y;
	public Egg() {
		System.out.println("New Egg()");
		y = new Yolk();
	}
}
class BigEgg extends Egg {
	public class Yolk {
		public Yolk() {
			System.out.println("BigEgg.Yolk()");
		}
	}
	public static void main(String[] args) {
		new BigEgg();
	}
} 

输出如下,Yolk并没有被继承

New Egg()
Egg.Yolk()

如果希望内部类也被继承,需要改动程序(这里是内部类继承内部类,同时外部类继承外部类,注意与上文的外部类继承内部类区分开来。)

class Egg2 {
	protected class Yolk {
		public Yolk() {
			System.out.println("Egg2.Yolk()");
		}
		public void f() {
			System.out.println("Egg2.Yolk.f()");
		}
	}
	private Yolk y = new Yolk();
	public Egg2() {
		System.out.println("New Egg2()");
	}
	public void insertYolk(Yolk yy) { 
		y = yy; 
	}
	public void g() { 
		y.f();
	}
}

class BigEgg2 extends Egg2 {
	public class Yolk extends Egg2.Yolk {
		public Yolk() {
			System.out.println("BigEgg2.Yolk()");
		}
		public void f() {
			System.out.println("BigEgg2.Yolk.f()");
		}
	}
	public BigEgg2() { 
		insertYolk(new Yolk());
	}
	public static void main(String[] args) {
		Egg2 e2 = new BigEgg2();
		e2.g();
	}
}

输出如下,Yolk方法被覆盖

Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()

利用内部类控制框架


内部类可以做这些事情:

(1) 在单独一个类里表达一个控制框架应用的全部实施细节,从而完整地封装与那个实施有关的所有东西。内部类用于表达多种不同类型的action(),它们用于解决实际的问题。除此以外,后续的例子使用了private内部类,所以实施细节会完全隐藏起来,可以安全地修改。
(2) 内部类使我们具体的实施变得更加巧妙,因为能方便地访问外部类的任何成员。若不具备这种能力,代码看起来就可能没那么使人舒服,最后不得不寻找其他方法解决。

例子:

abstract class Event {
	private long evtTime;
	public Event(long eventTime) {
		evtTime = eventTime;
	}
	public boolean ready() {
		return System.currentTimeMillis() >= evtTime;
	}
	abstract public void action();
	abstract public String description();
}

class EventSet {
	private Event[] events = new Event[100];
	private int index = 0;
	private int next = 0;
	public void add(Event e) {
		if(index >= events.length)
			return; // (In real life, throw exception)
		events[index++] = e;
	}
	public Event getNext() {
		boolean looped = false;
		int start = next;
		do {
			next = (next + 1) % events.length;
			// See if it has looped to the beginning:
			if(start == next) looped = true;
			// If it loops past start, the list
			// is empty:
			if((next == (start + 1) % events.length)&& looped)
				return null;
		} while(events[next] == null);
		return events[next];
	}
	public void removeCurrent() {
		events[next] = null;
	}
}

class Controller {
	private EventSet es = new EventSet();
	public void addEvent(Event c) { 
		es.add(c);
	}
	public void run() {
		Event e;
		while((e = es.getNext()) != null) {
			if(e.ready()) {
				e.action();
				System.out.println(e.description());
				es.removeCurrent();
			}
		}
	}
} 

class GreenhouseControls extends Controller {
	private boolean light = false;
	private boolean water = false;
	private String thermostat = "Day";
	private class LightOn extends Event {
		LightOn(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Put hardware control code here to
			// physically turn on the light.
			light = true;
		}
		public String description() {
			return "Light is on";
		}
	}
	private class LightOff extends Event {
		public LightOff(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Put hardware control code here to
			// physically turn off the light.
			light = false;
		}
		public String description() {
			return "Light is off";
		}
	}
	private class WaterOn extends Event {
		public WaterOn(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Put hardware control code here
			water = true;
		}
		public String description() {
			return "Greenhouse water is on";
		}
	}
	private class WaterOff extends Event {
		public WaterOff(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Put hardware control code here
			water = false;
		}
		public String description() {
			return "Greenhouse water is off";
		}
	}
	private class ThermostatNight extends Event {
		public ThermostatNight(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Put hardware control code here
			thermostat = "Night";
		}
		public String description() {
			return "Thermostat on night setting";
		}
	}
	private class ThermostatDay extends Event {
		public ThermostatDay(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Put hardware control code here
			thermostat = "Day";
		}
		public String description() {
			return "Thermostat on day setting";
		}
	}
	// An example of an action() that inserts a
	// new one of itself into the event list:
	private int rings;
	private class Bell extends Event {
		public Bell(long eventTime) {
			super(eventTime);
		}
		public void action() {
			// Ring bell every 2 seconds, rings times:
			System.out.println("Bing!");
			if(--rings > 0)
				addEvent(new Bell(System.currentTimeMillis() + 2000));
		}
		public String description() {
			return "Ring bell";
		}
	}
	private class Restart extends Event {
		public Restart(long eventTime) {
			super(eventTime);
		}
		public void action() {
			long tm = System.currentTimeMillis();
			// Instead of hard-wiring, you could parse
			// configuration information from a text
			// file here:
			rings = 5;
			addEvent(new ThermostatNight(tm));
			addEvent(new LightOn(tm + 1000));
			addEvent(new LightOff(tm + 2000));
			addEvent(new WaterOn(tm + 3000));
			addEvent(new WaterOff(tm + 8000));
			addEvent(new Bell(tm + 9000));
			addEvent(new ThermostatDay(tm + 10000));
			// Can even add a Restart object!
			addEvent(new Restart(tm + 20000));
		}
		public String description() {
			return "Restarting system";
		}
	}
	public static void main(String[] args) {
		GreenhouseControls gc =new GreenhouseControls();
		long tm = System.currentTimeMillis();
		gc.addEvent(gc.new Restart(tm));
		gc.run();
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值