《Java核心技术 卷1》 第五章 继承

基于已有的类创建新的类。

继承已存在的类就是复用这些类的方法,并且可以增加一些新的字段和方法,使新类能够适应新的情况。

类、超类和子类

"is-a"关系是继承的一个明显特征。

定义子类

Java中使用关键字extends表示继承。

该关键字表明正在构建的新类派生于一个已经存在的类。这个已经存在的类称为父类,新派生出的类称为子类。

子类继承父类后,有三个特点:

  1. 子类继承了父类的所有非private的属性和方法
  2. 子类可以添加新的属性和方法
  3. 子类可以覆盖从父类继承而来的方法

综上所述,子类拥有比父类更多的功能。

使用extends关键字来定义子类时,只需在子类中指出子类和父类之间的不同即可。

/**
 * 父类
 */
public class FatherDemo {

    public void method1(){
        System.out.println("method1");
    }
}
/**
 * 子类
 */
public class SonDemo extends FatherDemo{

    @Override
    public void method1() {
        // 调用父类的该方法
        super.method1();
        System.out.println("重写的新内容");
    }

    public void method2(){
        System.out.println("子类新增的method2");
    }
}

覆盖方法

又叫重写。子类中,如果想对父类的现有方法进行功能修改,可以覆盖父类的方法。

覆盖的方法,有如下特点:

  1. 覆盖方法与父类的现有方法的方法名、参数、返回值均相同,只改变方法的具体实现
  2. 覆盖方法不能低于父类现有方法的可见性:比如父类方法是public,子类方法必须是public。
  3. 子类中的覆盖方法,使用@Override注解标明
  4. 子类中若想使用父类的方法,可使用super关键字。可理解为,this为当前类的隐藏参数,super为父类的隐藏参数。

子类的构造器

子类的构造器可使用super关键字调用父类的构造器,并且super语句必须是子类构造器方法的第一条语句。

⭐️当子类进行实例化的时候,会自动调用父类的无参构造器。若父类没有无参构造器,并且子类也没有显示的调用父类的有参构造器,Java编译器就会报错。

多态

对于继承了父类的所有子类,子类的每个对象也是父类的对象。也就是说,程序中出现的出现父类对象都可以使用子类替换。

// 子类对象赋予父类变量
FatherDemo fatherDemo = new SonDemo();

在Java这种面向对象的设计语言,对象变量是多态的

阻止继承:final类和方法

在开发过程中,有时候我们可能并不希望其他人利用某个类来定义子类。这时我们可以使用final关键字。

  • final类不能被继承
  • final方法被子类不能重写

强制类型转换

有继承关系的类中,可以使用强制类型转换将父类强行转换成子类。

使用强制类型转换的唯一原因是:需要暂时忽略对象的实际类型之后使用对象的全部功能。

  • 只能在继承层次内进行强制类型转换
  • 在进行强制类型转换之前,必须使用instanceof进行检查。

抽象类

抽象类其实本质就是一个类,可以有,但是在类中有一个或者多个抽象方法

抽象类或者抽象方法都使用abstract关键字进行修饰。

抽象方法就是只有方法的定义,并没有实现。

/**
 * 抽象类
 */
public abstract class AbstractDemo {

    private String name;

    public AbstractDemo(String name) {
        this.name = name;
    }

    public void method1(){
        System.out.println("这是正常方法");
    }

    /**
     * 抽象方法
     */
    public abstract void method2();
}

抽象类就是用来给子类继承的,子类继承抽象类,然后对抽象方法进行重写即可使用。

有抽象方法的类一定是抽象类,但是抽象类可以没有抽象方法。

Object,所有类的父类

Object类是Java中所有类的始祖,每个Java类都扩展了Object。所以每个类都有Object的如下方法:

  • equals
  • hashcode
  • toString

equals

equals方法用于检测一个对象是否等于另一个对象。

public boolean equals(Object obj) {
	return (this == obj);
}

从源码我们可以看到,Object类的equals就是==,也就是说equals方法判断两个对象是否相等就是判断两个对象引用是否相等。但是在开发过程中,一般需要对equals进行重写。

Java语言规范要求equals方法具有提下特性:

  1. 自反性:对于任何非空引用x,x.equals(x)返回为true
  2. 对称性:对于任何引用x和y,当且仅当y.equals(x)返回true,x.equals(y)返回true
  3. 传递性:对于任何引用x、y和z,如果x.equals(y)为true,并且y.equals(z)为true,那么x.equals(z)也为true
  4. 一致性:如果x和y引用的对象没有变化,反复调用x.equals(y)应返回相同的结果
  5. 对于任意非空引用x,x.equals(null)返回false

hashCode

散列码(hash code)是由对象导出的一个整型值。并且没有规律。

⭐️hashCode方法与equals方法由密切关系:

  1. equals方法与hashCode方法定有必须相同:如果x.equals(y)返回true,那么x.hashCode()就必须与y.hashCode()返回相同的值
  2. 如果重写了equals方法,必须重写hashCode方法

toString

toString方法会返回表示对象值的一个字符串。

一般在开发中,都会进行重写。

泛型数组列表

见集合章节

对象包装器与自动装箱

Java中,所有的基本类型都有一个与之对应的类,这些类被称为包装器。

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charChar
  • 包装器是不可变的。一旦构造了包装器,就不允许更改包装器中的值
  • 包装器类使用final修饰,无法派生他们的子类

在日常使用过程中,基本数据类型与包装类可以自动相互转化,无需手动操作。这被称为自动拆、装箱

自动装箱
自动拆箱
基本数据类型
包装类

可变长参数

Java方法支持可变长参数。即方法中可传入任意个参数。

public void method1(int a,String... str){
    for (String s : str) {
        System.out.println(s);
    }
    System.out.println("多参数");
}

上面的方法中,我们除了可以传一个int类型的参数外,还可以传入多个String类型的参数。

使用可变长参数,这种参数必须放在参数列表的最后。Java编译器会这种参数视为一个数组。

枚举

之前曾经学习过枚举,这里主要列出关于枚举的几个重要特点:

  1. 枚举类只有几个特定的实例,无法构造新的实例
  2. 对比两个枚举类的值时,使用==即可
  3. 枚举的构造器总是private,所以可以省略
  4. 所有枚举类都是Enum类的子类
  5. 每个枚举类都有一个values方法,它将返回一个包含所有枚举值的数组。

反射

正在建设中

继承的设计技巧

  1. 将公共操作和字段放在父类种
  2. 不要使用受保护的字段
  3. 使用继承实现“is-a”关系
  4. 除非所有的继承方法都有意义,否则不要使用继承。
  5. 覆盖方法时,不要改变预期的行为。
  6. **使用多态,而不要使用类型信息。**便于维护和扩展。
  7. 不要滥用反射。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值