Java核心技术之继承

Java核心技术之继承

目录

一、继承的定义

多个类中存在相同属性和行为,将这些内容抽取到单独的一个类中,那么多个类无需再定义这些属性和行为,只需要继承那个类即可。 —— [ ImportNew ]

二、继承的实现

1.类的继承

定义子类

由继承的定义,可以得出超类和子类的概念,一般也称之为父类和子类。
定义中,“多个类”可以称之为子类,“单独的一个类”称为父类超类
子类可以直接访问父类中的非私有属性和行为。关键字extend表示继承。采用书上的例子进行讲解:

public class Employee
{
    private String name;
    private double salary;
    private LocalDate hireDay;

    public Employee(String name,double salary,int year,int month,int day){
        this.name = name;
        this.salary = salary;
        this.hireDay = LocalDate.of(year,month,day);
    }
    public String getName(){
        return this.name;
    }
    public double getSalary(){
        return this.salary;
    }
    public LocalDate getHireDay(){
        return this.hireDay;
    }

}

下面是由继承Employee类来定义Manager类的格式:

public class Manager extends Employee
{

/**添加方法和域**/

}

extend关键字代表,Manger类这一新派生的类继承自Employee类,Employee类是已存在的类,称为父类;Manager类是由Employee类派生得来的,称为子类。根据继承的定义,新派生的Manager可以直接访问Employee类中的非私有属性和方法。在Manager类中不需要定义getName()等方法,直接访问父类的方法就可以获得返回值。
在Manager类中新,增加一个用于存储奖金信息的域,以及用于设置这个域的新方法。

public class Manager extends Employee{
    private double bonus;
    ...
    public void set Bonus(double bonus){
        this.bonus = bonus;
    }
}

对与类来说,父类是对一类事物最抽象最通用的域和方法的抽象,子类再继承这些通用的内容后,可以在自己的类内定义新的只属于自己的域和内容。所以,子类会被父类拥有更加丰富的功能。

抽象类

抽象就是从多个事物中将共性、通用的内容抽象出来。抽象方法是只有定义没有方法体,其具体实现由子类去完成。包含一个或多个抽象方法的类称之为抽象类。Employee类和Manager类其实都可以继承自Person类,而Person类又可以派生出Student和Teacher类。假设,需要为Student类和Teacher类加一个getDescription方法,用于对不同身份的类进行信息描述。在父类Person中就可以将getDescription定义为一个抽象方法,具体的实现由相应的子类去完成。

public class Person(){
    .......
    public abstract String getDescription();
}

public class Student extends Person(){
    ......
    public String getDescription(){
        system.out.println("I am a student!");
    }
}

public class Teacher extends Person(){
    ......
    public String getDescription(){
        system.out.println("I am a Teacher!");
    }
}

如果多个对象都具有相同的功能,但是功能的具体内容并不相同,在父类中可以抽象这个功能的定义,将该方法定义成一个抽象方法,不去做具体实现。

抽象类的特点:
  • 抽象方法一定在抽象类中;
  • 抽象方法和抽象类都必须被abstract关键字修饰;
  • 抽象类不可以用new创建对象,因为调用抽象方法没有意义;
  • 抽象类中的抽象方法要被使用,必须由子类复写父类的所有抽象方法后建立子类对象的调用;如果子类只覆盖了部分的抽象方法,那么该子类还是一个抽象类;
  • 抽象类可以有抽象方法,也可以有非抽象方法;
  • 如果一个类是抽象类,那么,继承该类的子类要么是抽象类,要么重写了所有的抽象方法。
    特殊,如果一个类被定义成抽象类,但是在该类中并没有抽象方法,这样做仅仅是为了不让该类创建对象。
抽象类的注意事项:
  • final:如果方法被抽象,在子类中该法规就会被覆盖,而final不可以被覆盖,所以冲突。
  • private:如果函数被私有化,子类就无法直接访问,而抽象方法就是为了让子类访问并复写。
  • static:static方法不需要对象,可以用类名直接调用抽象方法,而抽象方法本身是没有实现的,所以调用抽象方法本身并没有意义。

2.覆盖方法

前面例子中的代码以及涉及到了覆盖方法的例子。就是,当我们父类定义好的方法并不适用于子类时,子类需要提供一个新的方法来覆盖(override)父类中的这个方法。根据定义Employee的getSalary方法只返回固定薪资salary的值,而Manager类生成的对象是“经理”,经理所获得薪资定义为固定薪资salary加上奖金bonus。此时Employee类中的getSalary方法就不在适用于当前的子类Manager类。
应该如何实现?

public double getSalary(){
    return salary+bonus;   //don't work编译时报错
}

这是因为Manager类并不能访问父类中的私有域。虽然每个Manager对象拥有一个salary域,但是只能通过Employee类中的非私有方法getSalar方法获取返回值,并不能直接访问到salary域。
如果将对salary域的访问替换成调用父类中公共方法getSalary是不是就能正常运行了呢?

