Java用接口代替C++的多重继承好在哪
1个回答
展开全部
抱歉,你只要提到“接口与继承”,“单继承多实现”这个概念你就绕不开。但什么是“继承”?其实“继承”一词,包含两层含义(大多数人把它们混着来说):
代码重用(功能扩展)
抽象多态
但“单继承”一词的“继承”,只包含上面第一层含义。事实上,大多数人一提起“继承”,大多数人立马会想起代码重用,但却对抽象多态知之甚少。你要明确,除了“单继承”以外,继承的目的可不仅仅限于代码重用上。有不少的材料会说“JAVA/C#不支持多继承,所以用接口来实现多继承”这句话是一种非常不负责任的说法,因为前后两个“继承”根本不是一个意思。但上面1和2在技术上都依赖一个基本特点:(这也是继承的技术本质)
父类/接口的引用可以指向子类的对象!
代码重用有什么好处,我就不详细叙述了,我下面只谈抽象多态有何用。
你学的是JAVA还是C#?如果是前者,继承用extends/implements,后者用“:”,我下面全部用冒号了。
比如说有某个实体类/工具类,里面有个函数要获取某个图形的面积
1
2
3
4
5
6
7
8
9
class Util
{
public void F(Shape s)
{
……
double result=s.CalculateArea();
……
}
}
现问题来了,shape类型有很多,不同了图形面积计算方法不一样,如正方形是s=a^2;椭圆面积是s=phai*a*b……那么不同形状图形各整一个类:
1
2
3
4
5
6
7
8
class Circle
{
public doulbe CalculateArea();
}
class Square
{
public doulbe CalculateArea();
}
那么对应的Util类就为这些不同的形状添加F()方法重载?
1
2
3
4
5
class Util
{
public void F(Circle s);
public void F(Square s);
}
那么如果有一百个形状呢?要重载一百个F()函数?一亿个呢?好吧,如果一亿个你都咬牙写了一遍。那么你写好,编译好了成为一个动态库,后面又再增加呢?如果你这个动态库要发布给别人使用,这就逼着别人只能用这几个固定的类而不能随心所欲增加新的类。另外,你要重载一亿个F()函数还得都获得这一亿个类的原型声明。这原型一旦做升轿了修改你又得重新编译,多麻烦?
所以多态就要来解决这个问题了:
有了多态,你只需声明一闹耐个接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
interface IShape
{
void CalculateArea();
}
class Util
{
public void F(IShape s)
{
……
double result=s.CalculateArea();//我Util类管你实现的类是什么类?只要你是IShape的子类,我就能调用!
……
}
}
那么使用者只需要让新增加的形状继承于IShape就可以作为参数调用。
class Circle : IShape
class Square: IShape
而抽象类,则是同时兼顾代码重用和抽象多态的折衷产品。
另外,既然你提到过“单继承多实现”,我就不放再说一说,为什么要有“单继承”?
对比JAVA/C#的单继承,C++是多继承的,所以他不需要专门“接口”。多继承,意味着这种语言完全“面向代码重用”(当然他并不排斥抽象多态)。如何为完全“面向代码重用”呢?就是我写一个类,从A继承一票功能,又从B继承一票功能,又从C……,总之,你写的类变成一个大杂烩,万金油。这会有一个逻辑上的不吵弯肆合理:所谓在其位谋其职,分工不明确,将会降低生产效率。
于是以JAVA/C#为代表的标准面向对象模型(面向接口编程),不再允许多继承,而是使用单继承。这意味着你一个类,只能是从属于一个种属/身份,不应该什么都干,什么都能干。类继承不但有代码重用,还起到类型限制的作用。而作为补充,你可以继承多个接口,那么你可以提供超出父类所提供的基本功能,但你不能从现成的拿过来用,而是得自己实现。这保证了你的接口继承紧紧围绕着你的父类所规范的身份转。接口的定义者,则是赋予某种简单功能较为松散的约定,意味着接口所定义的功能,并不与某个类型/身份紧密相连。
简单打个生活中的比方:比如说,你是某家公司的职员,也是驾照的持有者。那么“职员”应当是类或者抽象类,因为你只有具有某公司的职员身份,才有资格进入这家公司工作,而非谁都能去。而“驾照”更应该是接口,因为谁只要没有什么特殊的病或别的,不管具有什么身份,拿到驾照就可上路。
代码重用(功能扩展)
抽象多态
但“单继承”一词的“继承”,只包含上面第一层含义。事实上,大多数人一提起“继承”,大多数人立马会想起代码重用,但却对抽象多态知之甚少。你要明确,除了“单继承”以外,继承的目的可不仅仅限于代码重用上。有不少的材料会说“JAVA/C#不支持多继承,所以用接口来实现多继承”这句话是一种非常不负责任的说法,因为前后两个“继承”根本不是一个意思。但上面1和2在技术上都依赖一个基本特点:(这也是继承的技术本质)
父类/接口的引用可以指向子类的对象!
代码重用有什么好处,我就不详细叙述了,我下面只谈抽象多态有何用。
你学的是JAVA还是C#?如果是前者,继承用extends/implements,后者用“:”,我下面全部用冒号了。
比如说有某个实体类/工具类,里面有个函数要获取某个图形的面积
1
2
3
4
5
6
7
8
9
class Util
{
public void F(Shape s)
{
……
double result=s.CalculateArea();
……
}
}
现问题来了,shape类型有很多,不同了图形面积计算方法不一样,如正方形是s=a^2;椭圆面积是s=phai*a*b……那么不同形状图形各整一个类:
1
2
3
4
5
6
7
8
class Circle
{
public doulbe CalculateArea();
}
class Square
{
public doulbe CalculateArea();
}
那么对应的Util类就为这些不同的形状添加F()方法重载?
1
2
3
4
5
class Util
{
public void F(Circle s);
public void F(Square s);
}
那么如果有一百个形状呢?要重载一百个F()函数?一亿个呢?好吧,如果一亿个你都咬牙写了一遍。那么你写好,编译好了成为一个动态库,后面又再增加呢?如果你这个动态库要发布给别人使用,这就逼着别人只能用这几个固定的类而不能随心所欲增加新的类。另外,你要重载一亿个F()函数还得都获得这一亿个类的原型声明。这原型一旦做升轿了修改你又得重新编译,多麻烦?
所以多态就要来解决这个问题了:
有了多态,你只需声明一闹耐个接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
interface IShape
{
void CalculateArea();
}
class Util
{
public void F(IShape s)
{
……
double result=s.CalculateArea();//我Util类管你实现的类是什么类?只要你是IShape的子类,我就能调用!
……
}
}
那么使用者只需要让新增加的形状继承于IShape就可以作为参数调用。
class Circle : IShape
class Square: IShape
而抽象类,则是同时兼顾代码重用和抽象多态的折衷产品。
另外,既然你提到过“单继承多实现”,我就不放再说一说,为什么要有“单继承”?
对比JAVA/C#的单继承,C++是多继承的,所以他不需要专门“接口”。多继承,意味着这种语言完全“面向代码重用”(当然他并不排斥抽象多态)。如何为完全“面向代码重用”呢?就是我写一个类,从A继承一票功能,又从B继承一票功能,又从C……,总之,你写的类变成一个大杂烩,万金油。这会有一个逻辑上的不吵弯肆合理:所谓在其位谋其职,分工不明确,将会降低生产效率。
于是以JAVA/C#为代表的标准面向对象模型(面向接口编程),不再允许多继承,而是使用单继承。这意味着你一个类,只能是从属于一个种属/身份,不应该什么都干,什么都能干。类继承不但有代码重用,还起到类型限制的作用。而作为补充,你可以继承多个接口,那么你可以提供超出父类所提供的基本功能,但你不能从现成的拿过来用,而是得自己实现。这保证了你的接口继承紧紧围绕着你的父类所规范的身份转。接口的定义者,则是赋予某种简单功能较为松散的约定,意味着接口所定义的功能,并不与某个类型/身份紧密相连。
简单打个生活中的比方:比如说,你是某家公司的职员,也是驾照的持有者。那么“职员”应当是类或者抽象类,因为你只有具有某公司的职员身份,才有资格进入这家公司工作,而非谁都能去。而“驾照”更应该是接口,因为谁只要没有什么特殊的病或别的,不管具有什么身份,拿到驾照就可上路。
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询