中國推新能源車結合再生能源應用,拚減碳逾 20 萬噸

新華社報導,中國新能源汽車和再生能源綜合應用商業化推廣專案正式啟動,據中國汽車工程學會常務副理事長兼秘書長張進華表示,整個專案營運期間將直接減排二氧化碳超過 20 萬噸。

張進華指出,新能源汽車和再生能源綜合應用商業化推廣專案的實施,是落實中國汽車產業中長期發展規劃的重要工作之一。據瞭解,為促進中國新能源汽車與再生能源產業綜合應用,充分發揮新能源汽車全生命週期的節能減排效益,減少溫室氣體排放,中國工信部和聯合國工業發展組織共同向全球環境基金申報此項目並獲得批准,中國汽車工程學會將全面承擔專案實施與組織工作,實施週期為 3 年。

據瞭解,該專案具體內容包括組織制定新能源汽車和再生能源綜合應用的政策和標準法規,展開智慧充電系統、再生能源微電網、車網互動、移動充電系統、退役電池梯次利用等技術示範和驗證工作。目前,已確定將中國上海市、江蘇省鹽城市和如皋市作為示範城市,展開新能源汽車和再生能源綜合應用的技術示範和驗證。

(本文內容由 授權使用。首圖來源:)

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

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

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

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

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

挪威帶頭衝,歐洲電動車銷售量突破百萬大關

根據 EV volumes 資料顯示,歐洲上半年電動車(含純電池動力與插電式混合動力車)銷售量猛增,歷史累計銷售量已在 6 月正式突破百萬輛大關。

2018 上半年,歐洲電動車銷售量每月至少增加 5,000 輛,累計銷售量達 19.5 萬輛,較去年成長 42%,其中純電池動力車占 51%,其餘為混合動力車。

據 EV volumes 估計,歐洲 2018 全年電動車銷售量將達 43 萬輛,對照全球預估來到 135 萬輛。

挪威目前是歐洲電動車銷售量最高的國家,不過德國在後猛追,EV volumes 預期今年底德國電動車銷售量就將超越挪威。

中國電動車銷售量更早突破 100 萬輛,幾乎比歐洲快了一年,且需求持續成長,預估 2018 年底就會超越兩百萬輛。

(本文內容由 授權使用。首圖來源:)

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

【其他文章推薦】

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

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

中國電動車電池不到位?通用汽車被迫延後投產

中國推出「雙積分制」,規定各大車廠必須出售一定比例的電動車。通用汽車(GM)亟欲在中國開賣電動車,不料卻傳出當地生產的電動車電池達不到 GM 要求,暴露出中國電池業的隱憂。

《華爾街日報》報導,GM 原定下個月內生產油電混合車「Buick Velite 6」,明年再推純電動車。然而,內情人士透露上市計畫已經延後,原因是中國萬向集團旗下 A123 Systems 生產的電池,內部測試時效能和安全未達 GM 標準。A123 Systems 在杭州設有工廠,供應中國市場所需。電動車電池是相當複雜的零件,無法輕易更換,Velite 6 生產時程恐怕會大延誤。

GM 原本打算使用韓廠 LG Chem 的電池,可是 2016 年中國規定車廠必須使用當局核可的電池供應商,名單上全部都是中國廠,沒有一家外國業者入列。車廠抱怨此種排外政策是中國保護主義的實例,當局剔除外國業者,獨厚本土廠商。電池諮詢機構 LIB-X Consulting 總裁 Thomas Barrera 表示,中國業者急就章發展電池技術,或許有品質和安全風險。中國電池價格低廉,相當有吸引力,但是這些電池上市前,也許沒經過必須的品質檢測。

中國的電動車政策讓外國車廠陷入困境,車商必須使用中國製電池打造電動車,卻又不能在品質上做出妥協,使用品質欠佳的電池,車輛有著火風險。儘管多數外國車廠在公開場合信心滿滿表示,有能力達到中國政府目標,2019 年電動車產出將占總產量的 3~4%,但是少有業者詳細說明要如何辦到。

(本文內容由 授權使用。 CC BY 2.0)

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

【其他文章推薦】

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

※別再煩惱如何寫文案,掌握八大原則!

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

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

台達電開發 400kW 高功率電動車充電機,獲美專案經費

電源管理及散熱解決方案廠商台達電 30 日宣布獲美國能源部(Department of Energy,DOE)研發專案經費輔助,合作開發充電輸出功率可達 400kW 的高速電動車充電機(XFC),預期不到 10 分鐘的快速充電即可為未來電動車款提供 180 英里的行駛里程(約 288 公里)。此充電機將應用固態變壓器(SST)技術,其電網輸入至電動車輸出的能源轉換率將高達 96.5%,體積為現今直流充電機的一半,重量更僅有四分之一,同時設計高壓直流(HVDC)端口,以利與儲能及再生能源系統整合,建構智能微電網以減少充電站對市電電網的負擔。

