Java继承和多态


Java继承和多态

继承

定义

继承就是利用现有类创建新类的过程,现有的类称为 父类(基类),新类称为 子类(派生类)。比如现实中:儿子继承了父亲遗产一样。面向对象程序设计中的继承,就是代码重用。
Java中所有的类都继承自 Object 这个父类。

实现

在Java中实现继承需要使用到extends关键字;

[访问修饰符] class 派生类名 extends 基类名 {
        成员列表
    }

如:

class Student extends Person
{
    ……
}

访问修饰符 请参看之前章节的内容。

例子

例:

定义抽象类:Person。

public abstract class Person {  // 抽象类
    private String name;  // 私有变量
    
    public String getName() {  // Getter方法
        return name;
    }
    public void setName(String name) {  //Setter方法
        this.name = name;
    }
        
    public Person(String name) {  // 构造函数,用于初始化name
        super();
        this.name = name;
    }
    public abstract String getDesc();  // 抽象类中的抽象方法。  只有声明,没有具体实现。
  
      public String toString(){      // toString方法覆盖了Object类的toString方法
         return name + getDesc();
      }
}

public class Student extends Person {  // 继承类
    private String major; // 新增加的数据    
    
    public String getMajor() {
        return major;
    }
    
    public void setMajor(String major) {
        this.major = major;
    }    
    
    public Student(String name,String major) { // 构造函数用于初始化
        super(name);   // 调用超类构造函数
        this.major = major;
    }
    
    @Override
    public String getDesc() {  // 必须实现超类中的抽象方法
        // TODO Auto-generated method stub
        return " : a student, major is " + major;
    }

继承的作用

  • 当今软件设计的特征
    软件规模越来越大
    软件设计者越来越多
    软件设计分工越来越细
  • 引入继承,实现了代码重用;
  • 引入继承,实现了递增式的程序设计。
  • 继承是能自动传播代码和重用代码的有力工具;
  • 继承能够在某些比较一般的类的基础上建造、建立和扩充新类;
  • 能减少代码和数据的重复冗余度,并通过增强一致性来减少模块间的接口和界面,从而增强了程序的可维护性;
  • 能清晰地体现出类与类之间的层次结构关系。

注意事项

  • 继承是单方向的,即派生类可以继承和访问基类中的成员,但基类则无法访问派生类中的成员; 父类不能访问子类方法
  • 在Java中只允许 单一继承 方式,即一个派生类只能继承于一个基类,而不能象C++中派生类继承于多个基类的多重继承方式。

继承中的构造方法

  • 父类中的构造方法可以被重载,但不能被子类继承,即便它是public的;
  • 父类的构造方法负责初始化属于它的成员变量,而子类的构造方法则只需考虑属于自己的成员变量,不必去关注父类的情况。
  • 当实例化子类的对象时,必须先执行父类的构造方法,然后再执行子类的构造方法;
  • 如果父类还有更上级的父类,就会先调用最高父类的构造方法,再逐个依次地将所有继承关系的父类构造方法全部执行;
  • 如果父类的构造方法执行失败,那么子类的对象也将无法实例化。

class ParentClass {  //定义父类
  public ParentClass() {  //构造方法
    System.out.println("这是父类的构造方法。");
  }
}

class ChildClass extends ParentClass {  //子类继承于父类
  public ChildClass() {  //构造方法
    System.out.println("这是子类的构造方法。");
  }
}

public class ConstructorTest {  //该类用于容纳main方法
  public static void main(String[] args) {
    ChildClass cc = new ChildClass();  //实例化子类对象
  }
}

super

如果子类需要调用父类的方法或者属性怎么办?

  • 在子类的构造方法中,super关键字可以显式地调用父类的构造方法,用于将参数传递给它;需要注意的是: 该语句必须是子类构造方法的第一条语句

如:

class Point  //定义"点"类
{
  protected float mX, mY;  //x轴坐标和y轴坐标

