Java中final修饰的方法是否可以被重写示例详解

作者:卷卷子 时间:2022-02-25 13:35:40 

这是一次阿里面试里被问到的题目,在我的印象中,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)的效果是一样的。

来源:https://www.cnblogs.com/jrjrzivvv/p/13923108.html

标签:java,final,修饰
0
投稿

猜你喜欢

  • 学生视角看Java 面向对象的继承本质

    2022-04-23 21:51:10
  • 关于Spring Boot内存泄露排查的记录

    2023-06-27 18:46:19
  • SpringBoot实现redis缓存菜单列表

    2023-11-24 07:39:20
  • C语言头文件<string.h>函数详解

    2023-07-01 18:59:34
  • JAVA操作MongoDB数据库实例教程

    2023-11-18 13:22:27
  • java开发工作中对InheritableThreadLocal使用思考

    2023-11-24 21:46:44
  • Java 深拷贝与浅拷贝的分析

    2023-07-30 14:13:13
  • Intellij IDEA + Android SDK + Genymotion Emulator打造最佳Android开发环境

    2023-06-17 06:47:11
  • sms4j 2.0 全新来袭功能的调整及maven变化详解

    2023-11-05 00:31:51
  • Java基于Tcp的基础聊天功能实例

    2023-11-25 05:26:56
  • Android中TextView动态设置缩进距离的方法

    2023-08-07 09:52:00
  • 通过源码角度看看AccessibilityService

    2023-07-25 09:31:43
  • Android手动检查并申请权限方法

    2023-08-04 23:14:17
  • Android TextView实现跑马灯效果的方法

    2023-07-30 20:44:12
  • Java环境配置原理全面解析

    2023-11-23 07:56:48
  • Java实现调用外部程序的示例代码

    2023-11-10 06:43:12
  • Sonar编译问题对应:File [...] can't be indexed twice.

    2023-11-25 11:07:28
  • Spring3 整合MyBatis3 配置多数据源动态选择SqlSessionFactory详细教程

    2023-03-21 21:22:27
  • 关于SpringGateway调用服务 接受不到参数问题

    2023-08-31 13:05:00
  • 详解Java类型擦除机制

    2023-10-29 06:41:21
  • asp之家 软件编程 m.aspxhome.com