Java中的重载 / 重写 / 继承 / 多态

1.前言

最近在用Java编程,一开始我觉得自己对重载(Overload)、重写(Override)还是分得清的,对于继承和多态还是有所了解的。但实践中突然发现了几个问题:静态成员是否可以继承静态成员是否可以呈现出多态的性质重载是不是多态。这些问题还是挺值得细想的,所以总结博客一篇。

2.重载

在同一个类中,方法名相同,但各自的参数不同(包括参数个数、参数顺序、参数类型),称为方法重载(Overload)。方法重载的返回值类型和访问修饰符可以是不同的。
以上这些要求即为方法签名。方法签名包括:方法名称、参数列表(参数个数、参数顺序、参数类型)组成,不包括返回值和访问修饰符。
但如果方法签名相同,返回类型不同,编译时会报错。因为这些方法名、传参都相同的方法,JVM执行时不知道到底要执行哪个方法。

3.继承

继承就是子类继承父类的特征和行为,在Java中主要是继承字段和方法,但两者具体的处理有所不同。
如果子类只是单纯继承父类,没有定义与父类重名的字段或者方法,那调用子类的字段或方法与直接调用父类的没有什么区别,需要注意的是子类无法访问父类用private修饰的字段或方法。

3.1.方法

3.1.1.重写

在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为重写或者覆写(Override)。

对于访问修饰符

  • 如果是private方法,那么子类就不存在重写,只是新建了个方法。
  • 如果是protected/public方法,子类就可以重写,重写的方法只要修饰符范围大于等于父类方法修饰符范围编译时就不会报错。

对于返回类型
如果函数签名相同,返回类型不同,编译时会报错,原因同重载。

3.2.字段

子类中的字段只要和父类中的字段同名,那么即使它们类型不一样,父类的字段都会被隐藏
如果通过父类去引用子类,无论子类有没有重新声明字段,获取到的字段都是父类的:

class Boat {
  String name;
  String tonnage;

  Boat(String name, String tonnage) {
    this.name = name;
    this.tonnage = tonnage;
  }
}

class FishingBoat extends Boat {
  String name;
  Integer tonnage;

  FishingBoat(String name, int tonnage) {
    super(name, String.valueOf(tonnage));
    this.name = "FishingBoat " + name;
  }
}

public class ExtendsVariableDemo {
  public static void main(String[] args) {
    Boat ship = new FishingBoat("鹦鹉螺", 1000);
    System.out.println(ship.name); // 返回父类的name
    System.out.println(ship.tonnage); // 返回父类的tonnage
    System.out.println(ship.tonnage.getClass().toString()); // String
  }
}

3.3.多态

对于某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法:

Person p = new Student();
p.run(); // 实际执行的是Student的run()方法

3.3.1.多态分类

编译时多态
又称静态多态,重载是编译时的多态,因为根据调用传参的类型、数量便可决定调用的是哪个重载方法,不必等到运行时才去决定调用哪个方法,所以它是编译期就能决定的。

运行时多态
又称动态多态,重写是运行时的多态。重写的前提是类继承,重写的函数签名必须跟被重写的方法一致,因此无法通过传参的类型、数量来决定调用子类还是父类的方法,只能在运行时通过传入的实例来动态决定。

3.3.2.重写重载与多态

重写是多态,这点是没有争议的。但重载是不是多态没有定论。按照目前计算机科学领域主流的定义,重载属于多态。但在Java中,多态往往指的是动态多态。

3.4.静态成员

静态是属于类本身的,不是属于某一个实例的。当创建一个实例时,并不对static字段和方法进行拷贝,同一个类所有实例的static成员的存储空间都是同一块。
Java中静态字段和静态方法可以被继承,但如果存在同名字段或者方法,父类的静态成员是没有被重写(overwrite)而是被隐藏。

静态方法:子类可以继承父类的静态方法,但不具备多态的性质。如果子类重写了父类的静态方法,当由父类引用子类对象时,该父类实例调用的是父类自己的静态方法。对于静态方法,在子类中是不存在重写的,只有隐藏。
静态字段:由父类引用子类对象时,该父类实例调用的是父类自己的静态字段。

package oop;

class Book {
  public static String staticStr = "A的静态字段";

  public static void staticMethod() {
	 System.out.println("A的静态方法");
  }
}

class StoryBook extends Book {
  public static String staticStr = "B的静态字段";

  public static void staticMethod() {
    System.out.println("B的静态方法");
  }
}

public class ExtendStaticDemo {
  public static void main(String[] args) {
    // 声明为Book,实际为StoryBook
    Book book = new StoryBook();
    System.out.println(book.staticStr); // A的静态字段
    book.staticMethod(); // A的静态方法
  }
}

但如果在非静态方法中访问静态成员又如何?在将上面的例子稍作改动:

class Book {
  public static String staticStr = "A的静态字段";

  public static void staticMethod() {
	 System.out.println("A的静态方法");
  }

  public String say() {
    return staticStr;
  }

  public String hello() {
    return staticStr;
  }
}

class StoryBook extends Book {
  public static String staticStr = "B的静态字段";

  public static void staticMethod() {
    System.out.println("B的静态方法");
  }

  // 子类中重写了hello方法,但没有重写say方法
  public String hello() {
    return staticStr;
  }
}

public class Test {
  public static void main(String[] args) {
    // 声明为Book,实际为StoryBook
    Book book = new StoryBook();
    System.out.println(book.say()); // A的静态字段
    System.out.println(book.hello()); // B的静态字段
  }
}

调用book.say()时,由于子类没有定义say方法,调用父类的say方法,访问的字段是父类的静态字段。这个表现换成非静态字段也是一样的。
调用book.hello()时,由于这时调用的方法是非静态方法,多态的性质就被体现出来了,实际执行的方法是子类的方法,访问的字段是子类的静态字段。
总结起来就是:

  • 声明为父类就访问父类的静态成员。
  • 声明为子类就访问子类的静态成员。如果子类不存在该静态成员,就访问父类的静态成员。

4.参考

Java中子类是否可以继承父类的static变量和方法而呈现多态特性
JAVA静态方法是否可以被继承?
java中方法重载是多态的表现么?
多态
java中父类有static修饰的方法其子类能继承吗?若子类也有该方法,是覆盖还是重写?
判断对错。在java的多态调用中,new的是哪一个类就是调用的哪个类的方法

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值