zoukankan      html  css  js  c++  java
  • Java中final修饰的方法是否可以被重写

    这是一次阿里面试里被问到的题目,在我的印象中,final修饰的方法是不能被子类重写的。如果在子类中重写final修饰的方法,在编译阶段就会提示Error。但是回答的时候还是有点心虚的,因为final变量就可以用反射的方法进行修改,我也不太确定是否有类似的机制可以绕过编译器的限制。于是面试之后特地上网搜了下这个问题,这里简单记录一下。

    首先说一下结论:没有办法能够做到重写一个final修饰的方法,但是有其他的方法可以接近在子类中重新实现final方法并在运行时的动态绑定的效果。
    这里需要用到一个aop框架叫aspectj,它和spring aop都是比较常用的aop框架。区别是spring aop是基于动态代理的,而aspectj有独立的编译器可以实现静态代理。关于aspectj的安装配置网上有很多文章了,这里就不再赘述,直接快进到例子。

    首先定义一个SuperClass并在其中定义一个final方法。
    SuperClass.java

    public class SuperClass {
    
        public final void doSomething() {
            System.out.println("super class do something");
        }
    
        public static void main(String[] args) {
            SuperClass instance = new SubClass(); //此处是父类引用和子类对象
            instance.doSomething();
        }
    
    }
    

    SubClass.java

    public class SubClass extends SuperClass {
    
        //doSomething是final方法,无法被重写
    
    }
    

    super class do something

    Process finished with exit code 0

    运行main方法,SubClass继承了doSomething方法,但是不能重写,所以通常情况下调用的一定是SuperClass的doSomething方法。

    在SubClass中实现“重写”的doSomething方法
    SubClass.java

    public class SubClass extends SuperClass {
    
        //doSomething是final方法,无法被重写
        //子类只能在另一个函数中实现重写的逻辑
        protected void overrideDoSomething() {
            System.out.println("sub class do something");
        }
    
    }
    

    利用环绕通知修改实际调用的方法
    DoSomethingAspect.aj

    public aspect DoSomethingAsepct {
        //   环绕通知               匹配SuperClass类的doSomething方法
        void around() : execution(* SuperClass.doSomething()) {
            if (thisJoinPoint.getThis() instanceof SubClass) {
                //调用子类方法
                ((SubClass)thisJoinPoint.getThis()).overrideDoSomething();
            } else {
                //调用原方法
                proceed();
            }
        }
    
    }
    

    运行结果

    sub class do something

    Process finished with exit code 0

    可以看到,调用SubClass的doSomething方法时实际调用的是SubClass类的overrideDoSomething方法,而如果是SuperClass对象的话调用的又是SuperClass里的doSomething方法。根据实际的类型决定调用的方法,就比较接近动态绑定的机制了。而仅从调用的代码来看和子类重写方法(虽然实际是final)的效果是一样的。

  • 相关阅读:
    从远程仓库拉去的代码开发后用git推送到另外一个远程仓库
    Git回退本地和远程分支的的版本
    把win10本地hexo博客部署到腾讯云linux服务器
    linux安装mysql
    linux部署nginx
    apache服务器安装到linux
    SqlServerv报错:从数据类型 varchar 转换为 numeric 时出错。
    IDEA2020版Maven依赖成功导入但任然报错找不到包解决方案
    idea中左侧project栏自动隐藏如何解决
    拖延的坏处
  • 原文地址:https://www.cnblogs.com/jrjrzivvv/p/13923108.html
Copyright © 2011-2022 走看看