十四、OOP之理解《继承》

本文探讨了面向对象编程中的继承特性,阐述了其提高代码复用性和可维护性的优点,同时也指出了继承可能导致的代码耦合性问题以及遵循的高内聚低耦合原则。此外,文章还介绍了Java中的单继承、多层继承、this和super的区别,以及构造方法和重写的相关概念,最后提到了静态代码块的作用和执行特点。
摘要由CSDN通过智能技术生成

继承是面向对象三大特性之一,那他有什么好处呢?

1、好处

(1) 提高了代码的复用性

(2) 提高了代码的可维护性

(3) 是类中多态的前提
但是也同时存在一些弊端

2、弊端

(1) 提高了代码和代码耦合性 :事物和事物之间相互影响的程度

(2)开发的原则:高内聚,低耦合 程序设计追求 高内聚,低耦合

高内聚就是类的内部数据操作细节自己完成,不允许干涉
低耦合,仅暴露少量的方法给外部使用。

继承的好处是远远大于弊端的,继承还是要用
下面就先介绍一下继承的定义

一、继承

继承的本质是`对某一批类的抽象`,从而实现更得的建模

extends的英文意思是“扩展”。
也就是说:子类是父类的扩展。

  1. 继承是类与类之间的关系。除此之外,类和类直接的关系还有依赖,组合,聚合等。
    继承关系的两个类一个为子类(也叫派生类),一个为父类(也叫基类)。
  2. 子类继承父类,使用关键字extends来表示。
    子类和父类之间,从意义上应该具有“is a”的关系
  3. 方法重写: //@override 重写
    为什么需要重写? 父类的方法功能子类不一定需要或者不一定满足
    重写都是方法的重写,要有继承关系和属性无关 子类重写父类的方法
    父类的引用指向了子类 (对象)
    1.方法名必须相同
    2.参数列表必须相同
    3.修饰符 可以扩大 关键字只能是public
    4.抛出的异常 只能缩小
    5.方法体不同
    静态方法和非静态方法区别很大
    静态方法:方法的调用只和;左边的数据类型有关
    非静态的方法:重写 的关键字只能是public

1、继承就是让类和类产生关系,父子关系
JAVA中的类只有单继承,没有多继承!
一个儿子只能有一个爹

2、如何让两个类之间产生关系,使用一个关键字,extends 扩展 增加 继承

3、定义一个A类,定义一个B类,让A类继承B类,此时A类中就可以拥有B类中的所有内容

4、父类和子类的关系:

(1) 父类:就是用于被继承的类,别称:超类、基类

(2) 子类:用于继承的类,别称:派生类

注意事项:

1、父类中的私有成员不能被继承(不能在子类中直接访问)

(1) 父类中的一些私有成员,不能在子类中直接调用

(2) 其实在子类对象中,仍然包含父类这些私有的成员变量,不能直接使用这些私有的内容,需要通过公共的访问方式访问

2、父类的构造方法不能被继承

(1) 构造方法的作用:是给成员变量赋值。

  • 所以父类的构造方法给父类成员变量赋值
  • 子类构造方法给子类成员变量赋值
  • 子类成员变量一般比父类多,所以继承下来也不好用

(2) 父类的构造方法名需要和父类类名一致,子类的构造方法名,需要和子类一致,因为类名不同,无法继承

不能继承怎么解决呢?

(3) 解决:子类无法直接继承父类的构造方法,但是可以在子类中使用特殊格式调用父类的构造方法

3、继承的设计:不要为了部分功能而定义继承

(1) 狗类:属性 姓名 性别 年龄 行为 吃 喝

(2) 人类:属性 姓名 性别 年龄 钱 行为 吃 喝 吃狗肉

(3) 定义的时候 看人类有独有的钱还有行为吃狗肉,其他狗类都有,所以定义继承关系

(4) 继承的关系描述 子类和父类关系 is a

  • 僵尸 和铁桶僵尸 铁桶僵尸是个僵尸

  • 学生和人 学生是个人

  • 狗和哺乳动物 狗是个哺乳动物

