栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

Java继承

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java继承

文章目录
    • 一、继承的引入及概念
    • 二、继承的语法
    • 三、父类成员访问
      • 1、子类中访问父类的成员变量
      • 2、子类中访问父类的成员方法
    • 四、super关键字
      • super() 和 this()的区分
    • 五、子类构造方法
    • 六、初始化
    • 七、继承方式
    • 八、final关键字
    • 九、继承与组合

一、继承的引入及概念

狗的行为有吃饭、睡觉、汪汪叫等,猫的行为有吃饭、睡觉、喵喵叫等;如果将狗和猫分别写成两个类,Dog类中有吃饭、睡觉、汪汪叫三个方法,Cat类中有吃饭、睡觉、喵喵叫三个方法;此时两个类中的大部分代码是重复的,所以引入了继承。新建一个 Animal 类,Dog 类和 Cat 类中都含有 eat() 方法和 sleep() 方法,所以在Animal 类中写入这两个方法,再新建Dog类和Cat类,分别在其中写入 Bark() 汪汪叫的方法和 mew() 喵喵叫的方法。Animal 称为父类/基类/超类,Dog 类和Cat 类都称为子类/派生类。

继承机制:是面向对象程序设计使代码可以复用的最重要的手段,允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生的类称为派生类(子类)。继承实现了面向对象程序设计的层次结构。继承主要解决的问题是共性的抽取,实现代码的复用,也通过继承实现多态。

二、继承的语法

修饰符 class 子类 extends 父类{
}

eg.

public class Animal {
    String name;
    int age;

    public void eat(){
        System.out.println(name + "在吃饭~");
    }

    public void sleep(){
        System.out.println(name + "在睡觉~");
    }

}
public class Dog extends Animal{
   public void Bark(){
       System.out.println(name + "汪汪~");
   }
}

public class Cat extends Animal{
    public void mew(){
        System.out.println(name + "喵喵~");
    }
}

public class TestExtend {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "二哈";
        dog.age = 2;

        System.out.println(dog.name);
        System.out.println(dog.age);

        dog.eat();
        dog.sleep();
        dog.Bark();

    }
}

运行结果

二哈
2
二哈在吃饭~
二哈在睡觉~
二哈汪汪~

子类会将父类中的成员变量或者成员方法继承到子类中。
子类继承父类后,必须要添加自己特有的成员,体现出与父类的不同,否则就没有必要继承了。
父类中的构造方法没有被子类继承。

三、父类成员访问 1、子类中访问父类的成员变量

子类和父类不存在同名的成员变量
子类中没有与父类相同的成员变量,则访问的时候会访问从父类继承下来的成员变量

public class Base {
    int a;
    int b;
}
public class Derived extends Base {
    int c;

    public void method() {
        a = 10;  // 访问从父类继承下来的a
        b = 20;  // 访问从父类继承下来的b
        c = 30;  // 访问子类自己的c
    }
}

子类和父类成员变量同名
若子类中含有与父类相同的成员变量,则优先访问子类自己的成员变量;若子类中没有则会访问从父类继承下来的成员变量;若父类中也没有,则编译报错。即成员变量的访问遵循就近原则

public class Derived extends Base {
    int a;
    char b;
    
    public void method() {
        a = 10;   //访问子类自己的a
        b = 20;   //访问子类自己的b
        //c = 30;   //编译报错,子类和父类中都没有成员变量c
    }
}
2、子类中访问父类的成员方法

成员方法名字不同
子类中没有与父类相同的成员方法名

public class Base {
    public void methodA(){
        System.out.println("父类中的methodA()");
    }
}
public class Derived extends Base {
   public void methodB(){
       System.out.println("子类中的methodB()");
   }

   public void method(){
       methodA();  // 访问从父类继承的methodA()
       methodB();  // 访问子类自己的methodB()
       // methodC();  // 编译失败,子类和父类中都没有该方法
   }

}

