哈弗H6最強對手換代,天窗無敵,內飾升級,9.98萬你買嗎?

值得一提的是,全景影像四攝像頭還具備行車記錄儀功能,防護功能遠勝傳統行車記錄儀。此外,法國法雷奧一鍵泊車系統(12顆超聲波雷達)、鑰匙遙控泊車等功能在同級更是前所未見,勇氣可嘉。配置方面,前排座椅加熱、通風和空調功能被集成至排擋桿前方的獨立觸控屏上,估計出於成本控制輕觸后未見震動反饋,增加了盲操學習成本,所幸保留了聲音反饋。

滿足小有成就的現狀,缺乏居安思危意識,是營銷領域中不少先鋒產品的通病。等恍悟備受衝擊、該有所行動時,卻被時代洪流淹沒的例子,比比皆是。

(老款CS75)

上市四年以來,長安CS75無論在群眾口碑抑或銷量方面,都頗有建樹。隨着時間推移、消費升級,外觀和內飾開始顯得落伍、俗套。為了喚起潛在買家熱情,中期改款CS75厲兵秣馬、煥新而來。

全新CS75能否追隨自主SUV往上發展、實現高端化的潮流?身體力行前往世外桃源香格里拉,一試究竟。

外觀設計

長安睿騁CC砍獲德國紅點設計大獎后名噪一時,飄逸流暢的蝶翼式前臉讓長安轎車產品觀感度躍升一個維度。這份美好卻未能沿襲至全新CS75上,引以為憾。

所幸的是,新款CS75內外設計均往积極方向在推進。外觀一改老款地盤包工頭的“油膩”印象,大量的橫向鍍鉻飾條強調年輕化,比頗具爭議的“CHANGAN”字母臉強不止一星半點。

車燈儼然成為時下車型外觀設計的重中之重,深諳於此的長安為新款CS75換裝帶自動大燈功能的全LED大燈,造型犀利、燈腔內部精緻,跟來車怒目相視的感覺。

箭羽造型的霧燈區域安放在前包圍左右兩側,LED轉向燈帶巧妙地鑲嵌其上,內凹線條的勾勒對運動感的提升大有裨益,成功化解“中年危機”。

新款車型配有ACC自適應巡航功能,車頭底部的模塊能窺探一二,較強的塑料感缺乏精緻度。

車身尺寸與舊款別無二致,長/寬/高:4650/1850/1705mm,軸距:2700mm。側腰線條平鋪直敘、寬厚瓷實,屬四平八穩的類型。

后視鏡集成了轉向燈,從底部的攝像頭和鏡面標識可知,新款高配車型配備了盲區監測功能和全景影像。

試駕車型選用19英寸雙色鋁合金輪圈,與之搭配的是優科豪馬GEOLANDAR G91輪胎(225/55 R19),為四驅輪胎開發的獨特胎面膠配方,溝槽設計主打濕地操控、制動性能,乾地制動表現一般。

自主SUV一窩蜂玩壞了懸浮式車頂、碩大英文尾標后,又將魔爪伸向了當年林肯MKZ敢為人先的貫穿式尾燈。不出多久,貫穿式尾燈會淪為自主SUV中俗套的設計元素。

選用貨真價實的雙出排氣布局,扁平排氣口造型不落窠臼,與反光帶、尾燈造型遙相呼應,呈現出整體感喜人的尾部輪廓。

內飾配置

與外觀一樣,全新CS75的內飾表現出足夠的革新度和顛覆感,舊款內飾的鄉村氣息黯晦消沉,取而代之的是與時俱進的內飾氛圍。

軟質材料應用廣泛,多處的單雙縫線交替,方寸之間,盡顯品位。新車內飾供科技黑和輕奢棕兩色可選,後者配備仿木紋材料更是時刻在強調檔次感。

10.25英寸全液晶儀錶盤、10.25英寸懸浮式觸控屏、电子擋桿、平底方向盤、大面積的鋼琴烤漆面板、七色氛圍燈對車內質感的提升大有裨益。

其中試駕車型的10.25英寸懸浮式觸控屏配備全景影像和虛擬影像功能,显示效果細膩,提供優良閱讀效果,可謂女司機福音。

以配置水平見長的自主車,無鑰匙進入/啟動功能自然必備必不可少,全系標配德爾福STT智能啟停功能,優化燃油經濟性。

遠不止此,強調科技感的全液晶儀錶盤能與中控大屏實現雙屏互動,導航、ACC全速自適應巡航(0-150km/h)等信息同樣能呈現於儀錶盤,甚是方便。

值得一提的是,全景影像四攝像頭還具備行車記錄儀功能,防護功能遠勝傳統行車記錄儀。此外,法國法雷奧一鍵泊車系統(12顆超聲波雷達)、鑰匙遙控泊車等功能在同級更是前所未見,勇氣可嘉。

配置方面,前排座椅加熱、通風和空調功能被集成至排擋桿前方的獨立觸控屏上,估計出於成本控制輕觸后未見震動反饋,增加了盲操學習成本,所幸保留了聲音反饋。

溫度調節和吹風模式保留實體按鍵,長安工程師對人機工程學的考究是可感知的。但如何改善光滑面板的反光現象,會是道不小的難題。

最為人稱道的當屬換裝电子擋桿,採用輕觸方式激活p擋的方式同級罕見,但使用體驗有待商榷,需要適應一段時間。

貴為長安產品矩陣中的銷量擔當,新款CS75僅前排車窗支持一降升降功能,為車內乘員日常啟閉車窗增添不便,不應當,扣分項。