public class Demo01 {
    public static void main(String[] args) {
        Zi z = new Zi("张三",11);
        //父类中提供了公共的访问方式     子类中可以访问父类公共 部分的内容
        System.out.println(z.getName());
        System.out.println(z.getAge());
        //想要修改值可以通过set方法修改
        z.setName("张四");
        z.setAge(44);
        System.out.println(z.getName());
        System.out.println(z.getAge());
    }
}
class Fu{ //父类
    private String name;
    private int age;
    public Fu() {
        System.out.println("父类的空参构造");
    }
    public Fu(String name, int age) {
        System.out.println("父类的有参构造");
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
//子类继承父类
class Zi extends Fu{
    //如果没有提供构造方法 则子类中会提供一个空参构造
    public Zi(){
        //子类的构造方法第一行,默认有一句 super();表示访问父类的空参构造
        super();//super()这句话必须在构造方法的第一行
        System.out.println("子类的空参构造");
    }
    public Zi(String name,int age){
        //name和age是私有的,子类无法直接访问
//        this.name = name;
//        this.age = age;
//        super(实际参数);叫做super语句 作用访问父类的构造方法
        //所有的构造方法中,都会默认隐藏一句super()表示访问父类的构造方法
        //随便定义一个类型,都是有父类的,最顶层的父类叫做Object
        //如果手动添加任何一个super语句不会默认提供了
        super(name,age);//表示访问父类的有参构造
        System.out.println("子类的有参构造");
    }
    //子类拥有父类中的内容,方法也被继承下来
    public void show(){
        //父类定义的私有年龄和姓名  子类无法直接访问,所以通过公共的访问方式间接的去访问
        System.out.println(getName() + getAge());
    }
}

二、特点

1、java支持单继承、不支持多继承,支持多层继承

  • 单继承:一个子类只能有一个父类(一个孩子只能有一个亲爹)

  • 多继承:一个子类可以同时拥有多个父类(多个亲爹) 不可以

2、多层继承:
(爹还有爹,爷爷还有爹)
A类继承B类,B类继承C类,那么A类中就拥有B类中的内容,也拥有C类中的内容,越顶层的类,拥有的功能就越少,主要是公共的属性和行为,越底层的类,功能就越多,有很多属性和行为,以后学习某个体系要从最顶层的类开始学,再学底层的类,这样只需要看子类特有的内容即可

3、java不支持多继承的原因:

如果可以多继承,那么子类在调用多个父类中同名的方法,父类们对这个方法有很多不同的实现,子类继承就会不知道该调用哪个父类的方法。所以不能

代码演示:

public class Demo02 {
    public static void main(String[] args) {
        C c = new C();
        c.sayHello();
        c.sayHi();
    }
}
//爷爷类
class A{  //A是爷爷。B是爸爸。C是孙子
    public void sayHi(){
        System.out.println("孙子 你好啊");
    }
}
class B extends A{ 
    public void sayHello(){
        System.out.println("儿子你好啊");
    }
}
class C extends B{
}

三、继承中成员变量的关系

1、子类中定义和父类不同名的成员变量,在子类中既可以使用父类的成员变量,也可以使用子类的成员变量

2、子类和父类中定义同名的成员变量,子类就会根据就近原则,只能访问到子类自己定义的成员变量

解释一下上面两句话:子类访问某个变量-->优先会在自己的方法中寻找,有没有定义这样一个变量,找到了就用,找不到去自己的类中去查找,找不到去父类中找,父类中没有,就继续向上寻找,一直找到所有类的根类,Object,有就使用,没有就报错

五、this和super

superthis都可以访问成员变量,成员方法。也都可以在构造方法中使用,只能出现在构造方法的第一行,用来访问构造方法的内容 .

(1) this(实际参数);访问子类的构造方法

(2) super(实际参数);访问父类的构造方法

1、this和super解释说明: 一个代表当前的另一个代表父类

(1) this表示本类当前对象的引用

(2) super表示本类当前对象父类的引用

构造方法:
this本身调用者这个对象 本类的构造
super代表父类对象的应用 父类的构造

2、总结:

(1) this既可以访问父类的内容,也可以访问子类的内容

(2) super只能访问父类的内容

super类 对比 this

调用父类的构造方法,必须出现在子类方法或者出现在构造方法的第一个
super和this不能同时调用构造方法
前提:this没有继承也可以使用
super只能在继承条件下才可以使用

public class Demo03 {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.test();
        System.out.println(z);
    }
}
class Fu{ //定义父类
    int i = 10;
}
class Zi extends Fu{  //定义子类继承父类
    int i = 100;
    int m = 300;
    public void test(){
        int i = 20;
        System.out.println(i);//根据就近原则访问的是20
        System.out.println(this.i);//加上this的一定是成员
        //this既可以访问子类的成员变量,也可以访问父类的成员变量 也就是100
        System.out.println(super.i);//访问父类的i 也就是10
        System.out.println(this.toString());//表示本类当前对象的引用
        System.out.println(super.toString());//toString可以输出对应的信息
        System.out.println(super.m); //这行运行会报错,因为只能访问父类中定义的内容 子类的m没法访问
    }
}

六、继承中构造方法的关系

public class Demo04 {
    public static void main(String[] args) {
        Zi z = new Zi();
    }
}
class Fu{  //定义父类
    public Fu(){
        System.out.println("父类的空参构造被调用了");
    }
}
class Zi extends Fu{  //同样是定义子类继承父类
    public Zi(){
        //默认隐藏了一句super语句  super() 表示访问父类的空参构造
        this("李四");//        this("李四"); this语句和super语句只能放在构造方法的第一行
        System.out.println("子类的空参构造");
    }
    public Zi(String name){
//        super(name);//表示访问父类的有参构造
//        this();不能递归调用
        System.out.println("子类的有参构造");
    }
}

1、在初始化子类数据之前,必须对父类数据进行初始化(因为在初始化子类的时候,有可能会用到父类的数据,所以先把父类初始化完成)

2、如果在子类的构造方法中,没有显式的调用任何构造方法,此时在构造方法的第一行,系统会默认加上一句super() 默认访问父类的构造方法

3、如果在子类自己的构造方法中,显式的调用了任何构造方法,此时系统就不会再提供任何构造方法的调用

4、构造方法不能递归调用:不能自己调用自己,也不能间接的访问自己

5、this语句和super语句只能出现在构造方法的第一行,而且只能出现一个

七、继承中成员方法的关系(重写

1、方法名不同:子类既可以访问父类,也可以访问子类

2、方法名相同:实现子类的方法 java把这个叫做方法的重写

(1) 重载:在同一个类中,方法名相同,参数列表不同,与返回值类型无关

(2) 重写:在父子类中,方法名一样,参数列表一致,返回值类型一致,实现体不同

  • 通过@Override 检测一个方法是否是重写父类的方法
  • 是重写就不会报错 如果不是就报错

3、重写的方法本身还是属于父类,只不过在子类中重新实现了这个方法

4、重写的注意事项:

  1. 私有的方法不能被重写,子类可以定义一个和父类私有方法同名的方法,不算重写,只能算重新定义了一个方法

  2. 方法在重写的时候,权限不能越来越小,子类应该是越来越强大的,功能应该越来越多,不能将父类中的内容重写没了

八、补充一个代码块的知识点

1、根据位置的不同,有不同的名称,有不同的作用,有不同的执行时机

2、分类:
(1) 局部代码块
(2) 构造代码块
(3) 静态代码块

1.局部代码块

1、格式:使用大括号包括起来一段代码 位置在方法中

2、作用:

(1) 限制变量的生命周期

(2) 在局部代码块中定义的变量,只能在局部代码块中使用,一旦出了代码块就不能再访问了

(3) 某个变量只需要使用一次,后续就不再使用了,就可以使用局部代码块声明,从而节省内存空间

public class Demo01 {
    public static void main(String[] args) {
        int a = 10;
        int c;
        {
            //局部代码块  限制变量的生命周期,限制到当前大括号声明的位置开始,到大括号结束
            int b = 20;
            a = 20;
            System.out.println(a);
            c = 30;
            System.out.println(c);
            System.out.println(b);
        }
        System.out.println(b);
        System.out.println(c);
        System.out.println(a);
        c = 30;
    }
    static int b;
//   static int c;
}

2.构造代码块

1、格式:使用大括号包括起来的代码 位置在类中方法外

2、作用:给成员变量赋值

3、构造代码块的执行:

(1) 在创建对象的时候调用

(2) 在构造方法之前执行

(3) 无论你调用哪个构造方法,都会先执行一次构造代码中的内容

5、适用于,如果一个类的每一个构造方法,都需要执行同一个相同的内容,就可以提取公共的部分到构造代码块中

public class Demo02 {
    public static void main(String[] args) {
        Man m = new Man("小明",22);
        Man m2 = new Man("小明");
        Man m3 = new Man();
    }
}
class Man{
    private String name;
    private int age;
    //构造代码块,定义在类中方法外
    {
        //构造代码块执行 早于构造方法执行
        //如果构造方法都需要执行同一个内容,就可以提取到构造代码块中
        System.out.println("我是个男人,我被创建了");
    }
    public Man(String name) {
        this.name = name;
        System.out.println("一个参数的构造执行了");
    }
    public Man() {
        System.out.println("空参构造执行了");
    }
    public Man(String name, int age) {
        System.out.println("两个参数的构造方法执行了");
        this.name = name;
        this.age = age;
    }
}

3.静态代码块

1、格式:

static{

}

2、类中方法外

3、作用:

(1) 用于给静态的属性赋值

(2) 用于给那些只需要执行一次的代码,数据库的驱动类加载

4、执行的特点:

(1) 执行的时机早,早于对象所有的内容,随着类的加载而加载

(2) 由于.class只需要加载一次,所以静态代码块也只要加载一次

public class Demo03 {
    public static void main(String[] args) {
        System.out.println(Car.number);
        System.out.println(Car.number);
    }
}
class Car{
    //轮胎个数
    static int number;
    //静态代码块只要访问类就会 执行该内容
   static {
        number = 4;
        //作用主要是为了给静态变量赋值,
        System.out.println("只能执行一次");
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值