台達電指出,此研究專案將由深具汽車行業知識及經驗的台達底特律團隊,及位於北卡羅來納州  Raleigh 的台達電力電子研究室(DPEL)主導研究開發,通用汽車、DTE Energy、維吉尼亞理工大學 CPES 研究中心、NextEnergy、密西根州能源局之能源辦公室以及底特律市永續發展辦公室也將共同參與。此共同研發計畫為期三年,經費總計 700 萬美元,美國能源部將輔助一半費用。

台達電美洲區總經理黃銘孝表示,公司非常榮幸能主導此項重要研究計畫,並與頂尖的研究人員及合作夥伴共同開發嶄新技術。透過利用固態變壓器技術,將能創造前所未有的充電速度和便利性,樹立電動車快速充電的產業標竿,同時協助美國能源部達成提升電動車普及率的策略目標。

台達電表示,400kW 高速充電機採用碳化矽(SiC)MOSFET 元件並導入創新的固態變壓器拓撲設計(Topology),替代利用低壓交流電的傳統工頻變壓器技術,將可直接轉換 4.8kV 或 13.2kV 的中壓交流電為電動車以高達 3C 充電率快速充電。未來高續航里程的電動車款,10 分鐘的充電時間即可提供一半的最高續航里程,以續航里程為 360 英里的電動車為例,10 分鐘的充電,就可行駛 180 英里。此外,與現今業界的直流快速充電機相比,其系統效率預期將提升 3.5% 達到 96.5%、同時減少一半的設備體積,重量更只有四分之一。 而內建高壓直流端口,可讓此充電機在微電網內運行,降低電動車快速充電對電網的影響。此研究專案的原型機將於 2020 年測試運行。

台達電也表示,除了電動車充電技術的提升,此研究專案的數據和成果將能幫助汽車製造商、相關技術提供者、城市政府、與電力公司更加了解電動車高速充電如何影響電力需量反應規劃,以及充電站如何整合可再生能源,以避免大量的高速充電對電網基礎設施造成壓力。

(本文內容由 授權使用。首圖來源:科技新報)

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

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

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

網頁設計最專業,超強功能平台可客製化

電動車前景看俏,全球電動車累計銷售量已突破 400 萬

彭博能源財經(BNEF)最新報告指出,全球電動自小客車累計銷售已突破 400 萬大關,雖然乍看之下只佔總汽車銷售量的一小部分,但與 2015 年的 100 萬輛相比,其成長速度可說是一日千里。

BNEF 指出,若把電動巴士計算在內,電動車銷售量早在 7 月初就抵達 400 萬,其中電動自小客車全球銷售量在 2018 年 6 月底來到 350 萬輛,電動巴士則為是 421,000 輛,總銷售量為 397 萬。

報告顯示,電動車銷售量從 100 萬到 200 萬輛僅花費 17 個月,更在短短 6 個月就從 300 萬增加到 400 萬輛,而隨著電動車技術進步與價格下滑,未來電動車發展將踩油門加速,全球電動車銷售量僅需 6 個月、在 2019 年 3 月就能突破 500 萬。

電動車銷售量與日俱增,電動車銷售佔比在中國、歐洲和北美等主要市場也不斷提升,以 2018 年第二季來說,電動車就分別占當地總銷售的 4%、2.3% 與 1.6%。中國市場則是全球電動車發展迅速的一大功臣,中國市場早在 2011 年就佔全球電動自小客車總銷售的 37%,更占電動巴士的 99%。

BNEF 指出,未來中國將佔全球電動車總銷售的 42%,歐洲與北美分別占 26% 與 25%,若特斯拉平價電動車款 Model 3 在北美的銷售行情一路上漲,北美電動車銷售量則會迅速超越歐洲,而這兩個市場的銷售量也將同時達到 130 萬輛。

報告也表示,2018 年底之前還會有幾款電動車上市,這將能進一步提升全球電動車銷售市場。BNEF 指出,Model 3 將於 2019 年中旬進入歐洲市場、中國的「雙積分制」也將在 2019 年生效,新型車款與政策都能推動歐洲與中國電動車買氣。

中國雙積分制規定各大車廠必須出售一定比例的環保車,其中分為「油耗積分」與「新能源積分」,若車廠生產越多汽油車,油耗積分就會隨之減少;生產越多高性能電動車,新能源積分就越多。車廠每年正負積分必須抵銷歸零,如果積分沒辦法歸零就不能販售新車。

