--------------------------------------------------------------------------------------------莫听穿林打叶声,一蓑烟雨任平生--------------------------------------------------------------------------------------------

Java笔记day13

一、继承
1、定义
​    在Java中,将从已经存在的类产生新类的机制称为继承。
    原来存在的类叫父类(或叫基类),新类叫子类(或叫派生类)。
    子类中会自动拥有父类中的设计代码,还可以改写原来的代码或添加新的代码。
2、意义
    1)、减少程序设计的错误
​    2)、提高了代码的复用性,做到了代码的复用,可简化和加快程序设计,提高了工作效率
​    3)、提高了代码的维护性
​     4)、让类与类之间产生了关系,为后面学习多态做准备
​     5)、继承不仅仅是简单的拥有父类的设计代码,继承机制本身就具有进化的能力,跟生物世界一样子代总是比父代更能适应环境。
        通过对父类的设计做一些局部的修改,使得子类对象具有更好的适应能力和强大的生存能力
3、格式
​    人:
​        属性:姓名,年龄
​    行为:学习

​    学生:
​        属性:姓名,年龄
​        行为:学习

​   老师:
​        属性:姓名,年龄
​        行为:学习
​   继承:
​       按照我们之前学习的类的写法的时候,发现学生类和老师类中的成员大部分内容是一样的,
   name和age这两个成员辩能力,以及study()方法都是相同的。如果我们再继续定义类,比如医生,程序员,律师等等,
   他们同样也都具备了这些成员内容,每次写一个类都要重复写一遍,代码很麻烦而且很长。
​        学习了继承,就可以把这些相同的内容放到一个独立的类中,然后,让其他类与这个类产生一个继承关系,
    建立好这个关系之后呢,其他类也同样具备了这个独立的类的一些功能。
​       为了实现这样的技术,java提供了一个用于继承的关键字:extends

    格式:class 子类名 extends 父类名 {}

4、举例

class Person{
    String name;
    int age;
    public void study(){
        System.out.println("刻苦学习")
    }
}

class Teacher extends Person{

}

class Student extends Person{

}

public class Demo{
    public static void main(Sring[] args){
        Teacher T1 = new Teacher();
        T1.Study;
        
        Student S1 = new Student();
        S1.study;
    }
}

***老师和学生都能输出刻苦学习,老师和学生作为子类,继承了Person中的所有属性和方法***

5、继承的坏处和原则
坏处,弊端:
        继承将耦合性增强了
开发的原则:
        低耦合,高内聚
6、继承的特点
    1)、针对于类来说,Java它只支持单继承,不支持多继承,即父类可以拥有多个子类,但是子类只能有一个父类
​     2)、Java支持多层继承(继承体系)
​     3)、举例

class GrandFather{
    public void show(){
        System.out.println("我是爷爷");
    }
}

class Father extends GrandFather{
    //这里继承了爷爷的show()方法
    public void show1(){
        System.out.println("我是爸爸");
    }
}

class Son extends Father{
    //这里继承了爷爷的show()方法和爸爸的show1()方法
    public void show2(){
        System.out.println("我是儿子");
    }
}

public class ExtendsDemo3 {
    public static void main(String[] args) {
        //创建儿子对象
        Son s = new Son();
        s.show2();         //使用自己特有的方法
        s.show1();         //使用父亲的方法
        s.show();         //使用爷爷的方法
    }
}


7、继承中的成员变量的关系
        当子类的成员变量与父类的成员变量名字一致的时候,方法中访问的变量会先在该方法内部查找,如果找不到去该类中的成员变量上去查找,如果本类中也没有成员变量,去父类中查找,如果父类中也没有成员变量,报错

class A{
    int q = 11;
}

class B extends A{

}


public class ExtendsDemo5 {
    public static void main(String[] args) {
         B b = new B();
        System.out.println(b.q);    //继承A中的int q = 11;
    }
}


*******************************************************

class A{
    int q = 11;
}

class B extends A{
    int w = 22;
    public void fun1(){
        System.out.println(q);
    }
}


public class ExtendsDemo5 {
    public static void main(String[] args) {
        B b = new B();
        b.fun1();        //此时输出也是11
    }
}


*******************************************************

class A{
    int q = 11;
}

class B extends A{
    int w = 22;
    public void fun1(){
        int q = 100;
        System.out.println(q);
    }
}


