5. 类的继承和多态
5.1 继承
继承是子类使用父类的方法。Java支持类的单继承和多层继承,不支持多继承。即一个类只能继承一个类而不能继承多个类。继承关键字是extends,继承格式如下: class 子类名 extends 父类名
继承的限制:
(1) 不可同时继承多个父类;
(2) 子类不可直接使用继承的父类私有成员 子类继承父类全部属性和方法(包括私有),但子类不能直接使用父类的私有属性和方法,必须通过Setter和Getter方法进行间接操作;
(3) 先super初始化父类构造方法 若父类存在构造方法,不管子类有没有新的属性需要初始化,子类都必须创建构造方法并调用“super(需要初始化的父类属性名);”的方法来初始化父类构造方法,然后才再初始化自己的参数,先后顺序不可更改;
(4) Final修饰的类不能被继承。
5.2 覆写
所谓覆写是指子类定义了和父类相同的属性或方法,在覆写过程中不会改变父类的任何成员。覆写分为属性覆写和方法覆写, Final修饰的方法不能被覆写,但能重载。
如果父类中的方法/属性 使用了private修饰,那么该方法对于子类是不可见的,此时子类可以创建一个与该方法同名的子方法,但子方法没有覆写父类的方法,是子类自己的方法,只是名字一样。
子类覆写父类方法时,父类方法应是public类型,在子类覆写时,如有需要也只能在子类中调用父类原方法,可用super.方法()调用。子类覆写父类方法后,父类原方法不会发生改变。
注:父类的构造方法与子类的构造方法不存在覆写关系!!!
5.3 重载
重载发生在同一个类中,所谓重载,即方法名称相同,方法参数不同(包括类型不同,顺序不同,个数不同),通过传递不同形式的参数来完成不同类型的工作。重载主要用在构造方法重载和普通方法重载。这样一对多的方式实现了静态多态。
5.4 多态
多态是父类使用子类的方法。确切地说就是父类使用被子类覆盖的同名方法。多态分为方法多态和对象多态,方法多态主要体现在方法重载上,可以是构造方法的重载也可以是普通方法的重载,对象多态(向上转型自动完成,向下转型强制转换),对象多态性关键思想就是父类对象依据被赋值的每个子类对象的类型,做出恰当的响应。
5.4.1 java 多态的向上转型
向上转型父类只能调用自己的方法,调用方法的过程中,遇见了子类复写,此时就用子类的实现(这一点非常非常重要)。向上转型后,父类引用指向子类对象,子类覆写了父类的方法,此时用父类的引用调用覆写的方法,此时执行的是子类覆写的方法。
向上转型例子:
class Fa{
public void talk() {
System.out.print("我是Fa里面的\n");
}
public void speak() {
System.out.print("我是Fa里面的speak\n");
}
}
class Son extends Fa{
public void talk() {
System.out.print("我是Son里面的\n");
}
public void jump() {
System.out.print("我是Son里面的\n");
}
}
public class ExtendsDemo6 {
public static void main(String[] args) {
Son son=new Son();
Fa fa=son;//父类Fa 对象名fa =子类对象名;实现向上转型
fa.talk();
fa.speak();
}
}
输出为:
我是Son里面的Son
我是Fa里面的speak
如果在程序最后再加一个fa.jump();程序即报错;
public class ExtendsDemo6 {
public static void main(String[] args) {
Son son=new Son();
Fa fa=son;//父类Fa 对象名fa =子类对象名;实现向上转型
fa.talk();
fa.speak();
}
}
输出:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method jump() is undefined for the type Fa
综上,向上转型后,父类只能调用自己的方法,若有方法被覆写,则执行子类覆写的内容。
5.5 方法重载与覆写的区别
区别 | 重载 | 覆写 |
---|---|---|
英文单词 | Overload | Override |
定义 | 方法名称相同,参数类型、个数、顺序至少有一个不同。 | 方法名称、参数类型、个数及返回值类型必须相同。 |
范围 | 只能发生在同一类中 | 发生在类的继承关系——子类中 |
权限 | 不受权限控制 | 被覆写的方法不能拥有比父类更严格的访问权限。 |
5.6 java对象作为方法的参数传递
在Java中,当对象作为参数传递时,究竟传递的是对象的值,还是对象的引用,这是一个饱受争议的话题。若传的是值,那么函数接收的只是实参的一个副本,函数对形参的操作并不会对实参产生影响;若传的是引用,那么此时对形参的操作则会影响到实参。(引用自:https://blog.csdn.net/qq_28081081/article/details/80400111)
5.6.1. 基本数据类型作参数传递
这里是引用当基本数据类型(Boolean,byte,char,String,int,Long,float,double)作为参数传递时,传递的是实参值的副本,即传的是值,无论在函数中怎么操作这个副本,实参的值是不会被改变的。如下例子:
public class test {
public static void main(String[] args) {
int i = 1;
System.out.println("before change, i = "+i);
change(i);
System.out.println("after change, i = "+i);
}
public static void change(int i){
i = 5;
}
}
输出:
before change, i = 1
after change, i = 1
5.6.2. 对象作为参数传递
在Java中,当对象作为参数传递时,实际上传递的是一份“引用的拷贝”。 (实际传递的是对象的引用),例如:
public class Canshuchuandi {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("before change, sb is "+sb.toString());
change(sb);
System.out.println("after change, sb is "+sb.toString());
}
public static void change(StringBuffer stringBuffer){
stringBuffer.append("world !");
}
}
输出:
before change, sb is Hello
after change, sb is Hello world !