第七章总结

本文介绍了Java中的类继承、子类与父类的关系,包括如何使用`extends`关键字进行继承,以及子类如何覆盖父类的方法。同时,讨论了多态的概念,包括向上转型和向下转型,以及接口和抽象类的使用,强调了`equals()`、`hashCode()`和`toString()`方法的重要性。
摘要由CSDN通过智能技术生成

1. 类、超类和子类
继承:子类继承父类的全部属性与方法,并根据需求进行扩展。关键字 extends 表示继承。
父类:已存在的类
子类:由父类派生的类,与父类是继承"is a"关系。

通用的方法放在超类中, 而将具有特殊用途的方法放在子类中
子类中可以增加域、 增加方法或覆盖超类的方法,绝对不能删除继承的任何域和方法
单根继承原则:每个类都只能继承一个类,可以实现多个接口
public class Manager extends Employee 

    添加方法和域 
}

public class Manager extends Employee 

    添加方法和域 
}


本章教学使用的类:

 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; 
        hireDay = LocalDate,of(year, month, day); 
    } 
    
    public String getName()
    {
        return name;
    }
    public double getSalary() 
    { 
        return salary; 
    }
    public LocalDate getHireDay() { 
        return hireDay; 
    }
    public void raiseSalary(double byPercent) 
    { 
        double raise = salary * byPercent / 100; salary += raise;
    }
}

public class Manager extends Employee //子类
{
     private double bonus;
     public Manager(String name, double salary, int year, int month, int day) //子类构造器
     { 
        super(nanie, salary, year, month, day); 
        bonus = 0;
    }
    
    public double getSalary()//覆写 
    {    
        double baseSalary = super.getSalary(); //调用父类private域成员数据
        return baseSalary + bonus;
    }
    public void setBonus(double b)//增加的方法 { 
        bonus = b;
    }
}

 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; 
        hireDay = LocalDate,of(year, month, day); 
    } 
    
    public String getName()
    {
        return name;
    }
    public double getSalary() 
    { 
        return salary; 
    }
    public LocalDate getHireDay() { 
        return hireDay; 
    }
    public void raiseSalary(double byPercent) 
    { 
        double raise = salary * byPercent / 100; salary += raise;
    }
}

public class Manager extends Employee //子类
{
     private double bonus;
     public Manager(String name, double salary, int year, int month, int day) //子类构造器
     { 
        super(nanie, salary, year, month, day); 
        bonus = 0;
    }
    
    public double getSalary()//覆写 
    {    
        double baseSalary = super.getSalary(); //调用父类private域成员数据
        return baseSalary + bonus;
    }
    public void setBonus(double b)//增加的方法 { 
        bonus = b;
    }
}


2. 覆盖方法(override)
:子类与父类有相同的方法(名称形参相同)

返回类型不是签名的一部分可以不同,但要保证返回类型的兼容性
子类方法不能低于超类方法的可见性。如果父类方法是 public, 子类方法一定要声明为 public
子类虽然继承父类成员,但不能直接访问父类的private域,要调用父类接口
public double getSalary() 
{
    return salary + bonus; // won't work 

public double getSalary()

    double baseSalary = getSalaryO;// still won't work 
    return baseSalary + bonus; 

public double getSalary()//√

    double baseSalary = super.getSalary();
    return baseSalary + bonus; 

public double getSalary() 
{
    return salary + bonus; // won't work 

public double getSalary()

    double baseSalary = getSalaryO;// still won't work 
    return baseSalary + bonus; 

public double getSalary()//√

    double baseSalary = super.getSalary();
    return baseSalary + bonus; 

 


3. 子类构造器:
先构造父类(super),再初始化子类成员。

super 调用构造器的语句必须是子类构造器的第一条语句,没有的话会默认添加
public Manager(String name, double salary, int year, int month, int day) 

    super(name, salary, year, month, day); 
    bonus = 0; 

public Manager(String name, double salary, int year, int month, int day) 

    super(name, salary, year, month, day); 
    bonus = 0; 


super 关键字的作用:

调用父类的方法。
调用超类的构造器。
4. 多态
:一个类对象变量可以指示多种实际类的现象被称为多态

多态的作用:以统一的接口来操控某一类中不同对象的动态行为

一般是父类变量可以指示子类对象,但子类变量不能指示父类对象,除非进行向下类型转换
一般与覆写一起使用
4.1 动态绑定
:虚拟机知道实际引用的对象类型,在运行时能够自动地选择调用哪个方法的现象。

Employee[] staff = new Employee[3];
staff[0] = boss; //多态
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1 ); staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);

