Java继承

Posted Sakura

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java继承相关的知识,希望对你有一定的参考价值。

超类与子类

1.概念

Java用关键字extends表明正在构造的新类派生于一个已经存在的类。已存在的类称为超类(superclass),基类(base class)或父类(parent class);新类称为子类(subclass),派生类(derived)或孩子类(child class)。Java程序员一般使用术语超类和子类。

超类相比于子类并没有优于子类或拥有比子类更多的功能。相反,子类可能封装了更多的数据或功能。

一个例子:

class Employee {
    private int id;
    private String name;
    private double salary;
    public Employee(String name,double salary){
       ...
    }
    public String getName() 
    public double getSalary() {
        return salary;
    }
    public int getId() 

这样一个公司员工的类。属性有id,名字,薪水。

公司有经理,经理的待遇与普通员工有一些差异,不过差异不大。比如,经理在干完活后可以领取奖金,普通员工只能领取薪水,其他都一样。此时,面对这样一点小小的差异,我不愿意从头到尾编写一个新的类,那么就要用到继承。

为经理定义一个新类Manager,增加一点新功能,然后重用Emploee的部分代码即可,将其所有域保留下来。两者之间存在一种明显的关系,is-a关系。即每名经理也是一个员工。

每个子类也是一个超类。is-a关系是继承的一个明显特征。

增加奖金域:

public class Manager extends Emploee{
    private double bonus;
    ....
    public double setBonus(double bonus){
        this.bonus = bonus;
    }
    ....
}

这样,子类就可以使用超类一些方法,因为Manager类自动继承了Emploee中的这些方法。但Emploee却不能使用setBonus()方法。

2.覆盖方法

事实上,子类继承自父类的方法,有些不太适用于子类,例如,父类的getSalary()方法,返回薪水。经理的薪水是怎样的呢?显然,是原来的薪水加奖金。

使用下面的方法来覆盖父类的getSalary()方法:

public double getsalary(){
    double baseSalary = super.getSalary();
    return baseSalary + bonus;
}

这里用到了super关键字。直接return salary+bonus;这样的语句是不行的。

原因:Manager的getSalary()方法不能直接访问超类的私有域。只有Emploee类的方法才能访问。

因此,借助super调用超类的方法,可帮助我们访问超类中的域。

3.子类构造器

同样需要借助super构造器。因为需要访问超类私有域。

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

这样简写,当超类构造器有对应的参数的构造方法时,即会调用那个构造函数。若无,会产生错误。

如果子类没有显示的使用super调用超类的构造器,则自动调用超类的默认(无参数)构造器。

4.多态

现有一经理,两员工,输出薪水。

Employee[] staff = new Employee[3];
Manage boss = new Manager(); 
staff[0] = boss;
staff[1] = new Employee();
staff[2] = new Employee();
for (Employee e:staff){
  system.out.println(e.getSalary());
}

这段代码能够正确的输出薪水。jvm在运行时能够自动的选择调用正确的方法,引用超类时调用超类方法,引用子类时调用子类方法。虚拟机知道e实际引用的对象类型,正确调用方法。

一个对象变量能够指示不同多种实际类型的现象称为多态。

在运行时能够自动选择调用哪个方法的现象称为动态绑定。

如上例子,staff[0]赋值给e,即将一个子类的对象赋值给超类,e即引用了两种实际类型。这里,编译器将staff[0]看做Emploee对象,因而不能这样调用:staff[0].setBonus(5000);可以这样调用:boss.setBonus(5000);

不能将超类的引用赋值给子类变量,原因是显而易见的,相反的is-a关系。

5.阻止继承

有时候,希望阻止某个类定义子类。不允许拓展的类称为final类。如果在定义类时使用了而final修饰符,就表明这个这个类是final类。

public final class Executive extends Manager{
...
}

类中的方法也可以定义为final方法,这样做子类就不能覆盖该方法。

public final String getName()

6.抽象类和抽象方法

有时候,希望父类更加通用,派生出多种多样的子类,并且只将父类作为派生其他类的基类,而不作为想使用的特定的实例类。

这时,即可使用抽象类。

抽象类中可以有抽象方法,抽象方法只有声明而没有实现。如:

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

包含一个或多个抽象方法的类必须声明为抽象类

抽象类的实现在子类中,有以下两种方式:

1)在抽象类中定义部分抽象方法或不定义抽象方法,那么就必须将子类声明为抽象类。

2)在抽象类中定义全部抽象方法,子类就不是抽象的了

抽象类不能被实例化

可以定义一个抽象类的对象,但它只能引用非抽象类子类的对象。

Person p = new Student();

p引用的是子类Student的对象。

7.可见性控制

1)仅对本类可见---private

2)对所有类可见---public

3)对本包和所有子类可见---protected

4)对本包可见---默认

Object:所有类的超类

Object类是java中所有对象的超类,每个类都继承自Object。

以下是Object类的一些方法

1.equals方法

作用:检测一个对象是否等于另一个对象。实际上是判断两个对象是否具有相同的引用。

有些情况下,需要重写该方法,即有时检测而两个对象状态的相等性而不是引用。

覆盖equal方法的一种实现

 

1)显示参数命名为otherObject

2)检测this是否与otherObject引用同一对象,是返回true,否继续

if(this==otherObject) return true;

3)检测otherObject是否为null,是返回false,否继续

if(otherObject==null) return false;

4)比较this与otherObject是否为同一个类,(如果equals语义在每个子类中有所改变,使用getClass()方法;一致则使用instanceof),不是返回false,是继续

if(getClass()!=otherObject.getClass()) return false;

if(!(otherObject instance ClassName)) return false;

这里是考虑由超类决定相等概念还是由子类决定相等概念。

5)将otherObject转换成相应的类类型变量,比较所有域。

ClassName other = (ClassName) otherObject

.....

 

2.hashcode方法

hashcode是由对象导出的一个整形值。散列码是没有规律的。如果x和y是两个不同的对象,那么它们的散列值基本不会相同。

相同的字符串拥有相同的散列码。例如:String s ="OK",String t =new String("OK"), s.hashcode()和t.hashcode()返回结果都是2524。这是因为字符串散列码由内容导出。

如果重写quals方法,那么就需要重写hashcode方法,以便将对象插入到散列表中。

3.toString方法

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

一般用于获取对象状态

 

以上是关于Java继承的主要内容,如果未能解决你的问题,请参考以下文章

java中封装,继承,多态,接口学习总结

java代码在片段活动中不起作用

java 代码片段【JAVA】

# Java 常用代码片段

# Java 常用代码片段

创建片段而不从 java 代码实例化它