(Thinking in Java)内部类的简单使用

1. 成员内部类

1. 最基本使用

public class Demo {
	class Contents{
		private int i=11;
		public int value(){
			return i;
		}
	}
	
	class Destination{
		private String label;
		Destination(String whereTo){
			label=whereTo;
		}
		String readLabel(){
			return label;
		}
	}
	
	public void ship(String dest){
		Contents c=new Contents();
		Destination d=new Destination(dest);
		System.out.println(d.readLabel());
	}
	
	public static void main(String[] args) {
		Demo d=new Demo();
		d.ship("Tasmania");
	}
}

2.内部类可以访问外部类的成员

内部类可以访问外部类的成员变量。如下:

public class Demo {
	private Object[] items;
	private int next = 0;

	public Demo(int size) {
		items = new Object[size];
	}

	public void add(Object x) {
		if (next < items.length) {
			items[next++] = x;
		}
	}

	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 Selector selector() {
		return new SequenceSelector();
	}

	public static void main(String[] args) {
		Demo d = new Demo(10);
		for (int i = 0; i < 10; i++) {
			d.add(Integer.toString(i));
		}
		Selector selector = d.selector();
		while (!selector.end()) {
			System.out.print(selector.current() + " ");
			selector.next();
		}
	}
}

interface Selector {
	boolean end();

	Object current();

	void next();
}

因为在创建内部类对象的时候,内部类对象会捕获一个指向外部类对象的引用。访问外部类成员的时候,就是用这个引用来获取外部类成员的。内部类中也可以取得这个外部类对象引用。举例如下:

public class DotThis{
	void f(){
		System.out.println("DotThis.f()");
	}
	class Inner{
		public DotThis outer(){
			return DotThis.this;
			//A plain "this" would be Inner's this
		}
	}
	
	public Inner inner(){
		return new Inner();
	}
	
	public static void main(String[] args) {
		DotThis dt=new DotThis();
		DotThis.Inner dti=dt.inner();
		dti.outer().f();
	}
}

当要在其他类中创建一个内部类对象的时候,可以使用.new语法。

public class DotNew{
	public class Inner{
	}
	public static void main(String[] args){
		Inner dni=new DotNew().new Inner();
	}
}

当创造内部类对象的时候,如果这个内部类不是嵌套类(静态内部类),那么就必须要通过外部类对象,才能创建这个内部类对象,为什么呢,之前说过,因为这个内部类对象要获取外部类的引用啊。
并且在存在多个内部类的时候,多个内部类之间可以互相创建对象。例子就不举了。

小结:现在所说的都是成员内部类,其实内部类没那么复杂,既然叫做成员内部类了,他就只是类的成员罢了。他也可以带修饰符,他的修饰符和其他普通的成员变量的修饰符的意义也没有什么不同。

3. 内部类权限修饰符

当内部类被private修饰的时候,该类只能被外部类内的方法使用,其他类不能获取该内部类的引用,因为是private的,所以其他类根本不知道存在一个这样的类。当然也可以作为一个成员变量使用,但是如果作为成员变量,则其他类并不能直接创建内部类的引用,需要用其他手段获取该引用,如下:

class Outer{
	Inner in;
	private class Inner implements a_interface{
		void show(){
			System.out.println("123");
		}
	}
}
interface a_interface{
	void show();
}

class test{
	//Inner in=new Outer().in;这是错误的,因为test并不知道Outer类有一个Inner内部类,因为是私有的
	a_interface in=new Outer().in;//可以运用向上转型的方法获取private修饰的内部类。
}

小结:其实这也很好记,无论是public还是private,修饰到内部类上的时候,和他们修饰普通的成员变量(如string,int之类)的时候没什么不同,规则都一样,public就都能使用,private就类内可以用。所以规则就记住三条就好:1.先考虑外部类的权限,是否可以获取一个外部类对象。2.创建成员内部类对象的时候需要外部类对象。3.考虑内部类的权限,是否可以获取这样的一个内部类对象(或者说,在外部知不知道有这样一个内部类)。

2. 方法和作用域内的内部类

当我们需要解决一个复杂的问题,想创建一个类来辅助解决问题,但是不希望这个类是公共可用的,甚至不希望在外部类之内的其他地方可以访问到这个辅助类。我们可以运用方法内的内部类

public class Outer {
	public InterfaceDemo get_InterfaceDemo(String s) {
		 class InterfaceDemoTool implements InterfaceDemo {
			private String label;

			private InterfaceDemoTool(String label) {
				this.label = label;
			}

			public String readLabel() {
				return label;
			}
		}

		return new InterfaceDemoTool(s);
	}

	public static void main(String[] args) {
		Outer o = new Outer();
		InterfaceDemo i = o.get_InterfaceDemo("123");
	}
}

interface InterfaceDemo {
	String readLabel();
}

