分類
發燒車訊

電動車需求高、鋰價漲,澳洲Orocobre擴產

澳洲礦商Orocobre Limited聲稱鋰礦需求強、報價攀高,將擴產碳酸鋰,消息傳來激勵股價在8月31日飆高。

Barron’s.com、The Australian報導,Orocobre公布的全年度財報首度轉虧為盈,淨利來到1,940萬美元、遠優於去年的淨損2,200萬美元,而用於電池等工業產品的碳酸鋰,也將擴充產能。

Orocobre估計,2018會計年度的碳酸鋰產出,將從2017年度的11,862公噸擴充到14,000公噸,而2018年度的碳酸鋰均價,每噸則有望超過1萬美元。該公司在2017年度共計售出12,296公噸的碳酸鋰,每噸均價為9,763美元,4-6月當季的均價則是10,696美元,生產成本為3,710美元。

執行長Richard Seville說,全球鋰礦市場的基本面依舊穩健,不但需求強勁、供給吃緊,報價也相當具有吸引力。為了滿足特定電池夥伴的需求,Orocobre會分階段擴充Olaroz鋰礦廠的產能。

依據Orocobre計畫,位於阿根廷的Olaroz鋰礦廠,產能料將倍增。另外,該公司還會跟豐田通商(Toyota Tsusho Corporation)一同打造一座廠房,預計將年產10,000公噸的氫氧化鋰(lithium hydroxide)。

採用鋰電池的電動車需求日增、電池榮景全無降溫跡象,隨著鋰礦供給愈來愈難尋、未來恐有短缺之虞。

OilPrice.com 8月22日報導,特斯拉(Tesla Inc.)內華達州的Gigafactory超級電池廠,估計一年要生產50萬顆車用電池,另外還有諸多車用鋰電池廠也在加緊趕工,顯示未來鋰礦的需求將只增不減,且大部分將來自中國。全球如今有51%的鋰電池是在中國生產,僅10%產自美國。據統計,大陸業者規劃中的車用電池廠,產能預料會在2021年底前達到120億瓦小時(GW hours),是特斯拉內華達州電池廠的三倍之多。

然而,採集鋰礦在技術上其實有相當難度,成本不但高昂,且由於採礦過程牽涉到蒸餾法,產出也頗難預估。Orocobre在阿根廷北部設立的新礦場,鋰礦產出就比預期少逾20%。

假如鋰礦產能無法順利擴充、或是新開礦場產出不如預期,那麼電動車的榮景可能因而受阻。Electrek報導,福斯汽車(Volkswagen)研發部主管Ulrich Eichhorn 6月底就曾預估,業界需要多達40座規模跟特斯拉Gigafactory類似的超大電池廠,才能滿足電動車需求,假如新建礦場、工廠無法如期上線,那麼市場恐陷入短缺。

(本文內容由授權使用。圖片出處:public domain CC0)

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

分類
發燒車訊

谷歌打擊流氓索權APP:限制第三方移動軟件訪問用戶數據

  騰訊科技訊,手機軟件的“流氓索權”行為遭到了全球輿論的炮轟,媒體譴責流氓軟件大肆採集用戶的隱私信息,侵犯消費者權益。據外媒最新消息,谷歌最近宣布了一項新政策,對於違規採集手機短信和通話記錄的軟件,將做出撤架的懲罰。谷歌也將允許通話有關的軟件,繼續訪問用戶數據。

  據國外媒體報道,為了應對谷歌社交網絡 Google+ 之前爆出的隱私漏洞,該公司宣布了“閘門計劃”,準備限制第三方移動軟件訪問用戶數據,保護消費者隱私權已。

  谷歌規定,在安卓操作系統中,只有特定的客戶端軟件才能夠訪問用戶的短信和通話記錄。據報告,谷歌日前正式對外宣布,該公司將很快開始刪除發現違反規定的 Play 軟件商店中的應用程序。

  在很大程度上,谷歌希望將安卓手機上的短信記錄和通話歷史訪問權限限定於特定的安卓軟件,其中包括短信工具和撥號軟件。谷歌準備限制其他和通信功能無關的應用軟件採集用戶的通信歷史。

  谷歌公司表示:“我們的新政策旨在確保請求這些權限的應用程序對敏感數據進行全面和持續的訪問,以完成應用程序的主要使用功能,並確保用戶理解為什麼應用程序需要這些數據才能運行。”

  自去年 10 月以來,谷歌一直通過电子郵件與安卓應用軟件開發者聯繫,給他們 90 天的時間讓他們的應用程序符合最新規定的要求,或者請求谷歌破例待遇。谷歌規定允許開發人員在 3 月 9 日之前進行軟件更新,調整採集用戶數據的權限。

  該公司日前分享了在法規遵循方面的一些進展,包括最近幾個月如何根據開發人員的反饋擴展批準的應用軟件清單。“數以萬計的開發人員”要麼更新了應用程序以遵循新的政策,要麼請求擴展。谷歌還指出,它自己的應用程序也遵循同樣的標準。據悉,對破例情況進行審查的過程如下:

  ——普通用戶可能會理解為什麼這類應用程序需要完全訪問數據。

  ——該功能的用戶優勢。

  ——與應用程序的核心功能相關的權限的重要性。

  ——使用此用例的所有應用程序都存在訪問此敏感數據的風險。

  ——啟用該功能的備選方案的可用性。

  雖然某些使用功能不再被允許,但谷歌公司指出,該公司審核的許多安卓應用軟件,可以通過一個範圍更窄的軟件開發接口(API)來實現軟件的某些功能,而不是要求獲得訪問用戶隱私的權限。

  谷歌舉例說,使用短信功能進行用戶身份認證的開發人員可以選擇使用 SMS Shareever API,而希望使用短信功能共享內容的應用程序可以預先填充一條消息,並觸發默認的 SMS 應用程序加以显示。

  谷歌也表示,與此同時,未請求功能擴展的安卓應用程序將在“未來幾周內”從谷歌 Play 軟件商店中刪除。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