/**运行时报错**/
public double getSalary(){
    double salary = getSalary()
    return salary+bonus; 
}

如果Manager类一定要访问父类的私有域,只能借助于公有的接口getSalary()。虽然,借助getSalary能够访问到父类的私有域,但是上面的代码仍不能正确执行。这是因为,在Manager类中也有一个getSalary方法(就是我们需要实现的这个方法),所以这条语句会无限次的调用自己,知道程序崩溃。这里需要指出,我们希望调用Employee类中的getSalary方法时,需要使用特定的关键字super

super.getSalary()

上述语句调用的就是父类中的getSalary方法。

/**运行时报错**/
public double getSalary(){
    double salary = super.getSalary()
    return salary+bonus; 
}

super和this有什么区别?
super是一个关键字,代表父类的存储空间标识。(可以理解为父亲的引用)
super和this的用法相似。
this代表对象的引用(谁调用就代表谁);
super代表当前子类对父类的引用。

3.接口的实现

定义

接口是抽象方法和常量值的集合。从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量和方法的定义,没有变量和方法的实现。

定义接口
interface Instrument{
    int VALUE = 5;
    void play(Note n);
    void adjust();
}

下面是用关键字implements实现接口的格式:

class Wind implements Instrument{
    public void play(Note n){
        print(this + ".play() " + n);
    }
    public void adjust(){
        print(this + ".adjust()");
    }
}

class Percussion implements Instrument{
    public void play(Note n){
        print(this + ".play() " + n);
    }
    public void adjust(){
        print(this + ".adjust()");
    }
}

......

特点

  • 接口不能被实例化;
  • 一个类如果实现了接口,要么是抽象类(实现接口的部分方法),要么实现接口中的所有方法。

总结

继承与实现的区别:
  • 类与类之间称为继承关系:因为该类无论是抽象还是非抽象,它的内部都可以定义非抽象方法,这个方法可以被子类直接使用。只能单继承,可以多层继承。
  • 类与接口直接是实现关系:因为接口中的方法都是抽象的,必须由子类实现才可以实例化。可以单实现也可以多实现,还可以在继承一个类的同时实现多个接口。
抽象类与接口的区别

我们将接口视为一个特殊的抽象类。

成员变量
  • 抽象类能有变量,也可以有常量
  • 接口只有常量
成员方法
  • 抽象类可以有非抽象方法,也可以有抽象方法
  • 接口只能有抽象方法
构造方法
  • 抽象类有构造方法
  • 接口没有构造方法
构造方法

类与抽象类和接口关系
- 类与抽象类的关系是继承 extends
- 类与接口的关系是实现 implements

接口的思想特点
  • 接口是对外暴露的规则;
  • 接口是程序的功能扩展;
  • 接口的出现降低耦合性;(实现了模块化开发,定义好规则,每个人实现自己的模块,大大提高了开发效率)
  • 接口可以用来多实现;
  • 多个无关的类可以实现同一个接口;
  • 一个类可以实现多个相互直接没有关系的接口;
  • 与继承关系类似,接口与实现类之间存在多态性。

4.对象的多态

在Java程序语言中,对象变量是多态的,一个Employee变量既可以引用一Employee类对象,也可以引用一个Employee类的任何一个子类的对象,如Manager类。父类对象可以用子类替换。

Manager boss =  new Manager(...);
Employee[] staff = new Employee[3];
staff[0] = boss;

在例子中staff[0]和boss引用了同一个对象。但编译器将staff[0]看作是Employee对象,所以

boss.setBonus(5000);//it's ok
staff[0].setBonus(5000);//Error

staff[0]的声明的类型是Employee,而setBonus是Manager类的方法。多态至始至终都是子类再发生变化。

多态的前提:
  • 要有继承或者实现关系。
  • 要有方法的重写。
  • 要有父类引用指向子类对象。

三、继承的实例 —— Object

Object类是Java中所有类的超类(父类)。在Java中每个类都是由Object类扩展来的。我们可以看下Object类被抽象出来的几个方法:
这里写图片描述

1.equal()方法

Object类中的equals方法用于检测两个对象是否相等,看下equals方法源码是如何实现的:
这里写图片描述
通过源码可以看出,equals方法是在比较两个对象是不是同一个对象。而且equals方法不是Object类的私有方法,在定义新类时,可以重写equals()方法。以下,是JDK规定重写equals()方法应该遵守的约定:

  • 自反性:x.equals(x)必须返回true。

  • 对称性:x.equals(y)与y.equals(x)的返回值必须相等。

  • 传递性:x.equals(y)为true,y.equals(z)也为true,那么x.equals(z)必须为true。
  • 一致性:如果对象x和y在equals()中使用的信息都没有改变,那么x.equals(y)值始终不变。
  • 非null:x不是null,y为null,则x.equals(y)必须为false。

