zoukankan      html  css  js  c++  java
  • Java

      公众号偶然看到的一个帖子,构造方法,类方法,final方法,哪些能覆盖,哪些能重载,初学时也是被这些术语搞的很迷糊

    现在有时间了对这些做一个总结。全是自己的语言,可能不是很全面,表达意思应该够清楚

    一、叫法

    • 构造方法

      又叫构造器,构造函数。通常有无参构造器和带参数的构造器2种,每个类都有一个构造方法(如果没有显式的给出来,

    那么也有一个默认的无参构造器)无返回类型修饰符。访问修饰符可以是public,也可以是private,比如常见的单例模式就要求构

    造函数私有化。

    • 类方法

      static修饰符修饰的方法。因为static修饰的方法是属于类的而不是属于实例的(这个描述各种书籍上非常常见),因此不必

    去new 一个实例来调用,而是直接类名.方法名来调用这种方法,因此也称为类方法。

    • final方法

      最终的、不可改变的、终极的方法。怎么叫都行,单词修饰很清楚了,用了final表明设计上不再会去修改他,很巧,一

    个叫abstract的修饰符就是要设计者去实现去重写的,因此可以知道final和abstract永远不能共存。

    • 覆盖

      又叫重写,Override。多态是java的特性,覆盖是表现多态特性的具体做法。《Effective Java》有一个章节特别提出了,如

    果是覆盖方法,请一定记得加上@Override,在接下来的代码描述中你会看到,很多种方法混杂在一起的时候看起来是多么的难受

    • 重载

      重载只发生在一个类中,记住这点很重要,这也是跟覆盖这个概念撇清关系的最重要一点。重载要求同一个类中方法名相同

    而参数列表不同。参数列表,就是入参的个数,类型,顺序。抓住定义中的这两点,其他的通过什么返回值,访问权限,异常来重

    载一个方法那就是扯淡,混淆,不行。

    二、行还是不行?

    建议直接拷贝类到你的idea中去理解!重要的提示都加了注释

    首先看下重载。最经典最常见的莫过于这两个例子:构造方法的重载和System.out.println()这个方法了。我们直接看代码:

    public abstract class ClassTest {
    
        private int a;
    
        /**
         * abstract 和 final不能共存,报错
         */
        abstract final void test();
    
        /**
         * 构造方法
         */
        public ClassTest() {
            System.out.println("调用父类无参构造方法");
        }
    
        /**
         * 构造方法重载为带参的构造器
         */
        public ClassTest(int a) {
            this.a = a;
            System.out.println("调用重载的带参构造方法");
            System.out.println(this.a);
        }
    
        /**
         * 类方法(静态方法)
         */
        public static void staticMethod() {
            System.out.println("调用父类static方法(类方法)");
        }
    
        /**
         * 类方法可以被重载
         */
        public static void staticMethod(String s) {
            System.out.println("调用重载的类方法,s=" + s);
        }
    
        /**
         * final方法
         */
        public final void finalMethod() {
            System.out.println("调用父类final方法");
        }
    
        /**
         * final方法可以被重载
         */
        public final void finalMethod(String s) {
            System.out.println("调用重载的final方法,s=" + s);
        }
    
    }

    写一个客户端调用一下:

    public class Client {
        public static void main(String[] args) {
            ClassTest.staticMethod();
            ClassTest.staticMethod("hello");
        }
    }
    

    我们得出如下结论:构造方法,类方法,final方法均可以被重载

    接着我们看下覆盖的情况:

    还是用之前的定义的类,不过我们加入了一些别的情况:父类private的final方法和private的方法

    public class ClassTest {
    
        /**
         * 构造方法
         */
        public ClassTest() {
            System.out.println("调用父类无参构造方法");
        }
    
        /**
         * 类方法(静态方法)
         */
        public static void staticMethod() {
            System.out.println("调用父类static方法(类方法)");
        }
    
        /**
         * final方法
         */
        private final void finalMethod0() {
            System.out.println("调用父类private final方法");
        }
    
        /**
         * final方法
         */
        public final void finalMethod() {
            System.out.println("调用父类public final方法");
        }
    
        /**
         * 普通的私有方法
         */
        private void privateMethod() {
        System.out.println("调用父类public final方法");
    }
    }

    子类是:

    public class SubClassTest extends ClassTest {
    
        /**
         * 报错提示:父类构造器不可覆盖
         */
        @Override
        public ClassTest() {
            System.out.println("覆盖父类构造方法");
        }
    
        /**
         * 报错提示:父类的静态方法不能覆盖
         */
        @Override
        public static void staticMethod() {
            System.out.println("覆盖父类静态方法");
        }
    
        /**
         * 上面的@Override去掉,不再报错
         * 说明这个方法只是和父类的静态方法同名了而已,他是子类独有的,与父类的没半毛钱关系
         * 如果决定覆盖,请敲上@Override,一般做项目也不会像我这样测这些奇怪的情况,所以不加也知道是覆盖了,但是还是请加上
         */
        public static void staticMethod() {
            System.out.println("子类的同名方法");
        }
    
        /**
         * 报错提示:final方法不能被覆盖
         */
    //    @Override
    //    public final void finalMethod() {
    //        System.out.println("覆盖final方法");
    //    }
    
        /**
         * 未加@Override
         * 错误提示:final方法不能覆盖
         * 说明子类的final方法连名字都不能跟父类的同名,否则认为是覆盖
         */
        public final void finalMethod() {
            System.out.println("覆盖final方法");
        }
    
        /**
         * 未加@Override
         * 父类中该方法是private final的
         * 子类可以拥有对应的public权限的final同名方法
         */
        public final void finalMethod0() {
            System.out.println("调用子类同名的final方法");
        }
    
        /**
         * 错误提示:父类私有方法不能被覆盖
         */
        @Override
        public void privateMethod() {
            System.out.println("调用普通的private方法");
        }
    
    }
    

    编译结果我在注释里都写了,我们可以得出:构造方法,类方法,final方法都不能覆盖

    注意:

      1、子类可以拥有和父类同名的static方法,参看上面的staticMethod方法的注释,这个方法和父类的那个没半毛钱关系

      2、父类的public final方法,子类不能覆盖,也不能有自己的同样的方法(这就是我为啥,effective java也,强调加上@Override的原因)

      3、父类的private final方法,子类可以有对应的public final的,但是也和父类对应的这个方法没半毛钱关系,只是语法上允许

    注意:

      以上的类直接复制在开发工具上会报错的,这也是我们想要的

    三、为什么不行?从意义和设计上窥探下

      static方法为什么不能被覆盖,我们试着从意义上理解下,static是类的不是实例的,意味着它是无状态的,而覆盖发生在多态中,也就是

    每个实例各自去show,从java运行角度讲,static的方法在编译时就绑定完了,而多态要在运行时才确定,该调用谁覆盖后的方法。

      final方法为什么不能覆盖,设计final关键字的意义是,开发者知道这个方法一旦完成,就不打算再修改它,子类如果需要,可以直接调用

    如果各个子类也去覆盖这个final方法,那父类的这个方法再用final修饰就没啥意义了

      最后private修饰的方法会被隐形的指定为final的,所以也不能覆盖,这个可以在Thinking in Java中找到

    以上是个人一些小总结,不到之处,还请指正~~ 

  • 相关阅读:
    23种设计模式之单例模式
    6大设计原则之里氏替换原则
    6大设计原则之依赖倒置原则
    6大设计原则之接口隔离原则
    6大设计原则之迪米特法则
    Java日志第14天 2020.7.19
    Java日志第15天 2020.7.20
    Java日志第13天 2020.7.18
    Python 语音识别字幕生成器
    python list,tuple,str有序问题
  • 原文地址:https://www.cnblogs.com/yb38156/p/9599820.html
Copyright © 2011-2022 走看看