对接口的形象解释
接口
简单
的
说
接口就是一个契
约
或者
规
范
.
比如遥控器
,
国家出台了一个国家遥控器
规
范
,
明文要求所有的遥控器厂家都要遵循
这
个
规
范
,
如果不遵循
规
范就不
给
3C
认证标
志
,
就不允
许
上市出
卖
..
为
什
么
要
这
个
规
范呢
?
大家在
实践
生活中会
经
常碰到
,
甲厂的遥控器不能遥控乙厂的
电视
,
电视
遥控器不能遥控其它
电
器如空
调
,
冰箱
.!
原因是什
么
呢
?
是各个遥控器都没有遵循一个
规
范
,
电
波有
长
有短
,
电压
有高有低
,
导
致各自
为
政
,4
分
5
列
!
可以想像出国家遥控器
标
准只是
规
定遥控器的一些重要技
术
指
标
,
比如要
发
射波
应该
多
长
,
电压应该
多高
,...,
但它
绝对
不会
规
范出遥控器的材
质
,
形状
,
重量和
颜
色
,
也是
说规
范把所有同遥控无
关
的
东
西都抛弃了
!
每
个遥控器厂家只要遵循了
规
范
,
那
么对
遥控器可以有任意的
诠释
.
比如
A
厂可以用
铁
做
,
牢固无比
,B
厂可以用
纸
,
可以任意折叠
,anyway,
不管用什
么
做
,
做出什
么样
子
,
只要遵循
规
范的遥控器就可以遥控所有的
电
器
(
当然
电
器厂家也要遵循一定的
规
范
),
甚至可以遥控
导弹发
射
!
利害吧
,
这
就是接口的威力
.
再
详细
点
,
接口就是一个
规
范
,
他和具体的
实现
无
关
!
接口是
规
范
(
虚的
),
他只是一
张纸
,
一张契约书。
也
就
是
说
在
实际
的使用中接口只有依托一个
实现
了它的
类
的
实
例
,
才会有意
义
,
如上面的各个厂家做的遥控器
产
品
.
每
个
实现
接口的
类
(
厂家
)
必需
实现
接口中所有的功能
.
一旦一个
类实现
了一个接口
,
就可
说
一个
类
和接口捆
绑
了
(
这
个很重要
,
做
题
目的
时
候会用到
)
来个例子
interface
遥控器
规
范
//
国家定
义
的遥控器
规
范
,
每
个遥控器厂家必需
实现
(
诠释
)
它
{
int
波
长
();
int
电压
();
}
class
甲厂
铁
遥控器
:
遥控器
规
范
//
甲厂的遥控器
实现
(
诠释
)
了
这
个
规
范
,
它和遥控器
规
范捆
绑
了
!
好
,
它可以在市
场
上出售了
{
public int
波
长
(); //
规
范上定
义
的指
标
public int
电压
(); //
规
范上定
义
的指
标
public int
形状
() {
正方形
}; //
甲厂自己
对该产
品的
诠释
public int
材
质
() (
铁
}; //
甲厂自己
对该产
品的
诠释
}
class
乙厂
纸
遥控器
:
遥控器
规
范
////
甲厂的遥控器
实现
(
诠释
)
了
这
个
规
范
,
它和遥控器
规
范捆
绑
了
!
好
,
它可以在市
场
上出售了
{
public int
波
长
(); ////
规
范上
定
义
的指
标
public int
电压
(); //
规
范上定
义
的指
标
public int
形状
()(
圆
形
); //
甲厂自己
对该产
品的
诠释
,
是
圆
形
public int
材
质
()(
纸
); //
甲厂自己
对该产
品的
诠释
,
用
纸
做
,
好酷
!
}
class
电
器
{procedure
接收遥控
(
遥控器
规
范
) //
电
器上
,
接收遥控指令
{.....
接收
(
遥控器
规
范
.
波
长
) ;
接收
(
遥控器
规
范
.
电压
);
.....
}
}
static main()
{
甲厂
铁
遥控器
ControlA ; //
申明控制器
对
象
乙厂
纸
遥控器
ControlB ;
ControlA = new
甲厂
铁
遥控器
(); //
实
例化控制器
对
象
,
这
个
时
候系
统
在托管堆中
为该对
象分配了空
间
ControlB = new
乙厂
纸
遥控器
() ;
遥控器
规
范
ControlInterfaceA = (
遥控器
规
范
)
遥控器
1 ; //
把
对
象
实
例
转换
成一个
规
范
,
为
什
么
呢
?
因
为
"
我家的
电
器
".
只能
识别
遥控器
规
范
,
它
识别
不到具体的遥控器
遥控器
规
范
ControlInterfaceB = (
遥控器
规
范
)
遥控器
2; //
同上
电
器
我家的
电
器
= new
电
器
();
我家的
电
器
.
接收遥控
(ControlInterfaceA) //
我用甲厂遥控器遥控我家的
电
器
.
注意
:
这
里的
ControlInterfaceA
是不能
单
独存在的
,
它必要依
赖实现
了
"
遥控器
规
范
"
的
类
的
实
例
"ControlA".
道理很
简单
,
接口是一个指
针
,
不会被分配空
间
,
你就无法使用
,
只有和一个具体
类
的
实
例
联
系了
,
才有了可以活
跃
空
间
.
我家的
电
器
.
接收遥控
(ControlInterfaceB) //
我用乙厂遥控器遥控我家的
电
器
...
//
下面是我的的想像
,
我可以用遥控器来控制
导弹发
射
!
我的
导弹
.
接收遥控
(ControlInterfaceA);
我的
导弹
.
接收遥控
(ControlInterfaceB);
...
}
--------------------------------------------------------------------
接口的
执
行
好了
,
有了接口的概念
,
再来
谈
c#
程序在运行中是如何使用接口的
,
如何
访问
接口函数
.
具体流程如下
a.
当
调
用一个接口的函数
时
,
系
统
会去
检查这
个接口
对应实
例是什
么
?
b.
找到
这
个
实
例后
,
再去找
这
个
实
例
对应
的
实
例
类
是什
么
(
什
么
是
实
例
类
,
参看
读书
笔
记
二
)
c.
根据
这
个
实
例
类
去
检查该实
例
类
是否和接口
发
生了捆
绑
(
看是否
实现
了
该
接口
,
冒号后面就是
)
d.
好
!
如果
实
例
类实现
了
该
接口
(
发
生了捆
绑
) ,
它就在
这
个
实
例
类
中找函数的定
义
.
然后
执
行
该
函数
.
执
行
结
束
.
e.
如果没找到
,
他就
继续
往父
类
找
,
直到找到第一个和接口捆
绑
的父
类为
止
f.
找到后
,
它再
检查该
函数是否是虚
拟
函数
,
g.
如果不是
,
他
马
上就
执
行它
.
h
如果是
,
麻
烦
了
,
系
统
又要从
头
来
过
,
去
检查该实
例
类
的函数是否重
载
了
该
函数
,...
具体
过
程
见
(c#
读书
笔
记
2).
例子
:
Interface I
{
void Func() ;
}
Class A : I
{
public virtual void Func() { Console.WriteLine("FuncA")};
}
class B : A , I //
注意
这
里的意思
?
{
public void Func() { Console.WriteLine("FuncB")};
}
class C : A
{
public override void Func() { Console.WriteLine("FuncC")};
}
static main()
{ I a = new A() ; //
申明了接口
a,
并
马
上和一个
类
的
实
例
发
生
关
系了
I b = new B() ; //
申明了接口
b,
并
马
上和一个
类
的
实
例
发
生
关
系了
I c = new C() ; //
申明了接口
c,
并
马
上和一个
类
的
实
例
发
生
关
系了
a.Func() ; //
检查
a
的
实
例
A,
发现
A
和接口
I
捆
绑
了
,
所以
执
行
A
的函数
Func ,
结
果
: FuncA
b.Func() ; //
检查
b
的
实
例
B,
发现
B
和接口
I
捆
绑
了
,
所以
执
行
B
的函数
Func ,
结
果
: FuncB
c.Func() ; //
家常
c
的
实
例
C,
发现
其没有和接口
I
捆
绑
,
系
统继续
找它的父
类
.
发现
A
和
I
捆
绑
了
,
他就去找函数
A,
发现
A
是虚
拟
函数
,
系
统
又从
头
来找
类
的
实
例
C,
发现
C
重
载
(override)
了
Func,
好了
,
马
上
执
行
该
函数
.
结
果是
FuncC;
}