继承和多态(上)
目录
一.继承
1.何为继承
2.继承的语法
3.子类访问父类
(1)子类访问父类的成员变量
(2)子类访问的父类方法
二.super关键字
1.super用于调用父类的构造方法
2.super用于调用父类的实例方法
3.super用于访问父类的实例变量
三.子父类构造方法 和代码块的执行优先顺序
三.继承总结
1. 单继承
2. 多层继承
3.多个子类继承同一个父类
一.继承
1.何为继承
继承是面向对象编程中的一个重要概念,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。
通过继承,子类能够直接使用父类的已有功能,避免重复编写代码,同时还能在子类中扩展或修改父类的行为,从而实现代码的重用性和可扩展性。
举一个简单的例子,我们可以认为动物是一个父类,然后猫猫狗狗,牛牛羊羊等是子类。这些猫狗牛羊都拥有一些相同的共性,比如:要睡觉,要吃饭,能跑等等,这些就是通用的属性或方法,然后子类继承父类,子类能够直接使用这些功能,也可以重写该功能(睡觉,吃饭,跑等等),当然这些子类比如说狗,他可以在自己的类中拓展他自己本身有用的独一无二的技能,比如说狗叫汪汪汪等。
2.继承的语法
我们在java中如果想要表示类之间的继承关系的话,需要用到extends关键字,在想要成为子类的类名右旁加上extends 和父类类名。
修饰符 class 子类 extends 父类 {
// ...
}
举一个具体例子,按照上面的例子来写:
//Animal类
public class Animal {
int age;
String name;
public void eat(){
System.out.println(name+"正在吃饭...");
}
public void run(){
System.out.println(name+"正在跑...");
}
}
--------------------------------------------------
//Dog类
public class Dog extends Animal{
//构造方法
public Dog() {
super();
this.name="旺财";
this.age=2;
}
public void bark(){
System.out.println(name+"正在狗叫...");
}
}
--------------------------------------------------
//Cat类
public class Cat extends Animal{
//构造方法
public Cat() {
super();
this.name="咪咪";
this.age=1;
}
public void mew(){
System.out.println(name+"正在猫叫...");
}
}
---------------------------------------------------
//测试类
public class Test {
public static void main(String[] args) {
Dog dog=new Dog();
System.out.println(dog.name);
System.out.println(dog.age);
dog.bark();
dog.eat();
dog.run();
Cat cat=new Cat();
System.out.println(cat.name);
System.out.println(cat.age);
cat.mew();
cat.eat();
cat.run();
}
}
输出结果为:
在代码中测试类我们定义了一个Dog类型的dog对象,可以看到我们可以输出dog.name,dog.age,当然还有方法eat(),run(),这些成员变量和方法Dog类中都没有,但是继承了Animal类后就可以直接使用了,我们在构造方法那里其实就能看出来了。当然Cat类也是如此。
注意:
继承机制使得子类能够“继承”父类的属性和方法,即子类自动拥有父类中的变量和方法,不需要重新定义。
3.子类访问父类
(1)子类访问父类的成员变量
·当子类成员变量与父类成员变量同名时,优先访问自己的,也就是子类的。(无论类型相同与否)
·当子类和父类都没有定义某个成员变量时,就会编译错误。
·当子类成员变量与父类成员变量不同名时,则会根据情况访问子类或者父类的。
举个例子:
//父类Test
public class Test {
static String name = "haha";
static int a=66;
static int b=77;
static String d="父类d";
}
-------------------------------------
//子类Demo
public class Demo extends Test{
static int a=67; //与父类同名同类型
static int c=88; //父类没定义该变量
static int d=10; //与父类同名但是不同类型
public static void main(String[] args) {
System.out.println(a); //输出67 访问的子类
System.out.println(b); //输出77 访问的父类
System.out.println(name); //输出haha //访问的父类
System.out.println(c); //输出88 //访问的子类
System.out.println(d); //输出10 //访问的子类
// System.out.println(e); //编译错误:父类和子类都没定义d
}
}
输出结果:
(2)子类访问的父类方法
子类访问父类的方法分两种情况:
1.方法有参数的情况。
(1)当子类和父类的方法同名但是参数一个有一个无时,如果子类调用有参数的方法,则系统就会自动识别执行有参数的方法,如果调用无参数的方法,那么系统就会执行无参数的方法(无论子类或者父类)。
(2)如果子类父类都有参数且方法同名,系统会根据参数的多少或者类别自动识别并且执行。
2.方法无参数的情况。
(1)子类和父类方法同名都无参时,则会优先执行子类的方法。
注意:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。
举个例子:
//父类Test
public class Test {
public void methodA(){
System.out.println("调用父类的方法A");
}
public void methodB(String str){
System.out.println("调用父类的方法B:"+str);
}
public void methodC(){
System.out.println("调用父类的方法C");
}
}
------------------------------------------------------
//子类Demo
public class Demo extends Test{
//跟父类的方法A同名且无参数
public void methodA(){
System.out.println("调用子类的方法A");
}
//跟父类的方法B同名但是参数不同
public void methodB(int a){
System.out.println("调用子类的方法B:"+a);
}
//跟父类的方法C同名但是参数一个有一个无
public void methodC(int c){
System.out.println("调用子类的方法C:"+c);
}
public static void main(String[] args) {
Demo demo=new Demo();
demo.methodA(); //调用子类的方法A
demo.methodB("hello"); //调用父类的方法B:hello
demo.methodB(10); //调用子类的方法AB:10
demo.methodC(); //调用父类的方法C
demo.methodC(12); //调用子类的方法C:12
}
}
输出结果:
二.super关键字
在子类中,
super
提供了一种方式,能够直接访问父类被重写的方法、父类的属性,以及父类的构造方法。
注意事项:
-
必须在子类构造方法的第一行调用父类构造方法:如果需要使用
super
调用父类的构造方法,它必须是子类构造方法的第一个语句。如果子类构造方法没有显式调用super()
,则默认调用父类的无参构造方法。 -
不能在静态上下文中使用
super
:super
关键字仅用于实例方法或构造方法中,不能在静态方法或静态代码块中使用,因为静态方法不属于任何实例对象。
1.super
用于调用父类的构造方法
在子类的构造方法中,可以通过
super
关键字来调用父类的构造方法。这在需要初始化父类部分的属性或做一些父类构造的工作时非常有用。如果没有明确使用super
调用父类构造方法,系统会默认调用父类的无参构造方法(如果存在)。
class Animal {
Animal(String name) {
System.out.println("Animal构造方法: " + name);
}
}
class Dog extends Animal {
Dog(String name) {
super(name); // 调用父类构造方法
System.out.println("Dog构造方法");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
}
}
输出结果:
代码解释:在这个例子中,
super(name);
调用了Animal
类的构造方法,从而完成了父类的初始化工作。
2.super
用于调用父类的实例方法
在子类中,可以使用
super
关键字来调用父类的实例方法,尤其是在子类中重写了该方法的情况下。此时super
关键字帮助子类调用到父类版本的实现,避免因方法重写而无法访问原方法。
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void sound() {
super.sound(); // 调用父类的 sound 方法
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound();
}
}
输出结果:
代码解释:在这个例子中,
super.sound()
调用了Animal
类的sound
方法,而后才执行子类Dog
的sound
方法。这种情况在需要在重写方法中保留父类的一部分行为时非常有用。
3.super
用于访问父类的实例变量
当子类中有与父类同名的实例变量时,可以使用
super
来区分和访问父类中的变量。这样做可以避免子类中覆盖父类的变量。
class Animal {
String name = "Animal";
}
class Dog extends Animal {
String name = "Dog";
void printNames() {
System.out.println(super.name); // 输出父类的 name 属性
System.out.println(this.name); // 输出子类的 name 属性
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.printNames();
}
}
输出结果:
代码解释:在这个例子中,
super.name
用于访问父类Animal
中的name
属性,而this.name
访问的是子类Dog
中的name
属性。
三.子父类构造方法 和代码块的执行优先顺序
直接上例子,简单记一下就行:
//1、父类静态代码块优先于子类静态代码块执行,且是最早执行
//2、父类实例代码块和父类构造方法紧接着执行
//3、子类的实例代码块和子类构造方法紧接着再执行
//4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
class Person{
public Person(){
System.out.println("Person父类构造方法执行");
}
{
System.out.println("Person父类实例代码块执行");
}
static {
System.out.println("Person父类静态代码块执行");
}
}
public class Student extends Person{
public Student(){
System.out.println("Student子类构造方法执行");
}
{
System.out.println("Student子类实例代码块执行");
}
static {
System.out.println("Student子类静态代码块执行");
}
public static void main(String[] args) {
Student stu=new Student();
System.out.println("===================");
Student stu1=new Student();
}
}
输出结果:
三.继承总结
1. 单继承
Java中一个类只能直接继承自一个父类,这种机制称为单继承。
如下:
class Animal {
// 父类代码
}
class Dog extends Animal {
// Dog类继承了Animal类
}
2. 多层继承
Java支持多层继承,即一个类可以继承另一个类,而这个类本身又可以继承另一个类。
如下:
class Animal {
// 父类代码
}
class Mammal extends Animal {
// Mammal继承Animal
}
class Dog extends Mammal {
// Dog继承Mammal,也间接继承了Animal
}
3.多个子类继承同一个父类
Java中允许多个不同的类继承同一个父类,这称为多对一继承。
class Animal {
// 父类代码
}
class Mammal extends Animal {
// Mammal继承Animal
}
class Dog extends Animal {
// Dog继承Animal
}
Java中不支持的继承类型:多重继承
Java明确不支持类的多重继承,即一个类不能继承多个父类。
class Animal {}
class Mammal {}
class Dog extends Animal, Mammal {} // 错误