public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
}
因為要用到HttpServletRequest中的方法,我對ServletRequest進行了強轉,然后問題解決。可是后來一想不對啊,我們知道我們對子類實現進行向上轉型得到父類對象是安全的,因為子類會完全繼承父類的方法,我們向上轉型為父類,當我們調用父類的方法其實在子類實現中是能完全找到的。反之向下轉型是不安全的,我們子類除了完全繼承父類的方法外還會拓展自己的方法,所以我們在調用子類方法時可能在父類實現中是找不到的,所以向下轉型不安全。
可是本例中的實現卻讓我們困惑,我們不僅實現了向下轉型,同時還調用了子類拓展的方法,是父類沒有的,可是卻實現了。這不是和我們所學矛盾嗎?后來看了API和一些資料我終於明白了,這和我們所學其實並不沖突!我們先看API:
public interface HttpServletRequest extends ServletRequest
終於找到原因了,原來HttpServletRequest和ServletRequest都是接口,他們都只是定義了方法卻沒有提供相關實現。所以我們看到的ServletRequest request中的request對象其實並不是我們ServletRequest 的一個具體實現。
這里我們要看我們提出的問題是否安全,其實主要看request 對象的具體實現類究竟是繼承的哪個接口,如果繼承自HttpServletRequest接口那么我們向下轉型使用HttpServletRequest接口的方法就是安全的。測試如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(request instanceof HttpServletRequest){
System.out.println("-------------");
}
HttpServletRequest req = (HttpServletRequest) request;
if(req instanceof HttpServletRequest){
System.out.println("我是右邊類的實例");
}
HttpServletResponse resp = (HttpServletResponse) response;
}
輸出:
-------------
我是右邊類的實例
證明我們的request對象的確是HttpServletRequest的一個實例。
也就是說doFilter的參數request對象的生成方式不是ServletRequest request = new ServletRequest();這種形式,而是ServletRequest request = new HttpServletRequest();這種形式,參數里的request不是父類ServletRequest的對象,而是HttpServletRequest的上轉型對象:
根據《java面向對象程序設計(第2版)》,一個父類類型的對象如果是用子類new出來的時候(ServletRequest request = new HttpServletRequest();//就是這行代碼), 就不能稱之為父類對象,而是一個子類的上轉型對象。這兩者是有區別的,區別的其中一點就是父類對象不可強制轉換為子類對象,而子類的上轉型對象可以強制轉換回子類對象。
再說一下為什么在Filter里要強制轉換?
答:ServletRequest request;這個是將子類對象賦給父類引用,他運行時的類型是子類,編譯時的類型是父類,但是在運行時,父類類型對象調用的方法如果子類里面有,那就執行子類里面的方法,如果編譯時的類型也就是父類沒有調用的那個方法,則報錯。所以在那里要做一個強制類型轉換,否則就會報錯。
HttpServletRequest比ServletRequest多了一些針對於Http協議的方法.如getHeader (String name), getMethod () ,getSession () 等等..
疑問解決。