999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

Java注解機(jī)制的應(yīng)用研究

2022-02-20 00:42:34曾水新黃日勝
電腦知識(shí)與技術(shù) 2022年34期

曾水新 黃日勝

摘要:Java的注解機(jī)制在JDK5就已推出,后續(xù)發(fā)布的新版不斷完善,目前注解機(jī)制的應(yīng)用已經(jīng)很廣泛,如用于輔助開(kāi)發(fā)的工具Lombok、AutoValue、Immutables等,主流的開(kāi)發(fā)框架如Spring、MyBatis也大量以注解替代了XML配置文件。大多數(shù)開(kāi)發(fā)者僅會(huì)使用注解,但不了解其工作原理,該文詳細(xì)介紹了JDK內(nèi)置的注解、元注解的作用和用法,分析了注解的工作原理,并以案例演示了如何編寫(xiě)自定義注解,包括聲明注解、處理注解、使用注解三個(gè)流程,最后介紹了注解的應(yīng)用場(chǎng)景。

關(guān)鍵詞:Java;注解;反射技術(shù);框架技術(shù);編譯器

中圖分類(lèi)號(hào):TP311.1? ? ? 文獻(xiàn)標(biāo)識(shí)碼:A

文章編號(hào):1009-3044(2022)34-0035-04

1 引言

Java或Android的開(kāi)發(fā)者對(duì)注解(Annotation) 機(jī)制一定不會(huì)陌生,在項(xiàng)目開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)者會(huì)接觸到很多注解,如@Override、@Deprecated、@SuppressWarnings等,如果使用框架,可能會(huì)使用到注解@Controller、@Param、@Select等。目前關(guān)于注解原理的資料相對(duì)比較貧乏,很多開(kāi)發(fā)者會(huì)使用注解,但不了解注解的工作原理、運(yùn)行機(jī)制,也不清楚如何編寫(xiě)注解。

2 Java注解機(jī)制介紹

2.1 注解的概念

注解是JDK5.0引入的一種標(biāo)注機(jī)制,Oracle官方定義為:“Annotations, a form of metadata, provide data about a program that is not part of the program itself.”[1]。即注解是元數(shù)據(jù)的一種形式,注解提供了程序的信息但不屬于程序的一部分。注解可以對(duì)代碼添加附加信息,但不會(huì)侵入業(yè)務(wù)代碼,也不會(huì)影響代碼的具體執(zhí)行過(guò)程[2]。開(kāi)發(fā)者可以對(duì)包、類(lèi)、接口、字段、方法參數(shù)、局部變量等進(jìn)行注解,添加特殊標(biāo)記,在編譯期或運(yùn)行期可以對(duì)這些被標(biāo)記的類(lèi)、變量、方法或方法參數(shù)進(jìn)行一些特殊的操作。

注解與Javadoc注釋容易混淆,兩者貌似相同,實(shí)則區(qū)別很大:

Javadoc是Sun公司提供的一種工具,它可以從程序源代碼中抽取類(lèi)、方法、成員等注釋,然后形成一個(gè)和源代碼配套的API幫助文檔,相當(dāng)于產(chǎn)品說(shuō)明書(shū),是為了便于開(kāi)發(fā)者調(diào)用時(shí)了解類(lèi)、方法和屬性的作用、用法而誕生的,Javadoc是特殊的、格式化的注釋,本質(zhì)上還是注釋。注釋是給開(kāi)發(fā)者看的。

注解則不一樣,開(kāi)發(fā)者通過(guò)配置,使其在編譯時(shí)、類(lèi)加載時(shí)、運(yùn)行時(shí)可見(jiàn),還可通過(guò)Java的反射機(jī)制獲取注解內(nèi)容,加入自定義的處理邏輯。注解是非侵入性的,不會(huì)干涉代碼本身的處理流程,而是通過(guò)低耦合的“貼標(biāo)簽”形式,向原有代碼附加信息,編碼輔助工具、部署工具、IDE都可以讀取注解,為開(kāi)發(fā)者提供檢測(cè)代碼、自動(dòng)編碼、驗(yàn)證部署的服務(wù),注解是給機(jī)器看的。