在政策挹注之下,中國電動車發展將逐步加速。中國媒體也指出,中國政府預估新能源車產量可在 2020 年達到 200 萬輛,銷售佔比更會在 2025 年達到總汽車市場的 20%。

BNEF 先前預估,2025 年全球電動車累計銷售量將增加 10 倍、達到 1,100 萬輛,2020-2030 年電動車價格則可與傳統汽車相當,2030 年全球電動車銷售量有望突破 3,000 萬輛。

隨著氣候變遷與空氣污染加劇,各國開始意識到電動車開發的重要性、紛紛開始制定禁售汽柴油車時間表與路上零排放目標,未來電動車的發展還會再加快,說不定可提早突破 1,000 萬大關。

(首圖來源:。文/DaisyChuang)

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

Panasonic 歐洲 EV 零件傳大增產,擴產至 10 倍

日經新聞 1 日報導,因訂單以歐洲豪華車廠為中心呈現增加,故 Panasonic 計畫投下 100 億日圓資金,於 2023 年將歐洲電動車(EV)用零件產能擴增至現行的 10 倍以上水準。報導指出,Panasonic 所計畫增產的對象為 EV、插電式油電混合車(PHV)等電動化車款充電時所需要的車用充電器等產品,Panasonic 將擴增捷克工廠、斯洛伐克工廠的車用充電器等產品產能,搶攻需求看俏的電動化車款需求。

據報導,Panasonic 的車用充電器具備小型、高輸出等特性,有助於讓車用電池在更短的時間內完成充電,各家車廠預計於 2019 年以後開賣的新型 EV 已決定採用。

Panasonic 歐洲事業負責人 Laurent Abadie(Panasonic 常務執行幹部)接受日經新聞採訪時表示,「計畫將歐洲車用事業營收擴增至 2 倍以上水準」。Laurent Abadie 並透露,考慮祭出購併措施。

Panasonic 車用事業目前以車用電池為主,日美歐車廠所生產的約 70 款車種採用了 Panasonic 的電池產品,而 Panasonic 計畫將車用事業產品群多樣化,除了車用電池之外、也將對 EV 相關零件進行積極投資,目標在 2021 年度將車用事業營收擴增至 2.5 兆日圓、將較 2017 年度增加約 5 成。

Panasonic 於 7 月 31 日公布財報資料指出,因車用事業業績佳,提振上季(2018 年 4-6 月)合併營收較去年同期成長 7.7% 至 2 兆 87 億日圓、合併營益大增 19.1% 至 999.56 億日圓。Panasonic 預估 2018 年度(2018 年 4 月-2019 年 3 月)合併營收將成長 4.0% 至 8.3 兆日圓、合併營益將勁揚 11.7% 至 4,250 億日圓。

(本文內容由 授權使用。首圖來源: CC BY 2.0)

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

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

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

FB行銷專家,教你從零開始的技巧

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  ?

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

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

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

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

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

Spring Boot入門系列(十八)整合mybatis,使用註解的方式實現增刪改查

之前介紹了Spring Boot 整合mybatis 使用xml配置的方式實現增刪改查,還介紹了自定義mapper 實現複雜多表關聯查詢。雖然目前 mybatis 使用xml 配置的方式 已經極大減輕了配置的複雜度,支持 generator 插件 根據表結構自動生成實體類、配置文件和dao層代碼,減輕很大一部分開發量;但是 java 註解的運用發展到今天。約定取代配置的規範已經深入人心。開發者還是傾向於使用註解解決一切問題,註解版最大的特點是具體的 SQL 文件需要寫在 Mapper 類中,取消了 Mapper 的 XML 配置 。這樣不用任何配置文件,就可以簡單配置輕鬆上手。所以今天就介紹Spring Boot 整合mybatis 使用註解的方式實現數據庫操作 。

Spring Boot 整合mybatis 使用xml配置版之前已經介紹過了,不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html。

 

一、整合Mybatis

Spring Boot  整合Mybatis 的步驟都是一樣的,已經熟悉的同學可以略過。

1、pom.xml增加mybatis相關依賴

我們只需要加上pom.xml文件這些依賴即可。

       <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.2.4</version>
        </dependency>
        <!-- pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- druid 數據庫連接框架-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.2</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>

 

2、application.properties配置數據連接

application.properties中需要增加mybatis相關的數據庫配置。

############################################################
# 數據源相關配置,這裏用的是阿里的druid 數據源
############################################################
spring.datasource.url=jdbc:mysql://localhost:3306/zwz_test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true

