• Java随笔-继承


    1. 实现继承关系

    继承需要使用extends关键字。

    • 创建父类
    /**
     * 父类
     */
    public class Father {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    被继承类可称为超类、基类、父类。

    • 创建子类,并继承父类
    /**
     * 子类
     */
    public class Son extends Father{
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    继承类成为子类、派生类、孩子类。

    继承的作用:子类可以使用父类中的一些成员变量和方法,从而提高代码的重用性,提高开发效率。
    父类并非高于子类,恰恰相反,子类往往比父类更加丰富,除了可以调用父类的一些成员变量和方法外,还有自己独有的属性和方法。

    2. 子类调用父类的一些成员变量和方法

    • 父类
    /**
     * 父类
     */
    public class Father {
        // 共有属性
        public String name;
        // 受保护属性
        protected String power;
        // 私有属性
        private int age;
        // 默认属性
        boolean tall;
    
        // 共有方法
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
        // 私有方法
        private void salary(){
        }
    
        // 保护方法
        protected String getPower(){
            power = "父类的权益";
            return power;
        }
    
        // 默认方法
        void testDefaultMethod(){
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 子类
    /**
     * 子类
     */
    public class Son extends Father{
    
        /**
         * 调用父类的一些成员变量或方法
         */
        public void test01(){
            // 调用父类共有的属性和方法
            name = "父类" + getName();
    
            // 调用父类受保护的属性和方法
            String powerStr = power + getPower();
    
            // 调用父类私有的属性和方法
            // 'age' has private access in 'Father'
            // age;
            // 'salary()' has private access in 'Father'
            // salary();
    
            // 调用父类默认权限的属性和方法
            boolean tall = super.tall;
            testDefaultMethod();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    之所以说子类可以调用父类的一些成员变量和方法,是只能调用父类的public、protected、default(没有权限修饰)的成员变量和方法,父类私有(private修饰)的就不能调用。
    protected:只可以被本类,子类,同一个包中可以访问。如果是多层继承的话,若是修改protected修饰的属性和方法会很麻烦。

    3. 方法重写

    当子类重写父类的方法时会使用 @Override关键字标记。

    • 子类
        @Override
        public String getName() {
            // todosomething
            return super.getName();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    一般重写父类方法是为了自定义属性。去掉关键字其实就是子类的普通方法,若是还想在该方法中方位父类方法,需要使用super关键字,否则无法区分调用的是哪一个类中的方法,可能出现死循环问题。

       public String getName() {
            return "子类" + super.getName();
        }
    
    • 1
    • 2
    • 3

    方法重写有一定的规则:

    • 重写的方法参数要完全相同。
    • 返回类型可以一样,也可以是父类返回值的子类,其他的都不可以。
    • 访问权限不能比父类低,如果父类是protected,子类只能是public或protected,不能是其他的。
    • 重写的方法抛出的异常只是父类抛出的异常的子类或本身,不能是其他的。
    • 构造方法不能被重写。
    • final和private方法不能被重写,当然也写不到。
    • 子类只能重写父类的方法,显而易见的,这是重写的前提,也算是废话。

    4. 构造方法

    • 父类构造
        public Father() {
            System.out.println("这是父类的构造");
        }
    
    • 1
    • 2
    • 3
    • 子类构造
        public Son() {
            System.out.println("这是子类的构造");
        }
    
    • 1
    • 2
    • 3
    • 测试
        public static void main(String[] args) {
            Son son = new Son();
        }
    
    • 1
    • 2
    • 3
    • 结果
    S:\JDK16\bin\java.exe "-javaagent:S:\IntelliJIDEA\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=49229:S:\IntelliJIDEA\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\java\extend\out\production\extend Test
    这是父类的构造
    这是子类的构造
    
    • 1
    • 2
    • 3

    如果子类构造没有显式调用父类的构造方法,则会自动调用父类的无参构造。

    • 父类
    public class Father {
    //    public Father() {
    //        System.out.println("这是父类的构造");
    //    }
        public Father(String name) {
            System.out.println("这是父类的有参构造");
        }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 子类
    public class Son extends Father{
        public Son() {
            Father father = new Father("father");
            System.out.println("这是子类的构造");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 编译
      在这里插入图片描述
      如果父类中没有无参构造,并且在子类中又显式调用父类的其他构造,则编译报错。但是如果使用super关键字就没有问题。
        public Son() {
    //        Father father = new Father("father");
            super("father");
            System.out.println("这是子类的构造");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 编译
    S:\JDK16\bin\java.exe "-javaagent:S:\IntelliJIDEA\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=52386:S:\IntelliJIDEA\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath F:\java\extend\out\production\extend Test
    这是父类的有参构造
    这是子类的构造
    
    • 1
    • 2
    • 3

    5. 继承层次

    Java中支持多层继承,但不支持多继承。

    • 多层继承
    public class Son extends Father{}
    
    public class Grandson extends Son{
    }
    
    • 1
    • 2
    • 3
    • 4

    Grandson继承Son,Son继承Father。若是多继承则会报错。
    在这里插入图片描述
    Java类不支持多继承,但接口可以多继承。

    public interface Interface01 {
    }
    ...
    public interface Interface02 {
    }
    ...
    // 接口多继承
    public class Test implements Interface01, Interface02 {
    ...
    }
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6. 多态

    父类引用指向子类对象称为多态。

            // 多态
            Father father = new Son();
    
    • 1
    • 2

    置换法则:程序中任何出现父类对象的地方都可以用子类对象替换。

            Father[] fathers = new Father[10];
            fathers[0] = new Son();
            fathers = new Son[10];
    
    • 1
    • 2
    • 3

    即使父类数组被全部置换,但申明的还是父类,所以获取的对象还是父类,无法访问子类对象特有的属性和方法,也不能赋值给子类变量。

            // 置换法则
            Father[] fathers = new Father[10];
            fathers[0] = new Son();
            // 无需强转
            fathers = new Son[10];
            // 得到的只能是父类,不是子类
            Father father1 = fathers[0];
            // 非法
            Son son1 = fathers[0];
            // 强转
            Son son2 = (Son) fathers[0];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    强转会忽略对象实际类型,使用对象的全部功能,所以强转之前最好判断一下类型。

            Father[] fathers = new Father[10];
            fathers[0] = new Son();
            // 类型判断
            if(fathers[0] instanceof Son){
                Son son1 = (Son) fathers[0];
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7. 方法重载

    重载就是在一个类中,方法名相同,参数不同,返回值可以不同,也可以相同,多用于构造函数。

        public Father() {
            System.out.println("这是父类的构造");
        }
    
        public Father(String name) {
            System.out.println("这是父类的有一个参的构造");
        }
    
        public Father(String name, String power) {
            this.name = name;
            this.power = power;
            System.out.println("这是父类的有两个参的构造");
        }
    
        public Father(String name, String power, int age) {
            this.name = name;
            this.power = power;
            this.age = age;
            System.out.println("这是父类的有三个参的构造");
        }
    
        // 无参
        private void test(){
    
        }
    
        // int 参
        private int test(int a){
            return -1;
        }
    
        // 参数名相同,类型不同
        private int test(boolean a){
            return -1;
        }
        
        private String test(String str,int a){
            return str;
        }
    
        // 改变参数位置
        private String test(int a,String str){
            return str;
        }
    
        // 只改变返回值类型,不能算重载
    //    private int test(String str,int a){
    //        return a;
    //    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    8. final

    使用final类和方法,可以阻止继承。

    public final class FinalTest {
        void test() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4

    尝试继承final类。
    在这里插入图片描述
    final方法也是不能被重写的。

    public  class FinalTest {
        final void test() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4

    尝试重写final方法。
    在这里插入图片描述
    Java中基本数据类型和String都是final类,为了防止被继承。
    在这里插入图片描述
    在这里插入图片描述

    总结

    1. 继承时将公共方法和属性放在父类。
    2. 不要过度使用protected。同一个包中所有类都可以访问protected,不管是不是其子类,此时使用protected作用不大。其次,任何一个类都可能是某一个类的子类,都能直接访问protected,破环了封装性。
    3. 继承不要滥用,尽量在”is-a“的关系中使用继承。
    4. 如果不是继承的所有的方法都有意义,就不要使用继承。
    5. 对于类型信息的判断,要是有继承关系,尽量的使用多态。
    6. 反射不要滥用,因为反射只有运行时才会报错,很难发现错误。
    7. 重写的方法不要改变其原有作用,就是重写后的作用要和重写之前的作用差不多,若是相差太多还不如新写新的方法。
  • 相关阅读:
    基于Java的城市天然气费管理系统的设计与实现(源码+lw+部署文档+讲解等)
    计算机网络——HTTP 状态码
    【机械】基于matlab实现直齿圆柱齿轮应力计算附matlab代码
    信息论学习笔记(二):离散无噪声系统
    03 最小CMake项目
    前端react入门day01-了解react和JSX基础
    【QT系列教程】之二创建项目和helloworld案例
    5.编写程序 超强力方法
    h3c 网络设备清理所有配置
    git如何删除github上的文件,亲测有效
  • 原文地址:https://blog.csdn.net/qq_34202054/article/details/123241444