成员方法名字相同
通过子类对象访问父类与子类不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,没有找到则报错。
若父类和子类方法名相同,参数不同,即构成重载,则根据调用的方法传递的参数选择适当的方法访问;若父类和子类同名方法的原型一致(重写),则只能访问到子类的,父类的无法访问到。

public class Base {
    public void methodA(){
        System.out.println("父类中的methodA()");
    }

    public void methodB(){
        System.out.println("父类中的methodB()");
    }
}
public class Derived extends Base {
    public void methodA(int a){
        System.out.println("子类中有参数的methodA(int)");
    }

   public void methodB(){
       System.out.println("子类中的methodB()");
   }

   public void method(){
       methodA();  // 访问从父类继承的methodA()
       methodA(10); // 传参,访问子类自己的methodA(int)
       methodB();  // 访问子类自己的methodB()
       // methodC();  // 编译失败,子类和父类中都没有该方法
   }

}

如果子类存在与父类相同的成员,但需要在子类中访问父类相同名称的成员,则需要使用 super 关键字

四、super关键字

作用:在子类方法中访问父类的成员

public class Base {
    int a;
    int b;
    
    public void methodA(){
        System.out.println("父类中的methodA()");
    }

    public void methodB(){
        System.out.println("父类中的methodB()");
    }
}
public class Derived extends Base {
    int a;
    char b;

    public void methodA(int a){
        System.out.println("子类中的methodA()");
    }

   public void methodB(){
       System.out.println("子类中的methodB()");
   }

   public void method(){
        //访问子类中的a,b
        a = 10;
        b = 20;

        //访问父类中的a,b
       super.a = 30;
       super.b = 40;


       methodA();  // 访问从父类继承的methodA()
       methodA(10); // 传参,访问子类自己的methodA(int)
       methodB();  // 访问子类自己的methodB()
       super.methodB();  //访问父类中的methodB()
       // methodC();  // 编译失败,子类和父类中都没有该方法
   }

}

在子类方法中,访问父类的成员变量和方法。

super() 和 this()的区分

相同点:
1、都是Java关键字 、
2、只能在类的非静态方法中使用,用来访问非静态成员方法和字段
3、在构造方法中调用时,必须是构造方法中第一条语句,且不能同时存在

不同点:
1、this是当前对象(调用实例方法的对象)的引用,super相当于子类对象从父类继承下来部分成员的引用
2、在非静态成员方法中,this 用来访问本类的方法和属性,super 用来访问父类继承下来的方法和属性
3、this 是非静态成员方法的一个隐藏参数,super 不是隐藏参数
4、成员方法中直接访问本类成员时,编译之后会将this 还原(非静态成员都是通过this来访问的);子类中如果通过super 访问父类成员,编译之后在字节码层面super 是不存在的,super只在代码层面体现出来,告诉编译器访问基类的成员
5、构造方法中一定存在super 的调用,即使用户没有写编译器也会自动添加,this 则是用户不写则没有。

五、子类构造方法
public class Base {

    public Base(){
        System.out.println("Base()");
    }


}
public class Derived extends Base {

    public Derived(){
        // super();    
        // 子类构造方法中默认会调用基类的无参构造方法:super()
        // 用户没有写时,编译器会自动添加,super()必须是子类构造方法中的第一条语句,且只能出现一次
        System.out.println("Derived()");
    }

}
public class Test {
    public static void main(String[] args) {
        Derived d = new Derived();
    }
}

运行结果

Base()
Derived()

在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法;
创建哪个类的对象,就会调用那个类的构造方法;
构造子类对象时,先要将父类继承下来的成员初始化完整,然后再初始化子类自己新增的成员。

注意:1、若父类显式定义无参或者默认的构造方法,此时,子类的构造方法可以不用定义,如果需要再定义,在子类构造方法第一行默认有隐含的 super 调用,即调用基类构造方法。
2、如果父类构造方法是有参数的,此时编译器不会再给子类生成默认的构造方法,此时需要用户为子类显示定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
3、子类构造方法中,super() 调用父类构造时,必须是子类构造函数的第一条语句。
4、super() 和 this() 不能同时出现

