0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入了解Java泛型——從前世今生到PECS原則

OSC開源社區(qū) ? 來(lái)源:OSC開源社區(qū) ? 2024-11-21 11:45 ? 次閱讀

本文主要介紹泛型誕生的前世今生,特性,以及著名PECS原則的由來(lái)。

在日常開發(fā)中,必不可少的會(huì)使用到泛型,這個(gè)過程中經(jīng)常會(huì)出現(xiàn)類似“為什么這樣會(huì)編譯報(bào)錯(cuò)?”,“為什么這個(gè)列表無(wú)法添加元素?”的問題,也會(huì)出現(xiàn)感嘆Java的泛型限制太多了很難用的情況。

為了更好的使用泛型,就需要更深地了解它,因此本文主要介紹泛型誕生的前世今生,特性,以及著名PECS原則的由來(lái)。

泛型的誕生

背景

在沒有泛型之前,必須使用Object編寫適用于多種類型的代碼,想想就令人頭疼,并且非常的不安全。同時(shí)由于數(shù)組的存在,設(shè)計(jì)者為了讓其可以比較通用的進(jìn)行處理,也讓數(shù)組允許協(xié)變,這又為程序添加了一些天然的不安全因素。為了解決這些情況,Java的設(shè)計(jì)者終于在Java5中引入泛型,然而,正是因?yàn)橐敕盒偷臅r(shí)機(jī)較晚,為了兼容先前的代碼,設(shè)計(jì)者也不得不做出一些限制,來(lái)讓使用者(也就是我們)以難受換來(lái)一些安全。

優(yōu)點(diǎn)

簡(jiǎn)單來(lái)說(shuō),泛型的引入有以下好處:

程序更加易讀

安全性有所保證

以ArrayList舉例,在增加泛型類之前,其通用性是用繼承來(lái)實(shí)現(xiàn)的,ArrayList類只維護(hù)一個(gè)Object引用的數(shù)組,當(dāng)我們使用這個(gè)工具類時(shí),想要獲取指定類型的對(duì)象必須經(jīng)過強(qiáng)轉(zhuǎn):

import java.util.ArrayList;
import java.util.Date;

public class Main {
  public static void main(String[] args) {
    ArrayList list = new ArrayList();
    //強(qiáng)制類型轉(zhuǎn)換
    String res = (String) list.get(0);
    //十分不安全的行為
    list.add(new Date());
  }
}

這種寫法在編譯類型時(shí)不會(huì)報(bào)錯(cuò),但一旦使用get獲取結(jié)果并試圖將Date轉(zhuǎn)換為其他類型時(shí),很有可能出現(xiàn)類型轉(zhuǎn)換異常,為了解決這種情況,類型參數(shù)應(yīng)用而生。

類型參數(shù)

類型參數(shù)(Type parameter)使得ArrayList以及其他可能用到的集合類能夠方便的指示虛擬機(jī)其包含元素的類型:?

import java.util.ArrayList;


public class Main {
  public static void main(String[] args) {
    ArrayList objects = new ArrayList<>();
    objects.add("Hello");
  }
}

這使得代碼具有更好的可讀性,并且在調(diào)用get()的時(shí)候,無(wú)需進(jìn)行強(qiáng)轉(zhuǎn),最重要的是,編譯器終于可以檢查一個(gè)插入操作是否符合要求,運(yùn)行時(shí)可能出現(xiàn)的各種類型轉(zhuǎn)換錯(cuò)誤得以在編譯階段就被阻止。

import java.util.ArrayList;
import java.util.Date;


public class Main {
  public static void main(String[] args) {
    ArrayList objects = new ArrayList<>();
    //we can do it like that
    objects.add("Hello");
    //wrong example
    objects.add(new Date());
  }
}

基本用法

一般來(lái)說(shuō),使用泛型工具類很容易,但是自己編寫會(huì)相對(duì)困難很多,設(shè)計(jì)者必須考慮的相當(dāng)周全才能使自己的泛型類庫(kù)比較完善。