2.2 Java內(nèi)置的標(biāo)準(zhǔn)注解

1) @Override:該注解是使用頻率較高的一個(gè),標(biāo)注在方法上,表示該方法是重寫(xiě)父類(lèi)方法。編譯器會(huì)進(jìn)行檢測(cè)是否符合重寫(xiě)規(guī)則,如果不符合,比如父類(lèi)(包括接口)沒(méi)有這個(gè)方法,則會(huì)提示錯(cuò)誤。不寫(xiě)@Override其實(shí)也不會(huì)影響程序運(yùn)行,這個(gè)注解是否就沒(méi)有存在的意義?不是的,編寫(xiě)代碼時(shí),通常開(kāi)發(fā)者很清楚他要重寫(xiě)一個(gè)方法,但是可能單詞拼寫(xiě)錯(cuò)誤,如果沒(méi)加注解,編譯器就發(fā)現(xiàn)不了錯(cuò)誤。

2) @Deprecated:用于標(biāo)記類(lèi)、成員變量、成員方法或者構(gòu)造方法已廢棄,不推薦開(kāi)發(fā)者使用,如果開(kāi)發(fā)者調(diào)用了被標(biāo)記了@Deprecated的方法,編譯時(shí)會(huì)有警告信息,但仍能強(qiáng)制編譯。

3) @SuppressWarnings:該注解的作用是指示編譯器對(duì)被注解的代碼元素內(nèi)部的某些警告保持靜默,支持在類(lèi)、屬性、方法、參數(shù)、構(gòu)造方法、本地變量上使用。標(biāo)注了“@SuppressWarnings”不等于消除了警告內(nèi)容,只是編譯器不顯示而已,除非開(kāi)發(fā)者確定該警告的隱患不會(huì)影響程序的正常運(yùn)行,否則不建議使用該注解。

4) @SafeVarargs:JDK7加入的注解,用于取消編譯器產(chǎn)生的unchecked警告。在聲明一個(gè)有泛型的可變參數(shù)的構(gòu)造函數(shù)或者方法時(shí),編譯器會(huì)提示unchecked警告,如果開(kāi)發(fā)者確定該構(gòu)造函數(shù)或方法不會(huì)造成不安全的操作時(shí),可使用@SafeVarargs進(jìn)行修飾,編譯器就會(huì)忽略u(píng)nchecked警告。例如定義了一個(gè)靜態(tài)方法如下,添加上@SafeVarargs后,編譯器警告消失:

@SafeVarargs

public static void myMethod(T...array){

//函數(shù)主體

}

5) @FunctionalInterface:JDK8新增了函數(shù)式編程[3],相應(yīng)地加入了函數(shù)式接口注解,所謂函數(shù)式接口實(shí)際上是一個(gè)Lambda表達(dá)式,它本質(zhì)上是接口,比普通接口多了一個(gè)約束:有且僅有一個(gè)抽象方法。標(biāo)注了@FunctionalInterface注解,即指示編譯器檢查開(kāi)發(fā)者編寫(xiě)的接口是否符合函數(shù)式接口的約束條件,如不符合,編譯器會(huì)給出錯(cuò)誤提示。

2.3 Java內(nèi)置的元注解

元注解是注解的注解,是JDK的基礎(chǔ)注解,它作用在其他注解上面,用于標(biāo)記和描述注解的基本信息。編寫(xiě)一個(gè)注解需要指明其保留的時(shí)間和生效的上下文等最基本的信息,JDK原生的元注解則提供了可以用于標(biāo)注并描述這些信息的注解。JDK提供的元注解有:

1) @Retention:用于設(shè)定注解的生命周期,可以取值為:①RetentionPolicy.SOURCE,注解只在源碼階段保留,源碼被編譯之后就不存在了。②RetentionPolicy.CLASS,注解內(nèi)容被編譯到字節(jié)碼文件(.class) 里,但JVM讀取字節(jié)碼文件時(shí),并不將其加載,這是@Retention的默認(rèn)取值。③RetentionPolicy.RUNTIME,注解的生命周期貫穿于源碼、.class文件、JVM三個(gè)階段,因此程序在運(yùn)行時(shí)可以獲取到它們。

