java 19.继承
继承
共性抽取
类的继承格式
class 父类 {
}
class 子类 extends 父类 {
}
继承的关系:is-a,父类更通用,子类更具体。
java单继承,java不支持多继承,支持多级继承
继承的特性
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
public class Animal {
private String name;
private int id;
public Animal(String myName, String myid) {
//初始化属性值
}
public void eat() { //吃东西方法的具体实现 }
public void sleep() { //睡觉方法的具体实现 }
}
public class Penguin extends Animal{
}
implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
}
继承中成员变量的访问特点
在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
-
直接通过子类对象访问成员变量:等号左边时谁,就优先用谁,没有则向上找
-
间接通过成员方法访问成员变量:该方法属于谁,就优先用谁,没有则向上找
示例代码
父类子类都有一个变量num
package extendsDemo;
//父类
public class Fu {
int num = 10;
int numFu = 20;
public void methodFu() {
System.out.println(num);
}
}
//子类
package extendsDemo;
public class Zi extends Fu{
int numZi = 100;
int num = 200;
public void methodZi() {
System.out.println(num);
}
}
//demo
package extendsDemo;
public class demoFuZi {
public static void main(String[] args) {
Fu fu = new Fu();
Zi zi = new Zi();
System.out.println(zi.num); //200
System.out.println("------------------");
zi.methodZi(); //200
zi.methodFu(); //10
}
}
区分子类方法中重名的三种
父类成员变量:直接写成员变量名
子类成员变量:this.成员变量名
子类方法的局部变量:super.成员变量名
Fu.java
package extendsDemo;
public class Fu {
int num = 10;
}
Zi.java
package extendsDemo;
public class Zi extends Fu{
int num = 20;
public void methodZi() {
int num = 30;
System.out.println(num); //30 局部变量
System.out.println(this.num); //20 本类的成员变量
System.out.println(super.num); //10 父类的成员变量
}
}
demoFuZi.java
package extendsDemo;
public class demoFuZi {
public static void main(String[] args) {
Zi zi = new Zi();
zi.methodZi();
}
}
继承中成员方法的访问特点
在父子类的继承关系中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项:无论时成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
示例代码
Fu.java
public class Fu {
public void method() {
System.out.println("执行父类的方法");
}
}
Zi.java
public class Zi extends Fu{
public void method() {
System.out.println("执行子类的方法");
}
}
demoFuZi.java
public class demoFuZi {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}
java方法中的覆盖重写
重写:Override 在继承关系中,方法的名称一样,参数列表也一样
重载:OverLoad 在继承关系中,方法的名称一样,参数列表不一样
@Override
写在方法前面,用来检测是不是有效的正确覆盖重写。只是检测,方法是重写的话,不写@Override也是重写的。
子类方法的返回值必须小于等于父类方法的返回值范围。
java.lang.object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类
子类方法的权限必须大于等于父类方法的权限修饰符
public > protected > (default) > private
default不是关键字default,而是什么都不写,留空。
覆盖重写应用
设计原则:对于已经投入使用的类,尽量不要进行修改。推荐定义一个新的类,来重复利用其中共性内容,并且添加改动新内容。
示例代码
Fu.java
public class Fu {
public void call() {
System.out.println("打电话");
}
public void send() {
System.out.println("发短信");
}
public void show() {
System.out.println("显示号码");
}
}
Zi.java
public class Zi extends Fu{
public void show() {
super.show(); //把父类的show方法拿过来重复利用
System.out.println("显示姓名");
System.out.println("显示头像");
}
}
demoFuZi.java
public class demoFuZi {
public static void main(String[] args) {
Fu fu = new Fu();
fu.call();
fu.send();
fu.show();
System.out.println("---------------");
Zi zi = new Zi();
zi.call();
zi.send();
zi.show();
}
}
继承中构造方法的访问特点
- 在子类构造方法中有一个默认隐含的“super()”调用父类无参构造方法(不写编译器也会加上),所以一定是先调用父类构造,后执行子类构造。
- 可以通过super关键字在子类构造方法中调用父类重载构造。
- super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
总结:子类必须调用父类构造方法,不写则编译器自动加super(),写了则用写的指定的super调用,super只能有一个,还必须是第一个。
示例代码
Fu.java
public class Fu {
public Fu(){
System.out.println("父类无参构造");
}
public Fu(int num){
System.out.println("父类有参构造");
}
}
Zi.java
public class Zi extends Fu{
public Zi(){
super(); //在调用父类无参构造方法,编译器会自动加上super()
// super(10); //通过super关键字在子类构造方法中调用父类重载构造
System.out.println("子类构造方法");
}
}
demoFuZi.java
public class demoFuZi {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
super关键字的三种用法
- 在子类的成员方法中,访问父类的成员变量
- 在子类的成员方法中,访问父类的成员方法
- 在子类的构造方法中,访问父类的构造方法
示例代码
Fu.java
public class Fu {
int num = 10;
public void method(){
System.out.println("父类方法");
}
}
Zi.java
public class Zi extends Fu{
int num = 20;
public void methodZi(){
System.out.println(super.num); //子类访问父类成员变量
}
public void method(){
super.method();
System.out.println("子类调用父类成员方法");
}
public Zi(){
super(); // 3
System.out.println("子类构造方法调用父类构造方法");
}
}
demoFuZi.java
public class Zi extends Fu{
int num = 20;
public void methodZi(){
System.out.println(super.num); //子类访问父类成员变量
}
public void method(){
super.method();
System.out.println("子类调用父类成员方法");
}
public Zi(){
super(); // 3
System.out.println("子类构造方法调用父类构造方法");
}
}
this关键字的三种用法
super关键字用来访问父类内容,而this关键字用来访问本类内容。用法三种:
- 在本类的成员方法中,访问本类的成员变量
- 在本类的成员方法中,访问本类的另一个成员方法
- 在本类的构造方法中,访问本类的另一个构造方法
在第三种用法中要注意:
a. this(...)调用必须是构造方法的第一个语句,唯一一个。
b. super和this两种构造调用,不能同时使用。
示例代码
Fu.java
public class Fu {
int num = 10;
public void method(){
System.out.println("父类方法");
}
}
Zi.java
public class Zi extends Fu{
int num = 20;
//在本类的成员方法中,访问本类的成员变量
public void showNum(){
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
System.out.println("-----------------");
}
//在本类的成员方法中,访问本类的另一个成员方法
public void methodA(){
System.out.println("AAA");
}
public void methodB(){
this.methodA();
System.out.println("BBB");
}
//在本类的构造方法中,访问本类的另一个构造方法
public Zi(){
this(123); //本类的无参构造调用本类的有参构造
}
public Zi(int n){
this(1,2);
}
public Zi(int n, int m){
// this(); //错误写法
}
}
super与this关键字图解