zoukankan      html  css  js  c++  java
  • java继承

    1.方法继承

    animal类

    package com.imooc.animal;
    
    public class Animal {
        protected String name;  //名字
        private int month;  //月份
        private String species;  //品种
    
        //如果这里没有定义构造方法,编译器会自动生成
        public Animal(){}
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getMonth() {
            return month;
        }
    
        public void setMonth(int month) {
            this.month = month;
        }
    
        public String getSpecies() {
            return species;
        }
    
        public void setSpecies(String species) {
            this.species = species;
        }
    
        public void eat(){
            //子类只能继承父类的非私有成员,protected可以允许系内继承。
            System.out.println(this.getName() + " eating");
        }
    }

    cat类

    package com.imooc.animal;
    
    public class Dog extends Animal {
        private String sex;  //性别
    
        public Dog() {}
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        //睡觉
        public void sleep(){
            //以下几种打印方式都是可行的
            System.out.println(this.getName() + " sleep");
    //        System.out.println(getName() + " sleep");
    
            //下面方式必须是属性可继承。public/protected
    //        System.out.println(super.name + " sleep");
    //        System.out.println(this.name + " sleep");
    //        System.out.println(name + " sleep");
    
            //使用this.name和name都可以的原因,编译器会寻找这个
            //现在本实例空间内寻找,然后去父类空间寻找
        }
    }

    Dog类

    package com.imooc.animal;
    
    public class Cat extends Animal {
        private double weight; //体重
    
        public Cat() {}
    
        public double getWeight() {
            return weight;
        }
    
        public void setWeight(double weight) {
            this.weight = weight;
        }
    
        //跑动方法
        public void run() {
            System.out.println(this.getName()+" Running");
        }
    }

    Test测试方法

    package com.imooc.test;
    
    import com.imooc.animal.Cat;
    import com.imooc.animal.Dog;
    
    public class Test {
        public static void main(String[] args) {
            Cat one = new Cat();
            one.setName("花花");
            one.setSpecies("中华田园猫");
            one.eat();
            one.run();
            System.out.println("---------------------------------");
            Dog two = new Dog();
            two.setName("妞妞");
            two.setMonth(1);
            two.eat();
            two.sleep();
        }
    }

    2.方法的重写

    animal类

    package com.imooc.animal;
    
    public class Animal {
        protected String name;  //名字
        private int month;  //月份
        private String species;  //品种
        public int temp = 15;
    
        //如果这里没有定义构造方法,编译器会自动生成
        public Animal(){}
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getMonth() {
            return month;
        }
    
        public void setMonth(int month) {
            this.month = month;
        }
    
        public String getSpecies() {
            return species;
        }
    
        public void setSpecies(String species) {
            this.species = species;
        }
    
        public void eat(){
            //子类只能继承父类的非私有成员,protected可以允许系内继承。
            System.out.println(this.getName() + " eating");
        }
        public void eat(String name){
            System.out.println(name + " eating");
        }
    }

    Dog类

    package com.imooc.animal;
    
    public class Dog extends Animal {
        private String sex;  //性别
        // 属性值也是可以重写的,不过必须是public的访问类型
        public int temp = 300;
    
        public Dog() {}
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        //睡觉
        public void sleep(){
            System.out.println(this.getName() + " sleep");
        }
        /*
        * 方法重载
        * 1、同一个类中
        * 2、方法名相同,参数列表不同(参数顺序、个数、类型)
        * 3、方法返回值、访问修饰符任意
        * 4、与方法的参数名无关
        * */
        private String sleep(String name) {
            return name;
        }
        /*
        * 方法重写(覆写)
        * 1、有继承关系的子类中
        * 2、方法名相同,参数列表相同(参数顺序、个数、类型),方法返回值相同
        * 3、访问修饰符,访问范围需要大于等于父类的访问范围
        * 4、与参数名无关
        * */
        public void eat(){
            System.out.println(this.name + " 最近没有食欲,Dog重写");
        }
        //方法重写,与参数名无关,与参数顺序、个数、类型有关
        public void eat(String dogName) {
            System.out.println(dogName + "Dog被重写");
        }
    }

    3.访问修饰符

    Java中的访问修饰符主要有以下几类:
      • 公有的:public 允许在任意位置访问
      • 私有的:private 只允许在本类中进行访问
      • 受保护的:protected 允许在当前类、同包子类/非子类、跨包子类调用、跨包非子类不允许
      • 默认:允许在当前类、同包子类调用;跨包子类不允许调用

    访问修饰符的作用域范围:

    4.super关键字——调用父类的方法和属性

    当子类继承父类的时候,如果子类将一个方法进行重写了,
    那么在调用的时候,是调用子类的方法还是调用的父类的方法了?

    animal类

    package com.imooc.animal;
    
    public class Animal {
        protected String name;  //名字
    
        public Animal(){}
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        //父类定义了eat方法
        public void eat(){
            System.out.println(this.getName() + " eating");
        }
        public void eat(String name){
            System.out.println(name + " eating");
        }
    }

    Dog类

    package com.imooc.animal;
    
    public class Dog extends Animal {
    
        public Dog() {}
    
        public void eat(){
            System.out.println(this.name + " 最近没有食欲,Dog重写");
        }
    
        public void eat(String dogName) {
            System.out.println(dogName + "Dog被重写");
        }
    
        public void sleep(){
            eat();
        }
    }

    测试代码:

    package com.imooc.test;
    
    import com.imooc.animal.Dog;
    
    public class Test {
        public static void main(String[] args) {
            Dog two = new Dog();
            two.setName("妞妞");
            two.eat();  //妞妞 最近没有食欲,Dog重写
        }
    }

    我们发现,默认会调用子类的方法,这也符合调用顺序。

    那如果我就想调用父类的方法,该如何了?可以使用super关键字。
    super.eat();
    不仅是方法,父类中允许子类派生的属性,也可以通过super来继承。

    父类的构造方法不允许被继承、不允许被重写。

    5.继承的初始化顺序

    (1)静态优先
    (2)父类优先
    (3)非静态块优于构造函数

    写出下面代码的执行结果:

    public class ExecutionSequence {
        public static void main(String[] args) {
            new GeneralClass();
        }
    }
    
    class ParentClass{
        //静态代码块
        static {
            System.out.println("①我是父类静态块");
        }
        //非静态块
        {
            System.out.println("②我是父类非静态块");
        }
        //父类构造方法
        public ParentClass(){
            System.out.println("③我是父类构造函数");
        }
    }
    
    class GeneralClass extends ParentClass {
        //子类静态代码块
        static {
            System.out.println("④我是子类静态块");
        }
        {
            System.out.println("⑤我是子类非静态块");
        }
        public GeneralClass(){
            System.out.println("⑥我是子类构造函数");
        }
    }
    /*
    ①我是父类静态块
    ④我是子类静态块
    ②我是父类非静态块
    ③我是父类构造函数
    ⑤我是子类非静态块
    ⑥我是子类构造函数
    */

      为什么父类的构造函数在子类的非静态代码块之前?
    “父类优先的原则”优于“非静态块优于构造函数的原则”。

    6.super继承父类的构造方法

    public class Animal {
        String name;  //名字
    }
    
    public class Cat extends Animal {
        private double weight; //体重
    }
    
    public class Test {
        public static void main(String[] args) {
            Cat one = new Cat();
        }
    }

    如果都不定义给构造方法,那么编译器会默认创建无参构造

    public class Animal {
        String name;  //名字
    
        public Animal(){
            System.out.println("我是父类的无参构造,方法Animal");
        }
    
        public Animal(String name){
            this.name = name;
            System.out.println("我是父类的带参构造,方法名Animal,参数name");
        }
    }
    
    public class Cat extends Animal {
        private double weight; //体重
    
        public Cat(){
            System.out.println("我是子类的无参构造,方法Cat");
        }
    
        public Cat(String name,double weight) {
            this.name = name;
            this.weight = weight;
            System.out.println("我是子类的带参构造,方法名Cat,参数name、weight");
        }
    }

    情况一:

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

    结果:
    我是父类的无参构造,方法Animal
    我是子类的无参构造,方法Cat

    情况二:

    public class Test {
        public static void main(String[] args) {
            Cat one = new Cat("ke",58);
        }
    }

    结果:
    我是父类的无参构造,方法Animal
    我是子类的带参构造,方法名Cat,参数name、weight

    虽然构造方法不允许被继承、被重写,但是会影响子类的构造。
    子类构造默认调用父类的无参构造方法。


    如果你重新定义了有参构造方法,那么构造的时候就必须带参,所以一般都需要写上无参构造。

    如果子类希望调用父类的有参构造方法,可以使用super显式继承。
    同时super()必须放在子类构造方法有效代码的第一行。

    public class Cat extends Animal {
        private double weight; //体重
    
        public Cat(){
            System.out.println("我是子类的无参构造,方法Cat");
        }
    
        public Cat(String name,double weight) {
            super(name);
            this.name = name;
            this.weight = weight;
            System.out.println("我是子类的带参构造,方法名Cat,参数name、weight");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Cat one = new Cat("mao",68);
        }
    }

    结果:

    我是父类的带参构造,方法名Animal,参数name
    我是子类的带参构造,方法名Cat,参数name、weight

    下面是一个常见问题:

    public class Animal {
        String name;  //名字
    
        public Animal(String name){
            this.name = name;
            System.out.println("我是父类的带参构造,方法名Animal,参数name");
        }
    }
    
    public class Cat extends Animal {
        private double weight; //体重
    
        public Cat(){
            System.out.println("我是子类的无参构造,方法Cat");  //报错
        }
    
        public Cat(String name,double weight) {
            this.name = name;
            this.weight = weight;
            System.out.println("我是子类的带参构造,方法名Cat,参数name、weight");
        }
    }

    上面会直接报错。
    子类会默认调用父类的无参构造,但是父类只有有参构造,所以就会报错。
    需要super()显式继承或者定义父类的无参构造。

    super代表父类对象,this代表当前对象。
    当然构造方法也是可以调用同类中的构造方法。

    public class Cat extends Animal {
        private double weight; //体重
    
        public Cat(){
            System.out.println("我是子类的无参构造,方法Cat");
        }
    
        public Cat(String name,double weight) {
            this();
            this.name = name;
            this.weight = weight;
            System.out.println("我是子类的带参构造,方法名Cat,参数name、weight");
        }
    }

    结果:
    我是子类的无参构造,方法Cat
    我是子类的带参构造,方法名Cat,参数name、weight

    既然super和this都可以调用构造方法,那么二者可以共存吗?

    当你在调用构造方法的时候,super和this只能使用一个。

    7.Object类

    Object类是所有类的父类。
    一个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)
    Java中的每个类都可以使用Object中定义的方法。
    Object类官网:https://docs.oracle.com/javase/8/docs/api/
    Object类中定义的方法:

    上面都是Object类内置的方法,所以Java中所有的对象都可以调用这些方法。以equals为例:
    下面是其源码,主要是比较两个对象是否是同一个对象。

    public boolean equals(Object obj) {
        return (this == obj);
    }

    示例:

    public class Test {
        public static void main(String[] args) {
            Animal one = new Animal("mao");
            Animal two = new Animal("mao");
            //equals:比较两个引用是否指向同一个对象
            boolean flag = one.equals(two);
            System.out.println("one和two的equals比较: "+flag);
            System.out.println("one和two的==比较:"+(one==two));
        }
    }
    //one和two的equals比较: false
    //one和two的==比较:false

    那如果,我们需要比较两个对象的值该怎么做了?我们可以重写equals方法

    public boolean equals(Object obj){
        if (obj == null){
            return false;
        }
        Animal temp = (Animal) obj;  //对象类型强制转换
        if (this.getName().equals(temp.getName())){
            return true;
        }else {
            return false;
        }
    }

    上面这种写法,可以在类型转换的时候会报错,改进方式是直接传入Animal对象:

    public boolean equals(Animal obj){
        if (obj == null){
            return false;
        }
        if (this.getName().equals(obj.getName())){
            return true;
        }else {
            return false;
        }
    }

    需要说明的是toString这个方法:

    public class Test {
        public static void main(String[] args) {
            Animal one = new Animal("mao");
            System.out.println(one);
            System.out.println(one.toString());
        }
    }
    //com.imooc.animal.Animal@1b6d3586
    //com.imooc.animal.Animal@1b6d3586

    可以看出,输出对象名时,默认会直接调用类中的toString。
    继承Object中的toString方法时,输出对象的字符串表示形式:类型信息+@+内存地址。
    但是对字符串类型例外:

    String str1 = new String("hello");
    System.out.println(str1);  //hello

    很多时候我们会重写对象的toString方法,这样可以改变对象的默认打印。

    8.final关键字

    如果你希望一个类不被别人继承,那么可以定义final关键字:

    public final class Animal {
        String name;  //名字
    
        public Animal(){}
    }

    final class:该类没有子类
    final 方法:该方法不允许被子类重写,但是可以被子类继承使用。
    final 方法内局部变量:只要在具体被使用之前进行赋值即可,一旦赋值不允许被修改
    final 类中成员属性:赋值过程:1.定义直接初始化 2.构造方法 3.构造代码块

    可配合static使用,来定义只需要设置一次的内容

  • 相关阅读:
    js---查找数组中的最大值(最小值),及相应的下标
    JS数组遍历的几种方法
    在 forEach 中使用 async/await 遇到的问题
    js 事件冒泡和事件捕获
    JS中dom0级事件和dom2级事件的区别介绍
    Vue集成Ueditor
    vue富文本编辑器 Vue-Quill-Editor
    Redis问题1---redis满了怎么办
    jQuery火箭图标返回顶部代码
    遇到的小问题
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/12500367.html
Copyright © 2011-2022 走看看