泛型類

泛型類是有一個(gè)或者多個(gè)類型變量的類,泛型類中的屬性可以全都不是泛型,不過一般不會(huì)這樣做,畢竟類型變量在整個(gè)類上定義就是用于指定方法的返回類型以及字段的類型,定義代碼如下:?

public class Animal {
  private String name;
  private T mouth;
  
  public T getMouth(){
    return mouth;
  }
}

泛型類可以有多個(gè)類型變量:

public class Animal {
  private String name;
  private T mouth;
  private U eyes;


  public T getMouth(){
    return mouth;
  }
}

泛型方法

泛型方法可以在普通類中定義,也可以在泛型類中定義,例如:

public class Animal {
  private T value;
  public static  T get(T... a){
    return a[a.length-1];
  }
  public T getFirst(){
    return value;
  }
}

類型擦除

虛擬機(jī)沒有泛型類型對(duì)象,也就是說(shuō),所有對(duì)象在虛擬機(jī)中都屬于普通類,這意味著在程序編譯并運(yùn)行后我們的類型變量會(huì)被擦除(erased)并替換為限定類型,擦掉類型參數(shù)后的類型就叫做原始類型(raw type),正是因?yàn)橛蓄愋蛥?shù),所以下面的比較結(jié)果會(huì)為true:

256ea9d8-9f6d-11ef-93f3-92fbcf53809c.jpg

?

這里的替換規(guī)則我個(gè)人理解為:“替換最近上界”,也就是無(wú)限定符修飾,則為頂級(jí)父類Object,如果有,則會(huì)替換為其指定的類型。最直觀的示例如下,這就是類型擦除的體現(xiàn):

257bed8c-9f6d-11ef-93f3-92fbcf53809c.jpg

?

259165e0-9f6d-11ef-93f3-92fbcf53809c.jpg

??

前面說(shuō)過,泛型是在1.5才提出的,因此類型擦除的目的就是為了保證已有的代碼和類文件依然合法,也就是向低版本兼容。這樣做會(huì)帶來(lái)幾個(gè)問題:

1.類型參數(shù)不支持基本類型,只支持引用類型,這是因?yàn)榉盒蜁?huì)被擦除為具體類型,而Object不能存儲(chǔ)基本類型的值。

運(yùn)行時(shí)你只能對(duì)原始類型進(jìn)行類型檢測(cè):

2598cc86-9f6d-11ef-93f3-92fbcf53809c.jpg

?

2.不能實(shí)例化類型參數(shù)

不能實(shí)例化泛型數(shù)組,因?yàn)轭愋筒脸龝?huì)將數(shù)組變?yōu)镺bject數(shù)組,如果允許實(shí)例化,極易造成類型轉(zhuǎn)換異常。

強(qiáng)制轉(zhuǎn)換

在編寫泛型方法調(diào)用時(shí),如果擦出了返回類型,編譯器會(huì)插入強(qiáng)制類型轉(zhuǎn)換。例如下面的代碼:

public class Main {
  public static void main(String[] args) {
    Animal pair = new Animal<>();
    Integer first = pair.getFirst();
  }
}

getFirst擦除類型后的返回類型是Object,編譯器自動(dòng)插入轉(zhuǎn)換到Integer的強(qiáng)制類型轉(zhuǎn)換,也就是說(shuō),編譯器把這個(gè)方法調(diào)用轉(zhuǎn)換為兩條虛擬機(jī)指令:

對(duì)原始方法的調(diào)用。

將返回的Object類型強(qiáng)制轉(zhuǎn)換為Integer類型。

方法橋接

子類重寫父類方法時(shí),必須和父類保持相同的方法名稱,參數(shù)列表和返回類型。那么問題來(lái)了,如果按照之前的思路來(lái)講,當(dāng)泛型父類或接口的類型參數(shù)被擦除了,那么子類豈不是不構(gòu)成重寫條件?(參數(shù)類型很可能變化):

擦除前:

25aec6c6-9f6d-11ef-93f3-92fbcf53809c.jpg

