继承、多态,重载、重写的区别与总结

来源:互联网 发布:sql是什么的缩写 编辑:程序博客网 时间:2024/05/17 22:29
什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承、多态、重载和重写。 

继承(inheritance) 

简单的说,继承就是在一个现有类型的基础上,通过增加新的方法或者重定义已有方法(下面会讲到,这种方式叫重写)的方式,产生一个新的类型。继承是面向对象的三个基本特征--封装、继承、多态的其中之一,我们在使用JAVA时编写的每一个类都是在继承,因为在JAVA语言中,java.lang.Object类是所有类最根本的基类(或者叫父类、超类),如果我们新定义的一个类没有明确地指定继承自哪个基类,那么JAVA就会默认为它是继承自Object类的。 

我们可以把JAVA中的类分为以下三种: 

类:使用class定义且不含有抽象方法的类。 
抽象类:使用abstract class定义的类,它可以含有,也可以不含有抽象方法。 
接口:使用interface定义的类。 

在这三种类型之间存在下面的继承规律: 

类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。 
抽象类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。 
接口只能继承(extends)接口。 

请注意上面三条规律中每种继承情况下使用的不同的关键字extends和implements,它们是不可以随意替换的。大家知道,一个普通类继承一个接口后,必须实现这个接口中定义的所有方法,否则就只能被定义为抽象类。我在这里之所以没有对implements关键字使用“实现”这种说法是因为从概念上来说它也是表示一种继承关系,而且对于抽象类implements接口的情况下,它并不是一定要实现这个接口定义的任何方法,因此使用继承的说法更为合理一些。 

以上三条规律同时遵守下面这些约束: 

类和抽象类都只能最多继承一个类,或者最多继承一个抽象类,并且这两种情况是互斥的,也就是说它们要么继承一个类,要么继承一个抽象类。 
类、抽象类和接口在继承接口时,不受数量的约束,理论上可以继承无限多个接口。当然,对于类来说,它必须实现它所继承的所有接口中定义的全部方法。 
抽象类继承抽象类,或者实现接口时,可以部分、全部或者完全不实现父类抽象类的抽象(abstract)方法,或者父类接口中定义的接口。 
类继承抽象类,或者实现接口时,必须全部实现父类抽象类的全部抽象(abstract)方法,或者父类接口中定义的全部接口。 

继承给我们的编程带来的好处就是对原有类的复用(重用)。就像模块的复用一样,类的复用可以提高我们的开发效率,实际上,模块的复用是大量类的复用叠加后的效果。除了继承之外,我们还可以使用组合的方式来复用类。所谓组合就是把原有类定义为新类的一个属性,通过在新类中调用原有类的方法来实现复用。如果新定义的类型与原有类型之间不存在被包含的关系,也就是说,从抽象概念上来讲,新定义类型所代表的事物并不是原有类型所代表事物的一种,比如黄种人是人类的一种,它们之间存在包含与被包含的关系,那么这时组合就是实现复用更好的选择。下面这个例子就是组合方式的一个简单示例: 
Java代码 
public class Sub {   
    private Parent p = new Parent();   

    public void doSomething() {   
        // 复用Parent类的方法   
        p.method();   
        // other code   
    }   
}   