分類
發燒車訊

格力董事會今天換屆:董明珠能否連任 隱憂利好共存

  成都商報

  今天,格力電器(000651.SZ)2019 年第一次臨時股東大會即將召開,拖延了 7 個月的董事會換屆將至。在這 7 個月里,董明珠遇到了銀隆新能源的“黑天鵝”,也贏得了與雷軍的“5 年之賭”,隱憂與利好同在。

  董明珠能否在臨時股東大會拿下董事會董事資格,將直接影響她能否連任董事長職務。

  格力電器現任(第十屆)董事會原本應於 2018 年 5 月 31 日任期屆滿。當時,格力電器公告稱,鑒於公司新一屆董事會、監事會的董事、監事候選人提名工作仍在進行中,公司董事會、監事會換屆選舉工作將適當延期。

  7 個月後,今年 1 月 2 日,格力才公布候選董事的名單,並公告稱 1 月 16 日召開公司 2019 年第一次臨時股東大會,就上述董事提名人選進行表決。

  根據格力電器《公司章程》,董事由出席股東大會的半數股東投票通過;公司董事會設董事長一人,副董事長一人,董事長和副董事長由董事會以全體董事的過半數選舉產生。

  也就是說,如果想要連任董事長,董明珠需要在 1 月 16 日拿下董事會董事資格,再拿下新一屆董事會一半的票數。

  新一屆格力電器候選董事 9 人,比上屆增加兩人。其中,獨立董事仍為 3 人;非獨立董事從 4 人增至 6 人。

  成都商報-紅星新聞記者梳理髮現,這六名候選非獨立董事幾乎都來自格力電器的高管層,或是有格力電器背景的格力集團高管或一致行動人。其中,格力電器的大股東格力集團推薦了四位,分別是董明珠、黃輝、望靖東和張偉。

  黃輝是格力電器執行總裁,望靖東是格力電器副總裁、財務負責人和董事會秘書,張偉現任格力集團常務副總裁。另外,京海擔保提名的兩個格力電器非獨立候選董事張軍督與郭書戰,也都是董明珠一手搭建的格力電器經銷商體系的中堅力量。

  而三位格力電器獨立董事候選人,分別是中央財經大學中國企業研究中心主任、萬科獨立董事劉姝威,西安交通大學流體机械及壓縮機國家工程中心副主任、教授邢子文,以及廣東廣信君達律師事務所主任王曉華。

  三大隱憂

  銀隆內鬥、分紅危機、芯片困局

  從 2018 年 5 月 31 日任期屆滿至今,已過去 7 個多月。為何換屆董事會遲遲未開?有說法稱,董明珠當時自認無連任把握,延期是為了爭取時間創造連任條件。也有說法稱,董明珠作為銀隆新能源的大股東,與格力掌門人的身份有衝突,對連任不利。

  記者梳理髮現,銀隆新能源確為董明珠連任路上的隱憂。

  2016 年 8 月,格力電器曾宣布擬以 130 億元的價格收購珠海銀隆(后更名為“銀隆新能源”)100% 股權。但方案引起部分中小股東強烈反對,最終被否決。

  此後,董明珠以個人名義投資銀隆新能源,天眼查显示,董明珠實際出資為 1.92 億元,是銀隆新能源的第二大股東。隨後,多名“格力系”員工接手了銀隆新能源核心業務的分管副總裁。

  兩年過去了,成都已有多輛帶有“銀隆新能源”標誌的公交車穿行,董明珠卻陷入了銀隆新能源的困局之中。在 2018 年年初,珠海銀隆就被曝出拖欠供應商貨款至少 12 億元。此後,騙補、欠款、停工、裁員、資金鏈斷裂等負面消息不斷出現。

  近期,董明珠又被爆出與銀隆大股東的內鬥羅生門。2018 年 11 月 6 日,銀隆新能源第一大股東銀隆集團向北京西城區法院申請,對拓金資本管理有限公司、董明珠名下價值 1436.2329 萬元的財產採取保全措施;2019 年 1 月 9 日,銀隆新能源又在微信公眾號曬出魏銀倉等大股東冒領補償、職務侵佔等“七宗罪”。

  除了造車,做芯片也成了董明珠連任路上的“刺”。

  2016 年 4 月,董明珠表示,格力正在研究芯片。2016 年年報中,格力首次披露要研發自主知識產權的芯片。在此後的多個場合,董明珠堅稱,即使股票下跌,格力也是真的要“搞芯片”。

  一邊,董明珠對造車和做芯片都有放不下的執念;另一邊,諸多投資者並不買賬。在格力電器宣布 2017 年度將加大集成電路的資本開支后,股價大跌。

  因為要加大投入“搞芯片”,2017 年的年度股東大會上,董明珠宣布,在連續分紅十年後,格力將首次不分紅,引起市場一片嘩然。

  三大利好

  閨蜜護航、員工漲薪、訴諸法律

  成都商報-紅星新聞記者注意到,從 1 月 2 日公布董事候選名單至今,董明珠與格力的新聞不斷。

  實際上,候選董事的名單公布的本身,就被認為是對於董明珠連任的“利好”消息。在外界看來,黃輝、望靖東、張偉、張軍督、郭書戰等人均不足以對董明珠連任構成競爭,作為格力的“老同事”,他們更有可能表達對董明珠的支持。

  此外,獨立董事候選人之一的劉姝威更是自稱董明珠的好“閨蜜”,多次在公開場合力挺董明珠。不過,劉姝威被提名格力電器獨立董事後,也有市場人士質疑,她能否真正站在獨立董事“獨立”的立場?“作為董明珠的閨蜜,劉姝威作為格力電器的獨立董事,能否保持獨立性是一個現實問題。”著名財經評論人皮海洲稱。

  另外,“格力漲薪”的新聞也不斷霸佔各大網站的頭條。1 月 8 日,格力電器下發內部文件,宣布全員從 2019 年 1 月開始漲薪,總增加薪酬在 10 億元以內。加薪幅度在人均 1000 元左右。

  除了這些好消息,面對“一攤渾水”的銀隆新能源,董明珠還向大股東魏銀倉等人出招——1 月 9 日,銀隆新能源在官方公眾號公布魏銀倉等人涉嫌冒領補償、職務侵佔等“七宗罪”,稱相關刑事案件已於 2018 年 11 月 8 日正式立案,四起民事案件正等待排期開庭,涉及侵佔公司利益總額超過 12 億元。“以上案件,公司已經掌握並提供確鑿證據。目前,公司仍在繼續核查除上述案件外的大股東、原董事長魏銀倉及原總經理孫國華等侵佔公司利益事項,將通過法律手段挽回損失。”銀隆新能源稱。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

