1.类的继承
1.1 继承的定义
在程序中,一个类想要继承另一个类,需要使用关键字extends,其基本语法如下:
[修饰符] class 子类名 extends 父类名{
//程序核心代码
}
上述语法中,类的修饰符是可选的,用来指定类的访问权限,可以使用public或者省略不写,子类名和父类名都是必选的,并且子类和父类之间要使用extends关键字实现继承关系。
class Animal{
public String name;
//private String name;
void shout(){
System.out.println("动物发出叫声");
}
}
class Dog extends Animal{
public void printName(){
System.out.println("name:"+name);
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name="赖皮狗";
dog.printName();
dog.shout();
}
}
如果我们将上述第二行代码换成第三行,那么将会显示报错,错误如下图,这就是封装的重要性。
那么如何进行修改了?
class Animal{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
void shout(){
System.out.println("动物发出叫声");
}
}
class Dog extends Animal{
private String name;
public void printName(){
System.out.println("name:"+getName());
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("赖皮狗");
dog.printName();
dog.shout();
}
}
由上述代码所知,子类在继承父类的时候,会自动拥有父类所有的公共成员。
在类的继承中,需要注意以下问题:
(1)在Java中,类只支支持单继承,不允许多继承,也就是说一个类只能有一个直接父类,下面这种情况是不合法的。
class A()
class B()
class C extends A,B()
(2)多个类可以继承同一个父类,如下:
class A()
class B extends A()
class C extends A()
(3)在Java中,多层继承是可以的,即一个类可以再去继承另外的父类,例如:
class A()
class B extends A()
class C extends B()
1.2 重写父类的方法
在继承关系中,子类会自动继承父类中公共的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需要注意的是,子类中重写的方法需要和父类被重写的方法具有相同的方法名,参数列表以及返回值类型。
class Animal{
public void shout(){
System.out.println("动物发出叫声");
}
}
class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪汪。。。");
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.shout();
}
}
注意: 子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限,如父类中的方法访问权限是public,子类重写父类该方法的访问权限就不能是private。
1.3 super关键字
从上述程序运行结果可以看出,当子类重写父类的方法后,子类对象将无法直接访问父类被重写的方法。为了解决这个问题,在Java中专门提供了一个关键字super来访问父类的成员,例如访问父类的成员变量,成员方法和构造方法。具体用法如下:
(1)使用super关键字调用父类的成员变量和成员方法。
super.成员变量
super.成员方法([参数1,参数2...])
class Animal{
public String name="动物";
public void shout(){
System.out.println("动物发出叫声");
}
}
class Dog extends Animal{
public String name="犬类";
@Override
public void shout() {
super.shout();
}
public void printName(){
System.out.println("name = " + super.name);
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.shout();
dog.printName();
}
}
(2)使用super关键字调用父类的构造方法,形式如下
super([参数1,参数2...])
class Animal{
public Animal(String name) {
System.out.println("我是一只"+name);
}
}
class Dog extends Animal{
public Dog(){
super("癞皮狗");
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
注意: 通过super调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次,否则编译就会报错。
class Animal{
public Animal(String name) {
System.out.println("我是一只"+name);
}
}
class Dog extends Animal{
public Dog(){
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
从上述图片中可以看出,程序编译出现错误。出错的原因是,在子类的构造方法中,一定会调用父类的某个构造方法。这时可以在子类的构造方法中通过super关键字指定调用父类的哪个构造方法,如果没有指定,在实例化子类对象时,会默认调用父类的无参构造函数,而在上述代码中,父类中只定义了有参构造函数,未定义无参构造函数,所以在子类默认调用父类无参构造方法时就会出错。
为解决上述的编译错误,可以在子类中显式的调用父类中已有的构造方法,或者在父类中定义无参构造函数。
class Animal{
public Animal() {
System.out.println("我是一只动物");
}
public Animal(String name) {
System.out.println("我是一只"+name);
}
}
class Dog extends Animal{
public Dog(){
}
}
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
通过上述代码可以得出一个结论:在定义一个类时,如果没有特殊需求,当定义了有参构造方法后,尽量在类中在显式地定义一个无参构造方法,这样就可以避免该类在继承时出现错误。