2) @Documented:注解后Javadoc工具可從源代碼中抽取出類(lèi)、方法、成員等注釋形成一個(gè)配套的API幫助文檔,默認(rèn)情況下,類(lèi)和方法的注解內(nèi)容是不會(huì)出現(xiàn)在Javadoc中的,使用@Documented修飾后,該注解即可被Javadoc工具提取到API文檔。要使@Documented注解生效的前提是:@Retention的值需設(shè)置為RetentionPolicy.RUNTIME。

3) @Target:用于指定注解的放置目標(biāo)。注解可用于修飾包、接口、類(lèi)、方法、變量等類(lèi)型,@Target注解確定該注解可以出現(xiàn)在哪個(gè)位置,取值范圍定義在ElementType枚舉里:①TYPE:表示可用于標(biāo)注類(lèi)、接口、注解、枚舉;②FIELD:表示可用于標(biāo)注成員變量;③METHOD:表示可用于標(biāo)注成員方法;④ PARAMETER:表示可用于標(biāo)注參數(shù);⑤CONSTRUCTOR:表示可用于標(biāo)注構(gòu)造器;⑥LOCAL_VARIABLE:表示可用于標(biāo)注本地變量;⑦ANNOTATION_TYPE:表示可用于標(biāo)注注解(即元注解);⑧PACKAGE:表示可用于標(biāo)注包;⑨TYPE_PARAMETER:這是JDK8新增的,表示可用于標(biāo)注自定義類(lèi)型參數(shù);⑩TYPE_USE:JDK8新增的,表示可用于標(biāo)注除class外的任意類(lèi)型。

@Target可使用單個(gè)枚舉值,如設(shè)定為元注解,代碼為:

@Target(ElementType. ANNOTATION_TYPE)

也可使用多個(gè)枚舉值,需將多個(gè)枚舉值用大括號(hào)“{}”包圍,如設(shè)定注解可添加到成員方法和成員變量上,代碼為:

@Target({ElementType.METHOD, ElementType.FIELD})

4) @Inherited:用于指明父類(lèi)注解會(huì)被子類(lèi)繼承。@Inherited僅針對(duì)@Target(ElementType.TYPE)類(lèi)型的注解有效,并且僅針對(duì)class的繼承,對(duì)interface的繼承無(wú)效。

5) @Native:JDK8新增的注解,表示被修飾的成員變量可以被本地代碼引用,常被代碼生成工具使用。

6) @Repeatable:JDK8新增的注解。JDK8之前,同一程序元素前最多只能有一個(gè)相同類(lèi)型的注解。@Repeatable允許在相同的程序元素中重復(fù)注解。

3 自定義注解

內(nèi)置的注解并不多,開(kāi)發(fā)者可以編寫(xiě)自定義注解,主要有三個(gè)步驟:一是聲明注解,二是處理注解,三是使用注解。

3.1 自定義注解的聲明

3.1.1 自定義注解的語(yǔ)法

[[public] @interface 注解名稱{

[數(shù)據(jù)類(lèi)型 變量名稱();]

} ]

關(guān)鍵字“@interface”與標(biāo)準(zhǔn)的接口關(guān)鍵字interface是不一樣的,從反編譯的代碼中,可以看到類(lèi)似“public interface AnnoDemo extends Annotation {}”的代碼,意味著注解繼承了Annotation接口(在java.lang.annotation包中),即該注解就是一個(gè)Annotation,因此注解本質(zhì)上是一個(gè)特殊的接口(interface) ,接口里可以定義什么,注解里同樣也可以定義,它的修飾符與接口一樣,也是默認(rèn)被public abstract修飾。它和普通的接口不一樣的地方:

1) 定義普通接口使用interface修飾,但定義注解使用的是@interface。