for (Employee e : staff)
    System.out.println(e.getName() + " " + e.getSalary());//虚拟机知道调用Manager 还是 Employee的 getSalary()

//但编译器将 staff[0]看成 Employee对象
boss.setBonus(5000); // OK 
staff[0].setBonus(5000); // Error

Employee[] staff = new Employee[3];
staff[0] = boss; //多态
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1 ); staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);

for (Employee e : staff)
    System.out.println(e.getName() + " " + e.getSalary());//虚拟机知道调用Manager 还是 Employee的 getSalary()

//但编译器将 staff[0]看成 Employee对象
boss.setBonus(5000); // OK 
staff[0].setBonus(5000); // Error
 


4.2 强制类型转换
向上转换:子类向父类转换(直接转换)
向下转换:父类向子类转换(instanceof)

只能在继承层次内进行类型转换
在将父类转换成子类之前,应该使用 instanceof 进行检查
Manager boss = (Manager)staff[0]; //向上

if (staff[1] instanceof Manager)//向下 { 
    boss = (Manager) staff[1];
}

Manager boss = (Manager)staff[0]; //向上

if (staff[1] instanceof Manager)//向下 { 
    boss = (Manager) staff[1];
}
 


5. 抽象类
:不能被实列化的类,能提高成员变量和不被实现的方法。

abstract关键字:定义抽象类和抽象方法。

子类可以继承于抽象类,但是一定要实现父类们所有
abstract的方法。如果不能完全实现,那么子类也必须被定
义为抽象类。
抽象类的组成:

(optional)成员变量,个数不限
(optional)具体方法,方法有实现,个数不限
(optional)抽象方法,加abstract关键字,个数不限
抽象类可以包含具体数据和具体方法,但最好不要
接口一定是抽象方法,即使不加abstract
public abstract class Person {
    String s;
    public abstract String getDescription();
}
public abstract class Person {
    String s;
    public abstract String getDescription();
}

6. 接口
:是一种需求描述,内部包含抽象方法,接口不是类(interface)

public interface Comparable //接口定义

    int compareTo(Object other); 

public int compareTo(Object other Object) //接口实现 

    Employee other = (Employee) otherObject; 
    return Double.compare(salary, other.salary);
}

public interface Comparable //接口定义

    int compareTo(Object other); 

public int compareTo(Object other Object) //接口实现 

    Employee other = (Employee) otherObject; 
    return Double.compare(salary, other.salary);
}


6.1 接口的域和方法:
接口中的所有方法自动地属于 public abstract。 因此,在接口中声明方法时,不必提供关键字 public abstract
实现接口时,必须把方法声明为 public,并实现全部 abstract方法,如果没有全部实现,那么只能成为一个抽象类。
接口绝不能含有实例域,可以将接口看成 是没有实例域的抽象类,但是这两个概念还是有一定区别的
接口中不能包含实例域或静态方法,但却可以包含常量。接口中的域将被自动设为常量 public static final。
6.2 接口的特性:
接口也可以被扩展。
public interface Moveable 

    void move(double x, double y); 

public interface Powered extends Moveable 

    double milesPerCallon();
}

public interface Moveable 

    void move(double x, double y); 

public interface Powered extends Moveable 

    double milesPerCallon();
}
 


每个类只能够拥有一个超类, 但却可以实现多个接口,使用逗号将实现的各个接口分隔开。
class Employee implements Cloneable, Comparable
class Employee implements Cloneable, Comparable

接口不能直接实例化
public interface TestInterface{}
TestInterface testInterface = new TestInterface();//这种肯定是不允许的 
public interface TestInterface{}
TestInterface testInterface = new TestInterface();//这种肯定是不允许的 

接口可以声明变量,接受实现接口子类的赋值
– 此时该变量就是子类
– 与父类的多态不同
– 子类创建对象赋值给接口后,接口再赋值给子类需要强制转换

public interface Anim{}
public class Cat implements Anim {}
public class Dog implements Anim {}
Anim  anim= new Cat();//这种是可以的,声明变量被绑定在一个以此接口实现的对象
Anim  anim2= new Dog();