空間表現

國人喜聞樂見的全景天窗如常出席,1.12平方米的採光面積(同級最大)有效拉升乘員的暈車閾值。輔以靠背支持多角度調節的後排座椅以及接近純平的後排中央地板,絕對是說服長輩掏包的有力論證。

整體空間表現絲毫不怵主流中型SUV水準,不易聽到乘員的抱怨聲。手套箱、扶手箱足以安放常規單反相機,擋桿前方、杯架、四門門把手處的儲物格均能容納大尺寸智能手機,實屬難得。

此外,後排座椅安全帶卡扣可收折,不磕屁股。後排座椅支持4/6分割放倒,放倒後接近純平狀態,宜商宜居。

動態表現

新款CS75搭載全新藍鯨 280T 直噴增壓發動機,這枚1.5T發動機在德爾福高壓共軌直噴系統、霍尼韋爾增強脈衝渦輪增壓器、水冷中冷的加持下,最大馬力178ps/5500rpm、峰值扭矩265N·m/1450-4500rpm,官宣百公里加速時間為10s,搭配日本愛信第三代6AT。

此前舊款CS75機油增多事件牽動不少潛在買家的心,而全新CS75搭載的發動機選用全新的噴油方案以及熱管理系統,暖機時間較此前縮短近2min,輔以重新調校的ECU程序,各位無需過慮。

起步階段存有“起床氣”,若不將油門踩得比預期稍深,車輛更願意停留在慵懶狀態。高速下再深踩油門,引擎艙發出歇斯底里的嘶吼聲,小排量渦輪增壓的單薄感被進一步放大。

變速箱齒比設定綿密,3擋開始便能實現閉鎖控制,對動力輸出的連續性、降低動力損耗等大有裨益。升擋后發動機轉速小幅回落,努力維持在峰值扭矩輸出區間,兢兢業業地保持加速力道。至於推背感嘛,沒有。

剎車前半段虛位較大,制動力輸出不夠線性,日常市區行駛不易形成輕鬆駕駛氛圍。更青睞一點就有、漸進式的剎車腳感,還望廠商後期優化。

新車選用前麥弗遜、后多連桿獨立懸架結構,配備美國天納克MTV-CL減震器閥系,彈簧K值較同級家用SUV高,在面對坑窪、起伏路面時動作稍顯敏感。重心轉移與駕駛員預期不夠默契,但勝在拋跳抑制處理到位。

一鍵泊車、鑰匙遙控泊車、遠程控制(發動機、空調、空氣凈化、遠程防盜追蹤)、后追尾預警、開門碰撞預警、隨動氛圍燈、同級最大天窗、电子擋把、安第斯灰車漆,這些同級罕見甚至前所未見的配置,都被新款CS75一一用上。

(售價:9.98-15.98萬元)

相信這是CS75深思熟慮后的改進,因為長安深知顏值拼不過WEY VV5,內飾氛圍、机械規格也難敵領克01,為此選擇在產品年輕化、科技互聯環節大下苦功,清晰的定位有望搶佔豪華自主SUV的年輕潛在買家。

相近的預算,CS75要說服國人不選合資緊湊型SUV,尚屬馳高鶩遠。我想,大概還差一份如逸動、睿騁CC般驚艷、精緻、創新的設計手稿吧。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

Api接口簽名驗證

通過特性來統一驗證的入口,實現ActionFilterAttribute接口來進行接口的簽名驗證

    /// <summary>
    /// 標準接口基類Controller
    /// </summary>
    [SignVerification]
    public abstract class BaseApiController : Controller
    {
    }
    
    /// <summary>
    /// 接口簽名驗證
    /// </summary>
    public class SignVerificationAttribute : ActionFilterAttribute,IAuthenticationFilter
    {
    }

實現的思路為:

1.不同對接方的接口(插件)定義不同的驗證key,不同的插件間不能混用驗證key

2.不同的插件生成不同的partnerId,partnerKey。請求的Url中需要攜帶partnerId,通過partnerId作為key在redis中找到對應的插件驗證信息(包括:partnerId,partnerKey等)

3.Url參數中必須包含partnerId,ts(時間戳),sign(加密簽名)。ts時間戳的有效時間為5分鐘,sign為(時間戳:formBody:partnerId:partnerKey)的MD5加密

4.如果通過partnerId可以找到對應的驗證信息,再把(時間戳:formBody:partnerId:partnerKey)MD5加密后和sign比較確保請求沒有被篡改

5.確保partnerId為當前插件而非其他插件的,因為redis是共用的,只是通過key去取值而已

簽名方式

將時間戳和請求Form參數以及PartnerKey以冒號連接,如(時間戳:body:partnerId:PartnerKey)
將連接好的字符串進行MD5生成sign

Url參數

參數 說明 類型 必須 備註
pid partnerId string  
ts 時間戳(格式:yyyyMMddHHmmss) string 時間戳的有效時間為5分鐘
sign MD5(時間戳:body:partnerId:pkey) string 參考簽名方式

