类的继承在Java中有着非常广泛和重要的作用,今天我们来学学Java中继承的用法和细节。
一,继承的概念和作用
什么是继承呢?通俗的讲,继承是类与类之间的一种包含关系,比如:
public class Animal {
int age;
String name;
public void eat(){
System.out.println(name+" is eating");
}
}
public class Dog extends Animal {
private int count;
public void bark(){
System.out.println(getName()+"is barking,maybe hungry");
}
public void eat(){
count++;
System.out.println(getName()+"is eating,today has eaten for"+count+"times");
}
}
这两段代码中,Dog类就继承了Animal类。在这种继承关系中,我们称继承的Dog类为子类(派生类),称继承的Animal类为父类(基类,超类)。
(由于“父类”又称“超类”,在后续的代码中可以用super来代表父类来调用父类方法。)
在使用继承时,我们往往会先定义好父类,再在定义子类时使用extends关键字进行继承,就像这样:
public class 父类{
//父类的属性和方法
}
public class 子类 extends 父类{
//子类的属性和方法
}
而继承的效果是什么呢?
子类可以继承父类的属性和方法。也就是说,子类的属性可以访问父类中的属性,调用父类中的方法(私有属性方法不能直接使用)。
我们用继承的方法可以把很多子类中共同的属性或者方法集合到父类,精简代码量,使代码逻辑更加清晰。
二,继承中的方法重写
public class Animal {
int age;
String name;
public void eat(){
System.out.println(name+" is eating");
}
}
public class Dog extends Animal {
private int count;
public void bark(){
System.out.println(getName()+"is barking,maybe hungry");
}
public void eat(){
count++;
System.out.println(getName()+"is eating,today has eaten for"+count+"times");
}
}
在上面举例的代码当中,我们可以发现,父类Animal和子类Dog都存在eat方法。
根据前面说的,子类可以继承父类中的属性和方法,那么在这里,为什么会有两个eat方法呢?子类在调用eat方法时是调用的父类中继承的eat方法还是子类中新定义的eat方法呢?
这其实是继承中的方法重写。
方法重写顾名思义是对方法进行重写,在继承时,方法重载就是用子类中新写方法重载从父类中继承的方法,因为有些时候父类中统一的方法可能不能满足子类的功能实现,所以需要在子类中重新定义所需的对应方法,就像上面两端代码中的eat方法。
方法重写是有一定的前提:一是两个类需要有继承关系,二是子类重载方法的访问修饰符要大于父类,三是方法的返回值类型,方法名,参数类型要完全一样。
最终子类在调用该方法时,调用的是子类中重写的方法。
三,自动转型和强制转型
自动转型(向上转型)
我们在新建对象的过程中,往往会用到
A a = new A()
这种形式的代码,创建一个属于A类,名为a的新对象。而在存在继承关系的代码中,我们可能会看到这样的代码:
A a = new B();
//B为A的子类
这其实是类的继承中的自动转型(又叫向上转型)又叫这句代码可以理解为:创建了一个 B
类型的对象,并将其引用赋值给 A
类型的变量 a
。
其本质就是创建一个子类对象,将其当成父类对象来使用。
我们结合前面的Animal类和Dog类的代码来分析:
public class Animal {
int age;
String name;
public void eat(){
System.out.println(name+" is eating");
}
}
public class Dog extends Animal {
private int count;
public void bark(){
System.out.println(getName()+"is barking,maybe hungry");
}
public void eat(){
count++;
System.out.println(getName()+"is eating,today has eaten for"+count+"times");
}
public static void main(String[] args) {
Animal dog = new Dog();
dog.eat();
dog.bark();//这里会报错
}
}
这里我们创建了一个属于子类Dog类的对象dog,并把dog当成父类的对象来使用。
之后我们调用了eat方法和bark方法,发现eat方法的执行结果为子类重写的eat方法,而bark方法无法执行并会报错。
这是因为自动转型(向上转型)实现时,无法执行子类特有的方法,只能执行父类中特有的方法或者子类中重写父类的方法。并且在存在方法重写时优先执行子类中重写的方法。
强制转型(向下转型)
上面我们知道,向上转型实现后,我们无法调用子类特有的方法,其实我们可以通过弥补无法调用子类特有方法的不足。
就像这样
Dog d = (Dog)dog
这里我们用Dog类的对象g来接受向下转型为Dog的对象dog,后面就可以用g来调用子类中的特有方法。
将dog对象向下转型后,我们就可以调用dog特有的bark方法了,完整代码是这样:
public class Animal {
int age;
String name;
public void eat(){
System.out.println(name+" is eating");
}
}
public class Dog extends Animal {
private int count;
public void bark(){
System.out.println(getName()+"is barking,maybe hungry");
}
public void eat(){
count++;
System.out.println(getName()+"is eating,today has eaten for"+count+"times");
}
public static void main(String[] args) {
Animal dog = new Dog();
dog.eat();
dog.eat();
Dog d = (Dog)dog;
dog.bark();
}
}
四,继承中Object类的应用
在创建了一个新对象之后,我们发现即使这个类没有写任何方法,我们仍然有很多可调用的方法,如上图中的equals,hashCode等等,这是因为所有类在定义时都默认继承Object类,可以直接使用的方法其实是父类Object中的方法。
Object在Java中也默认是所以类的父类。