############################################################
# mybatis 相關配置
############################################################
mybatis.type-aliases-package=com.weiz.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
mapper.mappers=com.weiz.utils.MyMapper    #這個MyMapper 就是我之前創建的mapper統一接口。後面所有的mapper類都會繼承這個接口
mapper.not-empty=false
mapper.identity=MYSQL
# 分頁框架
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql

這裏的配置有點多,不過最基本的配置都在這。

 

3、在啟動主類添加掃描器

在SpringBootStarterApplication 啟動類中增加包掃描器。

@SpringBootApplication
//掃描 mybatis mapper 包路徑
@MapperScan(basePackages = "com.weiz.mapper") // 這一步別忘了。
//掃描 所有需要的包, 包含一些自用的工具類包 所在的路徑
@ComponentScan(basePackages = {"com.weiz","org.n3r.idworker"})
public class SpringBootStarterApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootStarterApplication.class, args);
}

}

注意:這一步別忘了,需要在SpringBootStarterApplication 啟動類中增加包掃描器,自動掃描加載com.weiz.mapper 裏面的mapper 類。

 

以上,就把Mybatis 整合到項目中了。 接下來就是創建表和pojo類,mybatis提供了強大的自動生成功能。只需簡單幾步就能生成pojo 類和mapper。

 

二、代碼自動生成工具

Mybatis 整合完之後,接下來就是創建表和pojo類,mybatis提供了強大的自動生成功能的插件。mybatis generator插件只需簡單幾步就能生成pojo 類和mapper。操作步驟和xml 配置版也是類似的,唯一要注意的是 generatorConfig.xml 的部分配置,要配置按註解的方式生成mapper 。

1、增加generatorConfig.xml配置文件

在resources 文件下創建 generatorConfig.xml 文件。此配置文件獨立於項目,只是給自動生成工具類的配置文件,具體配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="DB2Tables"  targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <!-- 是否去除自動生成的註釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--數據庫鏈接URL,用戶名、密碼 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/zwz_test" userId="root" password="root">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 生成模型的包名和位置-->
        <javaModelGenerator targetPackage="com.weiz.pojo" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成映射文件的包名和位置-->
        <sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置-->
        <!-- XMLMAPPER生成xml映射文件, ANNOTATEDMAPPER生成的dao採用註解來寫sql -->
        <javaClientGenerator type="ANNOTATEDMAPPER" targetPackage="com.weiz.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 要生成的表 tableName是數據庫中的表名或視圖名 domainObjectName是實體類名-->
        <table tableName="sys_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
    </context>
</generatorConfiguration>

注意:

這裏的配置 <javaClientGenerator type=”ANNOTATEDMAPPER” targetPackage=”com.weiz.mapper” targetProject=”src/main/java”>

type 的值很重要:
  XMLMAPPER : 表示生成xml映射文件。

  ANNOTATEDMAPPER: 表示生成的mapper 採用註解來寫sql。

 

2、數據庫User表

需要在數據庫中創建相應的表。這個表結構很簡單,就是普通的用戶表sys_user

CREATE TABLE `sys_user` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `username` varchar(32) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `nickname` varchar(64) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sex` int(11) DEFAULT NULL,
  `job` int(11) DEFAULT NULL,
  `face_image` varchar(6000) DEFAULT NULL,
  `province` varchar(64) DEFAULT NULL,
  `city` varchar(64) DEFAULT NULL,
  `district` varchar(64) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `auth_salt` varchar(64) DEFAULT NULL,
  `last_login_ip` varchar(64) DEFAULT NULL,
  `last_login_time` datetime DEFAULT NULL,
  `is_delete` int(11) DEFAULT NULL,
  `regist_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

 

3、創建GeneratorDisplay類