Cat newcat = (Cat) anim


public interface Anim{}
public class Cat implements Anim {}
public class Dog implements Anim {}
Anim  anim= new Cat();//这种是可以的,声明变量被绑定在一个以此接口实现的对象
Anim  anim2= new Dog();

Cat newcat = (Cat) anim
 


在 Java SE 8中,允许在接口中增加静态方法。理论上讲,没有任何理由认为这是不合法 的。只是这有违于将接口作为抽象规范的初衷。
6.3 接口的默认方法
:可以为接口方法提供一个默认实现,使用 default 修饰符标记。(直接进行调用或覆写)

可以把所有方法声明为默认方法, 这些默认方法什么也不做。只需要覆写需要的方法
public interface MouseListener 

    default void mousedieked(MouseEvent event) {}
    default void mousePressed(MouseEvent event) {} 
    default void mouseReleased(MouseEvent event) {} 
    default void mouseEntered(MouseEvent event) {} 
    default void mouseExited(MouseEvent event) {}
}
public interface MouseListener 

    default void mousedieked(MouseEvent event) {}
    default void mousePressed(MouseEvent event) {} 
    default void mouseReleased(MouseEvent event) {} 
    default void mouseEntered(MouseEvent event) {} 
    default void mouseExited(MouseEvent event) {}
}

默认方法冲突原则:

超类优先,如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略
接口冲突,如果一个超接口提供了一个默认方法,另一个接口提供了一个同名而且 参数类型(不论是否是默认参数)相同的方法,必须覆盖这个方法来解决冲突
6.4 接口示例
public interface ActionListener //监听事件

    void actionPerfonned(ActionEvent event); 

class TimePrinter implements ActionListener //接口实现
{
    public void actionPerformed(ActionEvent event) 
    { 
        System.out.println("At the tone, the time is " + new Date());
        Toolkit.getDefaultToolkit().beep(); 
    } 
    

ActionListener listener = new TimePrinter(); //类似于父类变量接受子类型
Timer t = new Timer(10000, listener);
t.start()

public interface ActionListener //监听事件

    void actionPerfonned(ActionEvent event); 

class TimePrinter implements ActionListener //接口实现
{
    public void actionPerformed(ActionEvent event) 
    { 
        System.out.println("At the tone, the time is " + new Date());
        Toolkit.getDefaultToolkit().beep(); 
    } 
    

ActionListener listener = new TimePrinter(); //类似于父类变量接受子类型
Timer t = new Timer(10000, listener);
t.start()
 


7. Object: 所有类的超类
:Object 类是 Java 中所有类的始祖, 在 Java 中每个类都是由它扩展而来的,构建出一个类型继承树

在 Java 中,只有基本类型 不是对象, 例如,数值、 字符和布尔类型的值都不是对象。
Object类里面默认就有clone, equals, finalize, getClass,
hashCode, toString等方法
单根继承原则:每个类都只能继承一个类,可以实现多个接口
7.1 equals() 方法
:检测一个对象是否等于另外一个对象。

检验引用是否相等
是否为同一类
内容域是否相等
public class Employee{
public boolean equals(Object otherObject) 
    { 
// a quick test to see if the objects are identical 
    if (this == otherObject) return true;//检验引用
// must return false if the explicit parameter is null 
    if (otherObject == null) return false;
// if the classes don't match, they can't be equal 
    if (getClassO != otherObject.getClass()) return false;//检验是否同类
// now we know otherObject is a non-null Employee Employee 
    other = (Employee) otherObject;
// test whether the fields have identical values 
    return name.equals(other.name) && salary = other.salary && hi reDay.equals(other.hireDay);//检验内容域
    }
}
public class Employee{
public boolean equals(Object otherObject) 
    { 
// a quick test to see if the objects are identical 
    if (this == otherObject) return true;//检验引用
// must return false if the explicit parameter is null 
    if (otherObject == null) return false;
// if the classes don't match, they can't be equal 
    if (getClassO != otherObject.getClass()) return false;//检验是否同类
// now we know otherObject is a non-null Employee Employee 
    other = (Employee) otherObject;
// test whether the fields have identical values 
    return name.equals(other.name) && salary = other.salary && hi reDay.equals(other.hireDay);//检验内容域
    }
}

getClass() 将返回一个对象所属的类
子类的equals方法:首先调用超类的 equals。如果检测失败,对象就不可能相等。如果父类中的域都相等,就需要比较子类中的实例域。

public class Manager extends Employee{
public boolean equals(Object otherObject) 
    { 
        if (!super.equals(otherObject)) return false; 
        // super.equals checked that this and otherObject belong to the same class 
        Manager other = (Manager) otherObject; 
        return bonus == other.bonus; 
    }
}
public class Manager extends Employee{
public boolean equals(Object otherObject) 
    { 
        if (!super.equals(otherObject)) return false; 
        // super.equals checked that this and otherObject belong to the same class 
        Manager other = (Manager) otherObject; 
        return bonus == other.bonus; 
    }
}

equals 方法具有下面的特性:

自反性:对于任何非空引用 x, x.equals(x)应该返回 true
对称性: 对于任何引用 x 和 y,当且仅当 y.equals(x) 返回 true, x.equals(y) 也应该返回 true
传递性:对于任何引用 x、y 和 z, 如果 x.equals(y) 返回 true, y.equals(z)返回 true, x.equals(z) 也应该返回 true
一致性: 如果 x 和 y引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果。
如果子类能够拥有自己的相等概念,则对称性需求将强制采用 getClass ()进行检测
如果由超类决定相等的概念,那么就可以使用 imtanceof()进行检测
7.2 hashCode() 方法
:散列码( hash code) 是由对象导出的一个整型值,如果x与y对象相同则 x.hashCode( ) == y.hashCode( )

public class Employee 