分類
發燒車訊

特斯拉「電池交換技術」新專利曝光,為將推出的電動連結車鋪路?

 

最近,汽車廠商特斯拉(Tesla)於4 月底新申請的「電池交換系統與技術」專利在外媒報導中爭相曝光,引起不少議論。如果你在趕路中,但汽車電力已經見底,你可以選擇到電池交換站,讓技術人員在15 分鐘內幫你更換好全車電池組,取代前往超級充電站也需等待至少半小時的充電時間。不過這項技術對於充電站點挺充足的美國來說,客戶們似乎不太買單?也許真的有時間壓力的商業卡車會更為青睞。

其實,特斯拉在2013 年就曾現場展示Model S 車款的快速電池互換技術,只要90 秒就能換上充滿電的電池重新上路,執行長Elon Musk 事後謙稱這只是處於測試階段,無法和主流充電市場抗衡,但從特斯拉到了今年還在申請電池交換的新專利就知道,他們顯然一直沒有放棄直接更換電池這條路。

在4 月底提交的這份新專利中,特斯拉描述了一種類似於「汽車升降架」的概念,利用液壓升降機將車子托高之後,由技術人員從車底下「手動」幫車輛進行全車電池組更換,取代了之前的「自動」電池交換設計理念。

(source:)

外媒《Clean Technica》將這項技術描述為「快速交換電能儲存系統(quick-swap Electric Energy Storage System ,縮寫EESS)」,專利明確提到Model X 和Model S 的電池組都可以進行更換,但沒有提及Model 3,外界猜測或許還是可以和系統相容。而目前看來,電池交換系統可以考慮設置在遠途道路上(如兩個城市之間的高速公路),確保車輛一路行駛過來都不會有斷電風險。

不過,由於充電站推行在美國非常成功,更習慣進充電站邊「加油」邊休息聊天的特斯拉客戶們,對於電池更換技術並沒有表現出太熱衷的態度,Elon Musk 之前在提到電池互換策略時也曾表示,如果真的要落實這項技術,最可能推及的是商業車,這讓外界專家紛紛預測它很可能支持特斯拉即將在10 月26 日推出的電動聯結車(semi-truck),不過這一點尚未經官方確認。

(合作媒體:。圖片出處:)  

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

分類
發燒車訊

中國推「雙積分」發展新能源車,明年4月起實施

新華社報導,中國工信部等五部委於9月28日聯合發布《乘用車企業平均燃料消耗量與新能源汽車積分並行管理辦法》(簡稱:「雙積分」管理辦法),擬從兩個方面進行積分核算管理,並納入準入條件;積分為負且未抵償歸零的企業,將調整生產或進口計畫。該辦法自2018年4月1日起實施,中國境內乘用車生產企業、進口乘用車供應企業一視同仁;而有關先前市場熱議的禁售燃油車時間表一事則未提及。

截至2016年底,中國汽車保有量達到1.94億輛,車用汽柴油占全國汽柴油消費70%以上。中國工信部表示,為緩解能源與環境壓力,促進節能與新能源汽車產業發展的要求,辦法中建立積分核算制度和積分管理平台,明確積分核算方法,有條件地放寬小規模企業的燃料消耗量達標要求;對傳統能源乘用車年度生產量或進口量不滿3萬輛的乘用車企業,則不設定新能源汽車積分比例要求。

2019年度、2020年度,新能源汽車積分比例要求分別為10%、12%;2021年度及以後年度的新能源汽車積分比例要求,由中國工信部另行公佈。

另外,對積分計算和轉讓問題,辦法中提出,建立積分交易機制,由企業自主確定負積分抵償方式;企業平均燃料消耗量積分中,正積分可按照80%或者90%的比例結轉後續年度使用,也可在關聯企業間轉讓;新能源汽車積分中,正積分可自由交易,但不得結轉。

(本文內容由授權使用。圖片出處:public domain CC0)

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

分類
發燒車訊

印度政府宣布向Tata Motors採購1萬輛電動車

 