package com.weiz.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorDisplay {

    public void generator() throws Exception{

        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定 逆向工程配置文件
        File configFile = new File("generatorConfig.xml"); 
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                callback, warnings);
        myBatisGenerator.generate(null);

    } 
    
    public static void main(String[] args) throws Exception {
        try {
            GeneratorDisplay generatorSqlmap = new GeneratorDisplay();
            generatorSqlmap.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

這個其實也是調用mybatis generator實現的。跟mybatis generator安裝插件是一樣的。

注意:利用Generator自動生成代碼,對於已經存在的文件會存在覆蓋和在原有文件上追加的可能性,不宜多次生成。如需重新生成,需要刪除已生成的源文件。

 

4、Mybatis Generator自動生成pojo和mapper

運行GeneratorDisplay 如下圖所示,即可自動生成相關的代碼。

 

 

上圖可以看到,pojo 包裏面自動生成了User 實體對象 ,mapper包裏面生成了 UserMapper 和UserSqlProvider 類。UserMapper 是所有方法的實現。UserSqlProvider則是為UserMapper 實現動態SQL。

注意:

  UserMapper 中的所有的動態SQL腳本,都定義在類UserSqlProvider中。若要增加新的動態SQL,只需在UserSqlProvider中增加相應的方法,然後在UserMapper中增加相應的引用即可,

  如:@UpdateProvider(type=UserSqlProvider.class, method=”updateByPrimaryKeySelective”)。

 

 

三、實現增刪改查

在項目中整合了Mybatis並通過自動生成工具生成了相關的mapper和配置文件之後,下面就開始項目中的調用。這個和之前的xml 配置版也是一樣的。

1、在service包下創建UserService及UserServiceImpl接口實現類

創建com.weiz.service包,添加UserService接口類

package com.weiz.service;

import com.weiz.pojo.User;

public interface UserService {
    public int saveUser(User user);
    public int updateUser(User user);
    public int deleteUser(String userId);
    public User queryUserById(String userId);
}

創建com.weiz.service.impl包,並增加UserServiceImpl實現類,並實現增刪改查的功能,由於這個代碼比較簡單,這裏直接給出完整的代碼。

package com.weiz.service.impl;

import com.weiz.mapper.UserMapper;
import com.weiz.pojo.User;
import com.weiz.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public int saveUser(User user) {
        return userMapper.insertSelective(user);
    }

    @Override
    public int updateUser(User user) {
        return userMapper.updateByPrimaryKeySelective(user);
    }

    @Override
    public int deleteUser(String userId) {
        return userMapper.deleteByPrimaryKey(userId);
    }

    @Override
    public User queryUserById(String userId) {
        return userMapper.selectByPrimaryKey(userId);
    }
}

 

2、編寫controller層,增加MybatisController控制器

package com.weiz.controller;

import com.weiz.pojo.User;
import com.weiz.utils.JSONResult;
import com.weiz.service.UserService;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
@RequestMapping("mybatis")
public class MyBatisCRUDController {

    @Autowired
    private UserService userService;

    @Autowired
    private Sid sid;

    @RequestMapping("/saveUser")
    public JSONResult saveUser() {

        String userId = sid.nextShort();
        User user = new User();
        user.setId(userId);
        user.setUsername("spring boot" + new Date());
        user.setNickname("spring boot" + new Date());
        user.setPassword("abc123");
        user.setIsDelete(0);
        user.setRegistTime(new Date());

        userService.saveUser(user);
        return JSONResult.ok("保存成功");
    }

    @RequestMapping("/updateUser")
    public JSONResult updateUser() {
        User user = new User();
        user.setId("10011001");
        user.setUsername("10011001-updated" + new Date());
        user.setNickname("10011001-updated" + new Date());
        user.setPassword("10011001-updated");
        user.setIsDelete(0);
        user.setRegistTime(new Date());

        userService.updateUser(user);
        return JSONResult.ok("保存成功");
    }


    @RequestMapping("/deleteUser")
    public JSONResult deleteUser(String userId) {
        userService.deleteUser(userId);
        return JSONResult.ok("刪除成功");
    }

    @RequestMapping("/queryUserById")
    public JSONResult queryUserById(String userId) {
        return JSONResult.ok(userService.queryUserById(userId));
    }
}

 

3、測試

在瀏覽器輸入controller裏面定義的路徑即可。只要你按照上面的步驟一步一步來,基本上就沒問題,是不是特別簡單。

 

 

最後

以上,就把Spring Boot整合Mybatis註釋版 實現增刪改查介紹完了,Spring Boot 整合Mybatis 是整個Spring Boot 非常重要的功能,也是非常核心的基礎功能,希望大家能夠熟練掌握。後面會深入介紹Spring Boot的各個功能和用法。

這個系列課程的完整源碼,也會提供給大家。大家關注我的微信公眾號(架構師精進),回復:springboot源碼。獲取這個系列課程的完整源碼。

 

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

【大廠面試08期】談一談你對HashMap的理解?

摘要

HashMap的原理也是大廠面試中經常會涉及的問題,同時也是工作中常用到的Java容器,本文主要通過對以下問題進行分析講解,來幫助大家理解HashMap的原理。

1.HashMap添加一個鍵值對的過程是怎麼樣的?

2.為什麼說HashMap不是線程安全的?

3.為什麼要一起重寫hashCode()和equal()方法?

HashMap添加一個鍵值對的過程是怎麼樣的?

這是網上找的一張流程圖,可以結合著步驟來看這個流程圖,了解添加鍵值對的過程。

1.初始化table

判斷table是否為空或為null,否則執行resize()方法(resize方法一般是擴容時調用,也可以調用來初始化table)。

2.計算hash值

根據鍵值key計算hash值。(因為hashCode是一個int類型的變量,是4字節,32位,所以這裡會將hashCode的低16位與高16位進行一個異或運算,來保留高位的特徵,以便於得到的hash值更加均勻分佈)

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

3.插入或更新節點

根據(n – 1) & hash計算得到插入的數組下標i,然後進行判斷

table[i]==null

那麼說明當前數組下標下,沒有hash衝突的元素,直接新建節點添加。

table[i].hash == hash &&(table[i]== key || (key != null && key.equals(table[i].key)))

判斷table[i]的首個元素是否和key一樣,如果相同直接更新value。

table[i] instanceof TreeNode

判斷table[i] 是否為treeNode,即table[i] 是否是紅黑樹,如果是紅黑樹,則直接在樹中插入鍵值對。

其他情況

上面的判斷條件都不滿足,說明table[i]存儲的是一個鏈表,那麼遍歷鏈表,判斷是否存在已有元素的key與插入鍵值對的key相等,如果是,那麼更新value,如果沒有,那麼在鏈表末尾插入一個新節點。插入之後判斷鏈表長度是否大於8,大於8的話把鏈錶轉換為紅黑樹。

4.擴容

插入成功后,判斷實際存在的鍵值對數量size是否超多了最大容量threshold(一般是數組長度*負載因子0.75),如果超過,進行擴容。

源代碼如下:

2.為什麼說HashMap不是線程安全的?

其實通過學習HashMap添加鍵值對的方法,我們可以看到整個方法內都沒有使用到鎖,所以一旦多線併發訪問,就有可能造成數據不一致的問題,

例如:

如果有兩個添加鍵值對的線程都執行到if ((tab = table) == null || (n = tab.length) == 0)這行語句,都對table變量進行數組初始化,就會造成已經初始化好的數組table被覆蓋,然後前面初始化的線程會將鍵值對添加到之前初始化的數組中去,造成鍵值對丟失。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // tab為空則創建 
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    ...後面的代碼省略
}

