Java编程思想-内部类与接口

内部类与接口

利用内部类可以解决:1.多重继承问题;2.内部类和接口可以实现闭包及回调

1.内部类实现多重继承

Java只能单继承,所以一个Java类无法继承多个类。要实现多继承有两种方法:其一,利用接口,Java类可以实现多个接口,但该方法只能多继承接口,不能用于类或者抽象类。其二,创建内部类,可以利用多个内部类来继承抽象类或者实现接口。这种方法更为灵活方便。

2.内部类实现闭包与回调代码片Callback.java

这段代码是Thinking in JAVA的经典代码,需要仔细琢磨,要在结合应用去思考才能理解其真意。

interface Incrementable{
	void increment();
}

class Callee1 implements Incrementable{

	private int i = 0;
	public void increment(){
		i++;
		System.out.println(i);
	}
}

class MyIncrement{
	public void increment(){System.out.println("Other operation");}
	static void f(MyIncrement mi){mi.increment();}
}

class Callee2 extends MyIncrement{
	private int i = 0;
	
	@Override
	public void increment(){
		super.increment();
		i++;
		System.out.println(i);
	}

	private class Closure implements Incrementable{
		public void increment(){
			Callee2.this.increment();
		}
	}

	Incrementable getCallbackReference(){
		return new Closure();
	}
}	


class Caller{
	private Incrementable callbackReference;
	Caller(Incrementable cbh){callbackReference = cbh;}
	Caller(){}
	void setClickOnListener(Incrementable listenor){callbackReference = listenor;}
	void go(){callbackReference.increment();}
}
public class Callback{
	public static void main(String[] args){
		Callee2 c2 = new Callee2();
		//c2.increment();
		Callee1 c1 = new Callee1();
		//c1.increment();
		MyIncrement.f(c2);
		Caller call1 = new Caller();
		call1.setClickOnListener(c2.getCallbackReference());
		call1.go();
	}
}

回调函数是指我们类里的方法会在某个地方被调用,回调函数本身就意味着要通用化,意味着有多种实现方式。在C/C++里面,回调函数是用函数指针实现的,这种函数指针一般只会对该函数的形参和返回类型做规定,具体的函数实现是空的,等待你来实现的。JAVA没有函数指针,怎么办呢?只能利用接口来做这种通用化设计,需要用回调函数的类会创建一个接口的引用(如:private Incrementable callbackReference;),并调用接口的方法(如:void go(){callbackReference.increment();})。具体的接口实现,也是等你来设计的。
比如Callee2.increment()就是回调函数真正要实现的功能。但为什么不在Callee2类里直接实现Increment able接口,反而要在内部类Closure里对Callee2.increment()方法做一次闭包封装呢?请看详解如下:
首先要理解JAVA的回调机制,请分析Caller类,Caller类是客户类,Caller类只知道Incrementable接口,所以Caller类内部定义了一个Incrementable对象引用,并在go()方法里调用了Incrementable接口的increment()方法。看到这里,是不是比较发懵,这个类什么都没干啊!!对的,Caller类是一个经典的回调函数使用者,他只是说我要调用这个接口的increment()方法;具体这个接口的方法实现等着你们来实现,你需要首先注册callbackReference引用,然后利用Caller.go()来激活回调函数。因为Incrementable是一个通用接口,其他类或者内部只要实现了这个接口就可以到Caller类来注册并在某个时刻调用接口函数。
再来分析Callee2类,本来如果Callee2类只要实现了Incrementable接口就可以到Caller去注册了(见Callee1类),为什么要大费周章弄个内部类Closure呢?用内部类Closure来实现Incrementable接口有如下好处:(1)可以不用改动Callee2类的其他部分(2)可以利用Closure来调用Callee2类的其他成员方法或者域,甚至是私有部分(3)可以私有化Closure类,只向外提供构建Closure对象的方法,隐藏具体实现,彻底把接口和实现分开。(4)更安全,Caller类只能调用接口的方法,其他什么都不能做。
以下代码片段是Android,经典的回调应用。

public class MainActivity extends AppCompatActivity {
	      TextView tv = (TextView) findViewById(R.id.sample_text);
	      /*这里用了匿名内部类实现了View.OnClickListener() 接口,并创建该类的匿名对象
	       *并利用setOnClickListener方法注册
	       *可以看到该匿名类调用了外围类的startActivity()方法。
	       */
	      tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,LLCamreaActivity.class);
                startActivity(intent);
            }
        });

在上面的程序中我们创建了一个匿名内部类来实现View.OnClickListener接口,我们不需要让我们的外围类MainActivity 来实现这个接口,我们也不需要更改MainActivity 类的代码,只需要在内部类实现View.OnClickListener接口,以便tv.setOnClickListener()方法能接受,再在内部类里调用MainActivity 实现好的方法即可。在将来的某个时刻,用户在tv控件上点击的话,就会回调MainActivity 类的startActivity()方法。

很神奇吧,tv控件可以回调MainActivity 类的方法,而且tv不用管到底是怎么实现的,tv除了只能看到onClick接口方法,他对MainActivity类 一无所知。这种通用性把闭包和回调发挥的淋漓尽致,你可以实现无数种onClick方法,对我而言,我只看到接口而已。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值