亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        基于ASM的Java作業(yè)輔助批閱工具的實(shí)現(xiàn)

        2020-02-14 05:58:28嚴(yán)忠林
        計(jì)算機(jī)時(shí)代 2020年1期
        關(guān)鍵詞:計(jì)算機(jī)輔助教學(xué)

        嚴(yán)忠林

        摘 ?要: 學(xué)習(xí)編程離不開(kāi)大量的實(shí)踐訓(xùn)練,但批閱學(xué)生提交的代碼卻是一件相當(dāng)費(fèi)神耗時(shí)的工作。Java教學(xué)大都圍繞其功能強(qiáng)大的標(biāo)準(zhǔn)類(lèi)庫(kù)來(lái)組織安排,并通過(guò)相應(yīng)練習(xí)使學(xué)生熟練掌握。為了提高效率,設(shè)計(jì)了一個(gè)作業(yè)輔助批閱工具,它能對(duì)Java類(lèi)文件進(jìn)行自動(dòng)修改,在運(yùn)行時(shí)獲取關(guān)鍵類(lèi)庫(kù)的使用信息,了解它們的調(diào)用頻次、先后次序、所用參數(shù)及返回值,可幫助理解程序邏輯,評(píng)判學(xué)生對(duì)教學(xué)內(nèi)容的掌握程度。

        關(guān)鍵詞: Java類(lèi)文件,ASM,代碼批閱,計(jì)算機(jī)輔助教學(xué)

        中圖分類(lèi)號(hào):TP399 ? ? ? ? ?文獻(xiàn)標(biāo)識(shí)碼:A ? ? 文章編號(hào):1006-8228(2020)01-53-04

        Abstract: Coding is essential for learning a new programming language. However, for the instructors, it is very time-consuming and tedious to read over all of the code submitted by the students. The syllabus of Java programming consists of using its powerful standard libraries, accompanied with corresponding practical coding projects. A tool is designed to help the instructors to improve their code review efficiency. This tool is able to automatically modify the Java class files and return the usage of the class libraries, including their calling frequency, calling order, parameters and return values. This tool is helpful for understanding the logic of the code from students and judging their level of understanding.

        Key words: Java class file; ASM; code review; CAI

        0 引言

        Java多年來(lái)一直是軟件開(kāi)發(fā)的首選語(yǔ)言,也是計(jì)算機(jī)專(zhuān)業(yè)學(xué)習(xí)的重點(diǎn),對(duì)相關(guān)知識(shí)和開(kāi)發(fā)能力都有較高要求,因此需要安排充實(shí)的教學(xué)內(nèi)容,進(jìn)行有效的訓(xùn)練實(shí)踐。對(duì)于語(yǔ)法已入門(mén)的學(xué)生,教學(xué)通常是圍繞著各種類(lèi)庫(kù)展開(kāi)的。特別是JDK提供的標(biāo)準(zhǔn)類(lèi)庫(kù),功能豐富全面、使用方便高效。從輸入輸出到集合框架、多線程、網(wǎng)絡(luò)、數(shù)據(jù)庫(kù),各種功能都是通過(guò)使用相應(yīng)對(duì)象,調(diào)用適當(dāng)方法來(lái)實(shí)現(xiàn)的。即使是JavaEE、云計(jì)算等進(jìn)階內(nèi)容,也大都?xì)w結(jié)為對(duì)特定類(lèi)庫(kù)和框架的學(xué)習(xí)。這些內(nèi)容的教學(xué)都需要有針對(duì)性地安排大量實(shí)踐,而學(xué)生的掌握程度,也要通過(guò)批閱提交的作業(yè),查看相應(yīng)API的使用情況才能知曉。因此準(zhǔn)確全面、高效及時(shí)地處理學(xué)生作業(yè),就變得非常重要。

        閱讀他人程序,從來(lái)就不輕松。那些真正能訓(xùn)練和體驗(yàn)面向?qū)ο缶幊痰淖鳂I(yè),處理的問(wèn)題和對(duì)應(yīng)的程序結(jié)構(gòu)都較復(fù)雜,代碼規(guī)模大,處理流程多變,運(yùn)行邏輯不是一眼能看清的。況且每個(gè)學(xué)生都有自己的編程風(fēng)格和習(xí)慣,審閱這些代碼相當(dāng)勞心費(fèi)力,如班級(jí)的人數(shù)再多一點(diǎn),就非常辛苦了。過(guò)去的應(yīng)對(duì)辦法,要么是不管代碼只看最后運(yùn)行結(jié)果,要么是僅抽選少數(shù)幾份作業(yè)批閱。它們都難以切實(shí)了解學(xué)生的學(xué)習(xí)情況,對(duì)教學(xué)效果的評(píng)估很容易產(chǎn)生偏差。而且如被學(xué)生察覺(jué)這種狀況,對(duì)師生間的信任、交流、配合也是有害的。

        那么如何才能既省時(shí)省力,又全面準(zhǔn)確地檢查學(xué)生的作業(yè)情況呢?我們的建議是批閱時(shí)多關(guān)注作為教學(xué)重點(diǎn)的那些核心API的使用,因?yàn)樽鳂I(yè)的目的就是要通過(guò)訓(xùn)練來(lái)掌握它們,它們通常也是程序處理的關(guān)鍵步驟。當(dāng)然收集這些信息應(yīng)該極其方便,最好是全自動(dòng)的,不用在文本中搜索查找。我們?cè)O(shè)計(jì)了一個(gè)工具達(dá)到此目的,它會(huì)在程序運(yùn)行中虛擬機(jī)執(zhí)行類(lèi)裝載時(shí)對(duì)某些指令作適當(dāng)修改,讓它在完成相應(yīng)操作的同時(shí)也輸出必要信息。這樣程序一運(yùn)行,使用了哪些API、其順序頻度、具體數(shù)據(jù)等一目了然,從中不難推測(cè)它的設(shè)計(jì)思路,明確相關(guān)內(nèi)容的掌握程度。

        1 類(lèi)文件結(jié)構(gòu)和ASM工具

        要修改Java虛擬機(jī)指令,必須對(duì)Java類(lèi)文件結(jié)構(gòu)有所了解。它有統(tǒng)一緊湊的層次格式[1],簡(jiǎn)化后的結(jié)構(gòu)如圖1所示,包含了類(lèi)本身、全部的字段成員和方法成員信息,大量細(xì)節(jié)依靠相關(guān)屬性來(lái)描述,所有常數(shù)和文字信息都通過(guò)對(duì)常量池的下標(biāo)引用來(lái)表達(dá)。

        我們要修改的代碼在相應(yīng)方法的Code屬性中,主要部分是由bytecode順序排列形成的字節(jié)數(shù)組,其中既有分支轉(zhuǎn)移及異常捕捉等復(fù)雜結(jié)構(gòu),又隱含了運(yùn)行中對(duì)局部變量和操作數(shù)棧的反復(fù)使用。它還包含多種屬性,有局部變量的相關(guān)信息、程序行與代碼的對(duì)應(yīng)關(guān)系、還有程序員相當(dāng)陌生的程序裝載時(shí)的代碼驗(yàn)證支持。它們相互聯(lián)系對(duì)照,要直接在其中修改代碼,既困難又易錯(cuò)。為此我們借用了一個(gè)使用廣泛、高效方便的開(kāi)源工具ASM。

        ASM是Java字節(jié)碼的分析、生成、變換工具[2],它對(duì)類(lèi)內(nèi)成員的增刪改、對(duì)代碼內(nèi)各指令的查找變換都進(jìn)行了優(yōu)化,隱藏了對(duì)常量池的操作,允許引入指令跳轉(zhuǎn)、劃定區(qū)域所需要的地址標(biāo)號(hào),能自動(dòng)計(jì)算運(yùn)行時(shí)Frame的容量、代碼驗(yàn)證用的StackMapTable等。針對(duì)類(lèi)文件的復(fù)雜結(jié)構(gòu),ASM采用Visitor設(shè)計(jì)模式,提供了基于事件和基于對(duì)象的兩套API。前者簡(jiǎn)單快捷,但必須按序、即時(shí)地處理類(lèi)內(nèi)各元素。后者在內(nèi)存中將各元素組織成樹(shù)型結(jié)構(gòu),便于根據(jù)上下文自由修改。ASM提供下列核心部件[3]。

        ● ClassVisitor、FieldVisitor、MethodVisitor等抽象類(lèi):定義了處理類(lèi)內(nèi)各種元素的visit方法簽名,用戶(hù)通過(guò)子類(lèi)可實(shí)現(xiàn)對(duì)類(lèi)內(nèi)部各種成員的過(guò)濾、變換、增補(bǔ)等操作。它們還可接受另一Visitor對(duì)象,組成處理鏈,實(shí)現(xiàn)對(duì)元素的后續(xù)處理。

        ● ClassNode、FieldNode、MethodNode:是以上各Visitor的子類(lèi),定義了記錄類(lèi)內(nèi)部各種元素的數(shù)據(jù)結(jié)構(gòu)和對(duì)應(yīng)的visit方法,用于實(shí)現(xiàn)基于對(duì)象的處理方式,在變換修改后還能用accept方法發(fā)起后續(xù)處理。

        ● ClassReader:它有accept方法,能接受Visitor對(duì)象,并執(zhí)行對(duì)指定類(lèi)文件內(nèi)部結(jié)構(gòu)的解析,進(jìn)而驅(qū)動(dòng)該對(duì)象執(zhí)行相應(yīng)方法進(jìn)行處理。

        ● ClassWriter:是ClassVisitor的子類(lèi),執(zhí)行相應(yīng)方法能構(gòu)造出對(duì)應(yīng)類(lèi)內(nèi)元素的二進(jìn)制表示,最后調(diào)用toByteArray方法,即可獲得完整的類(lèi)文件。

        使用ASM時(shí)要將Reader、自定義的Visitor和Writer串接在一起,有時(shí)甚至形成多路結(jié)構(gòu),共同完成較復(fù)雜的處理。圖3就是對(duì)作業(yè)代碼進(jìn)行修正變換所采用的結(jié)構(gòu),它會(huì)在代碼中搜尋指定的指令和結(jié)構(gòu),進(jìn)行必要的修改與添加。

        2 類(lèi)文件的修改變換

        2.1 方法調(diào)用指令及變換方案

        程序中使用類(lèi)庫(kù)主要是通過(guò)調(diào)用它提供的方法。Java虛擬機(jī)有5種方法調(diào)用指令,INVOKEVIRTUAL和INVOKEINTERFACE分別調(diào)用類(lèi)內(nèi)定義和接口定義的動(dòng)態(tài)綁定方法;INVOKESPECIAL調(diào)用無(wú)需動(dòng)態(tài)綁定的方法;它們都通過(guò)某個(gè)對(duì)象執(zhí)行,INVOKESTATIC調(diào)用不使用對(duì)象的類(lèi)方法;INVOKEDYNAMIC目前除了lambda表達(dá)式外,Java程序中并不使用。這些指令內(nèi)都標(biāo)明了方法的名稱(chēng)、類(lèi)型及所在類(lèi)在常量池中的索引,因此在代碼中查找和修改特定的調(diào)用指令是比較簡(jiǎn)單的。

        Java虛擬機(jī)執(zhí)行這些指令時(shí)都會(huì)在當(dāng)前線程的堆棧頂創(chuàng)建一個(gè)Frame作為運(yùn)行環(huán)境,其中包含局部變量區(qū)和操作數(shù)棧。方法調(diào)用指令前應(yīng)先有指令將所需參數(shù)按序壓入操作數(shù)棧,如是對(duì)象方法,首個(gè)參數(shù)一定是隱含的this引用。調(diào)用執(zhí)行時(shí)這些參數(shù)被轉(zhuǎn)錄至新的Frame,作為前幾個(gè)局部變量,在代碼中得到處理。調(diào)用完成后將撤消該Frame,如有返回結(jié)果,它會(huì)出現(xiàn)在原Frame的操作數(shù)棧頂。

        要在使用指定的API時(shí)獲得信息,就要找到對(duì)應(yīng)調(diào)用指令加以修改。比如對(duì)于正則表達(dá)式,通常關(guān)心其模式字符串的使用是否正確,這就要考察Pattern類(lèi)的compile方法。最簡(jiǎn)單的辦法是將該調(diào)用指令替換為對(duì)名為_(kāi)compile的一個(gè)新方法的調(diào)用,由它再去調(diào)用原來(lái)的Pattern.compile,但額外會(huì)輸出需要的信息,比如作為參數(shù)的模式字符串等。新方法保持與原方法的參數(shù)及返回完全一致,這樣調(diào)用指令前后無(wú)需再作其他修改,只要在代碼中引入新的_compile方法就可以了。使用這種修改調(diào)用指令的方法就可方便地獲取所有要關(guān)注的API的使用信息。

        除了主動(dòng)調(diào)用類(lèi)庫(kù)的方法外,應(yīng)用程序可能還要提供某些接口或抽象類(lèi)規(guī)定的實(shí)現(xiàn)代碼,比如Comparator接口就需要完成compare方法,它是被調(diào)用的。有時(shí)候了解它們的執(zhí)行,考察其參數(shù)和返回結(jié)果,對(duì)理解整個(gè)程序也很有意義。為此可使用另一種替換方法,假如要了解compare方法的被調(diào)用情況,可將類(lèi)文件中的原實(shí)現(xiàn)代碼改名為_(kāi)compare,另生成一個(gè)替代的compare方法,它會(huì)調(diào)用被改名的_compare來(lái)實(shí)現(xiàn)功能,但還能輸出需要的信息,這樣就能知道比較操作的時(shí)機(jī)、次數(shù)、每次比較的值和結(jié)果等。

        2.2 標(biāo)注變換點(diǎn)

        采用這種方案,必須事先聲明關(guān)注哪些方法,怎么輸出信息,為此要按圖2的樣例代碼所示定義CheckItems類(lèi)。它通過(guò)一些自定義的標(biāo)注指出關(guān)注的方法,@Item1和@Item2分別針對(duì)上述主動(dòng)調(diào)用和被動(dòng)調(diào)用的情形。它們都要寫(xiě)出完整的方法名,后面再緊跟處理方法,其中除了執(zhí)行原本的調(diào)用外,還說(shuō)明怎么輸出信息。這些引入的代碼會(huì)按前述方案進(jìn)行處理,有些要改名,會(huì)用無(wú)沖突的名字代替。但這些方法的參數(shù)和返回類(lèi)型必須和原方法完全一致,由于其中所有的方法調(diào)用都改換成了類(lèi)方法調(diào)用,所以如果原來(lái)是對(duì)象方法,其隱含的this引用也要作為第一個(gè)參數(shù)顯式寫(xiě)出,如圖2所示。

        CheckItems的父類(lèi)是Check,它為處理和保存調(diào)用信息提供了一些通用方法。

        ● 打開(kāi)并管理一輸出流,提供print()和println()等方法,用來(lái)記錄需要的信息。

        ● 提供fline()方法,返回調(diào)用點(diǎn)所在的源文件名和行號(hào),可幫助區(qū)分同一方法在不同地點(diǎn)的調(diào)用,也有利于源文件閱讀時(shí)的查找。

        ● 如果參數(shù)或返回值是基本類(lèi)型或字符串,可直接輸出,其意義很明晰。但對(duì)引用型變量t,則應(yīng)使用obj(t)方法,它返回一個(gè)由類(lèi)型和序號(hào)構(gòu)成的、較容易理解的名稱(chēng),如Thread1、Pattern3等,還保證同一引用一定獲得同一名稱(chēng),有助于在考察流程時(shí)確定各對(duì)象前后的同一性。

        ● 如果對(duì)象t是自定義類(lèi)型,還可用val(t)獲得其內(nèi)部各字段的名字和值,比如對(duì)學(xué)生定義的日期類(lèi)型,可能會(huì)輸出{year:2019,month:1,day:1},這樣可以切實(shí)了解代碼運(yùn)行中的數(shù)據(jù)細(xì)節(jié)及其變化,對(duì)分析、理解程序是非常必要的。

        如果要考察特定對(duì)象的生成情況,也可在其構(gòu)造方法的調(diào)用指令中,進(jìn)行類(lèi)似地修改替換,獲得信息輸出。但構(gòu)造方法在類(lèi)文件中被命名為,不是合法的Java標(biāo)識(shí)符,需要做些特殊處理。如圖2樣例代碼中的new Thread()所示,標(biāo)注中仍指明替換方法,但代碼中用newobj()代替,它只是占位符,實(shí)際變換后仍改為調(diào)用,當(dāng)然在此前還要添加指令完成相應(yīng)參數(shù)在操作數(shù)棧的準(zhǔn)備。

        在CheckItems類(lèi)中還可根據(jù)需要引入一些狀態(tài)變量來(lái)控制信息輸出。比如對(duì)循環(huán)中的操作,有時(shí)只要查看前幾次調(diào)用或最后的調(diào)用,有時(shí)只需統(tǒng)計(jì)調(diào)用次數(shù),通過(guò)引入變量就能實(shí)現(xiàn)這些控制。圖2的樣例代碼就統(tǒng)計(jì)了compare方法的調(diào)用次數(shù),并僅對(duì)前三次輸出。由此需引入對(duì)這些狀態(tài)變量進(jìn)行初始化和終極處理的begin和end方法,會(huì)在每份作業(yè)批閱的開(kāi)始和結(jié)尾處執(zhí)行。

        對(duì)多線程相關(guān)作業(yè),常常還關(guān)心用synchronized指示的對(duì)象鎖的狀態(tài)。該保留字在語(yǔ)法上有兩種用法:置于方法定義前或組成一個(gè)代碼塊,對(duì)應(yīng)地在類(lèi)文件中也有兩種處置[4]:在對(duì)應(yīng)方法的標(biāo)記中標(biāo)志;用MONITORENTER/MONITOREXIT指令劃出加鎖區(qū)間,虛擬機(jī)運(yùn)行時(shí)會(huì)相應(yīng)的進(jìn)行加/解鎖操作。批閱作業(yè)時(shí)如希望了解這些情況,可在CheckItems類(lèi)中加@LockInfo標(biāo)注,代碼處理時(shí)就會(huì)在合適位置插入指令,執(zhí)行時(shí)就可獲得加/解鎖的時(shí)機(jī)、運(yùn)行的線程、被鎖的對(duì)象等信息。

        批閱學(xué)生作業(yè)當(dāng)然很希望了解他們的設(shè)計(jì),有哪幾個(gè)類(lèi)、每個(gè)類(lèi)的內(nèi)部結(jié)構(gòu)等。雖然可以查閱源代碼,但要打開(kāi)不同的文件再翻閱查找,還是比較費(fèi)事。為此可在CheckItems類(lèi)中加@MemberInfo標(biāo)注,將會(huì)在處理類(lèi)文件時(shí)先輸出每個(gè)類(lèi)的梗概信息,包括它們的繼承/實(shí)現(xiàn)關(guān)系、所有字段和方法成員的名字、類(lèi)型、訪問(wèn)控制等內(nèi)容。這樣就大概了解了其設(shè)計(jì)結(jié)構(gòu),對(duì)理解后續(xù)運(yùn)行時(shí)輸出的信息也有幫助。

        2.3 代碼變換器結(jié)構(gòu)

        有了CheckItems文件,就明確了需要考察的方法調(diào)用以及對(duì)應(yīng)的信息輸出方式,現(xiàn)在只需有一個(gè)代碼變換器,將這些內(nèi)容“織入”到學(xué)生提交的作業(yè)中,代碼一經(jīng)執(zhí)行,那些關(guān)鍵步驟就被記錄下來(lái)。通過(guò)查看這些信息,就能了解學(xué)生的學(xué)習(xí)情況。

        代碼變換器利用ASM提供的各種工具類(lèi)構(gòu)建,結(jié)構(gòu)如圖3所示。其中Reader2讀入CheckItems,將其中內(nèi)容存于Node對(duì)象中,并向Visitor1指出需要進(jìn)行變換的方法。Reader1能讀入作業(yè)中的各個(gè)class文件,解析后交Visitor1處理,Visitor1如發(fā)現(xiàn)匹配的方法,將按約定修改名稱(chēng)、指令, 再送至Writer,同時(shí)將需要補(bǔ)充的內(nèi)容告訴Visitor2。Visitor2從Node中取得相應(yīng)元素,作必要修改后也送至Writer。最后由Writer綜合這些輸入,構(gòu)造出新的、能輸出需要信息、完整可運(yùn)行的二進(jìn)制類(lèi)文件。

        實(shí)際批閱作業(yè)時(shí)將全班的代碼組織在一個(gè)子目錄中,每人是獨(dú)立的包或jar文件,控制程序?qū)⒅饌€(gè)處理它們。對(duì)每份作業(yè),生成一個(gè)自定義的類(lèi)裝載器,負(fù)責(zé)裝載學(xué)生作業(yè)代碼并利用上述變換器進(jìn)行必要轉(zhuǎn)換。在調(diào)用main()啟動(dòng)運(yùn)行后,其輸出的信息將送至指定文件。為避免處理過(guò)程脫離控制,變換器還將攔截Runtime和System 類(lèi)的exit或halt調(diào)用,將其轉(zhuǎn)換為能被控制程序捕捉的異常。代碼變換器還會(huì)把代碼中所有的標(biāo)準(zhǔn)輸出也轉(zhuǎn)向至同一指定文件,這樣該程序的設(shè)計(jì)結(jié)構(gòu)、運(yùn)行過(guò)程中的關(guān)鍵信息和運(yùn)行結(jié)果都被放置在一起,理解、評(píng)判學(xué)生作業(yè)情況就很方便了。

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

        有了這一作業(yè)批閱輔助工具,可以大大提高工作效率。對(duì)于稍有規(guī)模的程序,要理解其思路,少不了要來(lái)回參照,分層拆剖。如果學(xué)生人數(shù)較多,對(duì)教師的心神精力是一個(gè)考驗(yàn)。而使用本工具,因?yàn)槊恳魂P(guān)鍵步驟都有提示,比照源代碼,其運(yùn)行邏輯通常立即就可以抓住。

        批改作業(yè)時(shí)只閱讀程序而不運(yùn)行,細(xì)節(jié)錯(cuò)誤很難發(fā)現(xiàn)。只看運(yùn)行最終結(jié)果,雖能發(fā)現(xiàn)有錯(cuò),但要找到問(wèn)題所在也很困難。而使用本工具,只要對(duì)輸出的信息有合適安排,那么定位錯(cuò)誤位置,找出癥結(jié)所在就會(huì)容易很多。

        當(dāng)然,在此基礎(chǔ)上還可以進(jìn)一步開(kāi)展工作,比如對(duì)處理過(guò)程、運(yùn)行結(jié)果添加自動(dòng)評(píng)分功能,對(duì)代碼實(shí)現(xiàn)簡(jiǎn)單的數(shù)據(jù)流、控制流分析以更清晰顯現(xiàn)程序邏輯等,這都有待于今后繼續(xù)努力。

        參考文獻(xiàn)(References):

        [1] Tim Lindholm, Frank Yellin. The Java Virtual Machine Specification Java SE 11 Edition[M] Addison-Wesley Professional,2018.8

        [2] Eric Bruneton. ASM 4.0 A Java bytecode engineering library[EB/OL].http://www.ow2.org/

        [3] objectweb.org. asm 7.0 API[EB/OL]. http://www.ow2.org/

        [4] James Gosling, Bill Joy. The Java LanguageSpecificationJava SE 11 Edition [M] Addison-Wesley Professional 2018.8

        猜你喜歡
        計(jì)算機(jī)輔助教學(xué)
        淺談現(xiàn)代教育技術(shù)在教學(xué)中的應(yīng)用
        東方教育(2016年9期)2017-01-17 23:11:53
        計(jì)算機(jī)輔助教學(xué)應(yīng)用分析和探索
        當(dāng)前計(jì)算機(jī)輔助教學(xué)的實(shí)踐與思考
        成才之路(2016年36期)2016-12-12 13:02:32
        藥物制劑專(zhuān)業(yè)物理化學(xué)教學(xué)探討
        計(jì)算機(jī)輔助教學(xué)在中學(xué)美術(shù)教學(xué)中的應(yīng)用
        《線性代數(shù)》計(jì)算機(jī)輔助教學(xué)初探
        計(jì)算機(jī)輔助教學(xué)網(wǎng)站設(shè)計(jì)與實(shí)現(xiàn)
        淺談《衛(wèi)生管理運(yùn)籌學(xué)》的教學(xué)改革與探索
        科技視界(2016年17期)2016-07-15 14:19:34
        多媒體技術(shù)是促進(jìn)美術(shù)教學(xué)的捷徑
        考試周刊(2016年27期)2016-05-26 00:56:18
        多媒體技術(shù)在小學(xué)語(yǔ)文教學(xué)中的魅力
        考試周刊(2016年13期)2016-03-18 04:41:00
        人妻风韵犹存av中文字幕| 久久久无码人妻精品一区| 无码少妇一区二区三区| 全部免费国产潢色一级| 亚洲国产成人精品久久成人| 久久精品国产亚洲av久按摩 | 无码一区二区三区在线| 亚洲熟妇在线视频观看| 99久久国产一区二区三区| 成人性生交大片免费5| 国产又黄又硬又粗| 欧妇女乱妇女乱视频| 甲状腺囊实性结节三级| 久久青青草原亚洲av | 国产爆乳无码一区二区麻豆| 久久人妻内射无码一区三区| 视频一区精品自拍| 日本激情一区二区三区| 国产香蕉一区二区三区在线视频| 中文无码一区二区三区在线观看| 三上悠亚av影院在线看| 日韩肥熟妇无码一区二区三区| 精品国产中文久久久免费| 优优人体大尺大尺无毒不卡| 亚洲综合区图片小说区| 国产午夜视频免费观看| 亚洲综合新区一区二区| 久久国语露脸国产精品电影| 久久精品麻豆日日躁夜夜躁| 国产精品玖玖玖在线资源| 青青青草视频手机在线| 久久精品国产亚洲av精东| 精品少妇爆乳无码av无码专区| 产国语一级特黄aa大片| 白白色福利视频在线观看| 欧美又大粗又爽又黄大片视频| 国产97在线 | 亚洲| 国产69口爆吞精在线视频喝尿 | 中文字幕无码av激情不卡| 无码中文字幕专区一二三| 一区二区人妻乳中文字幕|