3.為什麼要一起重寫hashCode()和equal()方法?

當我們的對象一旦作為HashMap中的key,或者是HashSet中的元素使用時,就必須同時重寫hashCode()和equal()方法

首先看看hashCode()和equal()方法的默認實現

可以看到Obejct類中的源碼如下,可以看到equals()方法的默認實現是判斷兩個對象的內存地址是否相同來決定返回結果。

    public native int hashCode();
	public boolean equals(Object obj) {
        return (this == obj);
    }

網上很多博客說hashCode的默認實現是返回內存地址,其實不對,以OpenJDK為例,hashCode的默認計算方法有5種,有返回隨機數的,有返回內存地址,具體採用哪一種計算方法取決於運行時庫和JVM的具體實現。

感興趣的朋友可以看看這篇博客
https://blog.csdn.net/xusiwei1236/article/details/45152201

然後看看hashCode()方法,equal()方法在HashMap中的應用

static final int hash(Object key) {
    int h;
    //因為hashCode是一個int類型的變量,是4字節,32位,所以這裡會將hashCode的低16位與高16位進行一個異或運算,來保留高位的特徵,以便於得到的hash值更加均勻分佈
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

為了將一組鍵值對均勻得存儲在一個數組中,HashMap對key的hashCode進行計算得到一個hash值,用hash對數組長度取模,得到數組下標,將鍵值對存儲在數組下標對應的鏈表下(假設鏈表長度小於8,沒有達到轉換為紅黑樹的閥值)。

下面是添加鍵值對的putVal()方法,當數組下標對應的是一個鏈表時執行的代碼

//遍歷鏈表
for (int binCount = 0; ; ++binCount) {
    if ((e = p.next) == null) {//已經遍歷到鏈表末尾,說明鏈表不存在這個key
        p.next = newNode(hash, key, value, null);//在末尾添加這個鍵值對
        if (binCount >= TREEIFY_THRESHOLD - 1) //超過鏈錶轉化為紅黑樹的閥值(也急速鏈表長度》=8)
            treeifyBin(tab, hash);
        break;
    }
    if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        break;
    p = e;
}

可以清楚地看到判斷添加的key與鏈表中已存在的key是否相等的方法主要是e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))),
也就是:
1.先判斷hash值是否相等,不相等直接結束判斷,因為hash值不相等,key肯定不相等。
2.判斷兩個key對象的內存地址是否相等(相等指向內存中同一個對象)。
3.key不為null,調用key的equal()方法判斷是否相等,因為有可能兩個key在內存中存儲的地址不一樣,但是是相等的。
就像是