?

擦除后:

25b99844-9f6d-11ef-93f3-92fbcf53809c.jpg

?

為了解決這個(gè)事情,Java引入了橋接方法,為每個(gè)繼承/實(shí)現(xiàn)泛型類/接口的子類服務(wù),以此保持多態(tài)性,字節(jié)碼如下:

25c50206-9f6d-11ef-93f3-92fbcf53809c.jpg

?

(圖片來(lái)源:RudeCrab)

其實(shí)現(xiàn)原理,就是重寫擦除后的父類方法,并在其內(nèi)部委托了原始的子類方法,巧妙繞過了擦除帶來(lái)的影響。不僅如此,就算不是泛型類,當(dāng)子類方法重寫父類方法的返回類型是父類返回類型的子類時(shí),編譯器也會(huì)生成橋接方法來(lái)滿足重寫的規(guī)則。

總結(jié)

Java核心技術(shù)中總結(jié)的非常到位:

虛擬機(jī)中沒有泛型,只有普通的類和方法。

所有的類型參數(shù)都會(huì)替換為他們的限定類型。

會(huì)合成橋接方法來(lái)保持多態(tài)。

為保持類型安全性,必要時(shí)會(huì)插入強(qiáng)制類型轉(zhuǎn)換。

變型(Variant)與數(shù)組

變型是類型系統(tǒng)中很重要的概念,主要有三個(gè)規(guī)則協(xié)變,逆變,和不變:

25cecc46-9f6d-11ef-93f3-92fbcf53809c.jpg

?

這三個(gè)類型可以解釋為:假設(shè)有一個(gè)類型構(gòu)造器f,它可以將已知類型轉(zhuǎn)換為另一種類型,那么,有Animal父類和Dog子類。

則f(Dog)是f(Animal)的子類,稱為協(xié)變;

則f(Dog)是f(Animal)的父類,成為逆變;

則f(Dog)和f(Animal)沒有任何關(guān)系;

而這個(gè)f(),可以是泛型,可以是數(shù)組,也可以是方法。

知道了以上概念,我們需要直接指出,泛型默認(rèn)是不支持協(xié)變的,原因很簡(jiǎn)單,類型安全:如果允許協(xié)變,可能會(huì)造成類型轉(zhuǎn)換異常。而數(shù)組支持協(xié)變,正如文章開頭所說(shuō),就是設(shè)計(jì)者希望可以對(duì)數(shù)組進(jìn)行比較通用的處理,防止方法為每一種類型編寫重復(fù)邏輯,這樣做也確實(shí)導(dǎo)致為數(shù)組賦值元素時(shí)可能會(huì)拋出運(yùn)行時(shí)異常ArrayStoreException,這是一個(gè)很危險(xiǎn)的坑。Effective Java中直接指出允許數(shù)組協(xié)變是Java的缺陷,我想這也是要多用列表而不用數(shù)組的原因之一。

泛型協(xié)變—PECS原則

為了讓泛型也支持多態(tài),讓其支持協(xié)變是很必要的,最常用的場(chǎng)景:我們想讓一個(gè)方法接受一個(gè)集合,并做統(tǒng)一的邏輯處理,如果泛型不支持協(xié)變,這種很基本的需求都會(huì)成為奢望。

上界

讓泛型支持協(xié)變很簡(jiǎn)單,只需要使用? extends的組合即可實(shí)現(xiàn),?稱為通配符,這種組合方式聲明了類型的上界,標(biāo)識(shí)泛型可接受的類型只能是指定類型或是其子類。在這里,ElectricVehicle和Diesel均是繼承自Car。

25d26144-9f6d-11ef-93f3-92fbcf53809c.jpg

?

為了杜絕可協(xié)變后出現(xiàn)類似于數(shù)組一樣的安全隱患,泛型設(shè)計(jì)采用了“一刀切”的方式,即:只要聲明了上界,除了null之外,一律不準(zhǔn)傳入給泛型。說(shuō)白了,就是只讀不寫,這樣當(dāng)然可以保證安全性。