class Parent {   
    public void method() {   
        // do something here   
    }   


public class Sub { 
private Parent p = new Parent(); 

public void doSomething() { 
   // 复用Parent类的方法 
   p.method(); 
   // other code 



class Parent { 
public void method() { 
   // do something here 



当然,为了使代码更加有效,我们也可以在需要使用到原有类型(比如Parent p)时,才对它进行初始化。 

使用继承和组合复用原有的类,都是一种增量式的开发模式,这种方式带来的好处是不需要修改原有的代码,因此不会给原有代码带来新的BUG,也不用因为对原有代码的修改而重新进行测试,这对我们的开发显然是有益的。因此,如果我们是在维护或者改造一个原有的系统或模块,尤其是对它们的了解不是很透彻的时候,就可以选择增量开发的模式,这不仅可以大大提高我们的开发效率,也可以规避由于对原有代码的修改而带来的风险。 

多态(Polymorphism) 

多态是又一个重要的基本概念,上面说到了,它是面向对象的三个基本特征之一。究竟什么是多态呢?我们先看看下面的例子,来帮助理解: 
Java代码 
//汽车接口   
interface Car {   
    // 汽车名称   
    String getName();   

    // 获得汽车售价   
    int getPrice();   
}   

// 宝马   
class BMW implements Car {   
    public String getName() {   
        return "BMW";   
    }   

    public int getPrice() {   
        return 300000;   
    }   
}   

// 奇瑞QQ   
class CheryQQ implements Car {   
    public String getName() {   
        return "CheryQQ";   
    }   

    public int getPrice() {   
        return 20000;   
    }   
}   

// 汽车出售店   
public class CarShop {   
    // 售车收入   
    private int money = 0;   

    // 卖出一部车   
    public void sellCar(Car car) {   
        System.out.println("车型:" + car.getName() + " 单价:" + car.getPrice());   
        // 增加卖出车售价的收入   
        money += car.getPrice();   
    }   

    // 售车总收入   
    public int getMoney() {   
        return money;   
    }   

    public static void main(String[] args) {   
        CarShop aShop = new CarShop();   
        // 卖出一辆宝马   
        aShop.sellCar(new BMW());   
        // 卖出一辆奇瑞QQ   
        aShop.sellCar(new CheryQQ());   
        System.out.println("总收入:" + aShop.getMoney());   
    }   


//汽车接口 
interface Car { 
// 汽车名称 
String getName(); 

// 获得汽车售价 
int getPrice(); 


// 宝马 
class BMW implements Car { 
public String getName() { 
   return "BMW"; 


public int getPrice() { 
   return 300000; 



// 奇瑞QQ 
class CheryQQ implements Car { 
public String getName() { 
   return "CheryQQ"; 


public int getPrice() { 
   return 20000; 



// 汽车出售店 
public class CarShop { 
// 售车收入 
private int money = 0; 

// 卖出一部车 
public void sellCar(Car car) { 
   System.out.println("车型:" + car.getName() + " 单价:" + car.getPrice()); 
   // 增加卖出车售价的收入 
   money += car.getPrice(); 


// 售车总收入 
public int getMoney() { 
   return money; 


public static void main(String[] args) { 
   CarShop aShop = new CarShop(); 
   // 卖出一辆宝马 
   aShop.sellCar(new BMW()); 
   // 卖出一辆奇瑞QQ 
   aShop.sellCar(new CheryQQ()); 
   System.out.println("总收入:" + aShop.getMoney()); 



运行结果: 

车型:BMW 单价:300000 
车型:CheryQQ 单价:20000 
总收入:320000 

继承是多态得以实现的基础。从字面上理解,多态就是一种类型(都是Car类型)表现出多种状态(宝马汽车的名称是BMW,售价是300000;奇瑞汽车的名称是CheryQQ,售价是2000)。将一个方法调用同这个方法所属的主体(也就是对象或类)关联起来叫做绑定,分前期绑定和后期绑定两种。下面解释一下它们的定义: 

前期绑定:在程序运行之前进行绑定,由编译器和连接程序实现,又叫做静态绑定。比如static方法和final方法,注意,这里也包括private方法,因为它是隐式final的。 
后期绑定:在运行时根据对象的类型进行绑定,由方法调用机制实现,因此又叫做动态绑定,或者运行时绑定。除了前期绑定外的所有方法都属于后期绑定。 

多态就是在后期绑定这种机制上实现的。多态给我们带来的好处是消除了类之间的耦合关系,使程序更容易扩展。比如在上例中,新增加一种类型汽车的销售,只需要让新定义的类继承Car类并实现它的所有方法,而无需对原有代码做任何修改,CarShop类的sellCar(Car car)方法就可以处理新的车型了。新增代码如下: 
Java代码 
// 桑塔纳汽车   
class Santana implements Car {   
    public String getName() {   
        return "Santana";   
    }   

    public int getPrice() {   
        return 80000;   
    }   


// 桑塔纳汽车 
class Santana implements Car { 
public String getName() { 
   return "Santana"; 


public int getPrice() { 
   return 80000; 




重载(overloading)和重写(overriding) 

重载和重写都是针对方法的概念,在弄清楚这两个概念之前,我们先来了解一下什么叫方法的型构(英文名是signature,有的译作“签名”,虽然它被使用的较为广泛,但是这个翻译不准确的)。型构就是指方法的组成结构,具体包括方法的名称和参数,涵盖参数的数量、类型以及出现的顺序,但是不包括方法的返回值类型,访问权限修饰符,以及abstract、static、final等修饰符。比如下面两个就是具有相同型构的方法: 
Java代码 
public void method(int i, String s) {   
    // do something   
}   

public String method(int i, String s) {   
    // do something   


public void method(int i, String s) { 
// do something 


public String method(int i, String s) { 
// do something 


而这两个就是具有不同型构的方法: 
Java代码 
public void method(int i, String s) {   
    // do something   
}   

public void method(String s, int i) {   
    // do something   


public void method(int i, String s) { 
// do something 


public void method(String s, int i) { 
// do something 


了解完型构的概念后我们再来看看重载和重写,请看它们的定义: 

重写,英文名是overriding,是指在继承情况下,子类中定义了与其基类中方法具有相同型构的新方法,就叫做子类把基类的方法重写了。这是实现多态必须的步骤。 
重载,英文名是overloading,是指在同一个类中定义了一个以上具有相同名称,但是型构不同的方法。在同一个类中,是不允许定义多于一个的具有相同型构的方法的。 

我们来考虑一个有趣的问题:构造器可以被重载吗?答案当然是可以的,我们在实际的编程中也经常这么做。实际上构造器也是一个方法,构造器名就是方法名,构造器参数就是方法参数,而它的返回值就是新创建的类的实例。但是构造器却不可以被子类重写,因为子类无法定义与基类具有相同型构的构造器。 
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 qq号被冻结了限制解封怎么办 被别人强制拉入qq群怎么办 qq群里的图片过期了怎么办 q附近人不能关注不能发信息怎么办 qq畅聊之火掉了怎么办 打印机打印时上面空白留太多怎么办 发短信一直空格里面写0怎么办 网贷获取我新手机号通讯录怎么办 系统音频驱动异常或未安装怎么办 附近功能已屏蔽你的qq好友怎么办 新申请的qq号忘了怎么办 刚申请的qq号忘了怎么办 以前申请的qq号忘了怎么办 小孩玩手机游戏扣费了怎么办 手机qq好友头像显示不出来怎么办 qq的一些重要数据被清理怎么办 华为p9微信听筒声音小怎么办 win10我的电脑图标没了怎么办 小米5x里的微信头像不清楚怎么办 微信头像换了总是模糊怎么办 找到老公暧昧对象的微信怎么办 朋友欠我钱一直拖找借口怎么办 陌陌附近的人不按距离排序怎么办 老婆一直要管我的钱怎么办 老公不肯把钱交给老婆管怎么办 愿意和做朋友不愿意做情侣怎么办 欠信用卡碰到第三方不愿协调怎么办 qq密码忘记了申诉不回来怎么办 当你老公烦你了你该怎么办 自己有漂亮媳妇还经常想去嫖怎么办 微信号封了找不到好友解封怎么办 别人总是提起你的黑历史怎么办 换了手机微信登录不上怎么办 qq不小心清空了聊天记录怎么办 人家介绍了外地媳妇跑了怎么办 火锅想吃香菜牛肉没有签子串怎么办 想读外省大学但家人反对怎么办 13岁被同学忽视他不知道怎么办 老婆发现老公在微信暧昧聊天怎么办 老婆微信和别人聊天暧昧我该怎么办 淘宝修改标题宝贝被删了怎么办