String a = new String("test");
String b = new String("test");

System.out.println("a==b is "+a==b);//打印為false
System.out.println("a.equals(b) is "+a.equals(b));//打印為true

背景

假設我們有一個KeyObject類,假設我們認為兩個KeyObject的屬性a相等,那麼KeyObject就是相等的相等的,我們將KeyObject作為HashMap的key,以KeyObject是否相等作為去重標準,不能重複添加KeyObject相等,value不等的值到HashMap中去

public static class KeyObject {
    Integer a;
    public KeyObject(Integer a) {
        this.a = a;
    }
}

假設都hashCode()方法和equals()方法都不重寫(結果:HashMap無法保證去重)

執行以下代碼:

public static void main(String[] args) {
    KeyObject key1 = new KeyObject(1);
    KeyObject key2 = new KeyObject(1);
    System.out.println("key1的hashCode為"+ key1.hashCode());
    System.out.println("key2的hashCode為" + key2.hashCode());
    System.out.println("key1.equals(key2)的結果為"+(key1.equals(key2)));
    HashMap<KeyObject,String> hashMap = new HashMap<KeyObject,String>();
    hashMap.put(key1,"value1");
    hashMap.put(key2,"value2");
    //打印hashMap
    for(KeyObject key :hashMap.keySet()){
        System.out.println("KeyObject.a="+key.a+" : "+hashMap.get(key));
    }
}

如果KeyObject的hashCode()方法和equals()方法都不重寫,那麼即便KeyObject的屬性a都是1,key1和key2的hashCode都是不相同的,key1和key2調用equals()方法也不相等,這樣hashMap中就可以同時存在key1和key2了。

打印結果:

key1的hashCode為728890494
key2的hashCode為1558600329
key1.equals(key2)的結果為false
KeyObject.a=1 : value1
KeyObject.a=1 : value2

假如只重寫hashCode()方法(結果:無法正確地與鏈表元素進行相等判斷,從而無法保證去重)

執行以下代碼:

 public static class KeyObject {
    Integer a;
    public KeyObject(Integer a) {
        this.a = a;
    }

    @Override
    public int hashCode() {
        return a;
    }

    public static void main(String[] args) {
        KeyObject key1 = new KeyObject(1);
        KeyObject key2 = new KeyObject(1);
        System.out.println("key1的hashCode為"+ key1.hashCode());
        System.out.println("key2的hashCode為" + key2.hashCode());
        System.out.println("key1.equals(key2)的結果為"+(key1.equals(key2)));
        HashMap<KeyObject,String> hashMap = new HashMap<KeyObject,String>();
        hashMap.put(key1,"value1");
        hashMap.put(key2,"value2");
        for(KeyObject key :hashMap.keySet()){
            System.out.println("TestObject.a="+key.a+" : "+hashMap.get(key));
        }
    }
}

此時equal()方法的實現是默認實現,也就是當兩個對象的內存地址相等時,equal()方法才返回true,雖然key1和key2的a屬性是相同的,但是他們在內存中是不同的對象,所以key1==key2結果會是false,KeyObject的equals()方法默認實現是判斷兩個對象的內存地址,所以 key1.equals(key2)也會是false,所以這兩個鍵值對可以重複地添加到hashMap中去。

輸出結果:

key1的hashCode為1
key2的hashCode為1
key1.equals(key2)的結果為false
TestObject.a=1 : value1
TestObject.a=1 : value2

假如只重寫equals()方法(結果:映射到HashMap中不同數組下標,無法保證去重)

public static class KeyObject {
    Integer a;
    public KeyObject(Integer a) {
        this.a = a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        KeyObject keyObject = (KeyObject) o;
        return Objects.equals(a, keyObject.a);
    }

    public static void main(String[] args) {
        KeyObject key1 = new KeyObject(1);
        KeyObject key2 = new KeyObject(1);
        System.out.println("key1的hashCode為"+ key1.hashCode());
        System.out.println("key2的hashCode為" + key2.hashCode());
        System.out.println("key1.equals(key2)的結果為"+(key1.equals(key2)));
        HashMap<KeyObject,String> hashMap = new HashMap<KeyObject,String>();
        hashMap.put(key1,"value1");
        hashMap.put(key2,"value2");
        for(KeyObject key :hashMap.keySet()){
            System.out.println("TestObject.a="+key.a+" : "+hashMap.get(key));
        }
    }
}

假設只equals()方法,hashCode方法會是默認實現,具體的計算方法取決於JVM,(測試時發現是內存地址不同但是相等的對象,它們的hashCode不相同),所以計算得到的數組下標不相同,會存儲到hashMap中不同數組下標下的鏈表中,也會導致HashMap中存在重複元素。