2) 普通接口使用implements關(guān)鍵字實(shí)現(xiàn)接口,注解的實(shí)現(xiàn)是由編譯器完成。

3) 普通接口可以繼承多個(gè)接口,注解不能繼承其他的注解或接口。

4) 在定義注解時(shí)可以定義屬性,但是屬性必須使用括號(hào)“()”,形式上是一個(gè)方法。

一個(gè)典型的注解聲明代碼如下:

[@Inherited

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})

public @interface AnnoDemo {

String role() ;

} ]

3.1.2 注解的屬性

如前所述,注解的屬性與普通類(lèi)屬性不一樣,它的屬性是抽象方法,注解的屬性規(guī)則有:

1) 返回值類(lèi)型必須是以下幾種:基本數(shù)據(jù)類(lèi)型、String類(lèi)型、枚舉類(lèi)型、注解、以上類(lèi)型的數(shù)組。

2) 使用時(shí)需給屬性賦值,如下面代碼SomeClass類(lèi)前面添加了@AnnoDemo注解,并為其role屬性賦值為admin。

[@AnnoDemo(role = "admin")

class SomeClass{

} ]

3) 可以使用default關(guān)鍵字設(shè)置屬性的默認(rèn)值,有默認(rèn)值的屬性,在使用時(shí)可不給屬性賦值。

[public @interface AnnoDemo {

String role() default "user";

}

@AnnoDemo

class SomeClass{

} ]

4) 注解如有多個(gè)屬性,賦值時(shí)可以在注解括號(hào)中用“,”號(hào)隔開(kāi)分別給對(duì)應(yīng)的屬性賦值。

5) 如注解只有一個(gè)屬性,可將其命名為value,賦值時(shí)可省略value直接定義值。

6) 給數(shù)組屬性賦值時(shí),如數(shù)組中只有一個(gè)值,則可以省略“{}”數(shù)組符號(hào)。

3.2 處理注解

注解的處理是自定義注解的核心,生命周期為SORCE、CLASS的注解,需編寫(xiě)注解處理器處理注解,生命周期為RUNTIME的注解,可通過(guò)反射獲取注解內(nèi)容,再進(jìn)行業(yè)務(wù)處理。

3.2.1 注解處理器

注解處理器(Annotation Processor) 是javac的一個(gè)工具,用于編譯時(shí)掃描和處理注解。開(kāi)發(fā)者如想在編譯期處理注解,需要編寫(xiě)一個(gè)注解處理器。編寫(xiě)注解處理器需要繼承JDK自帶的抽象處理器javax.annotation.processing.AbstractProcessor類(lèi),AbstractProcessor繼承于Processor接口,提供了以下方法:

1) init(ProcessingEnvironment processingEnv):初始化時(shí)處理工具會(huì)調(diào)用init()方法。ProcessingEnviroment對(duì)象提供很多有用的工具類(lèi)Elements, Types和Filer。

2) process(Set<? extends TypeElement> annos, RoundEnvironment roundEnvironment):這是開(kāi)發(fā)者需要實(shí)現(xiàn)的方法,需要編寫(xiě)該注解的業(yè)務(wù)邏輯。RoundEnviroment參數(shù)可讓你查詢包含特定注解的被注解元素。

3) getSupportedAnnotationTypes():獲取支持的注解類(lèi)型,方法的返回值是字符串集合,如果沒(méi)有支持的類(lèi)型,則返回空集。該方法也可以用@SupportedAnnotationTypes注解替代。

4) getSupportedSourceVersion():獲取支持的源代碼版本,一般情況下返回SourceVersion.latestSupported(),如果返回的版本小于當(dāng)前編譯器版本,會(huì)有警告提示。

3.2.2 插入式注解處理器原理

插入式注解處理器是JDK6之后提供了一種可以在編譯期進(jìn)行注解讀取和處理的能力,開(kāi)發(fā)者可通過(guò)實(shí)現(xiàn)JDK的API自定義注解處理器實(shí)現(xiàn)干涉編譯器的行為。編譯期的注解,需要插入式注解處理器進(jìn)行解析,注解處理器在編譯過(guò)程中是如何工作的?可以從Javac的編譯流程去分析,如圖1所示:

