1. 程式人生 > 程式設計 >Java中final修飾的方法是否可以被重寫示例詳解

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)的效果是一樣的。

總結

到此這篇關於Java中final修飾的方法是否可以被重寫的文章就介紹到這了,更多相關Java中final修飾的方法被重寫內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!