輸出結果如下:

key1的hashCode為1289479439
key2的hashCode為6738746
key1.equals(key2)的結果為true
TestObject.a=1 : value1
TestObject.a=1 : value2

總結

所以當我們的對象一旦作為HashMap中的key,或者是HashSet中的元素使用時,就必須同時重寫hashCode()和equal()方法,因為hashCode會影響key存儲的數組下標及與鏈表元素的初步判斷,equal()是作為判斷key與鏈表中的key是否相等的最後標準。

  • 所以只重寫hashCode()方法,會導致無法正確地與鏈表元素進行相等判斷,從而無法保證去重)
  • 只重寫equals()方法導致鍵值對映射到HashMap中不同數組下標,無法保證去重

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準

Spring Boot 把 Maven 幹掉了,擁抱 Gradle!

在國外某社交網站上有一個關於遷移 Spring Boot 遷移 Maven 至 Gradle 的帖子:

該貼子上也有很多人質疑:Maven 用的好好的,為什麼要遷移至 Gradle?

雖然該貼子只是說 Gradle 牛逼,但並沒有說遷移至 Gradle 所帶來的影響和價值。

所以,Spring Boot 官方對此也發了博文作了解釋:

https://spring.io/blog/2020/06/08/migrating-spring-boot-s-build-to-gradle

棧長簡單概括一下。

沒錯,Spring Boot 做了一個重大調整:

在 Spring Boot 2.3.0.M1 中,將首次使用 Gradle 代替 Maven 來構建 Spring Boot 項目。

為什麼要遷移?

Spring Boot 團隊給出的主要原因是,遷移至 Gradle 可以減少構建項目所花費的時間

因為使用 Maven 構建,回歸測試時間太長了,等待項目構建大大增加了修復 bug 和實現新特性的時間。

而 Gradle 的宗旨是減少構建工作量,它可以根據需要構建任何有變化的地方或者并行構建。

當然,Spring Boot 團隊也花了很多時間來嘗試用 Maven 進行 并行構建,但因為構建 Spring Boot 項目的複雜性,最終失敗了。

另外,Spring Boot 團隊也看到了在其他 Spring 項目中使用 Gradle 以及并行構建所帶來的提升,並且還可以使用 Gradle 在一些第三方項目上的構建緩存,這些優勢都促使 Gradle 帶到構建 Spring Boot 項目中來。

遷移有什麼好處?

棧長使用 Maven,哪怕只改一個代碼也是構建全部,構建項目確實要花不少時間。

Spring Boot 官方也給出了數據,一次完整的 Maven 項目構建一般需要一個小時或者以上,而在過去的 4 周時間內,使用 Gradle 構建的平均時間只用了 9 分 22 秒!!!

如下面截圖所示:

光從構建時間來看,效率真是倍數級的。

https://github.com/spring-projects/spring-boot/tree/v2.3.0.RELEASE

棧長特意去看了下,在 Spring Boot 2.2.8 中使用的是 Maven:

而最新發布的 Spring Boot 2.3.1 已經是切換到 Gradle 了:

會帶來什麼影響?

也許會有小夥伴質疑,Spring Boot 遷移到了 Gradle,會不會對公司現有的 Maven 項目或者後續的版本升級造成影響?

如果你只是使用 Spring Boot 框架來搭建系統,那還是可以繼續使用 Maven 來管理依賴的,Spring Boot 會繼續在 Maven 中央倉庫提交。

如下面所示:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot</artifactId>
    <version>2.3.1.RELEASE</version>
</dependency>

因為當版本確定之後,這個 Maven 構建只是一次性的,不會影響 Spring Boot 團隊的日常迭代效率。

但是,如果我們需要在本地構建 Spring Boot 源碼,或者你正在學習最新 Spring Boot 源碼,就需要掌握 Gradle 構建了。

題外話,Gradle 肯定是未來的趨勢,但也不一定非得遷移至 Gradle,只有適合自己的才是最好的,畢竟現在 Maven 和 Gradle 都是主流,但是 Maven 更佔有市場,很多主流開源項目都是以 Maven 依賴來作為示例演示的。

棧長也會陸續關注 Spring Boot 動態,後續也會給大家帶來各方面的教程,獲取歷史教程可以在Java技術棧公眾號後台回復:boot,掌握 Spring Boot 問題不大。

學習、從不止步。

推薦去我的博客閱讀更多:

1.Java JVM、集合、多線程、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、後端、架構、阿里巴巴等大廠最新面試題

覺得不錯,別忘了點贊+轉發哦!

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

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

※超省錢租車方案