具體代碼實現

    /// <summary>
    /// 接口簽名驗證
    /// </summary>
    public class SignVerificationAttribute : ActionFilterAttribute, IAuthenticationFilter
    {
        private readonly IDefaultUserService _defaultUserService;
        private readonly IInterfaceSignProvider _interfaceSignProvider;
        public SignVerificationAttribute()
        {
            _defaultUserService = ObjectContainer.GetService<IDefaultUserService>();
            _interfaceSignProvider = ObjectContainer.GetService<IInterfaceSignProvider>();
        }

        public void OnAuthentication(AuthenticationContext filterContext)
        {
            var request = filterContext.HttpContext.Request;
            var partnerId = request.QueryString["pid"];
            var timeStamp = request.QueryString["ts"];
            var sign = request.QueryString["sign"];//獲取Url參數
            var body = GetBodyText(request.InputStream);

            if (!ValidSign(filterContext,timeStamp, sign, body,partnerId,out IInterfaceSignInfo signInfo))//加密驗證
            {
                filterContext.Result = new ApiResult {Success = false, ErrorMessage = "無效簽名"};
                return;
            }

            var service = ObjectContainer.GetService<IAuthenticationService>();
            var userId = _defaultUserService.GetDefaultUserId(signInfo.LicNo);
            var identity = service.SignIn(userId, signInfo.LicNo, false, TimeSpan.FromMinutes(5), SessionType.WebApi);
            var newPrincipal = new GenericPrincipal(identity, new string[] { });
            filterContext.Principal = newPrincipal;
        }
        private static string GetBodyText(Stream stream)
        {
            using (var ms = new MemoryStream())
            {
                stream.CopyTo(ms);
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }

        private bool ValidSign(AuthenticationContext filterContext,string timeStamp, string sign, string body,string partnerId,out IInterfaceSignInfo signInfo)
        {
            signInfo = null;
            if (!string.IsNullOrEmpty(timeStamp) && !string.IsNullOrEmpty(sign)&& !string.IsNullOrEmpty(partnerId))
            {
                var cache = _interfaceSignProvider.GetInterfaceSignInfo(partnerId);//通過partnerId當key讀取redis
                if (cache.Enabled)
                {
                    var areaName = filterContext.RouteData.DataTokens["area"]?.ToString().ToLower();//獲取請求的area,即請求的是哪個插件
                    if (string.IsNullOrEmpty(areaName) || !cache.PluginCode.ToLower().StartsWith(areaName))
                    {
                        return false;//PluginCode需以areaName開頭,否則意味着不是同一個插件(如:PluginCode=juwov1,areaName=JuWo)
                    }
                    if (DateTime.TryParseExact(timeStamp, "yyyyMMddHHmmss", CultureInfo.CurrentCulture.DateTimeFormat, DateTimeStyles.AllowWhiteSpaces, out var time) &&
                        (DateTime.Now - time).TotalMinutes <= 5)//時間戳有效期為5分鐘
                    {
                        signInfo = cache;
                        var hashKey = EncryptHelper.Hash($"{timeStamp}:{body}:{partnerId}:{cache.PartnerKey}", "MD5").ToLowerInvariant();//MD5加密對比
                        return string.Equals(hashKey, sign);
                    }
                }
                
            }
            return false;
        }
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext){}
    }

 

這樣就實現了接口的簽名驗證了。但是還有一個問題是,如果同時存在多個不同的對接接口(插件)時,partnerId,PartnerKey應該是不一樣的。即插件1和插件2的驗證key是不能混用的。

可以通過路由來區分不同的插件,來選擇進入不同的area,通過area來區分不同的插件驗證key。

    public class JuWoAreaRegistration: AreaRegistration
    {
        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "JuWo_default",
                "api/JuWo/{controller}/{action}/{id}",
                new {action = "Index", id = UrlParameter.Optional},
                new[] {"iERP.Its.Web.Areas.JuWo.Controllers"}
            );
        }

        public override string AreaName => "JuWo";
    }

 在之前的ValidSign方法中,通過var areaName = filterContext.RouteData.DataTokens[“area”]?.ToString().ToLower();來獲取到當前請求的是哪個插件,在把url上獲取到的partnerId與我們之前約定好的比較看是否能對應。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

厲害了!除了find命令,還有這麼多文件查找命令,高手必備!

大家好,我是良許。

在系統里查找文件,是所有工程師都必備的技能(不管你用的是 Windows 、Linux、還是 MacOS 系統)。對於 Linux 操作系統,單單一個 find 命令就可以完成非常多的搜索工作。

但是,文件搜索命令遠不止一個 find 命令,還有很多。本文就對 Linux 下文件搜索命令進行一個科普,讓你能夠在短時間內找到自己需要的文件。

1. find

find 命令應該是最經典的命令了,談到搜索工具第一個想到的肯定是 find 命令。但是,find 命令非常強大,想要把它的功能都介紹一遍,恐怕要寫好幾篇文章。

所以,這裏就偷個懶,介紹最基本的,根據文件名查找文件的方法。假如我們想搜索當前目錄(及其子目錄)下所有 .sh 文件,可以這樣搜索:

2. locate

locate 是另外一個根據文件名來搜索文件的命令。區別於 find 命令,locate 命令無需指定路徑,直接搜索即可。

這個命令不是直接去系統的各個角落搜索文件,而是在一個叫 mlocate.db 的數據庫下搜索。這個數據庫位於 /var/lib/mlocate/mlocate.db ,它包含了系統里所有文件的索引,並且會在每天早上的時候由 cron 工具自動更新一次。

正因為如此,locate 的搜索速度遠快於 find 命令,因為它直接在數據庫里檢索,速度自然更快。

locate 命令在找到文件之後,將直接显示該文件的絕對路徑,比如:

但是 locate 命令有個弊端,它無法搜索當天所創建的文件,因為它的數據庫一天只在早上更新一次。比如我現在創建一個新文件,locate 沒辦法搜索到:

為了解決這個問題,我們可以使用 updatedb 命令手動去更新它的數據庫:

$ sudo updadb

然後,我們就可以搜索到新文件了。

3. which

which 命令主要用來查找可執行文件的位置,它搜索的位置指定在 $PATH$MANPATH 環境變量下的值,默認情況下,which 命令將显示可執行文件的第一個存儲位置:

如果某個可執行文件存儲在多個位置,可以使用 -a 選項列出所有的位置。

如果你想一次性查找多個文件,可以直接跟在 which 命令後面即可。

4. whereis

whereis 命令會在系統默認安裝目錄(一般是有root權限時默認安裝的軟件)查找二進制文件、源碼、文檔中包含給定查詢關鍵詞的文件。(默認目錄有 /bin, /sbin, /usr/bin, /usr/lib, /usr/local/man等類似路徑)。

一般包含以下三部分內容:

  • 二進制文件的路徑
  • 二進制文件的源碼路徑
  • 對應 man 文件的路徑

比如我們現在搜索 ls 命令:

我們可以使用 -b 選項來只搜索可執行文件所在位置,使用 -B 選項指定搜索位置,使用 -f 選項列出文件的信息。

同樣地,我們可以使用 -s 限定只搜索源碼路徑,使用 -m 搜索 man page 路徑,使用 -s 指定搜索源代碼文件的路徑,使用 -M 指定搜索幫助文件的路徑。

公眾號:良許Linux

有收穫?希望老鐵們來個三連擊,給更多的人看到這篇文章

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

「虹之松原」原來是海岸保安林 國寶級景點靠公私協力經營

環境資訊中心特約記者 廖靜蕙報導

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

熱浪再襲歐 德比荷法熱到40度 法德核電廠被迫停機

摘錄自2019年7月24、26日自由時報、中央社報導

今年夏天的第二波熱浪,25日讓歐洲多國氣溫再創新高,不少城市都測到超過攝氏40度的高溫。荷蘭25日在東部城鎮代倫(Deelen)測得破紀錄的攝氏41.7度高溫。比利時25日在東北部的小布羅赫爾空軍基地測到40.6度,為該國自1833年以來的最高溫。德國25日在西部林根(Lingen)測到41.5度。

法國巴黎25日創下史上最高溫,該市蒙蘇里(Montsouris)區下午測到42.4度的高溫。

熱浪也迫使南法一座核電廠於23日起停機至月底。

依賴海水冷卻反應爐的核電廠受熱浪影響,法國電力公司(EDF)表示,全法國的核電廠25日發電量減少約5.2十億瓦(GW)或8%,南部塔恩-加倫省(Tarn-et-Garonne)的戈費契(Golfech)核電廠,因加倫河(Garonne River)水溫過高,2個反應爐分別於23日起停機,直到本月30日。另有6座核反應爐發電量縮減。

德國電力公用事業公司意昂(E.ON)旗下核電公司PreussenElektra 26日表示,由於威塞河(Weser River)水溫過高,發電量1430 MW的格隆德(Grohnde)核電廠預計26日中午起至28日暫停運轉。若氣候改變可能調整計畫。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

【Spring註解驅動開發】在@Import註解中使用ImportBeanDefinitionRegistrar向容器中註冊bean

寫在前面

在前面的文章中,我們學習了如何使用@Import註解向Spring容器中導入bean,可以使用@Import註解快速向容器中導入bean,小夥伴們可以參見《【Spring註解驅動開發】使用@Import註解給容器中快速導入一個組件》。可以在@Import註解中使用ImportSelector接口導入bean,小夥伴們可以參見《【Spring註解驅動開發】在@Import註解中使用ImportSelector接口導入bean》一文。今天,我們就來說說,如何在@Import註解中使用ImportBeanDefinitionRegistrar向容器中註冊bean。

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

ImportBeanDefinitionRegistrar概述

概述

我們先來看看ImportBeanDefinitionRegistrar是個什麼鬼,點擊進入ImportBeanDefinitionRegistrar源碼,如下所示。

package org.springframework.context.annotation;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.type.AnnotationMetadata;

public interface ImportBeanDefinitionRegistrar {

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}

}

由源碼可以看出,ImportBeanDefinitionRegistrar本質上是一個接口。在ImportBeanDefinitionRegistrar接口中,有一個registerBeanDefinitions()方法,通過registerBeanDefinitions()方法,我們可以向Spring容器中註冊bean實例。

Spring官方在動態註冊bean時,大部分套路其實是使用ImportBeanDefinitionRegistrar接口。

所有實現了該接口的類都會被ConfigurationClassPostProcessor處理,ConfigurationClassPostProcessor實現了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中動態註冊的bean是優先於依賴其的bean初始化的,也能被aop、validator等機制處理。

使用方法

ImportBeanDefinitionRegistrar需要配合@Configuration和@Import註解,@Configuration定義Java格式的Spring配置文件,@Import註解導入實現了ImportBeanDefinitionRegistrar接口的類。

ImportBeanDefinitionRegistrar實例

既然ImportBeanDefinitionRegistrar是一個接口,那我們就創建一個MyImportBeanDefinitionRegistrar類,實現ImportBeanDefinitionRegistrar接口,如下所示。

package io.mykit.spring.plugins.register.condition;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @author binghe
 * @version 1.0.0
 * @description ImportBeanDefinitionRegistrar的實現類
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata: 當前類的註解信息
     * BeanDefinitionRegistry:BeanDefinition註冊類
     * 通過調用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以將所有需要添加到容器中的bean注入到容器中。
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){

    }
}