Thomson Reuters報導,印度政府9月29日宣布向Tata Motors Ltd採購1萬輛電動車、未來3到4年將用來分批汰換原有的公務車。Tata Motors將自11月起分兩階段供應電動車。印度政府約有50萬輛公務車。

英國最大汽車製造商Jaguar Land Rover(Tata Motors子公司)9月7日宣布,2020年起旗下所有新車都將具備電動或油電混合驅動選項。英國跟隨法國以及馬德里、墨西哥城和雅典等城市的抗空汙腳步,7月宣布將自2040年起禁止販售汽油和柴油新車。

livemint.com 9月30日報導,Tata第一批電動車將在今年11月交送給印度政府旗下合資企業「能源效率服務有限公司(Energy Efficiency Services Limited;EESL)」。

(本文內容由授權使用。圖片出處:public domain CC0)

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

分類
發燒車訊

不看好歐洲純電動車市場,BMW 高層:監管機構想要,但沒有顧客真的需要

電動車已成為多數車商的發展趨勢,然而近日在慕尼黑舉行的 NextGen 活動期間,BMW 執行董事 Klaus Fröhlich 卻語出驚人的表示,他認為電動車轉型被過度吹捧,實際上消費者對這些車輛根本沒有需求。

考量到 BMW 日前才宣布將加速純電動車發展計畫,Fröhlich 的發言看似大膽,但其實並非沒有道理。據了解,這項發言主要是針對遊說團體 Transport and Environment 日前公開譴責歐洲車商的回應。

該篇報告 T&E 引述 EEA 的最新排氣數據,指出歐洲在電動車銷售明顯落後中美兩國,主要原因是市場純電動車的選擇和可用性都受侷限,而 T&E 認為,這是因為歐洲車商故意推遲純電動車的銷售計畫,好最大程度提高燃油車的利潤,「在環境方面,車商只會做法律規定他們要做的事情」。

對這項指控,Fröhlich 表示,他認為 T&E 忽略了最重要的問題:那就是歐洲客戶實際上並不想買純電動車。

Fröhlich 解釋,與美國人為不同目的駕駛不同車輛的習慣不同,歐洲人通常是「單車家庭」,車庫中只會有一輛車使用,因此他們並不願完全依賴純電動車,不應該拿美國的市場情況來比較。

除此之外,還有充電基礎設施的普及問題,Fröhlich 認為,柴油引擎至少還有 20 年、汽油引擎至少還有 30 年,即使是俄羅斯、中東、中國中西部地區這些市場,在缺乏基礎建設下,燃油引擎都至少還有 10~15 年時間。

「純電動車只適用中國、美國加州市場,至於其他地方,有更大電池的混合式動力車應該是更好的選擇。」

除了基礎設施普及,Fröhlich 也指出,在電池原始材料,純電動車的成本要遠高於燃油或混合動力車,隨著未來市場對電池原料的需求增加,一旦供應鏈無法支持,那麼價格可能只會有增無減。

Fröhlich 表示,如果政府能提供許多協助,BMW 可生產足以淹沒歐洲的百萬台純電動車,但在他看來,歐洲人並不想買這些東西,「監管機構想要純電動車,但沒有顧客真的需要。」

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

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

分類
發燒車訊

.NET高級特性-Emit(2)類的定義,.NET高級特性-Emit(1)

  在上一篇博文發了一天左右的時間,就收到了博客園許多讀者的評論和推薦,非常感謝,我也會及時回復讀者的評論。之後我也將繼續撰寫博文,梳理相關.NET的知識,希望.NET的圈子能越來越大,開發者能了解/深入.NET的本質,將工作做的簡單又高效,拒絕重複勞動,拒絕CRUD。

  ok,咱們開始繼續Emit的探索。在這之前,我先放一下我往期關於Emit的文章,方便讀者閱讀。

  《》

一、基礎知識

  既然C#作為一門面向對象的語言,所以首當其沖的我們需要讓Emit為我們動態構建類。

  廢話不多說,首先,我們先來回顧一下C#類的內部由什麼東西組成:

  (1) 字段-C#類中保存數據的地方,由訪問修飾符、類型和名稱組成;

  (2) 屬性-C#類中特有的東西,由訪問修飾符、類型、名稱和get/set訪問器組成,屬性的是用來控制類中字段數據的訪問,以實現類的封裝性;在Java當中寫作getXXX()和setXXX(val),C#當中將其變成了屬性這種語法糖;

  (3) 方法-C#類中對邏輯進行操作的基本單元,由訪問修飾符、方法名、泛型參數、入參、出參構成;

  (4) 構造器-C#類中一種特殊的方法,該方法是專門用來創建對象的方法,由訪問修飾符、與類名相同的方法名、入參構成。

  接着,我們再觀察C#類本身又具備哪些東西:

  (1) 訪問修飾符-實現對C#類的訪問控制

  (2) 繼承-C#類可以繼承一個父類,並需要實現父類當中所有抽象的方法以及選擇實現父類的虛方法,還有就是子類需要調用父類的構造器以實現對象的創建

  (3) 實現-C#類可以實現多個接口,並實現接口中的所有方法

  (4) 泛型-C#類可以包含泛型參數,此外,類還可以對泛型實現約束

  以上就是C#類所具備的一些元素,以下為樣例:

public abstract class Bar
{
    public abstract void PrintName();
}
public interface IFoo<T> { public T Name { get; set; } } //繼承Bar基類,實現IFoo接口,泛型參數T
public class Foo<T> : Bar, IFoo<T>
  //泛型約束
  where T : struct {
//構造器 public Foo(T name):base() { _name = name; } //字段 private T _name; //屬性 public T Name { get => _name; set => _name = value; } //方法 public override void PrintName() {
    Console.WriteLine(_name.ToString()); }
}

  在探索完了C#類及其定義后,我們要來了解C#的項目結構組成。我們知道C#的一個csproj項目最終會對應生成一個dll文件或者exe文件,這一個文件我們稱之為程序集Assembly;而在一個程序集中,我們內部包含和定義了許多命名空間,這些命令空間在C#當中被稱為模塊Module,而模塊正是由一個一個的C#類Type組成。

 

 

 

   所以,當我們需要定義C#類時,就必須首先定義Assembly以及Module,如此才能進行下一步工作。

二、IL概覽

   由於Emit實質是通過IL來生成C#代碼,故我們可以反向生成,先將寫好的目標代碼寫成cs文件,通過編譯器生成dll,再通過ildasm查看IL代碼,即可依葫蘆畫瓢的編寫出Emit代碼。所以我們來查看以下上節Foo所生成的IL代碼。

  

 

 

   從上圖我們可以很清晰的看到.NET的層級結構,位於樹頂層淺藍色圓點表示一個程序集Assembly,第二層藍色表示模塊Module,在模塊下的均為我們所定義的類,類中包含類的泛型參數、繼承類信息、實現接口信息,類的內部包含構造器、方法、字段、屬性以及它的get/set方法,由此,我們可以開始編寫Emit代碼了

三、Emit編寫

  有了以上的對C#類的解讀和IL的解讀,我們知道了C#類本身所需要哪些元素,我們就開始根據這些元素來開始編寫Emit代碼了。這裏的代碼量會比較大,請讀者慢慢閱讀,也可以參照以上我寫的類生成il代碼進行比對。

  在Emit當中所有創建類型的幫助類均以Builder結尾,從下錶中我們可以看的非常清楚

元素中文 元素名稱 對應Emit構建器名稱
程序集  Assembly AssemblyBuilder
模塊  Module ModuleBuilder
 Type TypeBuilder
構造器  Constructor ConstructorBuilder
屬性  Property PropertyBuilder
字段  Field FieldBuilder
方法  Method MethodBuilder

  由於創建類需要從Assembly開始創建,所以我們的入口是AssemblyBuilder

  (1) 首先,我們先引入命名空間,我們以上節Foo類為樣例進行編寫

using System.Reflection.Emit;

  (2) 獲取基類和接口的類型

var barType = typeof(Bar);
var interfaceType = typeof(IFoo<>);

  (3) 定義Foo類型,我們可以看到在定義類之前我們需要創建Assembly和Module

//定義類
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Edwin.Blog.Emit"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("Edwin.Blog.Emit");
var typeBuilder = moduleBuilder.DefineType("Foo", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit);

  (4) 定義泛型參數T,並添加約束

//定義泛型參數
var genericTypeBuilder = typeBuilder.DefineGenericParameters("T")[0];
//設置泛型約束
genericTypeBuilder.SetGenericParameterAttributes(GenericParameterAttributes.NotNullableValueTypeConstraint);

  (5) 繼承和實現接口,注意當實現類的泛型參數需傳遞給接口時,需要將泛型接口添加泛型參數后再調用AddInterfaceImplementation方法

//繼承基類
typeBuilder.SetParent(barType);
//實現接口
typeBuilder.AddInterfaceImplementation(interfaceType.MakeGenericType(genericTypeBuilder));

  (6) 定義字段,因為字段在構造器值需要使用,故先創建

//定義字段
var fieldBuilder = typeBuilder.DefineField("_name", genericTypeBuilder, FieldAttributes.Private);

  (7) 定義構造器,並編寫內部邏輯

//定義構造器
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { genericTypeBuilder });
var ctorIL = ctorBuilder.GetILGenerator();
//Ldarg_0在實例方法中表示this,在靜態方法中表示第一個參數
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
//為field賦值
ctorIL.Emit(OpCodes.Stfld, fieldBuilder);
ctorIL.Emit(OpCodes.Ret);

  (8) 定義Name屬性

//定義屬性
var propertyBuilder = typeBuilder.DefineProperty("Name", PropertyAttributes.None, genericTypeBuilder, Type.EmptyTypes);

  (9) 編寫Name屬性的get/set訪問器

//定義get方法
var getMethodBuilder = typeBuilder.DefineMethod("get_Name", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual, CallingConventions.Standard, genericTypeBuilder, Type.EmptyTypes);
var getIL = getMethodBuilder.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(getMethodBuilder, interfaceType.GetProperty("Name").GetGetMethod()); //實現對接口方法的重載
propertyBuilder.SetGetMethod(getMethodBuilder); //設置為屬性的get方法
//定義set方法
var setMethodBuilder = typeBuilder.DefineMethod("set_Name", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual, CallingConventions.Standard, null, new Type[] { genericTypeBuilder });
var setIL = setMethodBuilder.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, fieldBuilder);
setIL.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(setMethodBuilder, interfaceType.GetProperty("Name").GetSetMethod()); //實現對接口方法的重載
propertyBuilder.SetSetMethod(setMethodBuilder); //設置為屬性的set方法

   (10) 定義並實現PrintName方法