当然在方法中还可以定义多个内部类,并且这些内部类之间的关系和普通一个java文件中多个类之间的关系好像没什么不同。也可以相互继承和创建对象。另外在方法中的内部类不能加private等权限修饰符,只能加abstract和final修饰符。
另外也可以在某个作用域内创建内部类对象

if(a==b){
	class inner{
	}
	new inner();
}

上面的例子中,在if外就不能知道有这么个inner类了,他的作用域只在{…}之中,同理,在方法内定义的内部类,在方法外也不能知道存在这么个类,因为这个内部类的作用域只在这个方法内。

3.匿名内部类

下面这块代码中get_inner()的意思是,创建一个继承自InnerFather的匿名类对象,并且自动向上转型为InnerFather后返回。

public class Outer {
	public InnerFather get_inner() {
		return new InnerFather() {
			void print(){
				System.out.println("Inner_Override");
			}
		};
	}

	class InnerFather {
		InnerFather() {

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

	public static void main(String[] args) {
		Outer o = new Outer();
		InnerFather i = o.get_inner();
		i.print();
	}
}

当然这只是有无参构造函数,当父类只有一个含参构造函数的时候,我们可以这样向匿名内部类传入一个构造函数参数。

public class Outer {
	public InnerFather get_inner(int i) {
		return new InnerFather(i) {
			void print(){
				System.out.println("Inner_Override");
			}
		};
	}

	class InnerFather {
		InnerFather(int i) {

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

	public static void main(String[] args) {
		Outer o = new Outer();
		InnerFather i = o.get_inner(10);
		i.print();
	}
}

可以通过构造代码块来实现匿名内部类的自定义的构造函数

abstract class Base {
	public Base(int i) {
		System.out.println("Base constructor");
	}

	public abstract void f();
}

public class AnonymousConstructor {
	public static Base getBase(int i){
		return new Base(i){
			{System.out.println("AnonymousConstructor constructor");}
			public void f(){
			}
		};
	}

	public static void main(String[] args) {
		Base base = getBase(47);
	}
}

(书上说,如果传入了新的对象,就比如下面例子中的s_in,这个s_in就必须是final的,但是我实验了一下发现并不用啊,我也没太搞懂。)

abstract class Base {
	public Base(int i) {
		System.out.println("Base constructor");
	}

	public abstract void f();
}

public class AnonymousConstructor {
	public static Base getBase(int i,String s_in){
		return new Base(i){
			{System.out.println("AnonymousConstructor constructor");}
			String s=s_in;
			public void f(){
			}
		};
	}

	public static void main(String[] args) {
		Base base = getBase(47,"hello");
	}
}

4.嵌套类

嵌套类指的是被static修饰的内部类。这意味着:1.创建嵌套类对象不需要外部类对象。2.不能再嵌套类对象之中访问非静态的外围类对象。普通内部类的成员和方法只能放在类的外部层次上(这句话我没搞懂= =),所以普通内部类不能有static的成员和方法。但是嵌套类可以有。

public class Outer {
	static class Inner{
		static int i=5;
	}
	public static void main(String[] args) {
		Inner i=new Outer.Inner();
	}
}

可以从上面的例子看到,在创建这个嵌套类对象的时候,并没有像最开始那样,用一个外部类对象来创建这个内部类对象。其实这和静态方法差不多。

可以在接口内部定义内部类,而且他们即使没有static修饰,也会自动变成public 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();
		}
	}
}

书上有句话说的很好,在开发的时候建议在每个类中都写一个main方法测试,但是这又必须带着那些已经编译过的额外代码,所以我们可以用嵌套类放置测试代码。

public class Outer {
	public void f(){
		System.out.println("I need to be tested");
	}
	
	public static class Tester{
		public static void main(String[] args) {
			Outer o=new Outer();
			o.f();
		}
	}
}

当然以上两段代码如果是在eclipse上运行的话,需要设置一下运行的main函数在哪,否则会报错

eclipse设置runconfigurations

5.多层内部类嵌套

纸老虎,爱有几层有几层,反正只要是外部类的东西,不管哪层外部类,都能访问到。

public class Outer {
	void f(){
		System.out.println("hello");
	}
	class Inner1{
		void g(){
			System.out.println("java");
		}
		class Inner2{
			void h(){
				f();
				g();
			}
		}
	}
	public static void main(String[] args) {
		Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2();
		in2.h();
	}
}

下面是个好玩的

public class Outer {
	void f(){
		System.out.println("hello");
	}
	class Inner1{
		void f(){
			System.out.println("java");
		}
		class Inner2{
			void h(){
				f();
			}
		}
	}
	public static void main(String[] args) {
		Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2();
		in2.h();
	}
}

最后打印结果是java。

大概就这么多吧,以后如果还有新东西再补。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值