public class ExtendsDemo5 {
    public static void main(String[] args) {
        B b = new B();
        b.fun1();        //此时输出是100,因为就近原则
}


*******************************************************

class A{
    int q = 11;
}

class B extends A{
    int w = 22;
    int q = 100;
    public void fun1(){
        System.out.println(q);
    }
}


public class ExtendsDemo5 {
    public static void main(String[] args) {
        B b = new B();
        b.fun1();        //此时输出为100,
}
/*
    当子类的成员变量与父类的成员变量名字一致的时候,方法中访问的变量会先在该方法内部查找,
    如果找不到去该类中的成员变量上去查找,如果本类中也没有成员变量,去父类中查找,如果父类中也没有成员变量,报错
*/

8、注意事项
1、子类只能继承父类的所有非私有的成员(成员变量和成员方法)

class Father{
    String name;
    private int age;

    public void eat(){
        System.out.println("吃饭");
    }
    
     private void fly(){
        System.out.println("飞翔");
     }
}

class Son extends Father{

}

public class ExtendsDemo4 {
    public static void main(String[] args) {
    Son s = new Son();    //创建儿子对象
    s.name = "小明";
    //s.age = 18;	
    System.out.println(s.name+"---"+s.age);

    //s.eat();
    //s.fly();        //父类私有的成员方法不能被继承,此处和上面的age都会报错    
   }
}

2、子类可以继承父类的构造方法吗?
      子类不能继承父类的构造方法,但是要想初始化子类就必须初始化父类,初始化的时候调用的是构造方法,这里其实是通过一个关键字去访问的父类构造方法,后面会学
 3、不要为了部分的功能特地的去使用继承
class A{
    show1();
    show2();
}

class B{
    fun1();
    fun2();
    fun3();
    fun4();
    show1();
}
    这里的A,B就不要为了使用继承而去创建一个C类存放show()方法,当作他们的父类了
那什么情况下使用继承呢?
    可以满足什么是什么的这个语句的时候,就可以用继承了("is a")
譬如:
    水果:
        苹果,橘子,西瓜,草莓
    液态:
        水,可乐,芒果
二、super关键字

1、使用super关键字的原因

class DemoFu{
    int a = 20;
}

class DemoZi extends DemoFu{
    int a = 10;
    public void fun(){
        System.out.println(a);
    }
}

public class ExtendsDemo1 {
    public static void main(String[] args) {
        DemoZi D1 = new DemoZi();
        D1.fun();
    }
}


​        这里的输出是DemoZi中的a的值,10,那么要是想要通过子类调用父类当中的a要怎么做呢?
​        Java提供了一个关键字给我们使用:super

class DemoZi extends DemoFu{
    int a = 10;
    public void fun(){
        System.out.println(a);
        System.out.println(super.a);
    }
}


​    此时fun()方法的第二行输出就是父类中的20
2、格式

​        与this对比着看

this代表的是当前对象的引用
super代表的是当前对象的类继承的父类的引用(可以直接操作父类中的成员)
​        super与this的使用格式:

访问成员变量:
    super.成员变量 (访问的是父类的成员变量)
    this.成员变量 (访问的是本类中成员变量)
访问成员方法:
    super.成员方法 (访问的是父类的成员方法)
    this.成员方法 (访问的是本类中的方法,可以是访问继承自父类中的成员方法)
访问构造方法:
    super(...)  (访问父类构造方法的方式)
    this(...)  (访问本类中的构造方法)

3、注意事项

class DemoSun extends DemoZi{
      int a = 30
    public void fun(){
        System.out.println(a);
        System.out.println(super.a);
    }
}


​    此时的super调用的仍然调用的是DemoZi中的a,10,而不是DemoFu中的a
所以super只代表直接父类中的引用,而不能跨层引用。如果继承超过两层,那么调用上面的变量和方法就只能新建对象调用,如果不能创建对象也就不能调用了
4、继承与构造方法的关系
​    先记住一句话,要想初始化子类,就必须初始化父类,而初始化调用的是构造方法
    子类中所有的构造方法中都会默认含有一个访问父类的无参构造方法的super()

class DemoZi extends DemoFu{
    int a = 10;
    DemoZi{
        super();      //super() JVM虚拟机会默认在调用子类构造方法的时候,
                     // 这里会默认有一个访问父类无参构造方法的super()
    }
    public void fun(){
        System.out.println(a);
    }
}


​        继承与构造方法注意事项
当父类没有提供无参构造方法的时候,如何解决?
    1、父类提供一个无参构造方法
    2、在子类的构造方法中第一句话上使用super访问父类中其他的构造方法,完成父类的初始化
注意事项:
    1、对构造方法的调用必须是构造器中的第一个语句
    2、 同一个只能被初始化一次
5、继承与成员方法的关系
1、当子类中的方法与父类中的方法不同的名字的时候
    根据调用方法的名字不同,调用的方法也不同
2、当子类中的方法与父类中的方法名字一样的时候
    1)先在本类中查找,看看有没有方法,如果有就直接调用
    2)如果本类中没有对应名字的方法,就去父类中找
    3)如果在父类中也没有找到对应的方法,报错