六、初始化

【没有继承时】 代码执行顺序:

public class Test {
    public String name;
    public int age;

    public Test(String name,int age){
        this.name = name;
        this.age = age;
        System.out.println("执行构造方法");
    }

    {
        System.out.println("执行实例代码块");
    }

    static{
        System.out.println("执行静态代码块");
    }

    public static void main(String[] args) {
        Test p1 = new Test("蓝胖子",18);
        System.out.println("*******创建第二个对象*********");
        Test P2 = new Test("胖虎",12);

    }
}

执行静态代码块
执行实例代码块
执行构造方法
*******创建第二个对象*********
执行实例代码块
执行构造方法

静态代码块先执行,并且只执行一次,在类加载阶段执行;
当有对象创建时,才会执行实例代码块,实例代码块执行完成后,构造方法执行。
【有继承关系时】

public class Base {

    public String name;
    public int age;
    public Base(String name,int age){
        this.name = name;
        this.age = age;
        System.out.println("父类:构造方法");
    }

    {
        System.out.println("父类:实例代码块");
    }

    static{
        System.out.println("父类:静态代码块");
    }

}
 public class Derived extends Base {
    public Derived(String name,int age){
        super(name, age);
        System.out.println("子类:构造方法");
    }

    {
        System.out.println("子类:实例代码块");
    }

    static{
        System.out.println("子类:静态代码块");
    }

}
public class Test {

    public static void main(String[] args) {
        Derived d1 = new Derived("蓝胖子",18);
        System.out.println("*******创建第二个子类对象*********");
        Derived d2 = new Derived("胖虎",12);

    }

    public static void main1(String[] args) {
        Base d1 = new Base("静香",11);
        System.out.println("*******创建第二个父类对象*********");
        Base d2 = new Base("大雄",12);

    }

}

运行结果

父类:静态代码块
子类:静态代码块
父类:实例代码块
父类:构造方法
子类:实例代码块
子类:构造方法
*******创建第二个子类对象*********
父类:实例代码块
父类:构造方法
子类:实例代码块
子类:构造方法

若执行main1函数,则只执行父类中的方法,如下

父类:静态代码块
父类:实例代码块
父类:构造方法
*******创建第二个父类对象*********
父类:实例代码块
父类:构造方法

一般情况下,将所有字段设为private,将所有方法设为public,不过还是建议写代码的时候想一想,不滥用访问权限

七、继承方式
  1. 单继承:一个父类对应一个子类
  2. 多层继承:一个父类对应一个子类,子类再对应下个子类
  3. 不同类继承同一个类:多个子类继承一个父类
  4. 多继承(Java中不支持):一个子类对应多个父类
    注意:Java中不支持多继承
    一般不希望继承超过三层;如果继承层次太多,则需要考虑对代码的重构。
    如果想要从语法层面进行限制继承,就可以使用 final 关键字。
八、final关键字

final 关键字用来修饰变量,成员方法以及类。

1、修饰变量或字段,表示常量(不能修改)
2、修饰类:表示此类不能被继承
3、修饰方法:表示该方法不能被重写

九、继承与组合

继承是 is-a 的关系
组合是 has-a 的关系
比如,汽车和轮胎类、发动机、方向盘、车载系统等关系是组合
宝马、大众、奥迪属于汽车,是继承关系
代码复用优先选择组合
原因(继承实现代码复用的缺点):
1、破坏类的封装性
2、子类和父类的耦合性太高(父类某个方法发生改变,子类一定会看到改变;基类某个方法多加了一个参数,子类调用该方法的函数都需要修改)
3、子类除了构造方法没有继承下来外,其他成员都继承到子类中了

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/984721.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号