它在Object类中的实现是判断两个对象是否指向同一块内存区域。这中测试用处不大,因为即使内容相同的对象,内存区域也是不同的。如果想测试对象是否相等,就需要覆盖此方法,进行更有意义的比较。例如

class Employee{
    ... 
    public boolean equals(Object otherObj){
        //快速测试是否是同一个对象
        if(this == otherObj) return true;
        //如果显式参数为null,必须返回false
        if(otherObj == null) reutrn false;
        //如果类不匹配,就不可能相等
        if(getClass() != otherObj.getClass()) return false;

        //现在已经知道otherObj是个非空的Employee对象
        Employee other = (Employee)otherObj;

        //测试所有的字段是否相等
        return name.equals(other.name)
            && salary == other.salary
            && hireDay.equals(other.hireDay);
    }
}
2.hashCode()方法

这里写图片描述
可以看出,hashCode()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。

与equals()方法类似,hashCode()方法可以被重写。JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明:

  • hashCode()在哈希表中起作用,如java.util.HashMap。

  • 如果对象在equals()中使用的信息都没有改变,那么hashCode()值始终不变。

  • 如果两个对象使用equals()方法判断为相等,则hashCode()方法也应该相等。

  • 如果两个对象使用equals()方法判断为不相等,则不要求hashCode()也必须不相等;但是开发人员应该认识到,不相等的对象产生不相同的hashCode可以提高哈希表的性能。


在软件设计里到处都是模式,框架。有次朋友问什么是模式?我也在学习中,就我的学习经验,给出以下小结。(注意:个人观点,仅供参考,欢迎指正。)??1.什么是模式???模式,即pattern。其实就是解决某一类问题的方法论。你把解决某类问题的方法总结归纳到理论高度,那就是模式。??Alexander给出的经典定义是:每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。??模式有不同的领域,建筑领域有建筑模式,软件设计领域也有设计模式。当一个领域逐渐成熟的时候,自然会出现很多模式。??什么是框架???框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。??2.为什么要用模式???因为模式是一种指导,在一个良好的指导下,有助于你完成任务,有助于你作出一个优良的设计方案,达到事半功倍的效果。而且会得到解决问题的最佳办法。??为什么要用框架???因为软件系统发展到今天已经很复杂了,特别是服务器端软件,设计到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事物处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。??框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。??软件为什么要分层???为了实现“高内聚、低耦合”。把问题划分开来各个解决,易于控制,易于延展,易于分配资源…总之好处很多啦:)。??3.以下所述主要是JAVA,J2EE方面的模式和框架:??常见的设计模式有什么???首先,你要了解的是GOF的《设计模式--可复用面向对象软件的基础》一书(这个可以说是程序员必备的了),注意:GOF不是一个人,而是指四个人。它的原意是Gangs Of Four,就是“四人帮”,就是指此书的四个作者:Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides。这本书讲了23种主要的模式,包括:抽象工厂、适配器、外观模式等。??还有其他的很多模式,估计有100多种。??软件设计模式太多,就我的理解简单说一下最常见的MVC模式。??MVC模式是1996年由Buschmann提出的:??模型(Model):就是封装数据和所有基于对这些数据的操作。??视图(View):就是封装的是对数据显示,即用户界面。??控制器(Control):就是封装外界作用于模型的操作和对数据流向的控制等。??另外:??RUP(Rational Unified Process)软件统一过程,XP(Extreme Programming)极端编程,这些通常被叫做“过程方法”,是一种软件项目实施过程的方法论,它是针对软件项目的实施过程提出的方法策略。也是另一个角度的模式。??4.常见的JAVA框架有什么???WAF:??全称:WEB APPLICATION FRAMEWORK??主要应用方面:EJB层,(WEB层也有,但是比较弱)。??主要应用技术:EJB等??出处:http://java.sun.com/blueprints/code/index.html??简述:这是SUN在展示J2EE平台时所用的例子PetStore(宠物商店系统)里面的框架。是SUN蓝皮书例子程序中提出的应用框架。它实现了 MVC和其他良好的设计模式。SUN的网站上有技术资料,最好下载PetStore来研究,WEBLOGIC里自带此系统,源码在beaweblogic700samplesserversrcpetstore。这是学习了解J2EE的首选框架。??免费。??Struts:??主要应用方面:WEB层。??主要应用技术:JSP,TagLib,JavaBean,XML等??出处:http://jakarta.apache.org/struts/index.html??简述:这是APACHE的开源项目,目前应用很广泛。基于MVC模式,结构很好,基于JSP。Jbuilder8里已经集成了STRUTS1.02的制作。??免费。??简述WAF+STRUTS结合的例子:WEB层用STRUTS,EJB层用WAF:??JSP(TagLib)——>ActionForm——>Action ——> Event——>EJBAction——>EJB ——>DAO——>Database JSP(TagLib)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值