1) 插入式注解處理器初始化。

2) 解析與填充符號(hào)表,包括詞法、語(yǔ)法分析;將源代碼的字符流轉(zhuǎn)換為標(biāo)記集合,構(gòu)造出抽象語(yǔ)法樹(shù);填充符號(hào)表,產(chǎn)生符號(hào)地址和符號(hào)信息。

3) 插入式注解處理器對(duì)注解的處理,執(zhí)行后如果產(chǎn)生了新的符號(hào),則返回上一步驟,重新處理這些新符號(hào)。

4) 分析與生成字節(jié)碼。

JDK編譯字節(jié)碼前,會(huì)先掃描源代碼中的注解,如果注解有對(duì)應(yīng)的注解處理器,則會(huì)調(diào)用process() 方法處理,因此可能會(huì)產(chǎn)生新的源代碼、修改原有代碼,因此需要進(jìn)行多輪的注解處理。

3.2.3 處理編譯期的注解

生命周期為SOURCE的注解,被編譯為.class文件時(shí)被抹去,生命周期為CLASS的注解,會(huì)被編譯到.class里,但運(yùn)行程序時(shí),不會(huì)被加載到JVM中,在運(yùn)行時(shí)是獲取不到它的信息的,因此這兩類(lèi)的注解,需要在編譯期處理,步驟為:

1) 開(kāi)發(fā)者編寫(xiě)一個(gè)繼承于AbstractProcessor類(lèi)的注解處理器,如MyProcessor,在MyProcessor里重寫(xiě)初始化方法init()、重寫(xiě)注解的邏輯實(shí)現(xiàn)process()方法,例如我們的注解的功能是為類(lèi)添加getter、setter方法,就可以在process()先獲取被注解的類(lèi),然后在類(lèi)中插入getter、setter。

2) 在編譯的參數(shù)中指定MyProcessor,如javac -processer com.zsx.MyProcessor,編譯時(shí)會(huì)自動(dòng)調(diào)用MyProcessor的process()方法。很多IDE如IntelliJ IDEA也支持注解處理器,只需在工具中配置注解處理器的路徑即可。

3.2.4 處理運(yùn)行時(shí)的注解

生命周期為RUNTIME的注解,虛擬機(jī)加載字節(jié)碼文件后,依然能讀取注解的信息,此類(lèi)注解可通過(guò)Java反射機(jī)制獲取注解內(nèi)容,再進(jìn)行業(yè)務(wù)邏輯處理。

獲取注解的關(guān)鍵是java.lang.reflect.AnnotatedElement接口,它的對(duì)象代表了一個(gè)被注解的元素,AccessibleObject、Class、Constructor、Executable、Field、Method、Package、Parameter類(lèi)都實(shí)現(xiàn)了這個(gè)接口,可獲取到AnnotatedElement對(duì)象,然后可調(diào)用該對(duì)象提供以下方法訪問(wèn)注解:

1) isAnnotationPresent(Class<?extends Annotation> annoClass):該方法功能是判斷指定類(lèi)型的注解是否存在,返回一個(gè)布爾類(lèi)型的值,如存在返回true,反之為false。

2) getDeclaredAnnotations():該方法獲取此元素上的所有注解,但不包括繼承的父類(lèi)的注解,返回Annotation類(lèi)型數(shù)組,如果該元素不存在注解,則返回長(zhǎng)度為0的數(shù)組。

3) getAnnotation(Class annoClass):返回該元素上指定類(lèi)型的注解,如果該類(lèi)型注解不存在,則返回null,傳入的參數(shù)annoClass為注解類(lèi)型的Class對(duì)象。

4) Annotation[] getAnnotations():該方法獲取此元素上的所有注解,并且包括繼承的父類(lèi)的注解,這是與getDeclaredAnnotations()的區(qū)別的地方。

例如,我們準(zhǔn)備利用注解機(jī)制實(shí)現(xiàn)日志工具,步驟為:

1) 聲明注解