//定義方法
var printMethodBuilder = typeBuilder.DefineMethod("PrintName", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, CallingConventions.Standard, null, Type.EmptyTypes);
var printIL = printMethodBuilder.GetILGenerator();
printIL.Emit(OpCodes.Ldarg_0);
printIL.Emit(OpCodes.Ldflda, fieldBuilder);
printIL.Emit(OpCodes.Constrained, genericTypeBuilder);
printIL.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString", Type.EmptyTypes));
printIL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
printIL.Emit(OpCodes.Ret);
//實現對基類方法的重載
typeBuilder.DefineMethodOverride(printMethodBuilder, barType.GetMethod("PrintName", Type.EmptyTypes));

  (11) 創建類

var type = typeBuilder.CreateType(); //netstandard中請使用CreateTypeInfo().AsType()

  (12) 調用

var obj = Activator.CreateInstance(type.MakeGenericType(typeof(DateTime)), DateTime.Now);
(obj as Bar).PrintName();
Console.WriteLine((obj as IFoo<DateTime>).Name);

四、應用

  上面的樣例僅供學習只用,無法運用在實際項目當中,那麼,Emit構建類在實際項目中我們可以有什麼應用,提高我們的編碼效率

  (1) 動態DTO-當我們需要將實體映射到某個DTO時,可以用動態DTO來代替你手寫的DTO,選擇你需要的字段回傳給前端,或者前端把他想要的字段傳給後端

  (2) DynamicLinq-我的第一篇博文有個讀者提到了表達式樹,而linq使用的正是表達式樹,當表達式樹+Emit時,我們就可以用像SQL或者GraphQL那樣的查詢語句實現動態查詢

  (3) 對象合併-我們可以編寫實現一個像js當中Object.assign()一樣的方法,實現對兩個實體的合併

  (4) AOP動態代理-AOP的核心就是代理模式,但是與其對應的是需要手寫代理類,而Emit就可以幫你動態創建代理類,實現切面編程

  (5) …

五、小結

  對於Emit,確實初學者會對其感到複雜和難以學習,但是只要搞懂其中的原理,其實最終就是C#和.NET語言的本質所在,在學習Emit的同時,也是在鍛煉你的基本功是否紮實,你是否對這門語言精通,是否有各種簡化代碼的應用。

  保持學習,勇於實踐;Write Less,Do More;作者之後還會繼續.NET高級特性系列,感謝閱讀!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

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

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

分類
發燒車訊

Java虛擬機詳解(十)——類加載過程

  在上一篇文章中,我們詳細的介紹了Java,那麼這些Class文件是如何被加載到內存,由虛擬機來直接使用的呢?這就是本篇博客將要介紹的——類加載過程。

1、類的生命周期

  類從被加載到虛擬機內存開始,到卸載出內存為止,其聲明周期流程如下:

  

  上圖中紅色的5個部分(加載、驗證、準備、初始化、卸載)順序是確定的,也就是說,類的加載過程必須按照這種順序按部就班的開始。這裏的“開始”不是按部就班的“進行”或者“完成”,因為這些階段通常是互相交叉混合的進行的,通常會在一個階段執行過程中調用另一個階段。

2、加載

  “加載”階段是“類加載”生命周期的第一個階段。在加載階段,虛擬機要完成下面三件事:

  ①、通過一個類的全限定名來獲取定義此類的二進制字節流。

  ②、將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。

  ③、在Java堆中生成一個代表這個類的java.lang.Class對象,作為方法區這些數據的訪問入口。

  PS:類的全限定名可以理解為這個類存放的絕對路徑。方法區是JDK1.7以前定義的運行時數據區,而在JDK1.8以後改為元數據區(Metaspace),主要用於存放被Java虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。詳情可以參考這邊該系列的第二篇文章——。

  另外,我們看第一點——通過類的權限定名來獲取定義此類的二進制流,這裏並沒有明確指明要從哪裡獲取以及怎樣獲取,也就是說並沒有明確規定一定要我們從一個 Class 文件中獲取。基於此,在Java的發展過程中,充滿創造力的開發人員在這個舞台上玩出了各種花樣:

  1、從 ZIP 包中讀取。這稱為後面的 JAR、EAR、WAR 格式的基礎。

  2、從網絡中獲取。比較典型的應用就是 Applet。

  3、運行時計算生成。這就是動態代理技術。

  4、由其它文件生成。比如 JSP 應用。

  5、從數據庫中讀取。

  加載階段完成后,虛擬機外部的二進制字節流就按照虛擬機所需的格式存儲在方法區中,然後在Java堆中實例化一個 java.lang.Class 類的對象,這個對象將作為程序訪問方法區中這些類型數據的外部接口。

  注意,加載階段與連接階段的部分內容(如一部分字節碼文件的格式校驗)是交叉進行的,加載階段尚未完成,連接階段可能已經開始了。

3、驗證

  驗證是連接階段的第一步,作用是為了確保 Class 文件的字節流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。

  我們說Java語言本身是相對安全,因為編譯器的存在,純粹的Java代碼要訪問數組邊界外的數據、跳轉到不存在的代碼行之類的,是要被編譯器拒絕的。但是前面我們也說過,Class 文件不一定非要從Java源碼編譯過來,可以使用任何途徑,包括你很牛逼,直接用十六進制編輯器來編寫 Class 文件。

  所以,如果虛擬機不檢查輸入的字節流,將會載入有害的字節流而導致系統崩潰。但是虛擬機規範對於檢查哪些方面,何時檢查,怎麼檢查都沒有明確的規定,不同的虛擬機實現方式可能都會有所不同,但是大致都會完成下面四個方面的檢查。