25f06be4-9f6d-11ef-93f3-92fbcf53809c.jpg

?

到這里可以順便說(shuō)一下集合的設(shè)計(jì),可以注意到集合中只有add方法是泛型參數(shù),而其余方法并不是,為何要這樣設(shè)計(jì),為何不把其余方法的參數(shù)類型也改為E?其原因就是在于,如果將contains和remove改為E,那么聲明上界之后,調(diào)用這兩個(gè)方法會(huì)引發(fā)編譯錯(cuò)誤,然而這兩個(gè)方法均為類型安全方法,自然不可聲明為E,add作為很明顯的寫方法,自然也需要用E作為參數(shù)類型,到這里,不得不感嘆類庫(kù)設(shè)計(jì)者的想法獨(dú)到。

25fa262a-9f6d-11ef-93f3-92fbcf53809c.jpg

?

下界

對(duì)應(yīng)協(xié)變的上界,自然有逆變的下界,很自然的,我們使用? super的組合來(lái)聲明一個(gè)泛型的下界,來(lái)表示可以接收本類型或者其父類型。

2608e958-9f6d-11ef-93f3-92fbcf53809c.jpg

?

而且相對(duì)應(yīng)的,正是由于最多只能接收父類型泛型,所以不會(huì)有類型轉(zhuǎn)換失敗的風(fēng)險(xiǎn),因此逆變可以添加元素,不過添加的元素類型只能是指定類型和其子類,切記不要把添加元素和接收泛型類參數(shù)給弄混了。

有利有弊,雖然逆變沒有了協(xié)變只讀不寫的限制,但是讀取元素時(shí)將不能確定具體的類型,只能用Object來(lái)接收:

261b1fba-9f6d-11ef-93f3-92fbcf53809c.jpg

?

PECS

正如上面對(duì)上下界的描述,我們已經(jīng)明白了大致的應(yīng)用場(chǎng)景,當(dāng)我們需要只讀不寫時(shí),就用協(xié)變,只寫不讀,就用逆變。又想讀又想寫,我們應(yīng)該指明準(zhǔn)確的泛型類型。

注明的PECS原則就總結(jié)了這一點(diǎn),PECS(Prodcuer extends Consumer super),也就是說(shuō),作為元素的生產(chǎn)者Prodcuer,要用協(xié)變,支持元素的讀取,而作為消費(fèi)者Consumer,要支持逆變,支持元素的寫入。

2621182a-9f6d-11ef-93f3-92fbcf53809c.jpg

?

Collections的copy方法就非常好的印證了這一點(diǎn):

262c6c66-9f6d-11ef-93f3-92fbcf53809c.jpg

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2987

    瀏覽量

    107266
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3825

    瀏覽量

    82561
  • specs
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    1647