三、重写
1、重写定义及举例

​        当子类中的方法与父类中的方法一样的时候,内部实现不一样,这种现象我们称之为方法的重写,方法的覆盖
    重写的定义:
        子类中的方法名与形参列表以及返回值都和父类一样,只是内部实现不一样。
    面试题:
        java中重写与重载的区别:
            1、重写是发生在继承的关系中,方法名,参数列表,返回值都和父类一样
            2、重载是发生在同一个类中,方法名字一样,参数列表不一样,与返回值无关
    生活中方法重写的举例:
            BB机--大哥大--小灵通--智能手机(打电的方式在不断重写)

class OldPhone{
    public void call(String name){
        System.out.println("给"+name+"打电话");
    }
}

class NewPhone extends OldPhone{
    public void call(String name){
        System.out.println("给"+name+"打电话");
        System.out.println("学习");
    }
}

public class ExtendsDemo4 {
    public static void main(String[] args) {
        NewPhone newPhone = new NewPhone();
        newPhone.call("小伟");
    }
}

****输出结果为给小伟打电话,学习****

 

2、方法重写注意事项
1、父类中的私有成员方法无法被子类重写
2、子类重写父类的方法的时候,访问权限不能比父类的访问权限低,要么和父类定义方法的权限一致,要么就比它的访问权限高
        建议重写的时候,子类与父类中方法定义的格式一致
3、父类中静态的成员方法,无法被子类重写,静态的成员是属于类本身的东西
4、重写是,返回值类型,方法名,参数列表都一样
    重载是,方法名一样,参数列表不一样,与返回值类型无关

四、final关键字

1、概述
如果说父类的东西不想让子类去继承:
    可以使用private修饰或者static
    由于继承方法中有一个现象:方法 重写。所以,当方法可以被重写的时候,父类原本的方法还在,但是调用是子类重写后的方法,如果我依旧想保留父类原本的方法,不想让子类重写,但是呢,我想让子类去用。

    针对于这样的情况,java提供了一个关键字:final

final: 最终的意思,不可以改变的意思。

使用格式:一般情况下,把final放在访问权限修饰的后面返回值前
    常见的情况下,final不仅可以修饰成员方法,也可以修饰类,变量

 2、举例

class Father4{
    //被final修饰的成员方法,不能被子类重写。
    public final void fun(){
        System.out.println("这是父类的fun方法");
    }
}

class Son4 extends Father4{
//    public void fun(){
//        System.out.println("这是子类的fun方法");
//    }            这里会报错
}

public class ExtendsDemo6 {
    public static void main(String[] args) {
    }
}

3、特点
final:最终的意思,它可以修饰变量,类,方法
    1、被final所修饰的类无法被其他类所继承
    2、被final所修饰的方法,子类无法重写,但是在同一个类中可以出现同名不同参数列表的
          被final修饰的方法,这里是重载
         总结一句话:被final修饰的方法不能被重写,但是可以被重载
    3、被final修饰的变量变成了常量,无法再重新分配值。
        常量:
            A: 字面值常量:
                10,12.34,"hello",'a',true
            B: 自定义常量
                其实就是被final修饰的变量。
                final int a = 10;
    4、被final修饰的局部变量是基本数据类型的时候,不可以修改值
        被final修饰的局部变量是引用数据类型的时候,该对象的地址值是无法改变的,但是引用堆内存中的变量是可以发生改变。
5、被final修饰变量,只要在构造方法完毕之前赋值就可以了,可以在构造方法中赋值,也可以在构造代码块中赋值

class Fu2{
    int a;
    final int b;
    {
        b = 100;
    }
    Fu2(){
//        b = 30;        也可以
        System.out.println(b);
    }

    public void fun1(){
        a = 20;
        System.out.println(a);
    }
}

public class FinalDemo3 {
    public static void main(String[] args) {
        Fu2 fu2 = new Fu2();
        fu2.fun1();
    }
}
posted @ 2021-12-11 20:17  等你回眸一笑  阅读(45)  评论(0)    收藏  举报