    public int hashCode() { 
    return 7 * name.hashCode() + 11* new Double(salary).hashCode0 + 13 * hireDay.hashCode();
    }
}
public class Employee 

    public int hashCode() { 
    return 7 * name.hashCode() + 11* new Double(salary).hashCode0 + 13 * hireDay.hashCode();
    }
}

Equals 与 hashCode 的定义必须一致:如果 x.equals(y) 返回 true, 那么 x.hashCode( ) 就必 须与 y.hashCode( ) 具有相同的值。
hashCode相等,equals不一定相等
hashCode相同,再判断equals,equals同则相同,不同则不同
7.3 toString() 方法
:它用于返回表示对象值的字符串,或自己所需信息的字符串

public String toString()
{
    return getClass().getName() + "[name=" + name +",salary: " + salary + ",hireDay=" + hireDay + "]"; 

public String toString()
{
    return getClass().getName() + "[name=" + name +",salary: " + salary + ",hireDay=" + hireDay + "]"; 


8. 对象包装器与自动装箱
包装器:要将 int 这样的基本类型转换为对象
:Integer、Long、Float、Double、Short、Byte、Character、Void 和 Boolean

ArrayList<Integer> list = new ArrayList<>();
list.add(3);//将自动地变换成 list.add(Integer.value0f(3));
//这种变换被称为自动装箱(autoboxing)。
ArrayList<Integer> list = new ArrayList<>();
list.add(3);//将自动地变换成 list.add(Integer.value0f(3));
//这种变换被称为自动装箱(autoboxing)。

public class BoxClassTest {
    public static void main(String[] args)
    {
        int i1 = 10;
        Integer i2 = 10;                // 自动装箱
        System.out.println(i1 == i2);   //true
        // 自动拆箱  基本类型和包装类进行比较,包装类自动拆箱
        
        Integer i3 = new Integer(10);
        System.out.println(i1 == i3);  //true
        // 自动拆箱  基本类型和包装类进行比较,包装类自动拆箱
        
        System.out.println(i2 == i3); //false
        // 两个对象比较,比较其地址。 
        // i2是常量,放在栈内存常量池中,i3是new出对象,放在堆内存中
        
        Integer i4 = new Integer(5);
        Integer i5 = new Integer(5);
        System.out.println(i1 == (i4+i5));   //true
        System.out.println(i2 == (i4+i5));   //true
        System.out.println(i3 == (i4+i5));   //true
        // i4+i5 操作将会使得i4,i5自动拆箱为基本类型并运算得到10. 
        // 基础类型10和对象比较, 将会使对象自动拆箱,做基本类型比较
        
        Integer i6 = i4 + i5;  // +操作使得i4,i5自动拆箱,得到10,因此i6 == i2.
        System.out.println(i1 == i6);  //true
        System.out.println(i2 == i6);  //true
        System.out.println(i3 == i6);  //false
    }    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值