可以看到,這裏,我們先創建了MyImportBeanDefinitionRegistrar類的大體框架。接下來,我們在PersonConfig2類上的@Import註解中,添加MyImportBeanDefinitionRegistrar類,如下所示。

@Configuration
@Import({Department.class, Employee.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class PersonConfig2 {

接下來,創建一個Company類,作為測試測試ImportBeanDefinitionRegistrar接口的bean,如下所示。

package io.mykit.spring.plugins.register.bean;

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試ImportBeanDefinitionRegistrar接口的使用
 */
public class Company {
}

接下來,就要實現MyImportBeanDefinitionRegistrar類中的registerBeanDefinitions()方法的邏輯了,添加邏輯后的registerBeanDefinitions()方法如下所示。

    /**
     * AnnotationMetadata: 當前類的註解信息
     * BeanDefinitionRegistry:BeanDefinition註冊類
     * 通過調用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以將所有需要添加到容器中的bean注入到容器中。
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
        boolean employee = registry.containsBeanDefinition("employee");
        boolean department = registry.containsBeanDefinition("department");
        if (employee && department){
            BeanDefinition beanDefinition = new RootBeanDefinition(Company.class);
            registry.registerBeanDefinition("company", beanDefinition);
        }
    }

registerBeanDefinitions()方法的實現邏輯很簡單,就是判斷Spring容器中是否同時存在以employee命名的bean和以department命名的bean,如果同時存在以employee命名的bean和以department命名的bean,則向Spring容器中注入一個以company命名的bean。

接下來,我們就運行SpringBeanTest類中的testAnnotationConfig7()方法來進行測試,輸出結果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001

可以看到,在輸出結果中,並沒有看到“company”,這是因為輸出結果中存在io.mykit.spring.plugins.register.bean.Department和io.mykit.spring.plugins.register.bean.Employee,並不存在我們代碼邏輯中的department和employee。所以,我們將registerBeanDefinitions()方法的邏輯稍微修改下,修改后的代碼如下所示。

/**
  * AnnotationMetadata: 當前類的註解信息
  * BeanDefinitionRegistry:BeanDefinition註冊類
  * 通過調用BeanDefinitionRegistry接口的registerBeanDefinition()方法,可以將所有需要添加到容器中的bean注入到容器中。
  */
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
    boolean employee = registry.containsBeanDefinition(Employee.class.getName());
    boolean department = registry.containsBeanDefinition(Department.class.getName());
    if (employee && department){
        BeanDefinition beanDefinition = new RootBeanDefinition(Company.class);
        registry.registerBeanDefinition("company", beanDefinition);
    }
}

接下來,我們再次運行SpringBeanTest類中的testAnnotationConfig7()方法來進行測試,輸出結果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig2
io.mykit.spring.plugins.register.bean.Department
io.mykit.spring.plugins.register.bean.Employee
io.mykit.spring.plugins.register.bean.User
io.mykit.spring.plugins.register.bean.Role
person
binghe001
company

可以看到,此時輸出了company,說明Spring容器中已經成功註冊了以company命名的bean。

好了,咱們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一起學習一起進步!!

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

寫在最後

如果覺得文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公眾號,跟冰河學習Spring註解驅動開發。公眾號回復“spring註解”關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發不再迷茫。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

小師妹學JVM之:深入理解JIT和編譯優化-你看不懂系列

目錄

  • 簡介
  • JIT編譯器
  • Tiered Compilation分層編譯
  • OSR(On-Stack Replacement)
  • Deoptimization
  • 常見的編譯優化舉例
    • Inlining內聯
    • Branch Prediction分支預測
    • Loop unswitching
    • Loop unrolling展開
    • Escape analysis逃逸分析
  • 總結

簡介

小師妹已經學完JVM的簡單部分了,接下來要進入的是JVM中比較晦澀難懂的概念,這些概念是那麼的枯燥乏味,甚至還有點惹人討厭,但是要想深入理解JVM,這些概念是必須的,我將會盡量嘗試用簡單的例子來解釋它們,但一定會有人看不懂,沒關係,這個系列本不是給所有人看的。

更多精彩內容且看:

  • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

JIT編譯器

小師妹:F師兄,我的基礎已經打牢了嗎?可以進入這麼複雜的內容環節了嗎?

小師妹不試試怎麼知道不行呢?了解點深入內容可以幫助你更好的理解之前的知識。現在我們開始吧。

上次我們在講java程序的處理流程的時候,還記得那通用的幾步吧。

小師妹:當然記得了,編寫源代碼,javac編譯成字節碼,加載到JVM中執行。

對,其實在JVM的執行引擎中,有三個部分:解釋器,JIT編譯器和垃圾回收器。

解釋器會將前面編譯生成的字節碼翻譯成機器語言,因為每次都要翻譯,相當於比直接編譯成機器碼要多了一步,所以java執行起來會比較慢。

為了解決這個問題,JVM引入了JIT(Just-in-Time)編譯器,將熱點代碼編譯成為機器碼。

Tiered Compilation分層編譯

小師妹你知道嗎?在JDK8之前,HotSpot VM又分為三種。分別是 client VM, server VM, 和 minimal VM,分別用在客戶端,服務器,和嵌入式系統。

但是隨着硬件技術的發展,這些硬件上面的限制都不是什麼大事了。所以從JDK8之後,已經不再區分這些VM了,現在統一使用VM的實現來替代他們。

小師妹,你覺得Client VM和Server VM的本質區別在哪一部分呢?

小師妹,編譯成字節碼應該都是使用javac,都是同樣的命令,字節碼上面肯定是一樣的。難點是在執行引擎上面的不同?

說的對,因為Client VM和Server VM的出現,所以在JIT中出現了兩種不同的編譯器,C1 for Client VM, C2 for Server VM。

因為javac的編譯只能做少量的優化,其實大量的動態優化是在JIT中做的。C2相對於C1,其優化的程度更深,更加激進。

為了更好的提升編譯效率,JVM在JDK7中引入了分層編譯Tiered compilation的概念。

對於JIT本身來說,動態編譯是需要佔用用戶內存空間的,有可能會造成較高的延遲。

對於Server服務器來說,因為代碼要服務很多個client,所以磨刀不誤砍柴工,短暫的延遲帶來永久的收益,聽起來是可以接受的。

Server端的JIT編譯也不是立馬進行的,它可能需要收集到足夠多的信息之後,才進行編譯。

而對於Client來說,延遲帶來的性能影響就需要進行考慮了。和Server相比,它只進行了簡單的機器碼的編譯。

為了滿足不同層次的編譯需求,於是引入了分層編譯的概念。

大概來說分層編譯可以分為三層:

  1. 第一層就是禁用C1和C2編譯器,這個時候沒有JIT進行。
  2. 第二層就是只開啟C1編譯器,因為C1編譯器只會進行一些簡單的JIT優化,所以這個可以應對常規情況。
  3. 第三層就是同時開啟C1和C2編譯器。

在JDK7中,你可以使用下面的命令來開啟分層編譯:

-XX:+TieredCompilation

而在JDK8之後,恭喜你,分層編譯已經是默認的選項了,不用再手動開啟。

OSR(On-Stack Replacement)

小師妹:F師兄,你剛剛講到Server的JIT不是立馬就進行編譯的,它會等待一定的時間來搜集所需的信息,那麼代碼不是要從字節碼轉換成機器碼?

對的,這個過程就叫做OSR(On-Stack Replacement)。為什麼叫OSR呢?我們知道JVM的底層實現是一個棧的虛擬機,所以這個替換實際上是一系列的Stack操作。

上圖所示,m1方法從最初的解釋frame變成了後面的compiled frame。

Deoptimization

這個世界是平衡的,有陰就有陽,有優化就有反優化。

小師妹:F師兄,為什麼優化了之後還要反優化呢?這樣對性能不是下降了嗎?

通常來說是這樣的,但是有些特殊的情況下面,確實是需要進行反優化的。

下面是比較常見的情況:

  1. 需要調試的情況

如果代碼正在進行單個步驟的調試,那麼之前被編譯成為機器碼的代碼需要反優化回來,從而能夠調試。

  1. 代碼廢棄的情況

當一個被編譯過的方法,因為種種原因不可用了,這個時候就需要將其反優化。

  1. 優化之前編譯的代碼

有可能出現之前優化過的代碼可能不夠完美,需要重新優化的情況,這種情況下同樣也需要進行反優化。

常見的編譯優化舉例

除了JIT編譯成機器碼之外,JIT還有一下常見的代碼優化方式,我們來一一介紹。

Inlining內聯

舉個例子:

int a = 1;
int b = 2;
int result = add(a, b);
...
public int add(int x, int y) { return x + y; }
int result = a + b; //內聯替換

上面的add方法可以簡單的被替換成為內聯表達式。

Branch Prediction分支預測

通常來說對於條件分支,因為需要有一個if的判斷條件,JVM需要在執行完畢判斷條件,得到返回結果之後,才能夠繼續準備後面的執行代碼,如果有了分支預測,那麼JVM可以提前準備相應的執行代碼,如果分支檢查成功就直接執行,省去了代碼準備的步驟。

比如下面的代碼:

// make an array of random doubles 0..1
double[] bigArray = makeBigArray();
for (int i = 0; i < bigArray.length; i++)
{
 double cur = bigArray[i];
 if (cur > 0.5) { doThis();} else { doThat();}
}

Loop unswitching

如果我們在循環語句裏面添加了if語句,為了提升併發的執行效率,可以將if語句從循環中提取出來:

  int i, w, x[1000], y[1000];
  for (i = 0; i < 1000; i++) {
    x[i] += y[i];
    if (w)
      y[i] = 0;
  }

可以改為下面的方式:

  int i, w, x[1000], y[1000];
  if (w) {
    for (i = 0; i < 1000; i++) {
      x[i] += y[i];
      y[i] = 0;
    }
  } else {
    for (i = 0; i < 1000; i++) {
      x[i] += y[i];
    }
  }

Loop unrolling展開

在循環語句中,因為要不斷的進行跳轉,所以限制了執行的速度,我們可以對循環語句中的邏輯進行適當的展開:

 int x;
 for (x = 0; x < 100; x++)
 {
     delete(x);
 }

轉變為:

 int x; 
 for (x = 0; x < 100; x += 5 )
 {
     delete(x);
     delete(x + 1);
     delete(x + 2);
     delete(x + 3);
     delete(x + 4);
 }

雖然循環體變長了,但是跳轉次數變少了,其實是可以提升執行速度的。

Escape analysis逃逸分析

什麼叫逃逸分析呢?簡單點講就是分析這個線程中的對象,有沒有可能會被其他對象或者線程所訪問,如果有的話,那麼這個對象應該在Heap中分配,這樣才能讓對其他的對象可見。

如果沒有其他的對象訪問,那麼完全可以在stack中分配這個對象,棧上分配肯定比堆上分配要快,因為不用考慮同步的問題。

我們舉個例子:

  public static void main(String[] args) {
    example();
  }
  public static void example() {
    Foo foo = new Foo(); //alloc
    Bar bar = new Bar(); //alloc
    bar.setFoo(foo);
  }
}

class Foo {}

class Bar {
  private Foo foo;
  public void setFoo(Foo foo) {
    this.foo = foo;
  }
}

上面的例子中,setFoo引用了foo對象,如果bar對象是在heap中分配的話,那麼引用的foo對象就逃逸了,也需要被分配在heap空間中。

但是因為bar和foo對象都只是在example方法中調用的,所以,JVM可以分析出來沒有其他的對象需要引用他們,那麼直接在example的方法棧中分配這兩個對象即可。

逃逸分析還有一個作用就是lock coarsening。

為了在多線程環境中保證資源的有序訪問,JVM引入了鎖的概念,雖然鎖可以保證多線程的有序執行,但是如果實在單線程環境中呢?是不是還需要一直使用鎖呢?

比如下面的例子:

public String getNames() {
     Vector<String> v = new Vector<>();
     v.add("Me");
     v.add("You");
     v.add("Her");
     return v.toString();
}

Vector是一個同步對象,如果是在單線程環境中,這個同步鎖是沒有意義的,因此在JDK6之後,鎖只在被需要的時候才會使用。

這樣就能提升程序的執行效率。

總結

本文介紹了JIT的原理和一些基本的優化方式。後面我們會繼續探索JIT和JVM的秘密,敬請期待。

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jvm-jit-in-detail/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

特斯拉將調整全球超級充電站充電價格,車主錯愕

根據國外專門報導電動車產業消息的《Electrek》網站報導,電動車大廠特斯拉(Tesla)正式終止任何形式的免費充電計畫之後,準備將全球超級充電站(Supercharger)充電價格平均提高 33%,這舉動令車主錯愕。

自 2018 年 11 月以來,特斯拉所有新款電動車都必須遵守新超級充電站充電付費計畫,雖然沒有擴及 2018 年 11 月前購買特斯拉電動車的車主,特斯拉仍舊對這些車主提供有限度的免費充電服務。不過,這項優惠措施到 2019 年 1 月底為止,也就是之後再也不會有任何特斯拉車主有免費充電服務;新付費方式將以每度(小時千瓦;1kWh),或是部分地區每分鐘來計算充電費用。

觀察特斯拉的新充電費率,將以不同地區、甚至每個充電站的使用需求計價。特斯拉還希望根據當地電價,訂定更合理、更全面的價格。換句話說,這會造成大多數地區的超級充電樁價格大幅上漲。

在 2018 年,特斯拉已提高美國超級充電站的充電價格。調漲後多數地區的充電價格漲幅為 20%~40%,部分地區漲幅甚至高達 100%。以紐約市為例,過去是每度 0.24 美元,現在則是 0.32 美元,上漲 33%。加州地區,過去每度為 0.26 美元,調整之後是 0.32 到 0.36 美元不等。這次特斯拉全球充電價格調漲,美國市場已是第 2 次漲價。

歐洲方面,雖然大多數市場充電價格仍維持每度 0.28~0.32 歐元,以特斯拉在歐洲最重要的市場和超級充電站最密集的挪威來說,充電價格預計從每小時千瓦 1.4 挪威克朗,上升到 1.86 挪威克朗,幾乎漲了 33%。相信未來其他地區也會是類似漲幅。

特斯拉一直聲稱超級充電站「永遠不會成為利潤中心」。漲價計畫決定後,面對記者的詢問,特斯拉還是重申這點,並表示正在調整超級充電站的充電價格,希望更能反映當地電力成本,以及場地使用情況的差異。隨著特斯拉電動車增多,未來也繼續每週開設新超級充電站,讓更多消費者可長途行駛,並享受到比汽油價格低的充電價格,達到零排碳量的目標。未來,還希望利用超級充電站獲得的收入,建立更多充電站。

目前特斯拉全世界共有 1,422 個超級充電站,共有 12,011 個充電樁,而特斯拉的目標,是在 2019 年將這個數字倍增。

(合作媒體:。首圖來源: CC BY 2.0)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

新型液流電池可發電與供氫,電動車與氫燃料車都適用

電池電動車與氫燃料電池車都有望成為新一代交通主力,但這兩種車款各採用不同的「充電方式」,一種是電力、一種是補充氫氣,各國得針對兩種不同的車系分別打造管線與「加油站」,而近日英國格拉斯哥大學打造新型液流電池,不僅可讓汽車在幾秒內完成燃料補充,還可以釋放電力與氫氣、完美解決兩種電動車系統不相容的狀況。

液流電池(flow battery)由兩個電解質槽組成,充放電時電解質會被幫補到中間的發電室,而發電室也會以薄膜隔開兩種溶液、形成兩個電極,最後產生離子交換來發電,而由於兩種電解質是分開存放,不會有電解質相互滲漏與自身放電等安全性問題,是一種良好的儲能生力軍。

只是液流電池體積龐大,即使該電池具有安全性與穩定性高等優點,仍不適合用於 3C 產品與電動車,目前大多研究團隊都是想把液流電池用在再生能源儲能系統。

而格拉斯哥大學這次想將突破以往液流電池無法用在汽車的印象,並成功透過奈米粒子溶液打造新型液流電池,其中團隊所用的電解質是一種奈米懸浮液(suspension),每個奈米粒子都可以當成一顆小型電池,儲存能量更是一般液流電池的 10 倍,還能以電力或氫氣的形式釋放。

且由於液流電池主要以液態電解質驅動,團隊更指出,新型液流電池可在幾秒內完成移除舊液體、補充新電解質,因此該系統的「充電」時間可跟一般汽油車一樣,大大縮短電動車的充電速度。

格拉斯哥大學 Regius Chair of Chemistry 教授 Leroy(Lee)Cronin 表示,若再生能源想要有效運作,還需要儲存容量、靈活性高的儲能系統來幫忙解決間歇性能源與電力尖峰等問題,而團隊提出的新型化學充電方式,除了可用在儲能系統,還可應用在電動車中。

該研究將有助於未來液流電池的應用,有望縮短液流電池與大規模商業化的距離。團隊也指出,新型液流電池的能量密度相當高,可提升將來電動車的續航里程與儲能系統的儲存容量,目前研究已發表在《》。

(首圖來源:。文/DaisyChuang)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

Java 從入門到進階之路(二十三)

在之前的文章我們介紹了一下 Java 中的  集合框架中的Collection 的迭代器 Iterator,本章我們來看一下 Java 集合框架中的Collection 的泛型。

在講泛型之前我們先來看下面一段代碼:

 1 public class Main {
 2     public static void main(String[] args) {
 3         Point point = new Point(1, 2);
 4 
 5         point.setX(2);
 6         int ix = point.getX();
 7         System.out.println(ix); // (2, 2)
 8 
 9         /**
10          * 如果想要 x 值變為 double 類型則可以強轉為 double 類型
11          * */
12         point.setX(2);
13         double dx = (double) point.getX();
14         System.out.println(dx); // 2.0
15     }
16 }
17 
18 class Point {
19     private int x;
20     private int y;
21 
22     public Point(int x, int y) {
23         this.x = x;
24         this.y = y;
25     }
26 
27     public int getX() {
28         return x;
29     }
30 
31     public void setX(int x) {
32         this.x = x;
33     }
34 
35     public int getY() {
36         return y;
37     }
38 
39     public void setY(int y) {
40         this.y = y;
41     }
42 
43     @Override
44     public String toString() {
45         return "(" + x + ", " + y + ")";
46     }
47 }

上面的代碼我們之前的文章講過,我們可以通過傳入 x 和 y 值來定義 Point 點,如果我們想要 double 類型的點時需要造型為 double 類型,那我要定義漢字類型的呢?那就造型成 String 類型,這就很麻煩,每次都需要自己來造型,有種鞋不合腳的感覺,那能不能定義我想要什麼類型就是什麼類型呢,如下:

 1 public class Main {
 2     public static void main(String[] args) {
 3         Point<Integer> point1 = new Point<Integer>(1, 2); // 必須是包裝類
 4         point1.setX(1);
 5         System.out.println(point1.getX()); // 1
 6 
 7         Point<Double> point2 = new Point<Double>(1.1, 2.1); // 必須是包裝類
 8         point2.setX(1.2);
 9         System.out.println(point2.getX()); // 1.2
10 
11         Point<String> point3 = new Point<String>("一", "二"); // 必須是包裝類
12         point3.setX("三");
13         System.out.println(point3.getX()); //
14     }
15 }
16 
17 /**
18  * 泛型
19  * 又稱參數化類型,是將當前類的屬性的類型,方法參數的類型及方法
20  * 返回值的類型的定義權移交給使用者,
21  * 使用者在創建當前類的同時將泛型的試劑類型傳入
22  * 数字和字母組合,数字不能開頭
23  */
24 class Point<T> { // 定義為泛型 T 類型
25     private T x;
26     private T y;
27 
28     public Point(T x, T y) {
29         this.x = x;
30         this.y = y;
31     }
32 
33     public T getX() {
34         return x;
35     }
36 
37     public void setX(T x) {
38         this.x = x;
39     }
40 
41     public T getY() {
42         return y;
43     }
44 
45     public void setY(T y) {
46         this.y = y;
47     }
48 
49     @Override
50     public String toString() {
51         return "(" + x + ", " + y + ")";
52     }
53 }

從上面的代碼中,我們定義了一個 T 的類型 Point,當我們要實例化該類時,根據自己的需求傳入想要的包裝類類型即可,這樣就滿足了不同的需求,各取所需。 

泛型從底層來說其實就是 Object,定義了泛型只是編譯器在做一些驗證工作,當我們對泛型類型設置值時,會檢查是否滿足類型要求,當我們獲取一個泛型類型的值時,會自動進行類型轉換。

在平時我們是很少自己來定義泛型的,泛型是用來約束集合中元素的類型,如下:

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 import java.util.Iterator;
 4 
 5 public class Main {
 6     public static void main(String[] args) {
 7         Collection<String> collection = new ArrayList<String>(); // 只能添加 String 類型的元素
 8         collection.add("one");
 9         collection.add("two");
10         collection.add("thee");
11         collection.add("four");
12         // collection.add(1); // 編譯錯誤
13         for (String string : collection) {
14             System.out.println(string); // one two three four
15         }
16         Iterator<String> iterator = collection.iterator();
17         while (iterator.hasNext()) {
18             // String string = (String) iterator.next(); 不需要再造型
19             String string = iterator.next();
20             System.out.println(string); // one two three four
21         }
22     }
23 }

  

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?