[@Retention(RetentionPolicy.RUNTIME)//聲明周期為運(yùn)行時(shí)

@Target(ElementType.METHOD)//允許加在方法上

public @interface LogTool {

String action() default "默認(rèn)操作";

String description() default "無(wú)說(shuō)明";

} ]

聲明一個(gè)LogTool注解,設(shè)置元素類(lèi)型為方法、生命周期為運(yùn)行時(shí),聲明兩個(gè)屬性分別為:action記錄操作類(lèi)型、description作為備注。

2) 使用注解

定義一個(gè)Dao類(lèi),模擬數(shù)據(jù)庫(kù)操作類(lèi),在其各個(gè)方法前加上LogTool注解。

[public class Dao {

@LogTool(action="新增",description="新增一行數(shù)據(jù)")

public void addUser(){

}

@LogTool(action = "更新")

public void updateUser(){

}

@LogTool(action="刪除")

public void delUser(){

}

@LogTool

public void initData(){

}

} ]

3) 處理注解

定義一個(gè)注解處理方法parse,傳入被注解的類(lèi),對(duì)該類(lèi)的所有方法進(jìn)行遍歷,使用isAnnotationPresent()方法判斷該方法是否被注解,如果是被注解的方法,通過(guò)getDeclaredAnnotation()方法獲取注解類(lèi)的實(shí)例,即可獲取注解的兩個(gè)屬性“操作類(lèi)型”及“備注”的值,然后對(duì)其進(jìn)行其他的業(yè)務(wù)操作。

public class AnnoParser {

public static void parse(Class annoClass) throws Exception{

Method[] array = annoClass.getMethods();

for(Method method : array){

if(method.isAnnotationPresent(LogTool.class)){

String methodName=method.getName();

LogTool methodLog = method.getDeclaredAnnotation(LogTool.class);

String action = String.valueOf(methodLog.action());

String description = String.valueOf(methodLog.description());

System.out.println("方法:"+methodName + " - " + action+"("+description+")");

}

}

}

public static void main(String[] args){

try {

AnnoParser.parse(Dao.class);

}catch(Exception e){

e.printStackTrace();

}

}

}

4 注解的應(yīng)用場(chǎng)景

注解目前在生產(chǎn)環(huán)境已經(jīng)得到了廣泛的應(yīng)用,給開(kāi)發(fā)者帶來(lái)了效率的提升:

1) 檢測(cè)代碼。例如內(nèi)置的@Deprecated、@Override可以幫助開(kāi)發(fā)者減少開(kāi)發(fā)錯(cuò)誤、規(guī)范代碼,企業(yè)也可以根據(jù)內(nèi)部的代碼規(guī)范,編寫(xiě)自定義注解,檢測(cè)代碼的合法性,提高編碼質(zhì)量。

2) 輔助編碼。可以幫助開(kāi)發(fā)者自動(dòng)生成部分煩瑣的代碼,提高編碼效率,如第三方庫(kù)Lombok、AutoValue等,可以自動(dòng)插入到編輯器和構(gòu)建工具中,通過(guò)注解生成諸如getter、setter或equals方法等,提高了開(kāi)發(fā)效率。

3) 替代配置文件。例如Servlet現(xiàn)在可以使用注解替代原來(lái)的web.xml部署文件,越來(lái)越多的框架如Spring、Mybatis等使用了注解進(jìn)行開(kāi)發(fā)。

4) 測(cè)試。例如Junit單元測(cè)試框架使用了大量的注解[4]。

5) 面向切面編程應(yīng)用。在需要非侵入式業(yè)務(wù)邏輯的面向切面編程(AOP) [5],如權(quán)限控制、日志、監(jiān)控等場(chǎng)景,注解是較好的解決方案。

5 結(jié)束語(yǔ)

