file 命令可以用來(lái)查看文件類型,還能查看文件的編碼格式,下面列舉一些 file 命令的參數(shù):file 命令參數(shù)名稱功能與作用描述-b表示 --brief,顯示查看結(jié)果時(shí),不顯示文件名-c表示 --checking-printout,顯示指令執(zhí)行過(guò)程-f表示 --files-from FILE,列出文件中文件名的文件類型-F表示 --separator STRING,使用指定符號(hào)替換輸出文件名后的默認(rèn)的 :-i輸出 mime 類型的字符串-L表示 --dereference,查看對(duì)應(yīng)軟鏈接對(duì)應(yīng)文件的文件類型-z表示 --uncompress,嘗試查看壓縮文件信息
數(shù)組是程序中用來(lái)存儲(chǔ)相同類型元素的集合體。在 C 語(yǔ)言中數(shù)組只能用來(lái)存儲(chǔ)相同類型的元素。數(shù)組的索引是從 0 開(kāi)始的,而不是我們數(shù)學(xué)中常用的 1 ,這點(diǎn)是當(dāng)年編程語(yǔ)言高度耦合硬件的殘留習(xí)慣。所以你要訪問(wèn)的最后一個(gè)元素的索引是 N-1 ,其中 N 是你定義的數(shù)組的大小。訪問(wèn)數(shù)組外的元素,也就是訪問(wèn)的索引溢出是一個(gè)經(jīng)常發(fā)生的錯(cuò)誤。很多黑客也會(huì)利用這點(diǎn)來(lái)訪問(wèn)內(nèi)存中的未知位置。
執(zhí)行命令安裝 ECharts:npm i echarts安裝完成后,可復(fù)用 webpack 例子中的 src/index.js 代碼:import * as echarts from 'echarts/src/echarts';import 'echarts/src/chart/bar';const myChart = echarts.init(document.getElementById('app'));// 指定圖表的配置項(xiàng)和數(shù)據(jù)const option = { title: { text: 'ECharts 入門示例', }, tooltip: {}, legend: { data: ['銷量'], }, xAxis: { data: ['襯衫', '羊毛衫', '雪紡衫', '褲子', '高跟鞋', '襪子'], }, yAxis: {}, series: [ { name: '銷量', type: 'bar', data: [5, 20, 36, 10, 10, 20], }, ],};myChart.setOption(option);上例代碼,在根目錄上執(zhí)行 npx rollup -c 命令,即可生成只含 echarts 核心包、bar 圖表以及上例代碼的文件,在頁(yè)面中引入該文件即可,建議下載 示例源碼 查看運(yùn)行效果。
Pandas 對(duì)于排序的操作分為按索引排序和按數(shù)據(jù)值排序,分別通過(guò)函數(shù) sort_index () 和 sort_values () 進(jìn)行實(shí)現(xiàn),接下來(lái)我們?cè)敿?xì)學(xué)習(xí)每個(gè)函數(shù)的使用方式。首先我們通過(guò) Excel 進(jìn)行數(shù)據(jù)的解析。Pandas 解析的數(shù)據(jù)對(duì)象 data 具體內(nèi)容如下:# 導(dǎo)入pandas包import pandas as pddata_path="C:/Users/13965/Documents/myFuture/IMOOC/pandasCourse-progress/data_source/第15小節(jié)/execl數(shù)據(jù)demo.xlsx"# 解析數(shù)據(jù)data = pd.read_excel(data_path)print(data)# --- 輸出結(jié)果 data 數(shù)據(jù)對(duì)象 --- BB AA CC EE DD0 11 3 3230.0 45.6 20.01 4 2 2124.0 67.0 NaN2 7 23 345.0 33.9 23.03 5 11 2361.0 59.5 4.04 10 45 326.0 69.9 55.05 33 33 NaN 75.0 67.0
使用 -type 參數(shù)可以查找不同類型的文件,其可以查找的文件類型如下:find -type 文件類型介紹描述f普通文件d目錄文件l符號(hào)鏈接文件b塊設(shè)備文件c字符設(shè)備文件p管道文件s套接字文件這里以查找 /home 目錄中的所有目錄為例,使用 find 命令跟上 -type 來(lái)限制文件類型,命令如下:cd /find ./home -type d執(zhí)行結(jié)果如下圖:Tips:find ./home -type d 其中的 ./home 表示要查找的相對(duì)路徑的目錄, -type d 表示查找文件類型為目錄。
Mesos 是一個(gè)開(kāi)源的集群管理框架,它可以將數(shù)據(jù)中心放在一臺(tái)電腦里運(yùn)行,從數(shù)據(jù)中心、操作系統(tǒng)的角度提供資源視圖。對(duì)外提供簡(jiǎn)單的 API,同時(shí)隱藏內(nèi)部的很多復(fù)雜架構(gòu)。它由 UC Berkeley 的Benjemin Hinderman,Andy Konwinski 和 Matei Zaharia 開(kāi)發(fā),早于 Docker 產(chǎn)生,Mesos 作為資源管理器,后來(lái)在 Twitter 里發(fā)展成熟,并很快成為 Apache 基金會(huì)的頂級(jí)項(xiàng)目。2.2.1 功能特性可擴(kuò)展到 10000 個(gè)節(jié)點(diǎn);使用 ZooKeeper 實(shí)現(xiàn) Master 和 Slave 的容錯(cuò);使用 Linux 容器實(shí)現(xiàn)本地任務(wù)隔離;基于多資源(內(nèi)存,CPU、磁盤(pán)、端口)調(diào)度;提供 Java,Python,C++ 等多種語(yǔ)言 API。
如果要把 Eclipse 中的文件導(dǎo)出來(lái),我們有以下三種方式:直接通過(guò)鼠標(biāo)左鍵把文件拖拉到我們的操作系統(tǒng)的文件系統(tǒng)中。通過(guò)操作系統(tǒng)的復(fù)制粘貼功能(如直接鼠標(biāo)右鍵選擇復(fù)制粘貼,又或者 Windows 操作系統(tǒng)中的快捷鍵 Ctrl + C 和 Ctrl + V)。使用導(dǎo)出向?qū)нx項(xiàng)。前兩種方式的操作較為簡(jiǎn)單,根據(jù)不同的操作系統(tǒng)版本,可能需要增加按住 Ctrl 或者 Shift 鍵操作。第三種導(dǎo)出向?qū)нx項(xiàng)的方式是我們的常用方式,下面我們來(lái)看看如何操作。
實(shí)際上使用點(diǎn)變型在 Kotlin 中還是有一定的使用場(chǎng)景,想象一下這樣一個(gè)實(shí)際場(chǎng)景,盡管某個(gè)泛型類是不變的,也就是具有可讀可寫(xiě)的操作,可是有時(shí)候在某個(gè)函數(shù)中,我們一般僅僅只用到只讀或只寫(xiě)操作,這時(shí)候利用使用點(diǎn)變型它能使一個(gè)不變型的縮小型變范圍蛻化成協(xié)變或逆變的。是不是突然懵逼了,用源碼來(lái)說(shuō)話,你就明白了,一起來(lái)看個(gè)源碼中的例子。Kotlin 中的 MutableCollection<E> 是不變的,一起來(lái)看下它的定義:public interface MutableCollection<E> : Collection<E>, MutableIterable<E> {//沒(méi)有in和out修飾,說(shuō)明是不變 override fun iterator(): MutableIterator<E> public fun add(element: E): Boolean public fun remove(element: E): Boolean public fun addAll(elements: Collection<E>): Boolean public fun removeAll(elements: Collection<E>): Boolean public fun retainAll(elements: Collection<E>): Boolean public fun clear(): Unit}然后我們接著看 filter 和 filterTo 函數(shù)的源碼定義:public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> { return filterTo(ArrayList<T>(), predicate)}//注意: 這里<T, C : MutableCollection<in T>>, MutableCollection<in T>聲明成逆變的了,是不是很奇怪啊,之前明明有說(shuō)它是不變的啊,怎么這里就聲明逆變了public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean): C { for (element in this) if (predicate(element)) destination.add(element) return destination}通過(guò)上面的函數(shù)是不是發(fā)現(xiàn)和 MutableCollection 不變相違背啊,實(shí)際上不是的。這里就是一種典型的使用點(diǎn)變型的使用,我們可以再仔細(xì)分析下這個(gè)函數(shù),destination 在 filterTo 函數(shù)的內(nèi)部只做了寫(xiě)操作,遍歷 Iterable 中的元素,并把他們 add 操作到 destination 集合中,可以驗(yàn)證我們上述的結(jié)論了。雖然 MutableCollection 是不變的,但是在函數(shù)內(nèi)部只涉及到寫(xiě)操作,完全就可以使用 使用點(diǎn)變型將它指定成一個(gè)逆變的型變類型,由不變退化成逆變明顯不會(huì)影響泛型安全所以這里處理是完全合法的。可以再去看其他集合操作 API,很多地方都使用了這種方式。上述關(guān)于不變退化到逆變的,這里再講個(gè)不變退化到協(xié)變的例子://可以看到source集合泛型類型聲明成了out協(xié)變了???fun <T> copyList(source: MutableList<out T>, destination: MutableList<T>): MutableList<T>{ for (element in source) destination.add(element)}MutableList<E> 就是前面常說(shuō)的不變的類型,同樣具有可讀可寫(xiě)操作,但是這里的 source 的集合泛型類型聲明成了 out 協(xié)變,會(huì)不會(huì)又蒙了。應(yīng)該不會(huì)啊,有了之前逆變的例子,應(yīng)該大家都猜到為什么了。很簡(jiǎn)單就是因?yàn)樵?copyList 函數(shù)中,source 集合沒(méi)有涉及寫(xiě)操作只有讀操作,所以可以使用 使用點(diǎn)變型將 MutableList 的不變型退化成協(xié)變型,而且很顯然不會(huì)引入泛型安全的問(wèn)題。所以經(jīng)過(guò)上述例子和以前例子關(guān)于如何使用逆變、協(xié)變、不變。還是我之前說(shuō)那句話,不要去死記規(guī)則,關(guān)鍵在于使用場(chǎng)景中讀寫(xiě)操作是否引入泛型類型安全的問(wèn)題。如果明確讀寫(xiě)操作的場(chǎng)景了完全可以按照上述例子那樣靈活運(yùn)用泛型的型變的,可以程序?qū)懙酶油昝馈?/p>
Go 語(yǔ)言中,通過(guò) func 關(guān)鍵字來(lái)聲明和定義函數(shù)。Go 語(yǔ)言和 C 語(yǔ)言不同,Go 語(yǔ)言函數(shù)的聲明和定義是一起的,不存在先聲明在定義,且聲明時(shí)不分前后均可互相調(diào)用。代碼示例package mainimport "fmt"func print(s string) { fmt.Println(s)}func main() { print("Hello Codey !")}第 5 行:聲明并定義一個(gè)名叫 print 的函數(shù),函數(shù)接收一個(gè) string 類型的參數(shù);第 6 行:函數(shù)體。一個(gè)輸出接收進(jìn)來(lái)參數(shù)的值的語(yǔ)句;第 9 行:聲明并定義了一個(gè)叫main的函數(shù)。Go 語(yǔ)言中程序的入口就時(shí) main 函數(shù),所有的程序都以main 函數(shù)作為入口;第 10 行:調(diào)用 print 函數(shù),傳入?yún)?shù)"Hello Codey !"。執(zhí)行結(jié)果:
阿里云 AI (https://ai.aliyun.com) 致力于構(gòu)建最全面、最開(kāi)放、最前沿的AI開(kāi)放平臺(tái),從 2015 年開(kāi)始,阿里云推出 AI 產(chǎn)品,包括語(yǔ)音識(shí)別,還有圖像識(shí)別、視覺(jué)識(shí)別等 130 多款細(xì)分產(chǎn)品,適用于 300 多個(gè)場(chǎng)景。阿里云的 AI 解決方案阿里云提供了提供最易用的 API、SDK 等開(kāi)發(fā)組件,助力企業(yè)快速高效的實(shí)現(xiàn)產(chǎn)品升級(jí)。對(duì)每項(xiàng)產(chǎn)品提供多種編程接口,包括:Python、Java、C++、ios、Android、Restful 等。以語(yǔ)音合成為例,阿里云 AI 的語(yǔ)音合成 Python SDK 提供了如下接口:SpeechSynthesizer,設(shè)置語(yǔ)音合成請(qǐng)求參數(shù),發(fā)送語(yǔ)音合成請(qǐng)求。SpeechSynthesizerCallback,用于獲取語(yǔ)音合成結(jié)果。
Unsafe 類是 Java 整個(gè)并發(fā)包底層實(shí)現(xiàn)的核心,它具有像 C++ 的指針一樣直接操作內(nèi)存的能力,而這也就意味著其越過(guò)了 JVM 的限制。Unsafe 類有如下的特點(diǎn):Unsafe 不受 JVM 管理,也就無(wú)法被自動(dòng) GC,需要手動(dòng) GC,容易出現(xiàn)內(nèi)存泄漏;Unsafe 的大部分方法中必須提供原始地址 (內(nèi)存地址) 和被替換對(duì)象的地址,偏移量需自行計(jì)算,一旦出現(xiàn)問(wèn)題必然是 JVM 崩潰級(jí)別的異常,會(huì)導(dǎo)致整個(gè)應(yīng)用程序直接 crash;直接操作內(nèi)存,也意味著其速度更快,在高并發(fā)的條件之下能夠很好地提高效率。
構(gòu)成 C 語(yǔ)言分支結(jié)構(gòu)的語(yǔ)句有兩大類。一類是 if 語(yǔ)句類,另外一類就是 switch 語(yǔ)句。其中 if 語(yǔ)句類中情況最為復(fù)雜,也最常使用。里面又由 4 個(gè)詳細(xì)的小類別構(gòu)成。由于單一的語(yǔ)句構(gòu)成的問(wèn)分機(jī)構(gòu)功能相對(duì)單一,所以在應(yīng)用的時(shí)候還會(huì)引入分支結(jié)構(gòu)的組合和嵌套來(lái)完成更為復(fù)雜的功能。這其中一些還比較容易混淆。大家在使用過(guò)程中要注意。分支結(jié)構(gòu)作為編程語(yǔ)言中極其重要的組成部分,需要大家能夠熟練地掌握。通過(guò)不斷的應(yīng)用來(lái)增強(qiáng)這方面的技能。
<?phpnamespace app\study\controller;use app\study\model\StudentModel;use cmf\controller\AdminBaseController;use PhpOffice\PhpSpreadsheet\Spreadsheet;use PhpOffice\PhpSpreadsheet\Writer\Xlsx;use think\facade\Request;class StudentController extends AdminBaseController{ public function add() { return $this->fetch(); } public function addPost() { try { $studentModel = new StudentModel(); $studentModel->name = $this->request->param('name', ""); $studentModel->age = $this->request->param('age', 0, 'intval'); $studentModel->id_number = $this->request->param('id_number', ""); $studentModel->created_at = time(); $studentModel->save(); } catch (\Exception $exception) { return $this->error($exception->getMessage()); } return $this->success('請(qǐng)求成功'); } public function upload() { return $this->fetch(); } public function uploadExcel() { $data = $this->request->param(); $file_url = "./upload/" . $data['file_url']; $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_url); $n = 2; while (true) { $name = $spreadsheet->getActiveSheet()->getCell('A' . $n)->getValue(); $age = $spreadsheet->getActiveSheet()->getCell('B' . $n)->getValue(); $id_number = $spreadsheet->getActiveSheet()->getCell('C' . $n)->getValue(); try { $studentModel = new StudentModel(); $studentModel->name = $name; $studentModel->age = $age; $studentModel->id_number = $id_number; $studentModel->created_at = time(); $studentModel->save(); } catch (\Exception $exception) { } if (empty($name) && empty($age) && empty($id_number)) { break; } $n++; } return $this->success('導(dǎo)入成功'); } public function down() { //讀取數(shù)據(jù) $students = StudentModel::select(); //設(shè)置 excel 信息 $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->getDefaultRowDimension()->setRowHeight(20);//設(shè)置默認(rèn)行高 $sheet->getDefaultColumnDimension()->setWidth(10);//設(shè)置默認(rèn)寬度 $sheet->getStyle("A1:Z1")->getFont()->setSize(10)->setBold(true);//設(shè)置第一行字體 $sheet->getStyle("A1:Z1")->getFont()->getColor()->setRGB("FFFFFF");//設(shè)置第一行字體顏色 $sheet->setCellValue('A1', 'ID'); $sheet->setCellValue('B1', '學(xué)生姓名'); $sheet->setCellValue('C1', '年齡'); $sheet->setCellValue('D1', '身份證號(hào)'); $n = 2; foreach ($students as $student) { $sheet->setCellValue('A' . $n, $student->id);//客戶名稱 $sheet->setCellValue('B' . $n, $student->name);//客戶編號(hào) $sheet->setCellValue('C' . $n, $student->age);// $sheet->setCellValue('D' . $n, $student->id_number); $n++; } $file = "學(xué)生信息" . date('YmdHis') . ".xlsx"; $writer = new Xlsx($spreadsheet); header('Content-Disposition: attachment;filename=' . $file);//告訴瀏覽器將輸出文件的名稱 header('Cache-Control: max-age=0');//禁止緩存 $writer->save("php://output");; }}
從上文堆內(nèi)存的結(jié)構(gòu)圖中,我們看到了比較多的JVM堆內(nèi)存中的專有名詞,比如:年輕代,老年代。那么對(duì)于堆內(nèi)存來(lái)說(shuō),分代是什么意思呢?為什么要進(jìn)行分代呢?分代:將堆內(nèi)存從概念層面進(jìn)行模塊劃分,總體分為兩大部分,年輕代和老年代。從物理層面將堆內(nèi)存進(jìn)行內(nèi)存容量劃分,一部分分給年輕代,一部分分給老年代。這就是我們所說(shuō)的分代。分代的意義:易于堆內(nèi)存分類管理,易于垃圾回收。類似于我們經(jīng)常使用的 Windows 操作系統(tǒng),我們會(huì)將物理磁盤(pán)劃出一部分存儲(chǔ)空間作為用戶系統(tǒng)安裝盤(pán)(如 C 盤(pán)),我們還極大可能將剩余的磁盤(pán)空間劃分為 C, D, E 等磁盤(pán),用于存儲(chǔ)同一類型的數(shù)據(jù)。易于管理:對(duì)于堆空間的分代也是如此,比如新創(chuàng)建的對(duì)象會(huì)進(jìn)入年輕代(YoungGen)的生成區(qū)(Eden),生命周期未結(jié)束的且可達(dá)的對(duì)象,在經(jīng)歷多次垃圾回收之后,會(huì)存放入老年代(OldGen),這就是分類管理;易于垃圾回收:將對(duì)象根據(jù)存活概率進(jìn)行分類,對(duì)存活時(shí)間長(zhǎng)的對(duì)象,放到固定區(qū),從而減少掃描垃圾時(shí)間及 GC 頻率。針對(duì)分類進(jìn)行不同的垃圾回收算法,對(duì)算法揚(yáng)長(zhǎng)避短。Tips:關(guān)于上文提到的垃圾回收部分的知識(shí),我們會(huì)在后邊的章節(jié)做專門的、詳細(xì)的講解,此處我們先做了解即可。
在將 Swagger Codegen 的依賴引入到 Spring Boot 中去后,我們就可以使用 Maven 自帶的命令來(lái)將上述配置信息分別生成服務(wù)端和客戶端代碼,命令如下:首先,將上述配置好的文件利用 Swagger Codegen 來(lái)生成服務(wù)端和客戶端代碼 java -jar swagger-codegen-cli.jar generate -i swagger.yaml -c swaggerConfig.json -l spring -o server代碼解釋:第一行,使用 generate 命令來(lái)將配置在 swagger.yaml 文件中的服務(wù)端代碼進(jìn)行生成。第一行,使用 -c 參數(shù),表明使用 json 配置文件,并且該配置文件的名稱為 swaggerConfig.json。第二行,使用 -l 參數(shù),表明客戶端所使用的語(yǔ)言為 spring 。第二行,使用 -o 參數(shù)來(lái)指定代碼最終的存放位置,server 表示將生成的代碼存放到名為 server 的文件夾下。然后我們使用 cd 命令來(lái)進(jìn)到我們生成代碼后所存放的目錄: cd server最后我們將生成的代碼打成 Jar 包: mvn package這是 Maven 自帶的打包命令,執(zhí)行該命令之后,Maven 會(huì)默認(rèn)讀取項(xiàng)目中的 pom 文件中配置的打包規(guī)則,即 packaging 節(jié)點(diǎn),如果該節(jié)點(diǎn)沒(méi)有配置任何規(guī)則,則 Maven 會(huì)默認(rèn)打成 Jar 包 (這里我們配置了 Jar)。這樣我們就可以在項(xiàng)目的 target 目錄下,找到我們利用 Swagger Codegen 所生成的服務(wù)端和客戶端代碼的 Jar 包了,我們可以把該 Jar 包放到其他環(huán)境中使用,也可以供其他項(xiàng)目使用,這就是我們利用 Swagger Codegen 所生成的服務(wù)端和客戶端代碼的最終使用目的。
簡(jiǎn)單來(lái)說(shuō),Redis(Remote Dictionary Server)也是一個(gè)數(shù)據(jù)庫(kù),不過(guò)和傳統(tǒng)數(shù)據(jù)庫(kù)不同點(diǎn)在于 Redis 的數(shù)據(jù)存儲(chǔ)在內(nèi)存中,所以讀寫(xiě)速度遠(yuǎn)超傳統(tǒng)數(shù)據(jù)庫(kù)(例如 MySQL ),同時(shí)因?yàn)镵ey—Value的數(shù)據(jù)存儲(chǔ)形式非常零活,所以Redis被廣泛應(yīng)用在緩存方向,并且能適配各種實(shí)戰(zhàn)的應(yīng)用場(chǎng)景。Redis 提供了多種語(yǔ)言的 API ,比如常見(jiàn)的 Java、C++、Python 等,基本是后端開(kāi)發(fā)中最常用的緩存中間件。掌握 MySQL 是后端開(kāi)發(fā)的必備技能,掌握 Redis 則是一個(gè)簡(jiǎn)歷加分項(xiàng)。我們?cè)谥暗恼鹿?jié)對(duì) MySQL 常見(jiàn)的題目進(jìn)行了剖析, 在本章中我們會(huì)介紹 Redis 相關(guān)的高頻面試題。
請(qǐng)書(shū)寫(xiě) SQL 語(yǔ)句,返回imooc_class和imooc_user表的全連接。SELECT * FROM imooc_class FULL OUTER JOIN imooc_user ON imooc_class.id = imooc_user.class_id;查詢結(jié)果如下:+--------+----------+----------+--------+---------------+| id | username | class_id | id | class_name |+--------+----------+----------+--------+---------------+| 1 | pedro | 1 | 1 | SQL必知必會(huì) || 2 | peter | 1 | 1 | SQL必知必會(huì) || 3 | faker | 2 | 2 | C語(yǔ)言入門 || 4 | lucy | 4 | 4 | JVM花落知多少 || 5 | jery | <null> | <null> | <null> || <null> | <null> | <null> | 3 | JAVA高效編程 |+--------+----------+----------+--------+---------------+一些數(shù)據(jù)庫(kù),比如 MySQL 是不支持全連接的,但可以通過(guò)左、右外連接的并集(Union)來(lái)模擬實(shí)現(xiàn),如下:SELECT *FROM imooc_userLEFT JOIN imooc_class ON imooc_class.id = imooc_user.class_idUNIONSELECT *FROM imooc_userRIGHT JOIN imooc_classON imooc_class.id = imooc_user.class_idWHERE imooc_user.class_id IS NULL;提示: SQLite 不支持右連接和全連接,也可以通過(guò)左連接來(lái)模擬右連接,從而實(shí)現(xiàn)全連接。
macOSwindow/linux說(shuō)明? DCtrl D選擇詞(重復(fù)按下時(shí)多重選擇相同的詞進(jìn)行多重編輯)? ? DCtrl ? D復(fù)制(多)行? JCtrl J合并(多)行? ? ?Ctrl ? ?在當(dāng)前行前插入新行? ? /Ctrl ? /塊注釋? YCtrl Y恢復(fù)撤銷? ? VCtrl ? V粘貼并自動(dòng)縮進(jìn)? ? SCtrl ? S保存所有文件? ]Ctrl ]向右縮進(jìn)? [Ctrl [向左縮進(jìn)? ACtrl A全選? LCtrl L選擇行(重復(fù)按下將下一行加入選擇)? ? MCtrl ? M選擇括號(hào)的內(nèi)容? ?Ctrl ?在當(dāng)前行后插入新行? ? KCtrl ? K刪除行? K KCtrl K K從光標(biāo)處刪除至行尾? K ?Ctrl K ?從光標(biāo)處刪除至行首? K UCtrl K U改為大寫(xiě)? K LCtrl K L改為小寫(xiě)? CCtrl C復(fù)制? XCtrl X剪切? VCtrl V粘貼? /Ctrl /注釋? ZCtrl Z撤銷
首先在 application.properties 中指定配置文件的位置。實(shí)例:spring.cache.jcache.config=classpath:ehcache.xmlspring.cache.type=jcache然后在 resource 文件夾中添加 ehcache.xml 配置文件,內(nèi)容如下:實(shí)例:<?xml version="1.0" encoding="UTF-8"?><config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd"> <!-- 持久化路徑 --> <persistence directory="C://ehcache" /> <!--緩存模板 --> <cache-template name="CacheTemplate"> <expiry> <!--存活時(shí)間 --> <tti>60</tti> </expiry> <resources> <!--堆空間 --> <heap unit="entries">2000</heap> <!-- 堆外空間 --> <offheap unit="MB">500</offheap> </resources> </cache-template> <!--緩存對(duì)象 --> <cache alias="GoodsCache" uses-template="CacheTemplate"> </cache></config>Tips:Ehcache 的配置比較復(fù)雜,此處只是給出簡(jiǎn)單的示例,感興趣的同學(xué)可以查閱更多資料。
我們知道,如果需要運(yùn)行 Java 程序,必須要安裝 JDK,這說(shuō)明 JDK 中就包含了支持 Java 語(yǔ)言運(yùn)行的JVM ,我們來(lái)看下如何查看本機(jī)的 JVM 信息。無(wú)論是 Windows 操作系統(tǒng)還是 Linux 操作系統(tǒng),正確安裝 JDK 并且配置好環(huán)境變量后,在命令行輸入如下命令進(jìn)行查看:java -version以本人的機(jī)器為例,可以看到如下的執(zhí)行結(jié)果:C:\Users\Wayne.WangTJ>java -versionjava version "1.8.0_191"Java(TM) SE Runtime Environment (build 1.8.0_191-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)我們仔細(xì)看下最后一句執(zhí)行結(jié)果,Java HotSpot? 64-Bit Server VM (build 25.191-b12, mixed mode),這就是我的電腦中 Jvm 虛擬機(jī)操作系統(tǒng)的版本。 當(dāng)然了,安裝不同的版本,結(jié)果是有所區(qū)別的。
Reflect.get() 方法是從對(duì)象中讀取屬性的值,類似 ES5 中屬性訪問(wèn)器語(yǔ)法: obj[key] ,但是它是通過(guò)調(diào)用函數(shù)來(lái)獲得返回結(jié)果的。語(yǔ)法:Reflect.get(target, propertyKey[, receiver])target:需要取值的目標(biāo)對(duì)象;propertyKey:需要獲取的值的鍵值;receiver:如果 target 對(duì)象中指定了 getter,receiver 則為 getter 調(diào)用時(shí)的 this 值。如果目標(biāo)值 target 類型不是 Object,則拋出一個(gè) TypeError。// Objectvar obj = { a: 1, b: 2 };Reflect.get(obj, "a"); // 1// ArrayReflect.get(["a", "b", "c"], 1); // "one"第三個(gè)參數(shù) receiver 是 this 所在的上下文,不傳時(shí)指的是當(dāng)前對(duì)象,如果傳如一個(gè)人對(duì)象則 this 指向該對(duì)象。下面我們來(lái)看個(gè)實(shí)例:let obj = { name: 'imooc', lesson: 'ES5 Wiki', get info() { console.log(`這是慕課 ${this.lesson}`); return 0 }};Reflect.get(obj, 'info'); // 這是慕課 ES5 WikiReflect.get(obj, 'info', {lesson: 'ES6 Wiki'}); // 這是慕課 ES5 Wiki
請(qǐng)書(shū)寫(xiě) SQL 語(yǔ)句,返回imooc_class和imooc_user兩表的內(nèi)連接集合。分析:使用 Select 搭配 Inner Join 即可。語(yǔ)句SELECT * FROM imooc_user INNER JOIN imooc_class ON imooc_user.class_id = imooc_class.id;結(jié)果如下:+----+----------+----------+----+---------------+| id | username | class_id | id | class_name |+----+----------+----------+----+---------------+| 1 | pedro | 1 | 1 | SQL必知必會(huì) || 2 | peter | 1 | 1 | SQL必知必會(huì) || 3 | faker | 2 | 2 | C語(yǔ)言入門 || 4 | lucy | 4 | 4 | JVM花落知多少 |+----+----------+----------+----+---------------+一般情況下,交叉連接是默認(rèn)的連接方式,因此我們可以省略INNER關(guān)鍵字:SELECT * FROM imooc_user JOIN imooc_class ON imooc_user.class_id = imooc_class.id;這樣也能得到同樣的結(jié)果;使用 Join 和 On 關(guān)鍵字可以顯式連接兩表,我們也可以通過(guò) Where 進(jìn)行隱式的連接:SELECT * FROM imooc_user, imooc_class WHERE imooc_user.class_id = imooc_class.id;
Ruby 的每個(gè)迭代器都從哈希和數(shù)組中返回每個(gè)元素,最常見(jiàn)的是 each 迭代器。下面是一個(gè)數(shù)組的例子。實(shí)例:[1, 2, 3, 4, 5].each do |number| puts numberend# ---- 輸出結(jié)果 ----12345解釋:number 參數(shù)代表著每次迭代器循環(huán)的每個(gè)元素,一共循環(huán) 5 次,分別輸出 1,2,3,4,5。上面的場(chǎng)景同樣適用于哈希:實(shí)例:{a: 1, b: 2, c: 3}.each do |item| puts "======" puts item puts item.class puts "======"end# ---- 輸出結(jié)果 ----======a1Array============b2Array============c3Array======解釋:通過(guò)上述例子我們可以看到,我們?cè)诿看蔚鰜?lái)的元素是一個(gè)Array,第一個(gè)元素是每個(gè)鍵值對(duì)的鍵,第二個(gè)元素是每個(gè)鍵值對(duì)的值。
上面我們已經(jīng)了解了v-if的使用方法。事實(shí)上,v-if的條件渲染和JavaScript條件判斷語(yǔ)句中的if、else、else if非常類似。3.6.1 使用 v-else 指令來(lái)表示 v-if 的 “else 塊”:558代碼解釋:在 HTML 代碼中,當(dāng)隨機(jī)數(shù)大于 0.5 的時(shí)候會(huì)顯示中文的“你好,慕課網(wǎng)!”,否則,顯示英文的 “Hello, imooc!”。3.6.2 v-else-if,充當(dāng) v-if 的“else-if 塊”,可以連續(xù)使用:559在 HTML 代碼中,我們通過(guò)判斷 number 的值來(lái)控制元素的顯示隱藏。首先判斷 number 是否為 1 ,如果是顯示 A,如果不是,則判斷 number 是否為 2,如果是顯示 B,否則顯示 C。
我們可以使用 Android Studio 界面將 Gradle 關(guān)聯(lián)到外部 CMake 或 ndk-build 項(xiàng)目:從 IDE 左側(cè)打開(kāi) Project 窗格,然后選擇 Android 視圖。右鍵點(diǎn)擊我們想要關(guān)聯(lián)到原生庫(kù)的模塊(例如 app 模塊),然后從菜單中選擇 Link C++ Project with Gradle。從下拉菜單中,選擇 CMake 或 ndk-build。如果選擇 CMake,請(qǐng)使用 Project Path 旁的字段為我們的外部 CMake 項(xiàng)目指定 CMakeLists.txt 腳本文件。如果選擇 ndk-build,請(qǐng)使用 Project Path 旁的字段為我們的外部 ndk-build 項(xiàng)目指定 Android.mk 腳本文件。如果 Application.mk 文件與我們的 Android.mk 文件位于同一目錄下,Android Studio 也會(huì)包含此文件。點(diǎn)擊 OK。
#include <stdio.h>int main(){ int x, y; x = 0; y = 10; printf("%s\n", (x > y) ? "x > y" : "x < y"); return 0;}運(yùn)行結(jié)果:x < y這個(gè)語(yǔ)句還可以配合賦值語(yǔ)句使用,給變量賦值。#include <stdio.h>int main(){ int x, y, z; x = 0; y = 10; z = (x > y) ? 20 : 50; printf("%d\n", z); return 0;}運(yùn)行結(jié)果:50我們?cè)谥v述 C 語(yǔ)言邏輯運(yùn)算的時(shí)候知道了,在 C 語(yǔ)言中,即使引入了布爾類型,但是在使用 printf 函數(shù)輸出的時(shí)候,也是沒(méi)有辦法來(lái)直接輸出布爾類型的,只能是通過(guò)輸出整除類型來(lái)替代。如果我們想直接輸出布爾類型,可以通過(guò)編寫(xiě)一個(gè)小的程序來(lái)擴(kuò)展輸出,將 0 和 1 直接替換為 false 和 true 輸出。但是這樣做如果輸出次數(shù)很多是值得寫(xiě)這樣一個(gè)程序的,要是只是像我們測(cè)試或者只是單次輸出,那么就顯得有些復(fù)雜了。這時(shí)候,我們這次介紹的三目運(yùn)算符就有用武之地了。#include <stdio.h>#include <stdbool.h>int main(){ bool x, y, z; x = false; y = true; printf("x = %s; y = %s\n", x ? "true" : "false", y ? "true" : "false"); z = x || y; printf("x || y = %s\n", z ? "true" : "false"); z = x && y; printf("x && y = %s\n", z ? "true" : "false"); printf("!x = %s\n", !x ? "true" : "false"); printf("!y = %s\n", !y ? "true" : "false"); return 0;}運(yùn)行結(jié)果:x = false; y = truex || y = truex && y = false!x = true!y = false在上面的代碼中每個(gè) printf 函數(shù)都使用了本節(jié)介紹的三目運(yùn)算符。其實(shí)就是在每個(gè) printf 函數(shù)里都內(nèi)置了一個(gè)判斷語(yǔ)句。這個(gè)判斷語(yǔ)句會(huì)根據(jù)傳入的變量的值來(lái)進(jìn)行判斷,分別用 true 和 false 來(lái)替換 1 和 0 ,這樣就可以實(shí)現(xiàn)布爾值的輸出了。
對(duì)象的屬性在訪問(wèn)的時(shí)候,務(wù)必要關(guān)心屬性是否真的存在。特別是服務(wù)端返回的數(shù)據(jù),如果碰到數(shù)據(jù)出錯(cuò),就可能造成頁(yè)面無(wú)反應(yīng)、白屏等問(wèn)題:const getList = async () => { // 假裝拿了服務(wù)端的數(shù)據(jù),并返回了 return { code: 1, data: { list: null, page: 1, count: 1111, }, };};getList() .then((res) => { // 取出數(shù)據(jù) const { data } = res; const { list, page, count } = data; list.forEach(() => { // 處理一些業(yè)務(wù) }); // 拋錯(cuò):TypeError: Cannot read property 'forEach' of null // alert 不會(huì)執(zhí)行 alert('獲取數(shù)據(jù)成功'); });上面這段代碼,執(zhí)行是會(huì)報(bào)錯(cuò)的,因?yàn)?list 是 null,并不是期望的數(shù)組,這樣就導(dǎo)致了代碼無(wú)法正常執(zhí)行下去。所以在使用的時(shí)候,最好可以判斷或者處理一下不可靠的數(shù)據(jù)。// 使用 if 判斷// ...if (list) { list.forEach(() => { // 處理一些業(yè)務(wù) });} else { // ...}// ...// 提供一個(gè)默認(rèn)值const { list = [], page, count } = data;list.forEach(() => { // 處理一些業(yè)務(wù)});// ...// 提供一個(gè)默認(rèn)值const { list, page, count } = data;(list || []).forEach(() => { // 處理一些業(yè)務(wù)});// ...方法還有很多,還可以封裝一個(gè)函數(shù)專門用來(lái)取對(duì)象屬性的值,目的就是要代碼變得更加可靠,防止一些可能會(huì)造成重要后果的異常。如在 react 組件中,如果 render 函數(shù)中拋出了錯(cuò)誤沒(méi)有處理,就可能導(dǎo)致組件或者頁(yè)面白屏。新的 ECMAScript 標(biāo)準(zhǔn)提供了可選鏈和雙問(wèn)號(hào)操作符來(lái)更好的處理這個(gè)問(wèn)題。const object = { a: { b: 2, c: { d: 3, }, },};const f = object.a?.b?.c?.d?.e?.f ?? 10;console.log(f); // 輸出:10關(guān)于這個(gè)知識(shí)點(diǎn)不再展開(kāi),可以參考 ES6+ 相關(guān)的 Wiki。簡(jiǎn)單的說(shuō),在訪問(wèn)對(duì)象屬性的時(shí)候,如果數(shù)據(jù)源不可靠,一定要做好處理異常的準(zhǔn)備。
本小節(jié)實(shí)現(xiàn)列出所有聯(lián)系人的功能,如下所示: def list_person(self): for person in self.persons: print('%s,%s,%s' % (person['name'], person['address'], person['phone']))在第 1 行,定義函數(shù) list_person,實(shí)現(xiàn)列出所有聯(lián)系人的功能在第 2 行,遍歷列表 self.persons,循環(huán)變量 self.persons 是一個(gè)字典在第 3 行,打印變量 person 的內(nèi)容對(duì)每個(gè)聯(lián)系人打印輸出一行,假設(shè)通訊錄中已經(jīng)存儲(chǔ)了張三和李四兩個(gè)聯(lián)系人,輸出如下:C:\> python addressBook.py1. create person2. list all persons3. query person4. delete person5. quitEnter a number(1-5): 2張三,南京,12306李四,北京,10086在第 7 行,用戶選擇執(zhí)行功能 2在第 8 行,打印聯(lián)系人張三的信息在第 9 行,打印聯(lián)系人李四的信息
4.4.1 創(chuàng)建目錄對(duì)于一個(gè)不存在的目錄,我們可以使用boolean mkdir()方法創(chuàng)建一個(gè)目錄。例如,我們想在imooc目錄下創(chuàng)建一個(gè)codes目錄,就可以使用該方法編寫(xiě)一段創(chuàng)建目錄的代碼。實(shí)例如下:import java.io.File;public class FileDemo4 { public static void main(String[] args) { // 傳入目錄絕對(duì)路徑 File dir = new File("C:\\Users\\Colorful\\Desktop\\imooc\\codes"); if (!dir.exists()) { // 調(diào)用 mkdir() 方法 boolean result = dir.mkdir(); if (result) { System.out.println("目錄創(chuàng)建成功"); } } }}代碼中我們調(diào)用了File對(duì)象的boolean exists()方法,此方法用于測(cè)試由此抽象路徑名表示的文件或目錄是否存在。當(dāng)不存在時(shí),我們才去創(chuàng)建目錄。運(yùn)行代碼前,imooc文件目錄樹(shù)結(jié)構(gòu)如下:└── imoooc ├── FileDemo2.java ├── Hello.java └── images運(yùn)行結(jié)果:目錄創(chuàng)建成功運(yùn)行代碼后,imooc目錄下多了一個(gè)codes目錄,樹(shù)結(jié)構(gòu)如下:└── imoooc ├── FileDemo2.java ├── Hello.java ├── images └── codes另外,F(xiàn)ile 類也提供了一個(gè)boolean mkdirs()方法,用來(lái)創(chuàng)建由這個(gè)抽象路徑名命名的目錄,包括任何必要但不存在的父目錄。實(shí)際上是在遞歸執(zhí)行mkdir()方法。4.4.2 刪除目錄如果我們想要?jiǎng)h除剛剛創(chuàng)建的codes目錄,可以調(diào)用boolean delete()方法,實(shí)例如下:import java.io.File;public class FileDemo5 { public static void main(String[] args) { // 傳入目錄絕對(duì)路徑 File dir = new File("C:\\Users\\Colorful\\Desktop\\imooc\\codes"); if (dir.exists()) { // 調(diào)用 delete() 方法 boolean deleted = dir.delete(); if (deleted) { System.out.println("刪除目錄成功"); } } }}運(yùn)行代碼前,imooc文件目錄樹(shù)結(jié)構(gòu)如下:└── imoooc ├── FileDemo2.java ├── Hello.java ├── images └── codes運(yùn)行結(jié)果:刪除目錄成功運(yùn)行代碼后,樹(shù)結(jié)構(gòu)如下:└── imoooc ├── FileDemo2.java ├── Hello.java └── images
Java 語(yǔ)言抽象了 java.net.Socket 類,表示一個(gè) Socket,既可以用在客戶端,又可以用在服務(wù)器端。其實(shí) java.net.Socket 也是一個(gè)包裝類,對(duì)外抽象了一組公共方法,具體實(shí)現(xiàn)是在 java.net.SocketImpl 類中完成的,它允許用戶自定義具體實(shí)現(xiàn)。java.net.Socket 類包含的主要功能如下:創(chuàng)建 Socket,具體就是創(chuàng)建一個(gè) java.net.Socket 類的對(duì)象。建立 TCP 連接,可以通過(guò) java.net.Socket 類的構(gòu)造方法完成,也可以調(diào)用它的 connect 方法完成。將 Socket 綁定到本地接口 IP 地址或者端口,可以調(diào)用 java.net.Socket 類的 bind 方法完成。提示:服務(wù)器需要做 bind 操作,客戶端一般不需要做 bind 操作。關(guān)閉連接,可以調(diào)用 java.net.Socket 類的 close 方法完成。接收數(shù)據(jù),可以通過(guò) java.net.Socket 類的 getInputStream 方法,返回一個(gè) java.io.InputStream 對(duì)象實(shí)現(xiàn)數(shù)據(jù)接收。發(fā)送數(shù)據(jù),可以通過(guò) java.net.Socket 類的 getOutputStream 方法,返回一個(gè) java.io.OutputStream 對(duì)象實(shí)現(xiàn)數(shù)據(jù)發(fā)送。java.net.Socket 類提供了一組重載的構(gòu)造方法,方便程序員選擇,大體分為四類:可以傳入服務(wù)器的 host 和 port 參數(shù)原型如下: public Socket(String host, int port) throws UnknownHostException, IOException public Socket(InetAddress address, int port) throws IOException對(duì)于 host 參數(shù),你可以傳入 IP 地址或者是域名。當(dāng)然,你可以傳入構(gòu)造好的 InetAddress 地址結(jié)構(gòu)。在 java.net.Socket 的構(gòu)造方法中,首先會(huì)構(gòu)造一個(gè) InetAddress 地址結(jié)構(gòu),然后進(jìn)行域名解析,最后調(diào)用它的 connect 方法和服務(wù)器建立連接??梢詡魅虢壎ǖ谋镜氐刂穮?shù)原型如下: public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException這類構(gòu)造方法也可以傳入 host 和 port 外,功能和上面類似。另外,還可以傳入 localAddr 和 localPort,會(huì)調(diào)用 java.net.Socket 類的 bind 方法,綁定在本地的接口地址和端口。無(wú)參構(gòu)造方法 public Socket()此構(gòu)造方法,除了構(gòu)造一個(gè) java.net.Socket 類的對(duì)象,并不會(huì)去 connect 服務(wù)器。你需要調(diào)用它的 connect 方法連接服務(wù)器。public void connect(SocketAddress endpoint, int timeout) throws IOException自己調(diào)用 connect 方法,需要構(gòu)造 SocketAddress 結(jié)構(gòu),當(dāng)然你可以設(shè)置連接的超時(shí)時(shí)間,單位是毫秒(milliseconds)。訪問(wèn)代理服務(wù)器public Socket(Proxy proxy) 當(dāng)你需要訪問(wèn)某個(gè)代理服務(wù)器時(shí),可以調(diào)用此構(gòu)造方法,Socket 會(huì)自動(dòng)去連接代理服務(wù)器。創(chuàng)建一個(gè)簡(jiǎn)單的 java.net.Socket 客戶端,示例代碼如下:import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.IOException;import java.io.OutputStream;import java.net.InetSocketAddress;import java.net.Socket;import java.net.SocketAddress;public class TCPClient { // 服務(wù)器監(jiān)聽(tīng)的端口號(hào) private static final int PORT = 56002; private static final int TIMEOUT = 15000; public static void main(String[] args) { Socket client = null; try { // 在構(gòu)造方法中傳入 host 和 port // client = new Socket("192.168.43.49", PORT); // 調(diào)用無(wú)參構(gòu)造方法 client = new Socket(); // 構(gòu)造服務(wù)器地址結(jié)構(gòu) SocketAddress serverAddr = new InetSocketAddress("192.168.0.101", PORT); // 連接服務(wù)器,超時(shí)時(shí)間是 15 毫秒 client.connect(serverAddr, TIMEOUT); System.out.println("Client start:" + client.getLocalSocketAddress().toString()); // 向服務(wù)器發(fā)送數(shù)據(jù) OutputStream out = new BufferedOutputStream(client.getOutputStream()); String req = "Hello Server!\n"; out.write(req.getBytes()); // 不能忘記 flush 方法的調(diào)用 out.flush(); System.out.println("Send to server:" + req); // 接收服務(wù)器的數(shù)據(jù) BufferedInputStream in = new BufferedInputStream(client.getInputStream()); StringBuilder inMessage = new StringBuilder(); while(true){ int c = in.read(); if (c == -1 || c == '\n') break; inMessage.append((char)c); } System.out.println("Recv from server:" + inMessage.toString()); } catch (IOException e) { e.printStackTrace(); } finally { if (client != null){ try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } }}這里我們創(chuàng)建的是阻塞式的客戶端,有幾點(diǎn)需要注意的地方:通過(guò) OutputStream 的對(duì)象向服務(wù)器發(fā)送完數(shù)據(jù)后,需要調(diào)用 flush 方法。BufferedInputStream 的 read 方法會(huì)阻塞線程,所以需要設(shè)計(jì)好消息邊界的識(shí)別機(jī)制,示例代碼是通過(guò)換行符 ‘\n’ 表示一個(gè)消息邊界。java.net.Socket 的各個(gè)方法都拋出了 IOException 異常,需要捕獲。注意調(diào)用 close 方法,關(guān)閉連接。