Loading

JavaSE继承

类、子类、超类

定义子类

待续

覆盖方法

待续

Super关键字

子类中的方法不能够直接访问超类的私有域,只有超类本身才能够反问私有部分,如果子类一定要访问超类私有域,可以使用super关键字

public class Manager extends Employee{
    
    ...
    
    //子类中获取薪水的方法
    public double getSalary()
    {
        //调用父类中的获取薪水方法
        double baseSalary = super.getSalary();
        //返回Manager的薪水+奖金的总工资
        return baseSalary + bonus;
    }
    
    ...
}

子类构造器

public Manager(String name, double salary, int year, int month, int day)
{
    super(name, salary, year , month, day) ;
    bonus = 0;
}

由于Manager 类的构造器不能访问Employee 类的私有域, 所以必须利用Employee 类 的构造器对这部分私有域进行初始化, 我们可以通过super 实现对超类构造器的调用。使用 super 调用构造器的语句必须是子类构造器的第一条语句。

阻止继承:final 类和方法

有时候,可能希望阻止人们利用某个类定义子类。不允许扩展的类被称为final类

如果在定义类的时候使用了final修饰符就表明这个类是final 类。

public final class Executive extends Manager
{
    ...
}

类中的特定方法也可以被声明为final。
如果这样做,子类就不能覆盖这个方法( final 类中的所有方法自动地成为final 方法)

public class Employee
{
    ...
    
    public final String getName(){
       ... 
    }
    
    ...
}

抽象类

Person类作为Employee和Student的顶层类,拥有其子类很多共有的特征,可以使用抽象类来定义Person类,便于让子类进行扩展

  • 包含一个或多个抽象方法的类本身必须被声明为抽象的
public abstract class Person
{
    ...
    // 返回一个人的简短描述
    public abstract String getDescription();
}
  • 除了抽象方法之外,抽象类还可以包含具体数据和具体方法
public abstract class Person
{
    private String name;
    
    public Person(String name)
    {
        this.name = name ;
    }
    
    public abstract String getDescription();
    
    public String getName0
    {
        return name;
    }
}

PS:许多程序员认为,在抽象类中不能包含具体方法。建议尽量将通用的域和方法(不管是否是抽象的)放在超类(不管是否是抽象类)中

  • 抽象类的两种选择方式
    • 一种是在抽象类中定义部分抽象类方法或不定义抽象类方法,这样就必须将子类也标记为抽象类
    • 另一种是定义全部的抽象方法,这样一来,子类就不是抽象的了

受保护访问

一般,将类中的域标记为private,而方法标记为public。任何声明为private 的内容对其他类都是不可见的

在有些时候,人们希望超类中的某些方法允许被子类访问,或允许子类的方法访问超类的某个域。为此,需要将这些方法或域声明为 protected

  • 例如,如果将超类Employee中的实例域hireDay声明为proteced,而不是私有的, Manager中的方法就可以直接地访问它。
  • 对控制可见性的4个访问修饰符进行总结:
    • 仅对本类可见private
    • 对所有类可见public
    • 对本包和所有子类可见protected
    • 对本包可见—默认(很遗憾),不需要修饰符

Object:所有类的超类

equals() 方法

待续

hashCode() 方法

散列码( hash code)是由对象导出的一个整型值。散列码是没有规律的。如果 x 和 y 是两个不同的对象, x.hashCode( ) 与y.hashCode( ) 基本上不会相同

hashCode 方法定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址

toString() 方法

用于返回表示对象值的字符串

常用的方法汇总

方法名 描述
boolean equals(Object otherObject ) 比较两个对象是否相等, 如果两个对象指向同一块存储区域, 方法返回true
String toString( ) 返冋描述该对象值的字符串。在自定义的类中, 应该覆盖这个方法
String getName( ) 返回这个类的名字
Class getClass( ) 返回包含对象信息的类对象
Class getSuperclass( ) 以Class 对象的形式返回这个类的超类信息

对象包装器与自动装箱

  • 将int 这样的基本类型转换为对象
  • 所有的基本类型都有一个与之对应的类

例如,Integer 类对应基本类型int
通常, 这些类称为包装器( wrapper ) 这些对象包装器类拥有很明显的名字:Integer、Long、Float、Double、Short、Byte、Character 、Void 和Boolean ( 前 6 个类派生于公共的超类Number)

  • 包装器类的特点
    • 对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值
    • 对象包装器类还是final , 因此不能定义它们的子类

假设想定义一个整型数组列表。而尖括号中的类型参数不允许是基本类型就用到了Integer 对象包装器类

ArrayList<Integer> list = new ArrayList<>();

而对此数组列表进行数值添加有

// 自动装箱
list.add(3)

//会自动变为
list.add(Integer.ValueOf(3));

以上变换被称为自动装箱(autoboxing)。相反,将一个Integer 对象赋给一个int 值时,将会自动地拆箱。

//自动拆箱
int n = list.get(i);

//拆箱
int n = list.get(i).intValue();
  • 自动装箱注意事项:
    • 由于包装器类引用可以为null,所以自动装箱有可能会抛出一个NullPointerException 异常
    • 如果在一个条件表达式中混合使用Integer 和Double 类型,Integer 值就会拆箱,提升为double, 再装箱为Double
    • 装箱和拆箱是编译器认可的,而不是虚拟机。编译器在生成类的字节码时, 插人必要的方法调用。虚拟机只是执行这些字节码。
Integer n = null;
System.out.println(2 * n); // Throws NullPointerException

Integer n = 1;
Double x = 2.0;
System.out.println(true ? n : x); // Prints 1.0
posted @ 2020-07-02 21:14  codeduck  阅读(141)  评论(0编辑  收藏  举报