經(jīng)過(guò)多年的迭代優(yōu)化后,目前JDK對(duì)注解已有了較完備的支持,包括內(nèi)置注解、元注解、注解處理器、自定義注解四部分。注解機(jī)制是非常巧妙的、簡(jiǎn)約而強(qiáng)大的設(shè)計(jì),一方面,它簡(jiǎn)約:API簡(jiǎn)潔,對(duì)使用者友好、耦合度低;另一方面,它強(qiáng)大:開(kāi)放、擴(kuò)展性強(qiáng),應(yīng)用面廣,極大地推動(dòng)了Java生態(tài)如開(kāi)發(fā)框架、分析工具、開(kāi)發(fā)工具、部署工具等的發(fā)展。

參考文獻(xiàn):

[1] Lesson:Annotations[EB/OL].[2021-03-20].https://docs.oracle.com/javase/tutorial/java/annotations.

[2] 劉學(xué)玉.JAVA編程語(yǔ)言在計(jì)算機(jī)軟件開(kāi)發(fā)中的應(yīng)用[J].電子技術(shù)與軟件工程,2022(1):57-60.

[3] 趙榮彪.JDK1.8新特性與編程性能[J].信息技術(shù)與信息化,2021(5):145-146,150.

[4] 劉彥楠.JUnit參數(shù)化測(cè)試的應(yīng)用研究[J].信息與電腦(理論版),2021,33(14):30-32.

[5] 遲慧智,孔德智.Java方法增強(qiáng)技術(shù)研究[J].電子產(chǎn)品可靠性與環(huán)境試驗(yàn),2022,40(3):75-80.

【通聯(lián)編輯:謝媛媛】

主站蜘蛛池模板: 国产制服丝袜91在线| 午夜不卡视频| 欧美亚洲日韩不卡在线在线观看| 玖玖精品视频在线观看| 少妇被粗大的猛烈进出免费视频| 永久免费AⅤ无码网站在线观看| 综合天天色| 日本伊人色综合网| 久久精品免费国产大片| 蜜芽一区二区国产精品| 亚洲成人在线免费| 久久成人免费| 91麻豆精品国产高清在线| 伊人AV天堂| 青青操国产视频| 亚洲欧美h| 国禁国产you女视频网站| 国产菊爆视频在线观看| 91啦中文字幕| 日本91在线| 国产一国产一有一级毛片视频| 尤物亚洲最大AV无码网站| 欧美综合区自拍亚洲综合绿色| 国产91视频免费| 国产青青草视频| 亚洲视频三级| 国产在线一二三区| 国产视频大全| 国产精品黑色丝袜的老师| 乱人伦视频中文字幕在线| 国产麻豆va精品视频| 国产一区二区福利| 巨熟乳波霸若妻中文观看免费| 性视频久久| 色一情一乱一伦一区二区三区小说| 国产激情无码一区二区免费| 在线国产91| 欧美人在线一区二区三区| 亚洲成综合人影院在院播放| 精品视频福利| 国产人人射| 日本精品视频一区二区| 国产97视频在线观看| 亚洲男人天堂久久| 国产jizzjizz视频| 毛片网站免费在线观看| 中文字幕调教一区二区视频| 就去吻亚洲精品国产欧美| 国产视频一二三区| 国产情精品嫩草影院88av| 日韩精品一区二区三区中文无码| 国产精品女主播| 欧美性天天| 国产日韩欧美成人| 香蕉eeww99国产在线观看| 久热re国产手机在线观看| 亚洲人成高清| 五月婷婷亚洲综合| 一区二区三区国产精品视频| 亚洲AⅤ波多系列中文字幕| 亚洲一区二区成人| 国产色婷婷| 欧美特级AAAAAA视频免费观看| 日本成人福利视频| 国产不卡在线看| 国产手机在线ΑⅤ片无码观看| 韩国v欧美v亚洲v日本v| 成人福利免费在线观看| 欧美激情视频二区| 操操操综合网| 亚洲国产欧美国产综合久久| 久久不卡精品| 澳门av无码| 日本人真淫视频一区二区三区| 无码一区18禁| 亚洲天堂网在线播放| 无码日韩人妻精品久久蜜桃| 国产精品自拍合集| 91久久国产综合精品女同我| 亚洲精品在线观看91| 亚洲无码37.| 色婷婷在线播放|