①、文件格式驗證

  校驗字節流是否符合Class文件格式的規範,並且能夠被當前版本的虛擬機處理。

  一、是否以魔數 0xCAFEBABE 開頭。

  二、主、次版本號是否是當前虛擬機處理範圍之內。

  三、常量池的常量中是否有不被支持的常量類型(檢查常量tag標誌)

  四、指向常量的各種索引值中是否有指向不存在的常量或不符合類型的常量。

  五、CONSTANT_Utf8_info 型的常量中是否有不符合 UTF8 編碼的數據。

  六、Class 文件中各個部分及文件本身是否有被刪除的或附加的其他信息。

  以上是一部分校驗內容,當然遠不止這些。經過這些校驗后,字節流才會進入內存的方法區中存儲,接下來後面的三個階段校驗都是基於方法區的存儲結構進行的。

②、元數據驗證

  第二個階段主要是對字節碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規範要求。

  一、這個類是否有父類(除了java.lang.Object 類之外,所有的類都應當有父類)。

  二、這個類的父類是否繼承了不允許被繼承的類(被final修飾的類)。

  三、如果這個類不是抽象類,是否實現了其父類或接口之中要求實現的所有普通方法。

  四、類中的字段、方法是否與父類產生了矛盾(例如覆蓋了父類的final字段、或者出現不符合規則的重載)

③、字節碼驗證

  第三個階段字節碼驗證是整個驗證階段中最複雜的,主要是進行數據流和控制流分析。該階段將對類的方法進行分析,保證被校驗的方法在運行時不會做出危害虛擬機安全的行為。

  一、保證任意時刻操作數棧中的數據類型與指令代碼序列都能配合工作。例如不會出現在操作數棧中放置了一個 int 類型的數據,使用時卻按照 long 類型來加載到本地變量表中。

  二、保證跳轉指令不會跳轉到方法體以外的字節碼指令中。

  三、保證方法體中的類型轉換是有效的。比如把一個子類對象賦值給父類數據類型,這是安全的。但是把父類對象賦值給子類數據類型,甚至賦值給完全不相干的類型,這就是不合法的。

④、符號引用驗證

  符號引用驗證主要是對類自身以外(常量池中的各種符號引用)的信息進行匹配性的校驗,通常需要校驗如下內容:

  一、符號引用中通過字符串描述的全限定名是否能夠找到相應的類。

  二、在指定類中是否存在符合方法的字段描述符及簡單名稱所描述的方法和字段。

  三、符號引用中的類、字段和方法的訪問性(private、protected、public、default)是否可以被當前類訪問。

4、準備

  準備階段是正式為類變量分配內存並設置類變量初始值的階段,這些內存是在方法區中進行分配。

  注意:

  一、上面說的是類變量,也就是被 static 修飾的變量,不包括實例變量。實例變量會在對象實例化時隨着對象一起分配在堆中。

  二、初始值,指的是一些數據類型的默認值。基本的數據類型初始值如下(引用類型的初始值為null):

  

 

   比如,定義 public static int value = 123 。那麼在準備階段過後,value 的值是 0 而不是 123,把 value 賦值為123 是在程序被編譯后,存放在類的構造器方法之中,是在初始化階段才會被執行。但是有一種特殊情況,通過final 修飾的屬性,比如 定義 public final static int value = 123,那麼在準備階段過後,value 就被賦值為123了。

5、解析

  解析階段是虛擬機將常量池中的符號引用替換為直接引用的過程。

  符號引用(Symbolic References):符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義的定位到目標即可。符號引用與虛擬機實現的內存布局無關,引用的目標不一定已經加載到內存中。

  直接引用(Direct References):直接引用可以是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。直接引用是與虛擬機實現內存布局相關的,同一個符號引用在不同虛擬機實例上翻譯出來的直接引用一般不會相同。如果有了直接引用,那麼引用的目標必定已經在內存中存在。

  解析動作主要針對類或接口、字段、類方法、接口方法四類符號引用,分別對應於常量池的 CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANTS_InterfaceMethodref_info四種類型常量。

6、初始化

   初始化階段是類加載階段的最後一步,前面過程中,除第一個加載階段可以通過用戶自定義類加載器參与之外,其餘過程都是完全由虛擬機主導和控制。而到了初始化階段,則開始真正執行類中定義的Java程序代碼(或者說是字節碼)。

  在前面介紹的準備階段中,類變量已經被賦值過初始值了,而初始化階段,則根據程序員的編碼去初始化變量和資源。

  換句話來說,初始化階段是執行類構造器<clinit>() 方法的過程

  ①、<clinit>() 方法 是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊(static{})中的語句合併產生的,編譯器收集的順序是由語句在源文件中出現的順序所決定的,靜態語句塊中只能訪問到定義在靜態語句塊之前的變量,定義在它之後的變量,在前面的靜態語句塊中可以賦值,但是不能訪問。

  比如如下代碼會報錯:

  

 

   但是你把第 14 行代碼放到 static 靜態代碼塊的上面就不會報錯了。或者不改變代碼順序,將第 11 行代碼移除,也不會報錯。

  ②、<clinit>() 方法與類的構造函數(或者說是實例構造器<init>()方法)不同,它不需要显示的調用父類構造器,虛擬機會保證在子類的<init>()方法執行之前,父類的<init>()方法已經執行完畢。因此虛擬機中第一個被執行的<init>()方法的類肯定是 java.lang.Object。

  ③、由於父類的<clinit>() 方法先執行,所以父類中定義的靜態語句塊要優先於子類的變量賦值操作。

  ④、<clinit>() 方法對於接口來說並不是必須的,如果一個類中沒有靜態語句塊,也沒有對變量的賦值操作,那麼編譯器可以不為這個類生成<clinit>() 方法。

  ⑤、接口中不能使用靜態語句塊,但仍然有變量初始化的賦值操作,因此接口與類一樣都會生成<clinit>() 方法。但接口與類不同的是,執行接口中的<clinit>() 方法不需要先執行父接口的<clinit>() 方法。只有當父接口中定義的變量被使用時,父接口才會被初始化。

  ⑥、接口的實現類在初始化時也一樣不會執行接口的<clinit>() 方法。

  ⑦、虛擬機會保證一個類的<clinit>() 方法在多線程環境中被正確的加鎖和同步。如果多個線程同時去初始化一個類,那麼只會有一個線程去執行這個類的<clinit>() 方法,其他的線程都需要阻塞等待,直到活動線程執行<clinit>() 方法完畢。如果在一個類的<clinit>() 方法中有很耗時的操作,那麼可能造成多個進程的阻塞。

  比如對於如下代碼:

package com.yb.carton.controller;

/**
 * Create by YSOcean
 */
public class ClassLoadInitTest {


    static class Hello{
        static {
            if(true){
                System.out.println(Thread.currentThread().getName() + "init");
                while(true){}
            }
        }
    }

    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"start");
            Hello h1 = new Hello();
            System.out.println(Thread.currentThread().getName()+"run over");
        }).start();


        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"start");
            Hello h2 = new Hello();
            System.out.println(Thread.currentThread().getName()+"run over");
        }).start();
    }

}

View Code

  運行結果如下:

  

 

   線程1搶到了執行<clinit>() 方法,但是該方法是一個死循環,線程2將一直阻塞等待。

  知道了類的初始化過程,那麼類的初始化何時被觸發呢?JVM大概規定了如下幾種情況:

  ①、當虛擬機啟動時,初始化用戶指定的類。

  ②、當遇到用以新建目標類實例的 new 指令時,初始化 new 指定的目標類。

  ③、當遇到調用靜態方法的指令時,初始化該靜態方法所在的類。

  ④、當遇到訪問靜態字段的指令時,初始化該靜態字段所在的類。

  ⑤、子類的初始化會觸發父類的初始化。

  ⑥、如果一個接口定義了 default 方法,那麼直接實現或間接實現該接口的類的初始化,會觸發該接口的初始化。

  ⑦、使用反射 API 對某個類進行反射調用時,會初始化這個類。

  ⑧、當初次調用 MethodHandle 實例時,初始化該 MethodHandle 指向的方法所在的類。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

分類
發燒車訊

搶攻 EV 需求,三菱化學傳倍增美國鋰電池關鍵材料產能

日刊工業新聞 3 日報導,為了搶攻電動車(EV)需求,三菱化學(Mitsubishi Chemical)將擴增鋰離子電池關鍵材料「電解液」產能,計畫於 2019 年度內(2020 年 3 月底前)將美國工廠(位於田納西州曼非斯)電解液年產能提高至 2 萬噸、將達現行的 2 倍水準。

三菱化學計畫於 2020 年度結束前(2021 年 3 月底前)將電解液全球年產能提高至 8.5 萬噸、將較 2017 年度大增 95%,且計畫將另一項鋰電池關鍵材料「負極材」全球年產能提高至 2.9 萬噸(將較 2017 年度增加 61%),目標在 2020 年度將電池材料等新能源部門營收提高至 1,000 億日圓、2025 年度進一步倍增至 2,000 億日圓的規模。

三菱化學 2018 年 12 月 26 日宣布,日本國內外電動車、插電式油電混合車(PHV)、油電混合車(HV)市場呈現急速擴大,因此將擴增日本「電解液」產能,計畫將四日市事業所的電解液年產能自現行的 1.1 萬噸大幅擴產約 5 成至 1.6 萬噸。

日韓企業紛紛擴增鋰離子電池關鍵材料產能

旭化成(Asahi Kasei)3 月 14 日宣布,因鋰離子電池以電動車等車用需求為中心呈現急速增長,故決議投資 300 億日圓對位於日本滋賀縣守山市的守山製造所、以及位於北卡羅萊納州的美國工廠進行增產投資,增產鋰離子電池關鍵材料「分隔膜」,上述增產工程預計於 2021 年度上半年開始商轉,預估 2021 年度旭化成分隔膜全球年產能將擴增至約 15.5 億平方公尺、將較 2018 年度末提高 1 倍。

住友化學(Sumitomo Chemical)日前也傳出將階段性提高南韓工廠產能,目標在 2021 年度將分隔膜總年產能(合併日本工廠產能計算)提高至 6 億平方公尺、將達現行的近 2 倍水準。

全球第 2 大鋰離子電池關鍵材料「分隔膜」廠商南韓 SK Innovation 5 月 27 日表示,計畫在 2025 年結束前將分隔膜產能提高至現行的 5 倍,SK Innovation 社長金俊 27 日在首爾舉行的記者會上表示,「目標藉由大規模增產、搶當全球龍頭」。在全球分隔膜市場上,日本旭化成市佔約 2 成、位居首位,SK Innovation 市佔率超過 1 成居次。

日本民間調查機構矢野經濟研究所公布調查報告指出,因中國自 2019 年起開始實施新能源車規範,加上 2019-2020 年期間日歐車廠將進行車輛電動化,提振車用鋰離子電池材料需求今後將持續擴大,預估 2020 年全球 4 大關鍵材料(正極材、負極材、電解液和分隔膜)市場規模(廠商出貨金額)將擴增至 281.46 億美元、將較 2017 年暴增 9 成(增加 91.3%)。

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

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

【其他文章推薦】

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選