什么是继承?

继承是面向对象编程中的一个重要概念,它允许我们创建一个新的类,该类从现有的类中继承属性和方法。被继承的类称为父类或基类,新的类称为子类或派生类。


继承的主要优点是代码重用。当我们需要在多个类中使用相同的代码时,我们可以将该代码放在父类中,并让子类继承它,从而避免在每个类中重复编写相同的代码。此外,继承还使代码更易于维护和扩展。

如何实现继承?

在Java中,我们使用关键字extends来实现继承:

class 父类{ ... //成员变量、成员方法 } class 子类 extends 父类{ ... //类体 }

下面是一个简单的示例:

public class Animal {
    public void eat() {
        System.out.println("Animal is eating");
    }
}

public class Dog extends Animal {
    public void bark() {
        System.out.println("Dog is barking");
    }
}

在上面的示例中,Dog类继承自Animal类。子类Dog可以访问父类Animal中的所有非私有属性和方法。

继承的类型

在Java中,继承有以下几种类型:

  • 单一继承:每个类都只能继承一个类。这意味着一个类只能有一个直接父类。
  • 多重继承:一个类可以从多个类中继承属性和方法。然而,Java不支持多重继承,因为它可能导致类之间的冲突。
  • 多层继承:一个类可以从另一个类继承,而这个类又可以从另一个类继承。这样的继承称为多层继承。

 

 继承中的访问修饰符

在Java中,访问修饰符用于控制类、方法和属性的访问权限。在继承中,访问修饰符有以下规则:

  1. 子类可以访问父类中的公共(public)和受保护(protected)成员,但不能访问父类中的私有(private)成员。
  2. 子类中的成员不能访问父类中的私有成员。
  3. 如果子类中有一个方法具有相同的名称和参数列表作为父类中的方法,则称为方法重写。子类可以重写父类的公共和受保护方法。重写方法必须具有相同的返回类型或其子类型。
  4. 子类可以使用super关键字调用父类的构造函数,但必须是子类构造函数的第一条语句。例如:
public class Animal {
    public Animal(String name) {
        // constructor logic here
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // call the parent constructor
        // additional constructor logic here
    }
}

 继承的优点

1.继承过来的字段和方法,可以像任何其他字段和方法一样被直接使用;
2.在子类中可以声明一个与父类中同名的新字段或静态方法,从而“隐藏”父类中的字段或方法;
3.可以在子类中声明一个在父类中没有的新字段和方法;
4.可以在子类中编写一个父类当中具有相同名的新实例方法,这称为“方法重写”或“方法覆盖”;
5.可以在子类中编写一个调用父类构造方法的子类构造方法,既可以隐式地实现,也可以通过使用关键字super来实现。
 

继承需要注意的点

1.子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
2.子类必须先调用父类的构造器, 完成父类的初始化。

3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
4.如果希望指定去调用父类的某个构造器,则显式的调用一下:super(参数列表)5) super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)。
5. super0)和 this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器 。
6.java 所有类都是 Object 类的子类,Object 是所有类的基类。
7.父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)9)子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。
8.不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系。

 继承的本质分析(重要)

public class ExtendsTheory { 
	public static void main(String[] args) { 
		Son son = new Son();//内存的布局 
		//?-> 这时请大家注意,要按照查找关系来返回信息 
		//(1) 首先看子类是否有该属性 
		//(2) 如果子类有这个属性,并且可以访问,则返回信息 
		//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..) 
		//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object...
		System.out.println(son.name);//返回就是儿子 
		//System.out.println(son.age);//返回的就是 39 
		//System.out.println(son.getAge());//返回的就是 39 
		System.out.println(son.hobby);//返回的就是旅游 
	} 
}
class GrandPa { //爷类 
	String name = "爷爷";
	String hobby = "旅游"; 
}
class Father extends GrandPa {//父类 
	String name = "爸爸"; 
	private int age = 39; 
	public int getAge() { 
		return age; 
	} 
}
class Son extends Father { //子类 
	String name = "儿子"; 
}

重写和隐藏父类方法

重写

方法的重写是指子类重写(override)父类的方法,使其实现不同的功能。重写的方法必须和被重写的方法有相同的名称、参数列表和返回类型。在子类中使用@Override注解可以帮助检查是否满足重写的条件。

下面是一个重写的示例:

class Animal {
    public void speak() {
        System.out.println("I am an animal.");
    }
}

class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("I am a dog.");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal a = new Animal();
        Dog d = new Dog();
        a.speak(); // Output: I am an animal.
        d.speak(); // Output: I am a dog.
    }
}

在上面的示例中,Dog类重写了Animal类的speak方法,使其输出不同的字符串。在Test类的main方法中,分别创建了一个Animal对象和一个Dog对象,并调用它们的speak方法。

需要注意的是,重写的方法可以使用super关键字来调用父类的方法实现。例如,在Dog类的speak方法中可以使用super.speak()来调用Animal类的speak方法。

隐藏

方法的隐藏是指子类定义了一个和父类同名但参数列表不同的方法,使得父类的方法被隐藏。被隐藏的方法只能通过父类的引用调用,而不能通过子类的引用调用。子类定义的方法和父类定义的方法虽然同名,但实际上是两个不同的方法,它们只是方法名相同而已。

下面是一个隐藏的示例:

class Animal {
    public void speak() {
        System.out.println("I am an animal.");
    }
}

class Dog extends Animal {
    public void speak(int times) {
        for (int i = 0; i < times; i++) {
            System.out.println("Woof!");
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Animal a = new Dog();
        Dog d = new Dog();
        a.speak(); // Output: I am an animal.
        d.speak(); // Output: Woof!
        d.speak(3); // Output: Woof! Woof! Woof!
    }
}

在上面的示例中,Dog类定义了一个和Animal类同名但参数列表不同的speak方法。在Test类的main方法中,创建了一个Animal对象和一个Dog对象,并分别调用它们的speak方法。由于a是一个Animal类型的引用,它只能调用Animal

方法重写和隐藏后的修饰符

在子类中被重写的方法,其访问权限允许大于但不允许小于被其重写的方法,例如:父类中一个受保护的实例方法(protected)在子类中可以是公共的(public)的,但不可以是私有的(private)。如果一个方法在父类中是static方法,那么在子类也必须是static方法;如果一个方法在父类中是实例方法,那么在子类中也必须是实例方法。

继承中的this和super

在Java中,子类可以继承父类的属性和方法。子类对象可以使用this关键字来访问自己的属性和方法,使用super关键字来访问父类的属性和方法。

this关键字表示当前对象,可以用于访问当前对象的属性和方法。当子类继承父类的属性和方法时,如果子类中的属性和方法与父类中的同名,那么子类中的属性和方法会隐藏父类的属性和方法。此时,如果要访问父类的属性或者调用父类的方法,可以使用super关键字,或者使用this关键字来区分子类和父类中的同名属性或方法。