原文標(biāo)題:深入了解Java泛型——從前世今生到PECS原則

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 0人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    深入了解U8g2與LVGL圖形庫(kù)

    在單片機(jī)開發(fā)領(lǐng)域,圖形顯示功能變得越來(lái)越重要。無(wú)論是工業(yè)控制界面、智能家居設(shè)備,還是手持儀器儀表,都需要一個(gè)高效且易用的圖形庫(kù)來(lái)實(shí)現(xiàn)豐富的可視化效果。U8g2 和 LVGL 就是其中兩款備受關(guān)注的圖形庫(kù),它們各有特點(diǎn),適用于不同的應(yīng)用場(chǎng)景。今天,我們就來(lái)深入了解這兩個(gè)圖形庫(kù)。
    的頭像 發(fā)表于 02-13 11:01 ?1839次閱讀

    深入了解 PCB 制造技術(shù):銑削

    了 PCB 銑削的復(fù)雜性、銑削工藝、其優(yōu)勢(shì)、挑戰(zhàn)和應(yīng)用。 了解 PCB 銑削 PCB 銑削涉及從覆銅板上機(jī)械去除材料,以創(chuàng)建電氣隔離并形成電路圖案。與使用化學(xué)溶液溶解不需要的銅的傳統(tǒng)蝕刻方法不同,銑削使用精確控制的銑削鉆頭來(lái)物理雕刻出所需的痕跡。該過程通
    的頭像 發(fā)表于 01-26 21:25 ?539次閱讀
    <b class='flag-5'>深入了解</b> PCB 制造技術(shù):銑削

    深入了解渦街流量計(jì) 原理及內(nèi)部構(gòu)造

    渦街流量計(jì)是一種常用的流量測(cè)量?jī)x表,LUB系列渦街流量計(jì)的內(nèi)部構(gòu)造與原理密切相關(guān),共同構(gòu)成了其高精度、寬量程比和穩(wěn)定運(yùn)行的基礎(chǔ)。本文將深入介紹渦街流量計(jì)的原理及內(nèi)部構(gòu)造,以便更好地了解渦街流量計(jì)
    的頭像 發(fā)表于 01-06 15:17 ?785次閱讀

    安泰功率放大器應(yīng)用:納米材料的前世今生

    ,因此在各個(gè)領(lǐng)域具有廣泛的應(yīng)用前景。那么你知道納米材料是如何被發(fā)現(xiàn),又是如何走入我們的生活,獲得長(zhǎng)足發(fā)展的嗎?今天Aigtek安泰電子帶大家詳細(xì)了解一下。 納米材料的前世今生 1861年,隨著膠體化學(xué)的建立,科學(xué)家們開始了對(duì)直徑
    的頭像 發(fā)表于 01-02 14:05 ?421次閱讀
    安泰功率放大器應(yīng)用:納米材料的<b class='flag-5'>前世</b><b class='flag-5'>今生</b>

    如何為不同的電機(jī)選擇合適的驅(qū)動(dòng)芯片?納芯微帶你深入了解!

    在現(xiàn)代生活中,電機(jī)廣泛使用在家電產(chǎn)品、汽車電子、工業(yè)控制等眾多應(yīng)用領(lǐng)域,每一個(gè)電機(jī)的運(yùn)轉(zhuǎn)都離不開合適的驅(qū)動(dòng)芯片。納芯微提供豐富的電機(jī)驅(qū)動(dòng)產(chǎn)品選擇,本期技術(shù)分享將重點(diǎn)介紹常見電機(jī)種類與感性負(fù)載應(yīng)用,幫助大家更深入了解如何選擇合適的電機(jī)驅(qū)動(dòng)芯片。
    的頭像 發(fā)表于 12-23 09:58 ?962次閱讀
    如何為不同的電機(jī)選擇合適的驅(qū)動(dòng)芯片?納芯微帶你<b class='flag-5'>深入了解</b>!

    光耦合器的前世今生:從誕生現(xiàn)代應(yīng)用的演變

    光耦合器是一種重要的電子元件,其在電子信號(hào)隔離和傳輸中的作用不可替代。自20世紀(jì)60年代首次被研發(fā)以來(lái),光耦合器經(jīng)歷了從基礎(chǔ)隔離器件高性能元件的不斷演化,在現(xiàn)代電子設(shè)備中占據(jù)了重要地位。本文將深入探討光耦合器的發(fā)展歷程、技術(shù)特點(diǎn)以及在當(dāng)今科技領(lǐng)域中的廣泛應(yīng)用。
    的頭像 發(fā)表于 12-13 16:16 ?545次閱讀
    光耦合器的<b class='flag-5'>前世</b><b class='flag-5'>今生</b>:從誕生<b class='flag-5'>到</b>現(xiàn)代應(yīng)用的演變

    深入了解光伏逆變器測(cè)試系統(tǒng)

    的交流電(AC)。隨著太陽(yáng)能發(fā)電的廣泛應(yīng)用,確保光伏逆變器的可靠性和效率變得至關(guān)重要,這也使得光伏逆變器測(cè)試系統(tǒng)的作用愈發(fā)凸顯。 一、光伏逆變器的工作原理 要深入理解光伏逆變器測(cè)試系統(tǒng)的必要性,首先需要了解逆變器的
    的頭像 發(fā)表于 10-24 14:59 ?632次閱讀
    <b class='flag-5'>深入了解</b>光伏逆變器測(cè)試系統(tǒng)

    安全繼電器要符合什么原則

    安全繼電器在設(shè)計(jì)和使用過程中,必須符合的核心原則是 故障-安全原則 。這一原則的具體含義和要求可以歸納如下: 故障-安全原則 定義 :當(dāng)繼
    的頭像 發(fā)表于 09-21 10:12 ?1097次閱讀

    深入了解PCI轉(zhuǎn)XMC載板轉(zhuǎn)接卡

    電子發(fā)燒友網(wǎng)站提供《深入了解PCI轉(zhuǎn)XMC載板轉(zhuǎn)接卡.docx》資料免費(fèi)下載
    發(fā)表于 09-06 14:35 ?0次下載

    深入了解基于CANoe的VIO系統(tǒng)應(yīng)用

    VIO System是Vector推出的一款適用于前期單板級(jí)測(cè)試使用的硬件系統(tǒng),不僅可以進(jìn)行總線通訊測(cè)試,也可以同時(shí)進(jìn)行I/O信號(hào)測(cè)試,可以讓工程師在ECU或者傳感器開發(fā)前期就發(fā)現(xiàn)問題,能夠盡早排查解決,極大降低了人力物力開發(fā)成本。
    的頭像 發(fā)表于 09-01 16:21 ?3502次閱讀
    <b class='flag-5'>深入了解</b>基于CANoe的VIO系統(tǒng)應(yīng)用

    深入了解六軸力傳感器:原理、分類與應(yīng)用

    ? 在科技飛速發(fā)展的今天,傳感器技術(shù)作為連接物理世界與數(shù)字世界的橋梁,正逐步滲透各個(gè)行業(yè),成為推動(dòng)技術(shù)進(jìn)步和產(chǎn)業(yè)升級(jí)的重要力量。其中,六軸力傳感器以其獨(dú)特的多維力學(xué)測(cè)量能力,在機(jī)器人技術(shù)、自動(dòng)化
    的頭像 發(fā)表于 08-02 08:44 ?2467次閱讀
    <b class='flag-5'>深入了解</b>六軸力傳感器:原理、分類與應(yīng)用

    深入了解表面貼裝晶體濾波器:DSF753S 2POLE、DSF753S 3POLE 和 DSF753S 4POLE

    深入了解表面貼裝晶體濾波器:DSF753S 2POLE、DSF753S 3POLE 和 DSF753S 4POLE
    的頭像 發(fā)表于 07-31 11:05 ?783次閱讀
    <b class='flag-5'>深入了解</b>表面貼裝<b class='flag-5'>型</b>晶體濾波器:DSF753S 2POLE、DSF753S 3POLE 和 DSF753S 4POLE

    深入了解 MEMS 振蕩器 溫度補(bǔ)償 MEMS 振蕩器 TC-MO

    深入了解 MEMS 振蕩器/溫度補(bǔ)償 MEMS 振蕩器(TC-MO)-μPower MO1534/MO1569/MO1576/MO8021
    的頭像 發(fā)表于 07-30 16:38 ?1011次閱讀
    <b class='flag-5'>深入了解</b> MEMS 振蕩器 溫度補(bǔ)償 MEMS 振蕩器 TC-MO

    深入了解表面貼裝晶體諧振器DSX1210A

    深入了解表面貼裝晶體諧振器DSX1210A
    的頭像 發(fā)表于 07-25 14:27 ?754次閱讀
    <b class='flag-5'>深入了解</b>表面貼裝晶體諧振器DSX1210A

    深入了解恒溫晶體振蕩器DC5032AS

    深入了解恒溫晶體振蕩器DC5032AS
    的頭像 發(fā)表于 07-25 10:37 ?577次閱讀
    <b class='flag-5'>深入了解</b>恒溫晶體振蕩器DC5032AS

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品