  public Point(float x, float y)  //构造方法
  {
    mX = x;
    mY = y;
  }
  ……
}

class Circle extends Point  //定义"圆"类继承于"点"类
{
  protected float mRadius;    //半径

  public Circle(float x, float y, float r)  //构造方法
  {
    super(x, y);  //显式调用父类构造方法,必须是第一条语句
    mRadius = r;
  }
  ……
}
  • 如果父类和子类中有同名成员,在子类中默认访问是属于自己的那一个成员;super关键字可以明确地指定要访问父类中的成员;但前提条件是:父类中的该成员不是private的

多态

方法覆盖

定义
  • 在类的继承体系结构中,如果子类中出现了与父类中有同原型的方法,那么认为子类中的方法覆盖了父类中的方法(也称为方法重写);
  • 通过子类的实例调用被覆盖的方法时,将总是调用子类中的方法,而父类中的方法将被隐藏。

如:

/*如果不但名称相同,而且连方法原型也完全相同的话,则构成方法覆盖*/
class ParentClass {  //定义父类
  public void fun() {
    System.out.println("这是父类中的方法。");
  }
}

class ChildClass extends ParentClass {//子类继承于父类
  public void fun() {  //子类覆盖父类中的方法
    System.out.println("这是子类中的方法。");
  }
}

class OverriddenTest {  //用于容纳main方法
  public static void main(String[] args) {
    ParentClass parObj = new ParentClass();
    parObj.fun();  //父类的实例调用此方法

    ChildClass chiObj = new ChildClass();
    chiObj.fun();  //子类的实例调用此方法
  }
}
方法覆盖的注意事项
  • 子类中重写的方法,其访问权限不能比父类中被重写方法的访问权限更低
  • 在子类中重写方法时要保持方法的签名与父类中方法的签名一致

引用转型

  • 基类(父类)的引用可以指向派生类(子类)的对象。

如:

BaseClass obj = new DerivedClass();
  • 如果存在方法覆盖,那么将会调用其派生类中的方法

如:

class Shapes {  //基本形状类
  public void draw() {  //绘图的方法
    System.out.println("绘制了一个基本形状。");
  }
}
class Circle extends Shapes {  //圆形类继承于基本形状类
  public void draw() {  //覆盖父类的绘图方法
    System.out.println("绘制了一个圆形。");
  }
} 
class Square extends Shapes {  //正方形类继承与基本形状类
  public void draw() {  //覆盖父类的绘图方法
    System.out.println("绘制了一个正方形。");
  }
}
public class polymorphismDemo {
  public static void main(String[] args) {
    Shapes obj = new Shapes();  //父类的引用指向父类的实例
    obj.draw();                 //调用绘图方法
    obj = new Circle();         //父类的引用指向子类的实例
    obj.draw();                 //调用绘图方法
    obj = new Square();         //父类的引用指向子类的实例
    obj.draw();                 //调用绘图方法
  }
}

多态

在Java中,使用父类的引用,调用同一个方法,却可以得到不同的调用结果,这就是多态。即: 同一函数,多种形态。
实际上多态包括 动态多态静态多态

静态多态
  • 静态多态也称为编译时多态,即在编译时决定调用哪个方法;
  • 静态多态一般是指方法重载;
  • 只要构成了方法重载,就可以认为形成了静态多态的条件;
  • 静态多态与是否发生继承没有必然联系。
动态多态

动态多态也称为运行时多态,即在运行时才能确定调用哪个方法。
形成动态多态必须具体以下条件:

  • 必须要有继承的情况存在;
  • 在继承中必须要有方法覆盖;
  • 必须由基类的引用指向派生类的实例,并且通过基类的引用调用被覆盖的方法;

由上述条件可以看出,继承是实现动态多态的首要前提。

抽象

抽象方法

基类无法(或者没有必要)提供被覆盖方法的具体实现,那么就可以将这个方法定义为 抽象方法

[访问权限] abstract 返回值类型 方法名(参数列表){
}

如:

public abstract void draw(){
}
抽象类

如果某个类包含抽象方法,那么这个类就必须定义成 抽象类

[访问权限] abstract class 类名{
    成员列表
}

如:

public abstract class Shapes{
    public abstract void draw();
}
抽象类的注意事项
  • 抽象类不可以直接实例化,只可以用来继承;
  • 抽象类的派生子类应该提供对其所有抽象方法的具体实现;
  • 如果抽象类的派生子类没有实现其中的所有抽象方法,那么该派生子类仍然是抽象类,只能用于继承,而不能实例化;
  • 抽象类中也可以包含有非抽象的方法;
  • 构造方法和静态方法不可以修饰为abstract。

如:

abstract class Shapes {  //基本形状类,抽象类
    public abstract void draw();  //绘图方法,抽象方法
}
class Circle extends Shapes {  //圆形类继承于基本形状类
    public void draw() {  //实现抽象父类的抽象绘图方法
        System.out.println("绘制了一个圆形。");
    }
}
class Square extends Shapes {  //正方形类继承与基本形状类
    public void draw() {  //实现抽象父类的抽象绘图方法
        System.out.println("绘制了一个正方形。");
    }
}
public class abstractDemo {  //该类用于容纳main方法
    public static void main(String[] args) {
        Shapes obj;
        obj = new Circle();         //父类的引用指向子类的实例
        obj.draw();                 //调用绘图方法
        obj = new Square();         //父类的引用指向子类的实例
        obj.draw();                 //调用绘图方法
    }
}

接口

接口定义

如果某个类中所有的方法都是 抽象方法,那么可以考虑将该类定义为接口。

[访问权限] interface 接口名{
    成员列表
}

如:

public interface IMyInterface{
    public void doIt();
}
实现接口

接口只能用于实现,不能实例化(new)

[访问权限] class 类名 implements 接口名 {
    成员列表
}

如:

public class MyClass implements IMyInterface {
    public void doIt(){
    }
}
接口的注意事项
  • 接口中不能定义非抽象方法,也就是说接口中不能包含有函数实体。
    接口中的所有方法都默认为抽象方法,无需在每个方法前加abstract关键字。
  • 接口的实现类应该提供对接口中所有抽象方法的具体实现,否则将成为抽象类。
    与抽象类和它的继承类相似,也可以使用接口的引用指向其实现类的对象,从而达到动态多态的效果。
  • Java只支持单继承,而不能象C++那样可以多重继承,接口正是为了弥补这一点。
  • Java中还允许一个接口继承于另一个接口,即由父接口派生出子接口。

如:

public interface 子接口名 extends 父接口名 {
    成员列表
}

final关键字

final修饰变量

如果将某个变量修饰为final,那么该变量就成为 常量
如:

final double PI = 3.14159;

☆ 常量在声明时必须初始化。

final修饰方法

如果将某个成员方法修饰为final,则意味着该方法 不能被子类覆盖
如:

public final void fun() {
    ……
}
//如果在派生类中出现同原型的方法,将会报错。
final修饰类

如果将某个类修饰为final,则说明该类 无法被继承
如:

public final class MyClass {
    ……
}
//任何类想继承于MyClass类都将报错。

类和类之间的关系

  • 有——>has
    汽车有轮子。一般来说这种关系对应的是 属性

  • 是——>is
    圆形是个形状。一般来说这种关系对应的是 方法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-java.h...
    eddy_wiki阅读 1,184评论 0 5
  • 继承和多态 1. 继承的优缺点 优点:(1)子类可以灵活地改变父类中的已有方法;(2)能够最大限度的实现代码重用。...
    MinoyJet阅读 620评论 0 0
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,059评论 0 62
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,558评论 18 399
  • 昨天,我的大学室友给我发来一屏幕的微信语音 大致的意思是,她有一个又丑又丑的同学,通过整容把自己变成白富美,还有一...
    呼啦来了阅读 479评论 0 0