主頁 > 後端開發 > 1.1 語法入門(更新到冒泡排序)

1.1 語法入門(更新到冒泡排序)

2022-04-12 07:00:16 後端開發

目錄
  • 說在前面的話
    • 前言
      • 內容介紹
      • 更新內容
      • 其他說明
      • 本書由來
      • 幫助說明
      • 求職
      • 致謝與勘誤
    • 自序
      • 第 3 版自序
      • 第 2 版自序
      • 第 1 版自序
      • 第 0 版自序
  • 第一章 JDK 下載及準備作業
    • 1.1 Java 介紹
      • 1.1.1 Java 簡介
      • 1.1.2 Java 技術體系
      • 1.1.3 前后端的作業內容
      • 1.1.4 Java 語言特性
      • 1.1.5 Java 用途
    • 1.2 JDK 下載
      • 1.2.1 JDK 與 JRE 的區別
      • 1.2.2 JDK 下載與安裝
      • 1.2.3 卸載
      • 1.2.4 禁止 JDK 檢查更新
    • 1.3 撰寫代碼前的準備作業
      • 1.3.1 為何要寫筆記
      • 1.3.2 撰寫源代碼使用的記事本
      • 1.3.3 練習雙手打字
      • 1.3.4 Windows10 系統常用快捷鍵
      • 1.3.5 給初學者的一點建議
    • 1.4 Typora 軟體使用
      • 1.4.1 下載與安裝
      • 1.4.2 如何創建 Markdown 檔案
      • 1.4.3 常用的 Markdown 語法
      • 1.4.4 常用的設定
      • 1.4.5 官網打不開的原因
      • 1.4.6 自動上傳圖片
    • 1.5 常用的 DOS 命令
      • 1.5.1 打開 DOS 視窗的幾種方式
      • 1.5.2 進入目錄內:使用絕對路徑與相對路徑演示
      • 1.5.3 常用的 DOS 命令
    • 1.6 Joplin 使用
      • 1.6.1 下載地址
      • 1.6.2 常用設定
    • 1.7 MarkText 使用
      • 1.7.1 編輯區域
      • 1.7.2 偏好設定
      • 1.7.3 圖片上傳
      • 1.7.4 File
      • 1.7.5 Edit
      • 1.7.6 Paragraph
      • 1.7.7 Format
      • 1.7.8 Window
      • 1.7.9 View
      • 1.7.a Help
    • 1.x 總結回顧
    • 1.y 腦海練習
  • 第二章 撰寫第一個程式
    • 2.1 撰寫源代碼并運行
      • 2.1.1 創建 .java 檔案撰寫原始碼
      • 2.1.2 配置環境變數
      • 2.1.3 查看命令使用幫助
      • 2.1.4 解釋代碼含義
      • 2.1.5 編譯與運行
    • 2.2 代碼書寫規范
      • 2.2.1 代碼書寫細節
      • 2.2.2 代碼規范
      • 2.2.3 識別符號與關鍵字
    • 2.3 注釋
      • 2.3.1 單行注釋
      • 2.3.2 多行注釋
      • 2.3.3 檔案注釋
      • 2.3.4 IDEA 工具自動快捷鍵添加普通注釋
      • 2.3.5 使用 javac 命令編譯時出現的"錯誤: 編碼 GBK 的不可映射字符"
      • 2.3.6 查看與修改系統編碼
      • 2.3.7 使用 API 檔案
    • 2.x 總結回顧
    • 2.y 腦海練習
  • 第三章 變數
    • 3.1 變數
      • 3.1.1 字面量
      • 3.1.2 變數
    • 3.2 資料型別
      • 3.2.1 整數型別
      • 3.2.2 浮點型別
      • 3.2.3 字符型別
      • 3.2.4 布爾型別
    • 3.3 型別轉換
      • 3.3.1 基本資料型別轉換
      • 3.3.2 基本資料型別與 String 型別的轉換
    • 3.x 總結回顧
    • 3.y 腦海練習
  • 第四章 運算子
    • 4.1 算術運算子
      • 4.1.1 四則運算:加減乘除
      • 4.1.2 求余數:%
      • 4.1.3 ++、--
    • 4.2 賦值運算子
      • 4.2.1 基本賦值運算子:=
      • 4.2.2 擴展賦值運算子:+=、-=、*=、/=、%=
    • 4.3 關系運算子
      • 4.3.1 >、<、<=、>=
      • 4.3.2 ==
      • 4.3.3 !=
    • 4.4 邏輯運算子
      • 4.4.1 &
      • 4.4.2 |
      • 4.4.3 !
      • 4.4.4 ^
    • 4.5 條件運算子
      • 4.5.1 三目運算子
    • 4.6 運算子優先級
    • 4.x 總結回顧
    • 4.y 實戰演練
  • 第五章 流程控制陳述句
    • 5.1 輸入與輸出
      • 5.1.1 接收輸入
      • 5.1.2 普通輸出
      • 5.1.3 格式化輸出
    • 5.2 分支控制陳述句
      • 5.2.1 if else
      • 5.2.2 switch case
    • 5.3 回圈控制陳述句
      • 5.3.1 for
      • 5.3.2 while
    • 5.4 轉向控制陳述句
      • 5.4.1 break
      • 5.4.2 continue
      • 5.4.3 return
    • 5.x 總結回顧
    • 5.y 掀起波瀾
  • 第六章 陣列
    • 6.1 一維陣列
      • 6.1.1 陣列介紹
      • 6.1.2 一維陣列的宣告
      • 6.1.3 一維陣列的遍歷
      • 6.1.4 陣列元素默認值
      • 6.1.5 陣列賦值機制
    • 6.2 多維陣列
      • 6.2.1 二維陣列宣告
      • 6.2.2 遍歷二維陣列
      • 6.2.3 靜態方法呼叫
    • 6.3 排序
      • 6.3.1 時間復雜度
      • 6.3.2 空間復雜度
      • 6.3.3 冒泡排序
      • 6.3.4 簡單選擇排序
  • 加載速度太慢,該分了

說在前面的話

前言

內容介紹

介紹 JavaSE 基礎的基本語法知識,不會包含特別難以理解或更深層次的內容,通俗易懂,

前提

本書的所有例子使用 JDK8 在 Windows10 系統下完成,所以默認使用 exe;若你與我的不一致,快捷鍵、原始碼都有可能不同,但網上無償資源十分的多,搜索了解不同之處即可,

受眾人群

區別于教材,不會設問不答,而是十分詳細,不會為讀者留出思考和遐想的空間;目的只為節省時間,算是入門的自學讀物吧,

主要讓小白快速了解或回顧 JavaSE 的基礎語法知識,隨看即用,無閱讀門檻,

如果要明明白白,至少要有初高中數學知識,否則遇到什么函式、多次項、對數、極限...有可能迷糊,

主要內容

本書前 k 章,涵蓋了如 Java 基礎語法、變數、運算子、流程控制陳述句、面向物件、常用類、集合、IO 等部分,基本囊括作為后端開發人員必學的知識點,

另外把那些不常用的知識自成一章,移入擴充內容

本書示范中,將可能使用到的軟體、工具網址放入資源地址中,

章節編排

每章共有 3 級目錄,取名盡量保持唯一性;第 2 級目錄隨后跟著內容導視,用來統領第 3 級目錄的內容;若第 3 級目錄中還有大量知識點,會提取到內容如下

對于講原始碼的部分,先拋出結論,自成一節,在它的下一個目錄,粘貼全部原始碼,逐行分析,

每章的結尾會插入總結回顧與習題;習題的平均難度分級:腦海練習、實戰演練、掀起波瀾、頭腦風暴、大腦宕機、空空如也,

此外正文中可能會以課堂練習思考的形式發問,思考的答案緊跟題目后面,課堂練習答案在文章末尾,參考答案自成一章,

如何使用

因為人的大腦很特別,會自動屏蔽掉日常普通、枯燥乏味的事情,目的是保持記憶體充足,它只記住比較特別的,其它的都會慢慢遺忘,

什么是比較特別的?

  • 重復,一直重復;重復到大腦認為這不該忘記,有道言:熟能生巧、好記性不如爛筆頭,還談不上拼天賦包括努力,
  • 新奇的、有趣的、充滿致命危險的、富有挑戰性的、特殊的;與自己基因特性相關,偏向哪方面,大腦對哪感興趣,不用你重復多次,自然會記住,

所以我加入了總結回顧,記錄了這一章的重要內容,怕你看著看著就全忘了,放心,只有一點點,不會對你的大腦造成負擔,看完后,記得休息一會,

更新內容

第 3 版的更新內容

新增 switch case 分支、補碼、二進制轉換、字符編碼常識、值傳遞、String 字串常量池和 intern 方法的決議、第三代日期類、UUID、正則運算式等一系列內容,

將雙向鏈表移入 LinkedList 這節中,

取消了 b 標簽的使用,因為無法在 CSDN 中無法做到與博客園一樣的顯示,

取消了 img 標簽的使用,因為在 CSDN 中無法顯示圖片,

取消了 gif 動圖的使用,因為列印 pdf 檔案后就是靜圖;

取消了超鏈接使用,統一使用網址代替,

發現每章的內容過多,將每章繼續拆分為幾個小節,

移除了強型別語言、進制轉換、字符編碼、原碼補碼等內容,

第 2 版的更新內容

將所有目錄重新整合,改名,保證標題的唯一性,否則博客園可能跳轉錯誤,

將 字符編碼 部分內容移到 常用類 一章中;將 Eclipse 移至擴充內容中;將下載與準備作業合二為一,修改 \(\xi\) 符號的顯示問題;用 ① 替換 1. 避免格式亂碼,

由于章節過多,這篇只得拆分成 20 章,否則瀏覽器加載不過來,

其他說明

跳轉問題

博客園有時會出毛病,在同一篇文章中,如果兩個標題名相同,點擊只會跳轉到第一個同名標題;雖然已經開始在標題前面加 1.1.0 讓標題名唯一,但是目前還未改完,請從點擊如圖展示的標題串列中跳轉,(2022/03/11 18:00)

在這里插入圖片描述

封面制作

封面是用 Win10 3D 畫圖制作的,

愛好

喜歡養魚(草金魚)、養龜(草龜);看奧特曼;看優秀的國漫,如伍六七、凡人修仙傳;喜歡聽梁博的歌;歡迎交流,

夢想:

本書由來

本人就不是正兒八經的程式員,你就當我童心未泯吧,疫情大家都被困在家中,只能慌著想另謀出路,

培訓機構天天打廣告,制圖、CAD、編程、剪輯...,于是抱著試一試的心態,他們都說學 Java 好找作業,我怎么感覺教人賺錢的人最賺錢?

當然我沒去培訓機構,而是在網上一篇篇的看文章,因為學習路線圖挺多,你在知乎上隨便搜下,就有一大群打廣告,引流到自己的微信公眾號;讓我不禁感慨那些熟手竟然都混的這么艱難,

我越看,越覺得自己太滯后了,太脫節了,Java 是上個世紀末出現的,我到現在才知道,仿佛我們這個地方的時間流速比發達城市慢了幾千倍,我可能會想,如果要是早點知道就好了,也不至于大學期間抱著動力電池組、汽車檢測與故障判斷百無聊賴,只能在騰訊中迷失自我,尋求一點認同感,我現在才明白,并不是不知道自己到底喜歡什么,而是自己視野太窄,接觸東西太少,別人也是如此,給不了貼合實際的建議,所以還是靠自己尋,但是又不能完全不聽從別人建議,只希望別又浪費三年,

年齡越大越感覺似乎有一道屏障阻礙,不,不對,應該是高中時就有了這種局限性,

所以感覺自己就像困在繭中發育遲緩的兒童,或者像是一排紐扣,某個紐扣系錯位,其它全都錯位了,真擔心,還沒長起來,就 gg 了,我很明白,如果你也能感同深受,我祝你早日掙脫束縛,突破自己的局限性,

由此推出,可能我習以為常的概念,但其他人卻一無所知,看到線頭也認不出來,自然也不會揪,說實話,要不是學 Java 順帶接觸了前端,我永遠也不會知道瀏覽器頁面背后隱藏的 HTML 標簽,或許誤解為 Word 或者其它更高深的東西,再想到大學時還是如高中般按部就班,呆呆地等老師講,什么高等數學啊,沒講的就不知道要學,結果就講到極限沒講了,直到畢業后才醒悟,可惜已經沒有那么好的學習環境了,真傻,所以,我說非本科的,還是抽出時間干自己的事吧,只聽老師講沒多大用處,

那些本科、985、211 出來的,我不知道他們學校是否與社會脫節,還是不需要培訓直接就能勝任作業;又或者那些高材生早就摸索出了屬于自己的道路,只待畢業后就能大展身手;真是年輕有為啊,當然如果不是,也不要妄自菲薄,至少你學習能力強,也聰明,打敗了 50% 的同齡人,多接觸我們這樣的人,不要被外界評價降低了自己的自信心,哪怕現在積累散去,也可以東山再起,別放棄,要加油!

對我而言,也許受眼界或目光局限,看不遠,但我并不認為這是遺憾,種樹的最好時期除了十年前就是現在,

所以我的目標壓根就不是教小白前沿知識,因為當一個新概念傳到我們那,可能都不知道被多少人玩爛了;我只是相信還有一些人如同曾經的我一樣,沒來得及上道,視野受限,四處碰壁,我希望用自己的時間,能夠節省他們的時間,

當然我可沒有那么高尚,我很壞的,不受人待見,像是與世界格格不入披著人皮的異類,缺點也是一大堆,對此我沒有什么意見,認了,我只是見不得有人跟我一樣,踏同一個坑,犯同一個錯,浪費生命,自責內疚,消耗最美的年華,尤其連我的初中同學都結婚生子了,能幫一個就幫一個吧,

這個學習時間太長了,還不容易上手,可能學不出什么名堂,做好心理準備吧,如果你很久以后才看到這篇文章,這本書介紹的內容、軟體可能也會過時,(2021/07/15 19:29)

我以前聽說過一個段子,讓我改編一下吧:老師在課堂上將 100% 的知識講出了 70%,同學們接收到了 40%,動筆自己試下,寫出了 10 %,隔天只剩 1% 了,剩下全靠編,

于是我這知識算是從網上來,經過遺忘、組裝、變異后再回到網上去吧,

幫助說明

你幫助了我,我自然很樂意回饋你,但是請客,我不知道你是真心的感到開心,還是出于禮貌,很拘謹,不好意思拒絕,說不出口,又或者只是人的本性如此,不受控制地開心,而不是你的本心;這樣猜來猜去的,很累,再說了,本人沒有去高級餐廳的經驗,怕出洋相,

你如果有什么難處,力所能及下,我會幫助你的,(不借錢,被人騙過)

我聽力不好,醫生說是腦神經損傷,不可逆了(不可恢復):聽力的衰弱、接收頻率的丟失、無法被決議,說人話就是你叫我,我聽不見;聽見了聲音,不認為是人在喊我;知道你在喊我,但不知道你在講什么,需要重復幾次才能聽懂,所以不喜與人交流,不喜歡悄悄話,聲音太小了,

我的語言溝通能力方面不是很好,每當親戚叫我多接觸人,出去找個好作業,不要好高騖遠,實在不知道未來如何是好,常常被人當作矯情,

由于不怎么接觸人,時常感覺自己不近人情,只在家的附近活動,逢年過節不送禮,又不噓寒問暖走個表面形式,生病也不帶禮物看看,沒有那些樂呵呵的人受歡迎,我自認為挺討人嫌,不像個正常人,融入集體,至少我周圍看不到第 2 個我這樣的,我經常自擬為披著人皮的生物,似人,

哦,你如果想招聘我,想好這一點,我不適合與客戶打交道的,希望不會因此找不到作業而餓死吧,否則在全中國也是獨一份笑話,

我很早之前就聽說過:不要試圖改變他人,因為他人無法改變,要從自己身上找原因,每次出現問題,不用別人說,自己就開始把矛頭指向自己,現在發現改變自己也很難,之前一直對自己耿耿于懷,發現只會讓事情變得越來越糟,因為與最了解自己的自己對抗,這是一件多么愚蠢的事,它總能找到內心最柔弱處,給你致命一擊,

終于發現這樣不行了,不原諒自己,自己就會拖自己下水:反正就這樣了,無法挽回,還不如破罐子破摔;自己給自己過多壓力,整個人非但不能前進,反而會散去精氣神;一直被動接收別人的觀點,只會讓我深陷地獄,但我就是十分在意別人的看法,于是想著法子給自己洗腦:我憑什么要管別人的看法來折磨自己?我就這樣壞、無恥啦,我就是有這么多不完美的地方,我不當人啦!咋滴?想著想著,于是學會了擁抱自己,接納自己;哪怕自己有太多的缺陷與不足,擁有這個身體已經值得了,沒有必要追求過多,生和它一起,逝也和它一起,它才是最了解我的人,其它都是浮云,沒有必要與它不愉快,

于是擔子自然就放下了一大半,它再差勁那也是我,不必撇清關系,并且它還是挺好用的,就是忘得快,

當然你如果說想同情我,那倒沒有必要啊,我這不是聾,只是偶爾聽不懂,大多數情況下還可以對話,謝謝你的關心,祝你天天開心,歲月安好,

image-20220319211226182

image-20220319211414076

image-20220319211515985

image-20220319211547033

image-20220319211629972

image-20220319211711191

image-20220319211802840

image-20220319211850676

image-20220319211921329

image-20220319211946650

數學講的還是挺簡單的,于是買了幾本書,發現老師明明在視頻上講的通俗易懂,由淺入深,但是撰寫的大學教材是真的勸退人,幾千頁啊,戰線拉得太長了,并且那段時間在學 Java,于是沒再繼續了,我只知道一點,不用的知識一定會忘記,所以現在干脆不學了,等用時再補,果然遺忘才是人類最大的法寶,

image-20220319212006864

求職

天要下雨,人要吃飯;不管再怎么想,到了年齡,就算不結婚生子,但還是得找作業,

不講什么本人勤奮熱愛好學、吃苦耐勞這套老掉牙的事了,這玩意就是你情我愿,一拍即合,不行就拉倒,誰也沒有必要低聲下氣,彷佛占了什么便宜,雙向選擇嘛,

招聘網站一個個看(不太信任,聽說騙子挺多,還是需要線下跑來跑去,還可能被第三方公司外包,扯皮都沒法扯,精力都耗沒了),什么一面二面,還要花時間背沒有用的題目,互相試探,裝的很牛的樣子,然后等通知;或者一個個線下到處漫無目的地找;除以上途徑之外,我還想在各大網站上發布資訊,希望能夠找到合適的作業,

若你想要了解我掌握的東西,那你看看我寫的博客就行,也不會超出這個博客內容太多,忘了很正常,看看就撿起來了,我又不是電腦,沒必要一直存盤到腦海中,超時就丟掉,

要求:

  • 作業地址:離湖北越近越好,

  • 作業內容:與電腦相關就很好,敲字什么的無所謂,我不想丟失熟練度,

  • 作業形式:公司、團隊搭伙、工廠、私活、兼職、在家...都可以,

  • 作業要求:

    1)連續作業半小時 ~ 1 小時,因為現在碼字,眼睛不是很好,很干澀需要流淚才能緩解,需要休息 5 分鐘遠眺;我常常使用番茄鐘,提醒自己該休息了,以免精力不足,影響明天,

    2)可以接受重復性勞動,時長不能超過 9 小時;禁止夜班,沒得商量,為了身體著想,說不定工資還不夠看病呢,

  • 公司氣氛:不要勾心斗角、人人胡思亂想;不要官僚作風、氣氛緊張,

  • 工資要求:實習期間工資 3000 以上,

  • 個人缺點:

    1)手笨,不會系繩子,只會打蝴蝶結與死結,

    2)習慣沉默寡言,不會烘托氣氛;別覺得奇怪,各人秉性不同,不必強求,

    3)英語差,我嘗試過好多次了,暫時辦不到,以后有時間再試試,

  • 如果確定要為您辦事了,我會在入職前將魚放生,所以請不要耍我玩,

  • 補充一條,禁止傳銷、坑蒙拐騙其他人、等其它犯法行為,

你如果有意向,可以列出崗位的技術相關要求,若我有不熟悉的,我直接自學完了,再到你那來,給你干活去,這對我小菜一碟,

宣告:天下沒有不散的宴席,人都有分別的時候,好聚好散;請直接提出來,別耍陰謀,調來調去,或突然增大壓力,

本人聯系方式

不可以公開手機號,我怕銷售天天打我電話,可以私聊我,在此期間應該一直在家附近尋找作業,我習慣被動,現在疫情這么嚴重,除非一錘定音,否則實在不想外地跑來跑去,

QQ:2675385031

微信號:cqhjava

郵箱:[email protected]

博客園:https://www.cnblogs.com/cqhh/

CSDN:https://blog.csdn.net/cqh123hh

(有人問,有作業就不錯了,怎么還提這么高的要求?漫畫附圖:)

PS:這要求還算高?

image-20220320104756421

當然我很清楚,能夠看到這篇文章的,要么是小白急于尋找資訊,要么是好奇;我這啰里吧嗦的,這寫了也是白寫,所以沒有寄托太多的希望;再說了,這畢竟不是專門的招聘網站,

作業情況

物業維修員:2019.10 ~ 2020.5

狀態:待業中,最近被催著找作業,能敲電腦就行;只是怕又頭腦一熱,選錯了,又浪費 3 年,

分支:送餐員、流水線、文員、Java 初級工程師、漁場、志愿員...

致謝與勘誤

致謝

首先感謝父母給我一個好的身體,感謝母親耐心的支持,

其次感謝遇到的挫折與不堪,及時糾正我前進的方向,好吧我還是討厭它,為什么我總要給自己的生活添堵呢?

最后感謝在網上無私奉獻知識的大家,我是在家自學的,不懂就上網搜,算是野生吧,你們對我帶來了很大的幫助,可以說腦海中的知識體系都是網上博客園一篇篇的文章,一段段視頻堆砌而成的,真的很感謝你們,生活在和平的中國,享受如此豐富的資源,挺幸運的,我會把文章知識來源鏈接放在參考文獻中,但可能有遺漏,不能一一列出,但你們對我幫助也挺大,感謝,

這些在網上搜集的資料,如有侵權,煩請告知,

編者:cqh
2022 年 3 月 4 日,于湖北安陸

勘誤

筆者也只能算是新手,學識尚淺、水平有限,有些抽象、底層的東西以目前的功力無法一眼看破,找不到合適的方法去驗證結論,只能是憑第一感覺得到具體的規律,所以也可能是想當然,看法比較片面,你就當成強行解釋,笑一笑吧,對身體好,

部分解釋可能不詳細或不清楚(詞不達意),如果你有更好、更通俗易懂的語言,歡迎留言指出,

在閱讀文章時,請你時刻持有一種質疑的態度,這樣既能幫助自己思考,也能發現我文章的不足之處,如果文章中有什么錯漏的地方,還請不吝嗇指教與批評,十分感謝!

若有幫助,會將你列入鳴謝名單中,

書中原始碼地址

https://gitee.com/ccqqhh/java-se

自序

第 3 版自序

之前是想要找文獻與資料,四處找不到;現在是資料漫天飛,四顧茫然;曾經的我反復橫跳,浪費了很多時間與精力,干脆把曾經所做的學習筆記整合起來,方便大家,并且這期間,如果另有識訓,會持續更新此書的內容,(學海無涯苦作舟)

本人專科畢業,我始終認為只有自己喜歡的才需要學,忽略了高中這不是專項發展,而是篩選人才;那么多的人,企業正好設定為本科門檻可以節省篩選時間;此外你通不過本科,企業難道不會懷疑你的學習能力有問題?既然是為了賺錢,那為什么不選更好的?人才多的去,誰稀罕你這一個,

我倒是不后悔,因為學歷與錢對我而言不太重要,還比不上自身學會了寫代碼的那種喜悅;只是覺得大多數人經過 18 年的學習,轉眼間淘汰了一半人,估計都流向工廠的流水線了,太浪費了,

一直笑著說大不了回家種田,但其實要是真的能夠維持生活,沒有人愿意背井離鄉,出去打工的,我之前提到過滯后性,上一輩人因為這種滯后性,吃夠了虧,于是只讓我們專心學習,自己在外辛苦打工,承受所有的風險,只為了子代不再重蹈覆轍,以為我們考上大學了以后就能賺很多錢,可以享福了,卻忽略了其它方面,

我們都以為學成了,考上了好大學,也許前途就順了,但總還有一半人被淘汰了,比如我,父母還是抱有期望的,至少是個大學生啊!至少比我們強吧,結果期望越大,失望也就越大,

其實學校教的東西可用的很少,大多數就是純粹應付考試,等上了大學后,被忽略的其它方面,弊處就開始顯現;上一輩人突然覺得這么聰明的大學生,這點生活常識都不懂?人際交往、整理內務、洗衣做飯、修電腦啥都一團糟?你們在學校學了個啥?換我來吧!讀書有啥用!廢物!你們 90 后當家了,這個社會要完蛋!

我不太在意,我知道他的局限性,他所在的小地方,也就只能看到我,誤以為我就是大學生的縮影,但是網上有才有能力的人多了海了,否則你們找作業怎么這么難找,當然工廠、銷售...等崗位還是挺需要人的,

我認為有這些高智商的人材們,尤其是特別努力勤奮的,社會只會越來越好,但是對自己的命運不是特別樂觀,

我希望以后不會固步自封,局限自己的認知,覺得自己經歷過這么多的事情,可以一言堂,斷定周圍人的秉性,因為經驗有時效性,且與個人息息相關,在別人身上不一定適用,傳遞的觀念如果別人不聽后吃虧掉坑,我就在旁邊暗笑,那樣太可怕了,那說明我已經變質了,經驗此時反而束縛住了我前進的腳步,

警告自己的一句話:我知道人都會變,可是當你看到這曾經寫下的這句話,如果覺得很幼稚可笑,算了,不想前進了,就說明你已經融化了,那么狠狠地抽自己,往死里抽,別讓我瞧不起你,你欠我的,我現在拼死累活地,下決心,不是為了讓現在的你心安理得的阻礙其他人的夢想,嘲諷其他人,也不是讓你吃老本,坐吃山空,別以為這是理所當然,好好想想自己該做什么,還是在樓下打麻將與其他人夸天?

當初高中畢業,選專業,雖然實作不了小時候的理想,但是想著新能源汽車發展起來了,也可以保護環境啊,于是特別天真地就選了此專業,唉,實習時來的都是接插線、黑白班做飼料、賣挖掘機、開叉車...尤其看到要求男女不限,18 ~ 50,身體健康...沉默,我這時才明白自己早就已經 out 了,到這來只是將噩耗延遲而已,不禁懷疑我到底這 18 年的生涯到底學了什么?混成這個樣子?竟然不知道在簡歷添些什么東西,熱情開朗?踏實能干?會求微積分?也不明白自己有什么優點,自己的價值在哪?憑什么讓企業招聘我,再看看其它要求高的,不覺得我能夠達到,別人說不定看不上,真是賤啊,

好吧,烏龜殼雖然保護了我不受傷害,但是一旦有朝一日,從殼中脫離,沒有練成應對危機的本能,只能撲街,

因為上半年考了一個電工證與駕駛證,友每天恨鐵不成鋼,即使之前有多不敢,導致錯失了機會,所以這次一定不能放過!于是如同趕鴨子上架般慌著選擇了作業,貌似能扯上一點關系的物業維修,正遭疫情,每天都是抄水電表,沒積累可用的作業經驗,解封辭職后開始學 Java,跟著網上的博客與視頻一步步來,哎!覺得希望來了,這有什么難的,

那段時間,父親和親戚不再問讀書成績的事了,時常問我學了什么名堂,答:我學的這個集合很厲害,底層用多種資料結構存盤資料,你看這個雙向鏈...停停停,別跟我講這個,我聽不懂,這么有用,什么時候出去找事?可以賺多少錢?答:額...

得,趕進度吧,花了5個多月的時間,資料結構與演算法、MySQL、JDBC、HTML、CSS、JavaScript、Tomcat、Http 協議、Servlet、JSP、AJAX、JQuery、Maven、MyBatis、SVN、Git、Spring、SpringMVC、Dubbo、Linux、SpringBoot、SpringCloud、Nginx、SpringSession、FastDFS、RabbitMQ、SpringSecurity、Shiro、Swagger、CRM 專案...

期間為了方便翻閱和復習,加頁碼、加目錄、記時間、正字復習、畫星星、康奈爾...方法效果甚微,

所以以我為反例,別用紙質筆記,很不方便的,

(之前有人問我,5 個月怎么這么慢?其實我之前太貪心了,還想學數學、英語、物理...)

也不是沒有人勸我,江山易改本性難移,固定的思維就像茅坑里的石頭難以改變,每次聽到勸導,又開始神經發作,萬一呢?你到底怕什么呢?誰會吃了你?這是否已經成了本能?我想不通,也說不清了...

我的理智告訴我,我只是害怕未知,本能拒絕去嘗試,害怕再次失敗,又被人侮辱與嘲笑,尤其是年齡大了,沒有試錯機會了,只能盡力維持現狀,一旦沒有了父母的支撐,把我投入到大海中,要么四肢撲騰,學會游泳,要么淹死,說到底,我還是有很好的父母,堅實的后盾,實在太幸福了,所以才令人感到如此悲哀,再結合到三和大神、26 歲成人被餓死之類的,我能理解親戚他們的想法,算了,不說了,混成這個小孩模樣,也是沒誰了,希望能在餓死之前,主動尋求改變吧,沒想到還真自證了自己初中時的想法,諷刺啊,

覺得學的也差不多了,開始看招聘,清一色的本科以上要求,這還玩個毛啊,再從網上看看題目,倒是不難,但想流利的說出,還是要背;語文、英語對我還是有點難,由于耳朵問題,只習慣看字幕,真不想把時間花在這無用的試探之上,說到底,我的信心一直被摧殘,沒被培養起來,一做事就放下手頭的事跑過來看我,指指點點,說這不行那不行,不停地被否定,最后直接推開替換了我,一說話就被認為是借口,為什么別人行而我不行?對啊,我也納悶這到底是為什么,所以畏手畏腳,一想到作業就躲避,哎呀都是我不行的,干不了,主動失去信心,下賤自己,那么別人看到這個樣子,沒有一點正能量,只會讓現狀越來越壞,猶如囚籠之獸,現在回想起來,這本來就不難,小事一樁!為什么非要挫折教育呢???究竟經歷過什么事才會認為這是正確的做法?是不是我視野窄了,看不到背后的良苦用心?

得到一個規律:不犯錯,必敗事;如果小時候文文靜靜,逆來順受,畏手畏腳,被框在自以為的規矩下,不敢嘗試,看上去很聽話很乖;但年紀大了,躲得了一時,躲不了一世,沒有小錯帶來的經驗,將來必定踩坑,成為平庸的人;這雖然不是必然發生的,但是概率很大,常在河邊走總有一次會濕鞋嘛,小時犯錯相比大時犯錯,周圍人包容度更高,所以建議小時多嘗試,

受限于學歷,所以我降低了要求,不得非要與代碼搭邊,隨便啊,別進工廠黑白班、天天 12 小時,我還不想猝死,你們如果有什么好的渠道,智聯、前程、脈脈...歡迎交流啊!

回顧,自己表面掌握了什么高大上的框架,但框架用起來很簡單的,底層屏蔽了繁瑣細節的具體實作,從配置多個 XML 檔案到約定大于配置直接啟動,增刪改查就增幾個注解,改下 SQL 陳述句,越學越簡單,只是要背注解、方法名、操作步驟...才發現我其實也就是只會調下 API,太淺顯了,一遇到稍微深層次的問題就撲街,忘了代碼就在網上搜索復制粘貼,這不就是搬磚嗎?我學到這之后就沒學了,就是覺得太淺了,簡直把我當做硬碟在用,這些方法名,記流程有個鬼用,時代一換,又得重新開始,

我覺得是基礎沒打好,也許是哪里走錯,之前學的不夠系統,又把 JavaSE 內容看了一遍,尚硅谷、動力節點、狂神說...,識訓不大,

終于下定決心,這 Java 內容之多,之繁雜,總得有人要整理一下節省小白的時間,稍微撲騰一下吧;為了幫助和我一樣的人,避免踏入同一個坑,開始本書的第 1 版制作:

在這里插入圖片描述

在這里插入圖片描述

當時正是過年,前前后后忙了幾個月,又被打擊了一頓,說我在家里游手好閑、不學無術,不務正業,只曉得找借口,是廢物一個,在村里都不好意思說,不敢走親戚,抬不起頭,對外統一口徑是我好高騖遠,只曉得在家里玩;每當別人問起我的年齡時,是否還在上學,總是感到臉上一陣青一陣白十分羞愧,無力感縈繞在心頭葉訓不散,此時負標終于超過負荷,被最后一根稻草壓倒,期間強行振作,努力維護日常作息,又被說年輕人還是沒有被鍛煉到,還是要多給點壓力鍛煉下,否則太脆弱了,心理承受能力太差,連這點打擊就把你壓垮了,去做銷售扭轉下性格就好了,挺適合的,終于壓不住內心的痛苦崩潰了,開始自暴自棄,為什么所有的評價都認為只有我這么廢?算了吧,說的對啊,我的確沒用,還學什么啊,都賣了吧,我實在太脆弱了不堪一擊,整個人又壞又蠢,估計就連小學的我就瞧不起現在的自己,不搞了,自閉中;眼淚不能流,聲音不能出,打碎牙齒往肚子里嗚咽...男人!男人嘛,男人!你這么大個人,怎么還跟小兒一樣,好意思嗎?沒希望了,一生已經毀了,

但是過了一段日子后,越看越覺得這個筆記不對勁,寫的這么粗略,這是給自己看的吧?新手能夠看得懂嗎?強行驅動自己,做事必須有頭有尾,還是續了一根弦,

當時又看了韓順平老師的課程,他總結的學習方法很不錯,先 demo 再寫注意事項,然后由此撰寫了第 2 版:

初入門時 JDK 安的是 15,(應該是 8,做第一版教程時才應該把 8 刪了,重新下了 15)當我重新準備下載時,發現頁面找不到了,這才知道長期支持版本是什么東東,

好吧,為了回顧當初下載軟體時遇見的問題,場景重現,方便截屏,狠心格式化了電腦,把之前的 Node.js、Linux、MySQL、Navicat、Maven倉庫、Tomcat 等一切全部刪了,直到現在都還沒下載回來,之前放入 GitHub 倉庫的代碼,比如資料結構,被我認為代碼寫的太垃圾了,直接清空了,(現在就沒有參照了,真是白給)

只剩下 FastDFS、RabbitMQ、SpringSession 的 demo 了,

好,沒關系,大不了重新開始,

花了好幾個月,廢了很大心血,刪了改,改了刪,半夜突然醒來,打開電腦就只為修改一句話,信心滿滿,沒有多少評論,想著是不是網路上資源太多,唾手可得,根本就不缺我一人的努力,此時突然覺得我都沒有找到作業,所學知識之淺,路之狹窄已到頭,還敢斗膽發文章,也不稱稱自己的斤兩,這不是誤人子弟嗎,于是把之前的所有博客都刪了,秉持了不嘗試就不會失敗的鴕鳥原則,

我現在想明白了,去追趕那些前言技術,學習語法,如何使用,只會流于表面,疲于奔命;干脆放棄掉,重新開始,我覺得就連 Java 語法,也變得不太重要,畢竟只是背別人定義的規則,還是表面;但是要寫程式,沒有辦法,于是就有了語法入門篇,

根據紙質資料和粗略的第 1 版,以及網上的博客資料,拼拼湊湊得來了第 3 版,至此只完成到集合部分,并且我還是不滿意,決定抽出時間,繼續重置,

現在又要看最開始的老版筆記重新寫一遍,做事有始有終,不能輕言放棄,爬也要爬到終點!沒有什么是不可能的,還好現在沒作業,否則抽不出時間寫,由于刪了之前的博客,有很多都是后來在最初版的基礎上修修補補地,可能有很多疏漏、沒來得及添加的、知識變異了的,懇請大家提出寶貴的批評和建議,以便改正,學習路線就按韓老師的來,先 demo 再宣告課堂注意、出題目,按部就班的點還是挺不錯的,

2022.3.11

第 2 版自序

接受現實,痛定思痛,干脆抽出時間,整理曾經寫過的紙質筆記與博客,為尚未踏出校門的同學節省一點時間,

有的地方根本沒必要學,直接復制粘貼看看 API 就行,沒啥技術含量的,對于那些性格內向的人,心里有很多內容與墨水,但嘴里吐不出話的人,我特別能夠理解你的苦衷,珍惜校招吧,避免畢業就是失業的尷尬局面,

有些人的確很聰明,在這里我不想扯勤奮與努力,以前也講過,這只是表象,何況對于有些人也真的很難,考慮到通用性,內容稍微細一點,不要嫌我啰嗦,

我已經很知足了,陽光、空氣、可以動的四肢、能計算 1 + 1 的大腦,沒用什么遺憾了,對我而言,健康遠比時間、金錢、技術重要,不對,這該死的技術,這抵擋不住的魅力啊!!!

真的好懷念魔獸,如果阿爾薩斯王子沒走屠殺線一定會有美好的結局吧,

2021.7.4

第 1 版自序

最近學習了 MarkDown 語法與五筆打字,打算把紙質筆記整理成書,幫助大家,

經過一段時間的摸索中,得出了以下結論,希望對新手有幫助,

1、洗掉無效的軟體(打造合適的環境)

比如一直讓你刷刷刷,停不下來的,因為你每次刷,都在期待下一個視頻對你有用,但很大的可能只是滿足了你的多巴胺分泌,

上癮后不要責怪自己,想辦法清醒后把這些觸手可及的東西,不管是卸載、還是關閉推送、扔在角落...盡一切可能不要讓它來打擾你;如果你是因為沒有事情,好無聊,看這些來打發時間,那就找一些其他事情吧,如散步、健身、看書什么都可以...

這種大量占用時間碎片,令人上癮的軟體,可以說是一種毒瘤,我想不通為什么要研發它,錢真的很重要,但也不至于這樣吧,

我說過人就是個石頭,現在看看銷售營銷等一些手段玩弄心理,越發堅定這個想法;我們能做的只不過是別讓那些外力推動自己,

2、作業與學習之間的平衡

公司都是重復性勞動,沒有實際上的經驗提升,還要擔心上級領導的試探,同事的打壓,構建話術,下標后自學也只能學習 1、2 個小時,并且還不包括動手嘗試的環節,能夠學到手的知識十分淺顯,等學完,天都換了,

并且公司本質上是私人組織的、有了好點子想變現、以盈利為目的的結構;你想想你要是老板,誰不行直接替換掉,反正人才多的是,為何還要等你慢慢成長,真以為自己是潛力股嗎,

但是辭職也不可取,長時間在家,沒有了生活來源;走在路上還要被婆婆們嬉笑,

此外親戚們都不會理解,最親的人也會罵你不中用,你給他也講不明白,還會被覺得十分可憐,一開始還可以打哈哈,說自己已經畢業了,在學習編程;但之后呢?這條漫長的學習之路,不同于進廠教教就能直接上手,

我想提醒你,你是否也感覺大學的課完全沒必要上,但我們也許還如同高中一樣,按部就班,講什么就聽什么,那么到了畢業就等于失業,你應該抽空把自己的愛好發揚光大,如果等到上班再學,其他人會怎么想?

結論:請好好珍惜大學的時光,那是唯一適合自學的時候,否則你要承擔額外的精神壓力,扛不住人就廢了,

3、適當約束自己的好奇心

不要看到什么都想學,什么都想買,一直在搜,知識太多,你學不過來的,你先在網上搜索,比如后端的整套知識點,按順序來,一心一意,一套教程為主,有疑惑的再去別的地方比對,不要沒事就搜索一大堆資料收藏,又不開始,資料一定要精簡,那些看上去有用的知識但短期用不上的,直接取消收藏,等你到了這步,再找資源,別做松鼠,

關于難度高的,可以先跳過,記錄下來,后面再補上,比如資料結構、JVM 底層、多執行緒與高并發、GUI 等等...別把初學時間浪費在這上面,

不要背代碼,要掌握原理,方法可以到 API 檔案上查,之前基本都是概念上的東西,理解就好了,但學到集合、IO、常用類如 String,只背方法名一定會消滅你學習的興趣,

如果學習資料拋出一大堆讓人心癢癢的新名詞,操作不講規則與原理,沒有容易理解的例子,只是像背或粘貼似的敲打代碼以及一大堆的命令控制流程,那么我勸你趁早跳過,用時再翻閱,

4、管理好精力

并不是一直在同一個地方枯坐,作業效率才會高,

要合理分配精力,因為精力是有限的,學習并不是生活的全部,如果你整天撲到學習上,只會感動自己,隨著精力的消耗,自控力的減弱,一定會在某天突然崩掉,開始變得什么都沒有興趣,行動力拉到最低,即使強迫在學,也只是枯坐原地,享受著左耳進右耳出的枯燥感,

早起別熬夜,每天一定留至少 30 分鐘的時間午睡,(為了第 2 天的精神良好)學習時推薦使用番茄鐘,每過半小時就休息一小會,合理分配精力,(休息時不要看電子產品與動腦筋,要適當遠眺)

5、學好英語

沒什么說的,英語真的很通用很重要,為了閱讀懂優質的國外資料,看著機翻的我太拉跨的,簡直是啞巴英語,學不會也沒關系,就算關了一扇窗,把開這扇窗的力量用到別的地方去,一定不會浪費的,

6、必學的知識點

從大多招聘崗位的要求取出交集:

IO、集合、JVM、多執行緒、Spring、SpringBoot、SpringMVC、MyBatis、Dubbo、SpringCloud、JavaScript、Vue、MySQL 與 Oracle 取其一、SQL 調優、Redis、Tomcat、Nginx、Docker、Zookeeper、RabbitMQ、Kafka、Linux、HTTP 與 TCP / IP 協議、Socker、Maven、Git、AJAX、ElasticSearch

剩下的知識,應聘意中崗位時再選擇性補全,

7、選擇書籍還是視頻

視頻時間看完所需時間更長,但可以一步步來,如果章節內容劃分合理,每個視頻時常合適,學習者更輕松完成每個目標,掌握自己的進度,適合初學者,

書籍花費時間較少,但經常有斷節之處,初學者搞不明白缺少哪一個環節,看著晦澀難懂的文字,翻不了幾頁就草草放棄,適合耐得住性子的人,

8、不要過分追求完美(承認自己的不足之處)

想做就直接放手干,不要計劃的那么周全,稍微一有變動,就放棄目標,想明天再做,是吧,別覺得只有從容不迫、不慌不忙、按部就班地才叫做事,而達不到自己的心理預期就不做了,大多數人都是計劃趕不上變化,被搞得灰頭土臉的,

另外人都是有慣性的,如果設定了太高的目標難度,只要有一天沒堅持下來或不想做了,那么最終結果一定是放棄,

這不禁讓我懷疑,以前對生命的定義,我本來以為生命是一種奇跡,我感到自豪,超脫于物質之上;比如從下坡推一個石頭,它只會毫無疑問的滾落下去,而我們可以做出反應,

但經過太多的事后,我發現生命的本質與死物沒有太大區別;生命就像是一臺精密的操作儀器,如同電腦、機器人,只不過比它們先進點,

接收輸入做出反應,將應對方式與最終結果存盤;等下一次事件再發生時,可以不斷優化腦海中存盤的應對危機的方法,達成自我學習的本領,

9、學會分享

不要閉門造車,要發在各大網站上分享,Markdown 語法如果你都會了,直接發在博客網上,不要覺得自己技術菜,

第一,人人都有開始,你發出來了,別人才能糾正你的錯誤,避免成為井底之蛙,

第二,你又開始自耗了,不停地在腦海天人交戰,一頓腦補:會不會萬一發出來被人嘲笑怎么辦?...于是藏著掖著,生怕別人知道,出丑,事情還未做,就想一系列的后果,別人有多可惡,我覺得世上還是好心人多,當然不要被零星幾個惡評就忽略了大多數支持你的人,

第三,百分之 99.9 的人根本刷不到你的文章,或者一下就 × 過去了,即使刷到了,那還有 9.9 成人瀏覽刷的一下就關了,評論的那是少之又少,鳳毛麟角,如果幫助不到他,誰還關心你是誰,最多充當局外客感到可笑,當你還在糾結別人的看法時,糾結要不要做時,別人根本記都不記得你,我們在網路時代那是十分渺小,滄海一粟,很快被淹沒,就算有弄潮兒掀起了幾朵浪花,也會很快平息,所以別再糾結丟不丟臉了,

10、關于努力與勤奮

有人經常說,要自律,要吃苦,要努力,才能成功,你看看這些成功人士都是這樣...努力才能得到一切,才能成功,但我拋出一個結論:努力與吃苦,并不能成功,也不能改變命運,

他們忽略了一個東西,自律、吃苦等只是個表面行動展現出來的結果,并不是成功的原因,比如你打王者,技術很菜,但是你就想升段位,不用別人提醒,開了一把有一把,一直連跪,日夜顛倒,身體早就向你警告了,這種違反本能的行為真夠自律的,不打一定不會上王者,打了無數盤由于技術太菜,也不一定能上王者,

如果你真心地想要完成某個目標,你不會覺得這是折磨的,再次宣告,不是自律、努力才會成功,它們實際是想到達成目標,而自發控制自己身體機能活動的行為,

友情提醒:全身心很耗精力,記得番茄鐘打斷此狀態(半小時),休息的時間眺望遠方,不要看電視、玩智能設備,否則越來越累,

11、學完要多久?

如果你不復習,不怎么練,只看視頻的話,最多半年,能夠記住多少看命,

正常一年半(每天 8 小時以上不間斷)

12、是不是很難?

相比越到后面越抽象,一環扣一環的數學,Java 其實還算好,小白也能呼叫方法完成作業,理解一下就行,屏蔽了底層如何實作的繁瑣細節,看看 API 即可拿來用,

至于為什么一看就會,一敲就廢?是不是我沒有天賦?

說實話,這些東西不會就跳過,以后再補,只要學會呼叫方法,看看 API 就行,還沒有達到拼天賦的地步,努力也無需拼,努力只是外表展現的結果,而不是因,若你感覺自己很努力了,很痛苦,就像我之前說的這樣,你想想哪里出現了問題,是不是真的不感興趣,居然會覺得要強逼自己,努力才會成功?想著人只有逼逼自己才行?

話說回來,不會不是真的完全不會,而是你看時覺得很正常,但一到做時腦海中缺少一些關鍵片段,甚至連思緒的頭都沒有,無法串聯成珠,往往出錯,其他人只不過是由于過往經歷(熟能生巧)或者下自然地就補齊了這個漏洞,

沒必要擔心,如果你接觸它的時間過長,會彌補的,不用特意尋找解決它的辦法,多看看就行,(把同一個知識點學三遍差不多就熟了)

此外我覺得人略微笨些,是好事,意味著你能夠幫助這世界絕大多數人,不會出現理所當然,而一些人卻不能理解的事,知道哪里有檻,知道一些人哪里有誤區,只要你走通了,其他人就能走通,

花自己的時間,讓更多人節省了時間,值,努力活完短短的一生,將所得成果留給后代分享,人類真的是很了不起呢,

2021.2.11

第 0 版自序

今天是網上學習 Java 的第一天,自學,根據學習路線圖一篇篇在網上搜來的知識,

本人才疏學淺,感悟還不夠深,只能根據些許痕跡揣摩出背后道理,主要是臆想成分居多,如果有什么不對的地方,還請各位大師指點,大家一起共同進步,

另外希望把已建立的認知體系撕開一個口,推倒,包容,承認自己的失敗,不要斗氣就認這個死理,大不了掌握其它方法重頭再來,

2020.6.13

第一章 JDK 下載及準備作業

內容導視:

  • Java 介紹
  • JDK 下載
  • 撰寫代碼前的準備
  • md 軟體簡單使用
  • 常用的 DOS 命令

1.1 Java 介紹

內容導視:

  • Java 簡介
  • Java 技術體系
  • 前后端的作業內容
  • Java 語言特性
  • Java 用途

看不懂就跳過,這里不是重頭戲,說實話,挺無聊的,直接跳過也沒問題,(我只教如何開車,不教車的來歷、發動機缸數、如何運轉;你覺得只是浮于表面,沒辦法啊,又不是科班)

1.1.1 Java 簡介

Java 最早是由 SUN 公司(已被 Oracle 收購)的 James Gosling(詹姆斯·高斯林)在 1992 年開發的一種編程語言,最初被命名為 Oak,目標是針對小型家電設備的嵌入式應用,結果市場沒啥反響,誰料到互聯網的崛起,讓 Oak 重新煥發了生機,于是 SUN 公司改造了 Oak,在 1995 年以 Java 的名稱正式發布,原因是 Oak 已經被人注冊了,因此 SUN 注冊了 Java 這個商標,隨著互聯網的高速發展,Java 逐漸成為最重要的網路編程語言,

有興趣查看以下文章,了解 Java 發展歷史

  • 作者:JMCui,https://www.cnblogs.com/jmcui/p/11796303.html
  • 作者:苗子說全堆疊,https://baijiahao.baidu.com/s?id=1714823765201515049

此外 JDK1.5 與 JDK5 是一樣的意思,因為比之前版本的變化大,以此作為區分,表示與眾不同,就像美猴王自封齊天大圣,都是一個人(猴),

此外還有 J2EE 、JavaEE,只是叫法不同,不必糾結,

正式發行名稱 昵稱
JDK 1.0.x Java 1.0
JDK 1.1.x Java 1.1
Java 2 Platform,Standard Edition,v1.2 Java 2
Java 2 Platform,Standard Edition,v1.3 Java 3
Java 2 Platform,Standard Edition,v1.4 Java 4
Java 2 Platform,Standard Edition,v5.0 Java 5
Java Platform,Standard Edition 6 Java 6
Java Platform,Standard Edition 7 Java 7
Java Platform,Standard Edition 8 Java 8

1.1.2 Java 技術體系

分成了三個技術體系

(以前被稱為 J2SE、J2EE、J2ME)

JavaSE(Java Standard Edition):Java 標準版,包含核心的類別庫,主要開發桌面應用(如 Windows 下的應用程式),允許您在桌面和服務器上開發和部署 Java 應用程式,JavaSE 和組件技術提供了當今應用程式所需要的豐富的用戶界面、性能、多功能性、可移植性和安全性,并為 JavaEE 提供基礎,

JavaEE(Java Enterprise Edition):Java 企業版,為開發企業環境下的應用程式提供的一套解決方案,包括 Web 網站后臺開發等,該技術體系包含的技術:Servlet、JSP 等,企業版本幫助開發和部署可移植、健壯、可伸縮且安全的服務端Java 應用,JavaEE 是在 JavaSE 的基礎上構建的提供 Web 服務、組建模型、管理和通信 API,

JavaME(Java Platform Micro Edition):Java 微型版,JavaSE 的瘦身版,主要做嵌入式開發, JavaME 是專門為資源受限的設備設計的,如為 M2M、工業控制、智能電網基礎設施、環境傳感器和跟蹤等的無線模塊、手機、PDA、電視機頂盒和列印機上運行的應用程式提供一個健壯且靈活的環境,自從安卓系統出來后, JavaME 就用的比較少了,

JavaSE 是整個 Java 平臺的核心,做 Java 后端先學 JavaSE,

1.1.3 前后端的作業內容

前端

撰寫 html 代碼搭建一個框架展現網頁內容,如圖片、文字、視頻...,打開瀏覽器的任意網頁,按下 F12 可以看到網頁對應的 html 檔案

用 CSS 技術美化頁面,指定 html 標簽的位置、樣式等;

用 JavaScript 語言控制與用戶的互動,比如網頁彈窗、動態改變網頁內容、驗證登錄資訊、跳轉頁面等,

例:點擊登錄頁面,輸入用戶名與密碼,按下回車,會觸發事件執行 JavaScript 代碼,給用戶回應(登錄失敗或成功),

可以說前端相當于前臺,是可以看的見的內容,

后端

接收從前端頁面或其他后端服務傳遞過來的請求,處理業務邏輯,對資料庫中的資料增刪改查 CRUD,

給呼叫者一個回應,如把資料回傳給呼叫者、操作是否失敗、回傳對應的 html 代碼等,用戶是看不見的,

例:接收到前端傳過來的用戶名與密碼,查詢資料庫中是否存在,若不存在回傳用戶不存在,前端接收到后,改變頁面資訊給用戶提示,

不限于使用哪種編程語言,只要能把正確的資料回傳給呼叫者即可,

要保證訪問量很大時(同一時間內能夠處理盡可能多的請求)而服務器不宕機、回應時間短不至于用戶長時間等待、多個用戶訪問時保證資料的一致性等,(高可用、高并發、分布式、自動化)

1.1.4 Java 語言特性

Java 是一門編程語言,特性如下:

1、面向物件

Java 以類為結構組織代碼,對物件、繼承、封裝、多型、介面、包等均有很好的支持,為了簡單起見,Java 只支持類之間的單繼承,但是可以使用介面來實作多繼承,使用 Java 語言開發程式,需要采用面向物件的思想設計程式和撰寫代碼,

如果不想使用此特性,Java 也可以寫出面向程序的代碼,

2、平臺無關性

一次撰寫,到處運行(Write Once,Run any Where),因此采用 Java 語言撰寫的程式具有很好的可移植性,而保證這一點的正是 Java 虛擬機,在引入虛擬機之后,編譯后的 class 檔案可以在不同的平臺上運行,不需要重新編譯,

3、簡單性

Java 語言的語法與 C 語言和 C++ 語言很相近,使得很多程式員學起來很容易,對 Java 來說,它舍棄了很多 C++ 中難以理解的特性,如運算子的多載和多繼承等,而且 Java 語言不使用指標,加入了垃圾回識訓制,解決了程式員需要管理記憶體的問題,使編程變得更加簡單,

4、解釋執行

Java 程式在 Java 平臺運行時會被編譯成位元組碼檔案,然后可以在有 Java 環境的作業系統上運行,在運行檔案時,Java 的解釋器對這些位元組碼進行解釋執行,執行程序中需要加入的類在連接階段被載入到運行環境中,

解釋型的轉換工具稱為解釋器,程式在運行時使用解釋器,每翻譯一句,就執行一句,效率低,但跨平臺性能好,

編譯型的轉換工具稱為編譯器,事先把源代碼交給編譯器,它一下子全部翻譯,得到編譯后的代碼,可以直接被機器執行,

例如 JavaScript 語言有編譯型的轉換工具,如 chrome 的 V8 引擎,也有解釋型的轉換工具如 Netscape Navigator 的 JS 引擎,

5、多執行緒

Java 語言是多執行緒的,這也是 Java 語言的一大特性,它必須由 Thread 類和它的子類來創建,Java 支持多個執行緒同時執行,并提供多執行緒之間的同步機制,任何一個執行緒都有自己的 run() 方法,要執行的方法就寫在 run() 方法體內,

6、分布式

Java 語言支持 Internet 應用的開發,在 Java 的基本應用編程介面中就有一個網路應用編程介面,它提供了網路應用編程的類別庫,包括 URL、URLConnection、Socket 等,Java 的 RIM 機制也是開發分布式應用的重要手段,

7、健壯性

Java 的強型別機制、例外處理、垃圾回識訓制等都是 Java 健壯性的重要保證,對指標的丟棄是 Java 的一大進步,另外,Java 的例外機制也是健壯性的一大體現,

8、高性能

Java 的高性能主要是相對其他高級腳本語言來說的,隨著 JIT(Just in Time)的發展,Java 的運行速度也越來越高,

9、安全性

Java 通常被用在網路環境中,為此,Java 提供了一個安全機制以防止惡意代碼的攻擊,除了 Java 語言具有許多的安全特性以外,Java 還對通過網路下載的類增加一個安全防范機制,分配不同的名字空間以防替代本地的同名類,并包含安全管理機制,

1.1.5 Java 用途

1、Android 應用

許多的 Android 應用都是由 Java 程式員開發者開發,雖然 Android 運用了不同的 JVM 以及不同的封裝方式,但是代碼還是用 Java 語言所撰寫,相當一部分的手機中都支持 Java 游戲,這就使很多非編程人員都認識了 Java,

2、在金融業應用的服務器程式

Java 在金融服務業的應用非常廣泛,很多第三方交易系統、銀行、金融機構都選擇用 Java 開發,因為相對而言,Java 較安全 ,大型跨國投資銀行用 Java 來撰寫前臺和后臺的電子交易系統,結算和確認系統,資料處理專案以及其他專案,

3、網站

Java 在電子商務領域以及網站開發領域占據了一定的席位,開發人員可以運用許多不同的框架來創建 Web 專案,如 MyBatis、Spring 全家桶,

4、嵌入式領域

Java 在嵌入式領域發展空間很大,是指各種小型設備上的應用,包括機頂盒、車載的大屏影音娛樂設備、POS 機等,在這個平臺上,只需 130KB 就能夠使用 Java 技術,(在智能卡或者傳感器上)

5、大資料技術

Hadoop 以及其他大資料處理技術很多都是用 Java,例如 Apache 的基于 Java 的 HBase 和 Accumulo 以及 ElasticSearchas,

6、框架

解決企業應用開發的復雜性,讓開發更加方便,

7、軟體

制作小游戲、開發工具 IDE ,

1.2 JDK 下載

內容導視:

  • JDK 與 JRE 的區別
  • JDK 下載與安裝
  • 如何卸載
  • 如何禁止 JDK 檢查更新

即使撰寫了 Java 源代碼,系統也無法直接執行,需要 JDK 提供編譯和運行 Java 程式的環境,將代碼解釋為系統可識別的機器碼,

1.2.1 JDK 與 JRE 的區別

JRE(Java Runtime Enviroment):是 Java 的運行環境,面向 Java 程式的使用者,而不是開發者,

如果你僅下載并安裝了 JRE,那么你的系統只能運行 Java 程式,JRE 是運行 Java 程式所必需環境的集合,它包括 JVM(虛擬機)、Java 平臺核心類別庫(如 rt.jar)和支持檔案,它不包含開發工具(編譯器、除錯器等),

JVM(Java Virtual Machine):Java 虛擬機,是整個 Java 實作跨平臺的最核心的部分,能夠運行以 Java 語言撰寫的程式,其中的虛擬機屏蔽了底層運行平臺的差別,

JDK(Java Development Kit):是 Java 開發工具包,它提供了 Java 的開發環境(提供了編譯器 javac.exe 等工具,用于將 java 檔案編譯為 class 檔案)和運行環境(提供了 JVM 和 rt.jar 即 Runtime 輔助包,用于決議 class 檔案使其得到運行),

如果你下載并安裝了 JDK,那么你不僅可以開發 Java 程式,也同時擁有了運行 Java 程式的平臺,JDK 是整個 Java 的核心,包括了 JRE 和 開發工具 jar 包,如 tools.jar,

核心類別庫:主要是開發經常使用的類別庫,避免重復造輪子,如 java.lang 下的 String、包裝類等,已經被編譯成了 .class 檔案,需要時直接拿來用,不用自己重新寫一份,

JDK > JRE > JVM

如果你只是想運行 Java 程式,就只安裝 JRE 即可,

1.2.2 JDK 下載與安裝

JDK 下載地址:https://www.oracle.com/java/technologies/downloads/

有 JDK7、8、11,通常使用的是 JDK8、11,因為它們是長期支持版本,一般的版本支持半年就不再顯示,此時的你點開鏈接,說不定已經看不到 JDK7 了,

LTS 代表長期支持的版本,

Oracle 產品支持的三個策略:https://blog.csdn.net/iteye_21199/article/details/82305640

版本的有效時間:https://www.oracle.com/java/technologies/java-se-support-roadmap.html

JDK8 擴展支持到 2030 年,Oracle 將每三年指定一個版本作為長期支持版本,

查看自己電腦位數

x86 是 32 位,x64 是 64 位,

打開檔案資源管理器,右鍵此電腦屬性查看系統型別是 64 位作業系統,還是 32 位,

根據自己的系統、位數決定下哪個

比如我的電腦是 windows 系統 64 位,我使用的是 JDK8,按圖選,

特別說明

需要自己創建賬戶,若不想可在網上搜索 JDK8 下載,或下載最新版本,此時是 JDK16,下載 zip 和 exe 格式的都行,我將網盤鏈接放在了資源地址這章中,需要自取,

安裝

如果下載的是 exe 檔案,直接雙擊,指定安裝目錄,一直下一步,就安裝成功了;


(安裝后我又卸了,使用了 zip,所以地址前后不一致)

是 zip 解壓即可,點擊解壓后的檔案夾,地址欄上顯示的就是安裝目錄,要看到 bin 和其它目錄,如圖:

認為安裝目錄是 D:\cqh_environment\Java 就錯了,

記住 JDK 的安裝目錄,配置環境變數要用

安裝好后,看看目錄:

bin 目錄存放命令,如常用的 javac.exe、java.exe,用于編譯,運行程式,

lib 存放著 jar 包,如 dt.jar 是運行環境類別庫,存放了 Swing 組件;tools.jar 是工具類別庫,用來編譯與運行 java 檔案,

src.zip 存放著 Java 源代碼壓縮檔案,

rt.jar 在 jre\lib 中,

解釋

我們撰寫源代碼使用的檔案后綴為 .java,這種 .java 檔案經過編譯生成 .class 檔案,多個.class 打包放在 .jar 包中,

1.2.3 卸載

呃,這只是教你如何卸載,并不是現在讓你卸載...

打開控制面板/卸載程式,找到 Java,

或者打開 Windows 設定/應用/應用和功能,單擊要洗掉的軟體,會彈出卸載字樣,

如果你不知道如何打開它們,請用百度搜索,如如何打開Windows設定;其實由很多問題都已經得到回答,沒必要重復造輪子,學會使用搜索,對自學很有幫助,

卸載成功后,所有目錄名帶 Java、Sun、Oracle 的一律刪掉,如:

洗掉安裝 JDK 的目錄、洗掉 C:\Program Files (x86)\Common Files 和 C:\Program Files下的的 Java 和 Oracle 目錄、C:\Users\用戶名\AppData\LocalLow 下的 Oracle 和 Sun 目錄、C:\Users\用戶名\AppData\Roaming\Sun,

1.2.4 禁止 JDK 檢查更新

這是可選項,不是必須要做的,因為我覺得時不時彈出來像牛皮癬一樣挺煩,

打開控制面板\程式\Java,取消勾選自動檢查更新,不檢查;

高級\應用程式安裝\從不安裝,

1.3 撰寫代碼前的準備作業

如果你是什么都不懂的新手,請別慌著寫代碼,還有如下幾件事要做:

內容導視:

  • 為什么要寫筆記
  • 使用記事本撰寫源代碼
  • 如何學會雙手打字
  • Windows 系統常用的快捷鍵
  • 一點建議

1.3.1 為何要寫筆記

為了對抗遺忘,可以快速回顧、促進理解、加深記憶,將知識有條不紊地歸類,提煉反思應用,

不建議使用紙質的筆記,記錄麻煩,不方便攜帶,有老化被撕毀的風險,摘抄代碼時不能 ctrl+c 快速復制粘貼,

推薦使用 typora 軟體、博客、等各大網站記錄,

1.3.2 撰寫源代碼使用的記事本

工欲善其事必先利其器,使用系統自帶記事本撰寫程式,按下 tab 縮進一大節,逼得我每次使用 4 個空格,回退也難;關鍵字沒有顏色,不易于識別與查看,

下面介紹幾個更好的工具,安裝后,右鍵檔案選擇打開方式即可,

EditPlus

建議網上搜下漢化版的,下面是官方的收費的,

下載頁面:https://www.editplus.com/download.html

有 30 天的試用期,過后要購買許可證,

Notepad++

下載頁面:https://notepad-plus.en.softonic.com/download

Download 就是下載的意思,

如何設定主題

設定\語言格式設定\選擇主題,此外還可以根據不同語言設定樣式,

image-20220314193213707

image-20220314192900107

Sublime Text

官網:https://www.sublimetext.com/

Visual Studio Code

官網:https://code.visualstudio.com/

Atom

官網:https://atom.io/

不能指定安裝目錄;這種是以專案的方式管理檔案,

image-20220315100638692

也可以搜索一下其他的文本編輯器,看哪款適合你,

撰寫代碼

打開剛剛下好的軟體,輸入源代碼,最后 ctrl+s 保存,另存為 First.java,但是現在還不到寫代碼的時候,下一章好嗎?

1.3.3 練習雙手打字

一個指頭敲字,一邊看鍵盤,一邊看輸入的代碼,很容易出差錯,

既然選擇了在電腦上打字,就要提高自己的指法速度,敲代碼和寫筆記才會快,兩只手共同配合,

不用擔心,我也這么走過來的,雖然一開始沒有單只手指頭快,但堅持下來,不看鍵盤,手勢正確,打字速度會有明顯的提升,

推薦使用金山打字通,

下載頁面:http://www.51dzt.com/

從第一步,跟著圖中手勢位置慢慢打,差不多跟著敲一個星期,就基本實作盲打了,

頁面上有金山打字通的下載,點擊下載,

下載好后,雙擊執行 exe 檔案,安裝界面會跳出是否安裝其它軟體,根據自己需要確認是否勾選,

安裝好后點擊新手入門,練到不用看鍵盤,打字速度超過 30~60 字/分鐘差不多夠用了,(只需練習英文部分即可)

1.3.4 Windows10 系統常用快捷鍵

掌握常用的快捷鍵,能夠極大地提升效率,節省時間,

如果是有觸摸板的筆記本電腦,單擊是滑鼠左鍵,雙擊是滑鼠右鍵,

請打開 windows 設定\設備\觸摸板查看:(Windows + i 打開設定)

下面是我總結的常用幾個快捷鍵,如 Ctrl + A,在電腦鍵盤上找到這兩個鍵,同時按下去即可觸發全選操作,

如果打不出中文,懷疑是按 Caps Lock 開啟了大寫或者連續按下 Shift 啟動了粘滯鍵,再次按下此鍵即可恢復,

提前說明:

Ctrl + + 指同時按下 Ctrl、+ 這個鍵,別看見兩個加號就懵了,

文本相關

先選中文字,Windows 鍵是 Alt 左邊的

內容如下:

  • 常用的粘貼、選中、洗掉文字的快捷鍵
  • 翻頁、瀏覽文字的快捷鍵
  • 切換輸入法、中英轉換
操作 快捷鍵
跳過單詞 Ctrl + 左右箭頭,可配合 Shift 使用選中文字
選中文字 Shift + 箭頭、Shift + Home/End/Pgup/Pgdnd
復制 Ctrl + C
粘貼 Ctrl + V
全選 Ctrl + A
撤銷 Ctrl + Z
查找 Ctrl + F
替換 Ctrl + H
洗掉文字 Del、Backspace
上翻 Pgup Pause
下翻 Pgdn Break
行首 Home
行尾 End
頁首 Ctrl + Home
頁尾 Ctrl + End
切換當前語言下的輸入法 Shift + Ctrl
切換輸入法 Windows + 空格
中英文切換 Shift、Ctrl + 空格
切換語言 Shift + Alt

熱鍵相關

若桌面崩了,使用快捷鍵打開任務管理器,運行新任務,輸入 explorer 后回車,

內容如下:

  • 創建檔案、查看檔案屬性
  • 切換視窗,視窗最大化、最小化
  • 切換桌面,查看桌面
  • 截屏
  • 放大鏡
  • 快捷方式打開應用、資源管理器

有的快捷鍵按下去時講究先后順序,

例:如 Alt + Tab ,先按住 Alt 鍵不要松,再按 Tab,有先后順序(同時按也行),自己試試就知道我在講什么了,

← 指的是左箭頭,

說實話我向來很反感背知識,隨用即取就行,但是那面試題人人都背,你不看看,萬一被難倒了怎么辦?算了不考慮這些,下面這些快捷鍵你只看看經常使用的即可,

操作 快捷鍵
改變桌面圖示大小 按住 Ctrl + 滑鼠滑輪滾動、觸摸板兩指縮放
將檔案放入回收站 Ctrl + D 、 Del
永久洗掉檔案 Shift + Del
創建檔案夾 Alt + 2
查看當前檔案屬性 Alt + 1
所有視窗最小化 Windows + D 、 Windows + M 、三指下滑
所有視窗最小化又還原 雙擊 Windows + D 、三指下滑又上滑
當前視窗最小化 Windows + ↓
當前視窗還原、最大化 Windows + ↑
查找檔案 Alt +空格
瀏覽器打開新的標簽頁 Ctrl + T
瀏覽器查看下載檔案 Ctrl + J
瀏覽器當前頁面靜音 Ctrl + M
瀏覽器切換頁面 Ctrl + 數字、 Ctrl + Tab +(Shift)、 Ctrl + Pgup 和 Pgdn
打開新的視窗 Ctrl + N
使當前視窗失去焦點,圖層置于底下 Alt + Esc
打開任務管理器 Ctrl + Shift + Esc
鎖屏 Windows + L
關閉檔案 Ctrl + W
強制關閉檔案 Alt + F4
關機 Alt + F4
打開檔案資源管理器 Windows + E
將焦點定位到地址欄 Alt + D 、 F4
后退 Alt + ←、 Backspace
前進 Alt + →
回傳上一級 Alt + ↑
在窗格、功能區域之間切換 F6
重命名 F2
切換至下一個,配合 F2 有奇效 Tab
有些快捷鍵再加上此鍵,實作逆向選擇 如 Shift + Tab
即時切換應用 按住 Alt 不要松開單擊 Tab 、三指左右滑動
來回切換參考 同時按下 Alt + Tab
切換應用 Alt + Ctrl + Tab 松開,單擊 Tab 選擇應用后回車
重繪 F5 、 Ctrl + R 、 Ctrl + F5
同一應用不同視窗切換 Ctrl + Tab
瀏覽器不同視窗切換 Ctrl + Pgup Pause 、 Ctrl + Pgdn Break
創建新桌面 Ctrl + Windows + D
關閉新桌面 Ctrl + Windows + F4
查看已有桌面 Windows + Tab (再按還原)、三指上滑(下滑還原)
切換桌面 Windows + Ctrl + 左右箭頭
兩個應用分屏 Windows + ←、 Windows + →
放大縮小螢屏 Windows 加 +/-
瀏覽器放大縮小 Ctrl 加 +/-
打開/關閉管理通知 Windows + A
打開 Windows 設定 Windows + i
鎖定、切換用戶、注銷、打開任務管理器 Ctrl + Alt + Del

截屏

1)快捷鍵打開截全屏的工具

Windows + W

2)區域截屏

Windows + Shift + S

若點擊了截圖,照片會在 C:\Users\你的用戶名\AppData\Local\Packages\Microsoft.ScreenSketch_8wekyb3d8bbwe\TempState 下保存,

3)截全屏

Windows + PrtScSysRq

PrtScSysRq 鍵在 F12 右邊,保存的圖片在 C:\Users\自己的用戶名\Pictures\Screenshots 下,

PrtScSysRq

打開畫圖工具,Ctrl + V 將截屏捕捉,

4)截屏,范圍限制在當前作業頁面(得到焦點的頁面)

解釋,比如你打開了 QQ,正在使用它聊天,按下了這個快捷鍵,只會截 QQ 界面,

Windows + Alt + PytScSysRq

5)錄屏,范圍限制在當前作業頁面

Windows + Alt + R

捕獲的圖片和視頻在 C:\Users\用戶名\Videos\Captures 里,

6)游戲欄工具

Windows + G

Alt

打開軟體,按一下 Alt ,會有字符提示,并且將焦點定位到選單欄,此時可按左右鍵切換功能區,上下(不行就 Enter 回車)鍵打開功能區,

字符提示會顯示出功能的快捷鍵,例:檔案功能區會顯示出 F ,代表只需要 Alt + F 就可以打開此功能,彈出的下拉串列一般也有字母提示,按下對應字母即可,(有時需同時按下 Alt )

總結: Alt + 劃下劃線的字母,可以快速打開選單,

快速啟動任務欄上的軟體

你看看你的任務欄(螢屏的最下方),打開應用后可以右擊任務欄上的應用圖示,將其固定到任務欄,下次直接單擊此圖示就可以打開應用,或者 Windows鍵 + 數字,比如

瀏覽器在任務欄的第 1 個位置,只需 Windows + 1 就可以打開,或者 Windows + T,左右箭頭選擇后回車,

1.3.5 給初學者的一點建議

我希望你能后來居上,分享你的經驗讓我開開眼界,

下面是本人經過大量時間總結的經驗,但你可以不看,因為沒有什么規則可以量身定制,

1、約束好奇心,停止收藏資源

我直接說,你是學到死都學不完的,

資源無窮盡也,不要看到什么都想學,什么都想買,一直在搜,知識太多,你學不過來的,你先在網上搜索,比如后端的整套知識點,按順序來,一心一意,一套教程為主,有疑惑的再去別的地方比對,不要沒事就搜索一大堆資料收藏,又不開始,資料一定要精簡,那些看上去有用的知識但短期用不上的,直接取消收藏(也包括我),等你到了這步,再找資源,別做松鼠,

關于難度高的,可以先跳過,記錄下來,后面再補上,比如資料結構、JVM 底層、多執行緒與高并發、GUI 等等...別把初學時間浪費在這上面,這些東西都是唬人放棄的,

不要背代碼,要掌握原理,方法可以到 API 檔案上查,之前基本都是概念上的東西,理解就好了,但學到集合、IO、常用類如 String,只背方法名一定會消滅你學習的興趣,

這東西是一回生二回熟,第一遍不要想著要弄的多明白,簡單過一下即可,下次復習的時候,無師自通,我敢說人就是最強的智能機器人,

至于看視頻還是閱讀書籍,我感悟如下:

視頻時間看完所需時間更長,但可以一步步來,如果章節內容劃分合理,每個視頻時長合適,學習者更輕松完成每個目標,掌握自己的進度,適合初學者,

書籍花費時間較少,但經常有斷節之處,初學者搞不明白缺少哪一個環節,看著晦澀難懂的文字,翻不了幾頁就草草放棄,適合耐得住性子的人,

2、管理好精力

人一天能夠利用的時間極其有限,所以要學會合理分配精力,學習并不是生活的全部,要參與家務,如果你整天撲到學習上,只會感動自己,隨著精力的消耗,自控力的減弱,一定會在某天突然崩掉,開始變得什么都沒有興趣,行動力拉到最低,即使強迫在學,也只是枯坐原地,享受著左耳進右耳出的枯燥感,

早起別熬夜,每天一定留至少 30 分鐘的時間午睡,為了第 2 天的精神良好,學習時推薦使用番茄鐘,每過半小時就休息一小會,合理分配精力,(休息時不要看電子產品與動腦筋,要適當遠眺)

3、學會分享

不要閉門造車,要敢于發在各大網站上分享,Markdown 語法我會在下節中講到,你學會了,注冊個號,把筆記直接復制粘貼,發在博客網上;不要覺得自己技術菜,理由如下:

  1. 人人都有開始,你發出來了,別人才能糾正你的錯誤,避免成為井底之蛙,

  2. 你又開始自耗了,不停地在腦海天人交戰,一頓腦補:會不會萬一發出來被人嘲笑怎么辦?...于是藏著掖著,生怕別人知道,出丑;事情還未做,就想一系列的后果,別人有多可惡,我覺得世上還是好心人多,當然不要被零星幾個惡評就忽略了大多數支持你的人,這么大的林子總會有幾個腦殘,

  3. 百分之 99.9 的人根本刷不到你的文章,或者一下就 × 過去了,即使刷到了,那還有 9.9 成人瀏覽刷的一下就關了,評論的那是少之又少,鳳毛麟角,

  4. 對于四處搜索資源的人,是沒有精力留下痕跡的,沒有用的直接斃掉,有用的看完理解后也直接斃掉;這么快節奏的生活,沒人關心你是誰,最多充當局外客,當你還在糾結別人的看法時,糾結要不要做時,別人根本記都不記得你,我們在網路時代那是十分渺小,滄海一粟,很快被淹沒,就算有弄潮兒掀起了幾朵浪花,也會很快平息,所以別再糾結丟不丟臉了,

  5. 幫助別人就是幫助自己,雖然這個地球少了誰都能轉動,但我愿意相信天生我材必有用,自己的不可替代性,

  6. 你已經落后別人太多了,得到的都不是最新的知識;不要求自己跑的更快,但是也要有行動的勇氣吧,就算有 1000 個人從眾笑你、反對你,我也不會笑你,只會支持你,為你的敢于行動喝彩,

  7. 或者你擔心教會了徒弟餓死了師傅,認為自己憑什么白白讓別人分享自己的辛苦所得,讓那些白嫖怪輕而易舉獲取到所有,

    呃,我也不反對你,曾經的我認為那些動不動說要分享,文章標題、內容弄得很吸引人;結果在文章底部放了個二維碼,說要關注才能獲取驗證碼與資源,我一向嗤之以鼻,這不就是引流嗎,能賺多少錢啊?但是現在覺得別人有權力這么做,沒有人必須無償滿足你,既然付不了金錢,就只能搭進你的時間和人脈,

    對于那些開源的人,要不是他們的分享,讓我窺見一斑,那我現在應該不在家,而是進廠做流水線去了,是不會發文章的,或許抱怨這個世界不公平,所以再次感謝開源的人,感謝你們的無私奉獻,你們就是一道光,照亮被淘汰看不見希望的我,至于我的信念就從此轉變為螢火蟲也可與日月爭輝,(不禁想起了一句話:為眾人抱薪者,不可使其凍斃于風雪;為大眾謀福利者,不可使其孤軍奮戰;為自由開路者,不可使其困頓于荊棘)很抱歉我現在捉襟見肘,無法回饋你們,

    說實話,現在當我使用手機、電腦、冰箱、自來水等一切產品時,都會惴惴不安,一是因為怕現在習慣了離不開了,但是不了解底層原理,要是他們以后技術壟斷,坐地起價...;二是當我還在感嘆新技術新發展新氣象,日新月異,這些東西如此方便快捷,被制作被運送,傻瓜都能輕松使用,但是到底以犧牲了多少人的自由空暇為代價,令他們如同機械一般麻木,我們卻理所當然,嘻嘻哈哈,嘲笑著都是因為不努力,教導下一輩不要學他們,要成為人上人...捫心自問,真的能夠心安理得使用嗎?平等或許只是偽命題,

4、承認自己的不完美

人無完人,總有顧及不到,犯錯的時候,想做就直接放手干,不要計劃地那么周全,稍微一有變動,就放棄目標,想明天再做,是吧,別覺得只有從容不迫、不慌不忙、按部就班地才叫做事,而達不到自己的心理預期就不做了,大多數人都是計劃趕不上變化,被搞得灰頭土臉的,

5、調整心態(找準目標)

如果你學這個只是為了找作業,那么你一定會很痛苦,為了以后不再作業而作業,為了以后享福而選擇現在吃苦(為了不再吃苦而吃苦),為了將來而犧牲現在;這種矛盾的做法,并且大部分人實作不了財務自由,如果你只靠出賣自己的時間換來金錢的話,

你想得又得不到,或追趕不上前面的事物,你會處于十分焦慮的狀態,你真想財務自由,那么就要壟斷其他人的時間,給自己帶來利益(用金錢換他們的時間,創造價值收入囊中),或者搭上順風車,

但我不一樣,我寫這個,并不奢求得到回報,因為我寫這個同時,我就很滿足了,

但也不要擔憂,如果企業家全都使用機器人或者雇很少的人,短時間的確能夠讓利潤增加,因為減少了給員工那一項的支出;但是員工既是生產者也是消費者,如果他們沒有時間買或者沒有錢買,就算降低商品的價格,但為了有利潤可賺,員工的工資也會降,那就更沒有錢買,繼續降低商品價格...如此反復,就倒閉了;所以他們是不會讓窮人更窮的,

(我只是安慰你,這些玩意早被研究透了,說不定命運都被安排的明明白白)

6、相信自己

可你也與我有著同一樣的感受,為什么這些大佬如此牛逼,而自己什么都看不懂,不能理解,沮喪睡不著覺,我覺得這不是你的問題,而是每個人的必經之路,希望你能夠堅持下來,最后祝你學業有成,找個好飯碗,

7、選擇城市

之前聊天時,問到了這個問題:去大城市還是小城市發展?然后又說小城市容不下靈魂、大城市容不下肉身,其實我都沒有作業,村里人都知道我是游民,我給不了什么實質性的意見,

哈哈,沒關系,任何一個選擇都有得有失,你看看代價與風險是否自己能夠承受:是接受安穩,被人看扁;還是避開喧囂之地,舍命一拼,打下一片未來;就看你怎么選了,

8、沒有絕對正確的理論

給出一個貌似符合常理的結論,有人舉出反例,然后結論被推翻,再重新給出符合此反例的新的結論,不停周而復始...

如果這個結論目前還未被推翻,就暫時當作正確的吧,不需要懷疑一切,那樣會很累的,

1.4 Typora 軟體使用

簡潔、功能強大、實時預覽的 md 編輯器,

1.4.1 下載與安裝

下載地址:https://www.typora.io

往下翻,點擊 Windows(我的是 Windows 系統 64 位),點擊 Donwload Beta(x64),就會自動下載;

雙擊下載好的 .exe,

指定安裝位置,

下一步 next,

選中復選框代表創建桌面快捷方式,

1.4.2 如何創建 Markdown 檔案

創建以 .md 結尾的檔案,如 test.md,滑鼠右鍵新建/文本檔案,雙擊打開發現怎么還是記事本?

打開檔案資源管理器,把檔案擴展名和隱藏的專案打上對勾,就可以看到隱藏的后綴和檔案夾如 AppData;

此時剛剛創建的檔案顯露真身,原來還是 txt 檔案;右鍵重命名,把 .txt 去掉,再雙擊點進去,

1.4.3 常用的 Markdown 語法

此軟體使用的是 Markdown 語法,一種純文本格式的輕量級標記語言,通過簡單的標記語法,它可以使普通文本內容具有一定的格式,

md 語法的出現不是為了替代 html,而是更方便書寫,如果讓我寫那么多的 <>,不停思索如何嵌套,寫一大堆長長的 css,我會瘋掉的,

這款軟體它可以你更加關注內容,而不是注意怎么擺弄格式,Word 是邊寫邊在上面的邊欄調字體大小、顏色、格式,很不方便,

內容如下:

  • 字體格式:如標題、斜體、加粗
  • 跳轉鏈接:如超鏈接與圖片
  • 內容排列:如表格、有序無序串列、各種圖表、分割線

標題

一個 # + 空格,跟上標題內容即可,(Ctrl + 1 是一級標題,以此類推)

# 我是什么人
## 我是第2種人

一個 # 是一級標題,兩個 # 是二級標題,依此類推,直到 6 級標題,(越來越小)

復選框

一個減號 + 空格 + [ ] + 空格

- [ ] 鍛煉

粗、斜、斜加粗等字體

1、被兩個星號包裹的字自動變粗(Ctrl + B);

**我是粗**

我是粗

2、被一個星號包裹的字是斜體(Ctrl + i);

*我是斜*

我是斜

3、被 3 個星號包裹的字是粗斜;

***粗斜體***

粗斜體

4、Tab 上面有一個鍵,按住 Shift,再按住它,可以打出 ~,

~~廢棄~~

廢棄

參考

大于號 + 空格 + 內容

> 摘抄自大文豪張三的一句話

摘抄自大文豪張三的一句話

鍵盤風格

被成對的 kbd 標簽的內容,

<kbd>ctrl</kbd>

ctrl+c是復制

超鏈接和圖片

這些地址就是網址,

![圖片名](圖片地址)
[超鏈接名](超鏈接地址)

百度(右擊打開鏈接或按住 Ctrl,再單擊此鏈接)

表格

Ctrl + T 快捷鍵創建表格,Ctrl + Enter 添加新行,Shift + Ctrl + Del 洗掉一行,

名稱|性別|生日
--|--|--
趙三|男|1213.2.1
名稱 性別 生日
趙三 1213.2.1

代碼

單行使用`,多行三個`,指定代碼語言:

`單行代碼`
```java
多行代碼
```
```javascript
//實際寫法var foo = 'bar';
```

單行代碼

多行代碼
//實際寫法var foo = 'bar';

串列

1、無序串列

單個星號 + 空格 + 內容

* 語文
* 數學
* 英語
  • 語文
  • 數學
  • 英語

2、有序串列

數字. + 空格 + 內容

1. 起床
2. 刷牙
3. 吃飯
  1. 起床
  2. 刷牙
  3. 吃飯

3、串列套串列

* 起床  
    * 睜開眼睛  
    * 我是沙福林
* 刷牙
  • 起床
    • 睜開眼睛
    • 我是沙福林
  • 刷牙

大綱

可以把標題列出來,即 # 后的內容,

[TOC]

分割線

三個減號+回車(Enter)


以下內容不需要了解,幾乎不用,

甘特圖

```mermaid
gantt
        dateFormat  YYYY-MM-DD
        title 這是標題,上面是日期格式年月日
        section 計劃表
        準備行李(已完成)               :done,    des1, 2014-01-06,2014-01-08
        買機票(進行中)               :active,  des2, 2014-01-09, 3d
        拍照(計劃)               :         des3, after des2, 5d
```
gantt dateFormat YYYY-MM-DD title 這是標題,上面是日期格式年月日 section 計劃表 準備行李(已完成) :done, des1, 2014-01-06,2014-01-08 買機票(進行中) :active, des2, 2014-01-09, 3d 拍照(計劃) : des3, after des2, 5d

UML圖表

```mermaid
sequenceDiagram
張三->> 李四: 你好!李四, 最近怎么樣?
李四-->>王五: 你最近怎么樣,王五?
李四--x 張三: 我很好,謝謝!
李四-x 王五: 我很好,謝謝!

李四-->>張三: 打量著王五...
張三->>王五: 很好... 王五, 你怎么樣?
王五->>張三: 不好
```
sequenceDiagram 張三->> 李四: 你好!李四, 最近怎么樣? 李四-->>王五: 你最近怎么樣,王五? 李四--x 張三: 我很好,謝謝! 李四-x 王五: 我很好,謝謝! 李四-->>張三: 打量著王五... 張三->>王五: 很好... 王五, 你怎么樣? 王五->>張三: 不好

流程圖

```mermaid
graph LR
A[長方形] -- 鏈接 --> B((圓))
A --> C(圓角長方形)
B --> D{菱形}
C --> D
```
graph LR A[長方形] -- 鏈接 --> B((圓)) A --> C(圓角長方形) B --> D{菱形} C --> D

1.4.4 常用的設定

內容如下:

  • 常用的快捷鍵:如加粗、標題、表格等
  • 更改風格:如字體顏色、樣式,顯示代碼行號
  • 將筆記匯入匯出
  • 支持數學符號

因為都是中文,只講一點點,剩下的自己在選單欄上研究吧,

快捷鍵

直接點擊選單欄,查看快捷方式,如點擊視圖、段落,上面顯示了快捷方式更方便觸發;或者按住 Alt + O,即可打開格式:如 Ctrl + B 是加粗的快捷鍵,Ctrl + \ 是清除樣式,Ctrl + T 是創建表格的快捷方式,Ctrl + / 是查看源代碼,Windows + 句號是表情符號、視圖放大、縮小...

段落\YAML Front Matter(前言),因為我暫時用不上,看看其他人寫的文章吧:

https://zhuanlan.zhihu.com/p/78087948?from_voters_page=true

https://zhuanlan.zhihu.com/p/370113792

https://blog.csdn.net/weixin_46037781/article/details/118759174

https://blog.csdn.net/qq_43444349/article/details/105282118

主題

Alt + T 選擇自己想要的主題,

偏好設定

Ctrl + ,

如通用的自動保存選上,每次修改自動保存,不用按下 Ctrl + S,

高級模式選中除錯模式,關閉檔案后重新打開,右鍵檢查元素(或 Shift + F12),會發現此軟體就是一個瀏覽器,(瀏覽器按住 F12 鍵,會打開開發者模式,與這差不多)我們看到的筆記,實際是 md 語法被決議后生成的 HTML 標簽與 CSS 相配合展現的頁面;現在你再看看 md 語法到底有多方便了吧,這些標簽要你自己寫該多麻煩,

代碼塊顯示行號

Markdown,將顯示行號復選框勾選,

你看左邊的1
你看左邊的2    

更換主題

學了 CSS 后,再來,

之前創建 md 檔案時,給隱藏的專案了打上對勾,代表顯示隱藏的專案,其中 AppData 就是隱藏的專案,一般存放軟體的組態檔,

C:\Users\你的用戶名\AppData\Roaming\Typora\themes 下的幾個 CSS 檔案代表著不同的主題,如果不滿意頁面樣式,可以修改對應主題 CSS(記得留個備份)或自定義 CSS,重新打開筆記后,可以在主題中看到你的 CSS,隨便更換,

補丁:藍色背景下的 gif 動圖字體會模糊,必須在純色紅或白色背景下,gif 動圖字體才會清晰,所以取消動圖的使用,

將筆記轉成其他型別的檔案

PDF、HTML 等型別的都行,(without styles 是不帶樣式即沒有 CSS 修飾,自己試試就知道區別了)

或者打開瀏覽器,使用列印功能(Ctrl + P),無渲染與決議,很差勁,

支持數學公式

按下 Ctrl + , 快捷鍵打開偏好設定/Markdown/Markdown 擴展語法/勾選行內公式,再用 $某字母$ 顯示常用的數學符號,(當行內公式過多,可以考慮使用 $$某字母$$)

$$
\in
$$

\[\in \]

常用的的數學符號寫法:

  • 作者:DaneAI,https://blog.csdn.net/happyday_d/article/details/83715440
  • 作者:韓湘,https://blog.csdn.net/qq_38228254/article/details/78515800
  • 作者:白白舊維,https://www.cnblogs.com/1024th/p/11623258.html
  • 作者:櫻花贊,https://blog.csdn.net/weixin_43444930/article/details/119791074

恢復未保存的檔案

打開偏好設定,點擊恢復未保存的草稿,

image-20220314195918762

1.4.5 官網打不開的原因

它升級到了 1.0 版本了!收費了,

不要驚訝,能夠開源一定要有其它穩定的收入作為支撐;否則沒錢,功能不會太強大,作者都快餓死了,當然沒有功夫貢獻自己的力量,進行頻繁更新,跟上時代,

不能堅守本心的人會過的很苦:動搖,時刻懷疑自己的決定是否正確;后悔,要是當初如何...現在就...

Typora 代理商:https://typoraio.cn/

最后一個免費版,分享者:王炳明,https://wwe.lanzoui.com/i8PP3wzahrg

其實從來都沒有說過免費,之前只是 Beta 測驗版,類似于游戲中的公測吧,也不知道免費版什么時候就“關服”了,

作為一個即時渲染,所見即所得,按下 Ctrl + / 就可以看原始碼,簡潔實用,早已習慣,離不開它了,其它的軟體花里胡哨,什么功能都往里面加,試圖想代替其它同型別的軟體,結果搞得不倫不類,十分臃腫,

像其它 md 編輯器,大部分都是雙欄丑丑的大螢屏,十分占空間,并且滾動內容時,左右視圖不一致,還得分心同時看兩邊,真的是種折磨,應該讓軟體配合人,而不是讓人記住軟體的用法,主次關系要分清;真希望以后能夠統一,有個規范,其它軟體實作就可以了,

如果下載的是收費版,記得打開偏好設定\通用,將 Typora 服務器使用國內服務器復選框勾選一下,怕連不上服務器,激活不了此軟體,

1.4.6 自動上傳圖片

你如果使用久了,經常在網上發布文章,一定會遇見這個問題,

把寫好的 md 檔案,復制粘貼到博客園中,結果你發現圖片加載不出來,一看地址,C:\Users\自己的用戶名\AppData\Roaming\Typora\typora-user-images\xxx,

這才知道原來圖片被保存到了本地中,也難怪網上讀取不到,那么你發現了,將圖片直接拖拽到博客園的編輯頁面,會自動生成網路上的 URL,可以在全網都能訪問到,

但是時間長了,一張、一張拖拽也不是事啊,這時就需要圖床替我們自動保存圖片,下面介紹兩種方式;

命令列上傳圖片

打開偏好設定\影像,

image-20220314203029567

意思是當本地圖片被你拖進 md 檔案中,會自動上傳圖片,

點擊下載或更新,下好了后會出現打開組態檔按鈕,點擊彈出 JSON 檔案,將以下代碼粘貼到這個檔案中,

{
  "picBed": {
    "uploader": "smms",//代表當前的默認上傳圖床為 SM.MS
    "smms": {
      "token": "LFJLSJljlfaoFJOLAF"//這里面的token換成自己生成的token,一定要換
    }
  },
  "picgoPlugins": {}//為插件預留
}

這個 token 如何填?

打開 SM.MS 圖床:https://sm.ms/register
自己注冊賬號后,再登陸:https://sm.ms/login

點擊 User\Dashboard\API Token,進入:https://sm.ms/home/apitoken

點擊 Generate Secret Token 按鈕生成 token,將其填入 JSON 檔案,

填完后,保存 JSON 檔案,將圖片拖拽 md 檔案時,如有 Uploading 字樣,就成功了,

在 Pictures 可以管理或洗掉這些檔案,可惜根本沒法根據 URL 找到圖片,時間長了,定位洗掉圖片還是不方便,

說實話我很擔心,手賤全刪了,導致 md 檔案圖片全部失效,還是放在博客園中保險些,

PicGo app 上傳圖片

下載地址:https://github.com/Molunerfinn/PicGo/tags

選擇一個版本點擊,下翻,在 Assets 中選擇 exe 檔案下載,安裝后直接運行,

但無論怎么雙擊就是不會顯示視窗,看看電腦右下角,點擊藍色圖示:image-20220409200545365

圖片上傳區:圖片上傳 - SM.MS

圖床設定\SM.MS,填入 Token 后確定,設為默認圖床,

Typora 軟體,偏好\影像,按圖設定

image-20220409200916679

在 PicGo 的安裝目錄下有個 PicGo.exe,PicGo 路徑就選擇此 exe 的絕對路徑,

格式\影像\上傳所有本地圖片

Typora 在 Windows 下自動上傳圖片

目前支持上傳的方式有:自建服務器、騰訊云 COS、阿里云 OSS、七牛云 、Github、Gitee(碼云)...

作者:thobian,https://www.zhihu.com/question/56641227/answer/810364545

阿里云

作者:夏2同學,https://zhuanlan.zhihu.com/p/138878534

其它圖床

免費圖床整理,https://withpinbox.com/explore/collection/332056

1.5 常用的 DOS 命令

內容導視:

  • 打開 DOS 視窗的幾種方式

  • 進入目錄內:使用絕對路徑與相對路徑演示

  • 常見的 DOS 命令

寫出來的 Java 代碼,需要在命令視窗中執行編譯與運行命令,需要知道如何打開此黑視窗(Disk Operating System),

1.5.1 打開 DOS 視窗的幾種方式

  1. 螢屏最左下方,右擊 Windows圖示,點擊 Windows PowerShell,管理員權限更高,可以修改系統關鍵檔案,
  2. 點擊 Windows 圖示,往下翻在所有程式中找到 Windows 系統,點擊命令提示符,(可以右鍵以管理員權限運行)
  3. Windows + R 輸入 cmd 回車,(最常用
  4. 打開檔案夾資源管理器,在地址欄輸入 cmd 回車,(其次常用)
  5. 按住 Shift 別松,滑鼠右擊,在此處打開 PowerShell(S),

作者:「已注銷」,內容:將 Windows10 中的 WSL 添加至右鍵選單,https://blog.csdn.net/gulang03/article/details/79177500

1.5.2 進入目錄內:使用絕對路徑與相對路徑演示

下面說的目錄和檔案夾是一個意思,
輸入命令后按下回車才能執行,回車鍵是 Enter,

由于不是可視化界面,不能像之前一樣,點到哪里就跳到哪個檔案夾下,需要使用 cd 命令,跳轉到某路徑下,

路徑分為絕對路徑相對路徑

打開檔案資源管理器(Windows + E),隨便打開某盤下的檔案夾,可以看到地址欄上的路徑,假如以 D: 開頭,D: 稱為盤符,顯示的路徑稱為絕對路徑,D:\ 稱為 D 盤的根目錄(最上一級,不能再上了),

絕對路徑:從盤符開始的路徑,能夠完整的描述檔案位置的路徑就是絕對路徑,(唯一確定資源位置)
如路徑 D:\cqh_environment,指向 D 盤下的 cqh_environment 檔案,

相對路徑,是以當前路徑作為出發點的路徑,比如進入當前路徑的 a 目錄,

首先打開 DOS 視窗,切換盤符,

例:想要到 E 盤下,就輸入 E: 后回車,輸入 dir 回車查看當前路徑下有那些子檔案(沒有就在該盤手動創建檔案夾),使用 cd 檔案夾名稱 進入此檔案夾,

使用 cd a 時,單看這個 a,鬼才知道這是哪個地方的檔案夾,在哪里才能找到它,需要結合當前路徑 E:\ 才能知道,原來是要到 E 盤下去找 a,那么這個 a 就是相對路徑,

可以這么理解,我說北京市某某地址的小區,你馬上理解了要在哪去找,這是絕對路徑;但我說我家旁邊的一家店,你必須先知道我家在哪,再根據我家的位置確定這家店的位置,這就是相對路徑,


..:上級目錄

.:當前目錄

現在回到上級目錄,使用cd ..,現在演示一下絕對路徑,cd 絕對路徑,使用絕對路徑時,必須是當前所在盤下的路徑,

注意:路徑必須存在,你需要把目錄創建出來,才能使用 cd 命令進去,

如果使用相對路徑,先切換到根目錄,再執行 cd a\b\c\d

怎么回到根目錄?使用 cd E:\ 嗎?或者 cd ..\..\..\..?

還有一種簡單的方式 cd \ 即可


一個 cd .. 是回到上級目錄,
cd ..\.. 是回到上上級目錄,


若檔案名太長記不住,可以打出首字母,再按下 Tab 鍵,也可上下鍵切換已經輸入過的命令,或者你直接將檔案拖入這個黑視窗,地址就出來了,

通過剛才的例子,發現跳轉路徑時,必須是當前盤下的路徑,那么還不如使用相對路徑,反正盤名寫其它盤也沒用,解決辦法:加個引數 /d 即可,

例:現在在 C 盤下,我要直接到 E:\a\b\c\d,輸入 cd /d E:\a\b\c\d 即可,

1.5.3 常用的 DOS 命令

內容如下:

  • 進入目錄、回傳上級目錄
  • 打開常用的軟體
  • 清空螢屏
  • 新建、洗掉檔案
  • 查看系統變數
#切換盤符 C:
#查看當前目錄下的檔案 dir
#改變目錄 cd /d C:\a\b\c
#回傳上一級 cd..
#直接回到根目錄 cd \
#進入子目錄 cd 檔案夾名稱
#清空螢屏 cls
#退出 exit
#查看ip ipconfig
#查看ip詳細 ipconfig/all

#打開軟體
#打開計算器 calc
#打開繪圖 mspaint
#打開記事本 notepad

#查看網路 ping www.baidu.com
#網路診斷 ping www.baidu.com -t
#終止 Ctrl + C

#新建檔案夾 md 檔案夾名
#新建檔案 cd>檔案名.后綴
#洗掉檔案 del 檔案名.后綴(可帶*,*表示任意,小心別把所有東西刪了)
#洗掉檔案夾 rd 檔案夾名
#打開檔案 檔案名.后綴

#打包
#把當前的路徑下所有打包進a.jar
jar cvf a.jar .
#把當前的路徑下所有打包進b.war
jar cvf b.war .
#可以使用絕對路徑
jar cvf E:\cqh\b.war .

#查看系統變數的值,如第一個是C:\Windows
echo %SystemRoot%
echo %ProgramFiles%
echo %Path%

#咳咳,你打開環境變數(網上搜,下節也有),左邊是變數,右邊是值

1.6 Joplin 使用

與其說是 Markdown 編輯器,倒不如說它是一個同步小云盤、整理目錄的大師,不與 Typora 沖突,整個頁面布局(左中上下):目錄樹、筆記串列、筆記標題、筆記正文,

由于可以設定中文,只講一點點,

選單欄的 Tools\Options\General,右邊的 Language,下拉串列,選擇中文(簡體),

Alt + ?打開對應的選單欄:


F:檔案
E:編輯
V:視圖
G:跳轉
B:筆記筆記本
N:筆記
T:工具
H:幫助


Ctrl + Q:退出,

1.6.1 下載地址

官網:https://joplinapp.org

github下載地址:https://github.com/laurent22/joplin/releases

往下翻,選擇一個版本,點擊 Assets 選擇 exe 檔案下載,

1.6.2 常用設定

匯入 md 檔案

檔案\匯入,選擇匯入的是 Markdown 檔案還是目錄,(不要選帶文章前言的,匯出時會自動在文章前面加標題、創建和修改日期、時間,即 YAML Front matter)

把檔案同步到本地

工具\選項,同步,同步目標設為 File system,設定同步目錄,(當然你也可以花錢存云)

給同步目標上的備份檔案加密

工具\選項,加密,啟動加密;這樣的話,如果把同步檔案上傳到云端,也不怕別人偷看,


如果洗掉了同步目標的檔案,為了安全(故障保護默認開啟),不會洗掉本地檔案,

如果洗掉了本地檔案,同步時間一到,同步目標的檔案也會被洗掉,
可以趁著這時間差,從同步目標匯入資料到本地,

同步\顯示高級選項,自己重新上傳資料到同步目標或洗掉本地資料并從同步目標匯入資料


如果兩個終端資料不一樣(同時修改一個檔案,為不同內容),會把沖突的檔案移到新創建的"沖突"筆記本中,等你處理,

使用外部 md 編輯器

使用自己的 Markdown 編輯器:工具\選項\通用選項,右邊的文本編輯器命令,選一個能夠打開 md 檔案的 exe 命令,如 Typora.exe,(你還記得此軟體的安裝目錄嗎?)

在 Joplin 上任意選一個筆記,按下 Ctrl + E,自動轉用外部編輯器撰寫檔案,

自定義筆記本圖示

筆記本右擊\編輯,圖示\Select emoji,選一個表情,

網頁剪藏器

知識太多了,短時間內是看不完的,如果收藏,也有鏈接失效的風險,需要將文章內容復制下來,

工具:Chrome 瀏覽器,

由于插件市場打不開,點擊:https://www.extfans.com/

搜索 Joplin Web Clipper,需要關注公眾號,獲取驗證碼后下載,下載后解壓,里面有個 crx 檔案,打開谷歌瀏覽器,地址欄輸入:chrome://extensions/

把 crx 檔案直接拖入此頁面,添加擴展程式

image-20220409203712934

Joplin 軟體,工具\選項,網頁剪輯器,啟動網頁剪輯器,

使用:

螢屏截圖 2022-04-09 204022

Clip simplified page:簡化后的頁面

Clip complete page:完整頁面

In notebook:保存在哪個筆記本

Title:檔案名

同步到手機

真厲害啊!

把自己電腦當作服務器,同步到手機,教程:https://lightzhan.xyz/index.php/2020/11/15/joplin-webdav/

作者:lightzhan,密碼:h3mu,WebDAV 小秘:https://lightzhan.lanzoui.com/b015wjsri

螢屏截圖 2022-04-09 205026

打開 DOS 視窗,輸入 ipconfig 命令,IPv4 地址對應的就是主機地址;用戶名與密碼自己設定,

無線局域網配接器 WLAN:

   連接特定的 DNS 后綴 . . . . . . . :
   本地鏈接 IPv6 地址. . . . . . . . : fe10::209
   IPv4 地址 . . . . . . . . . . . . : 192.168.1.1
   子網掩碼  . . . . . . . . . . . . : 289.2.52.2
   默認網關. . . . . . . . . . . . . : fu81::22l

手機上自己搜索 Joplin app 吧,因為谷歌你們可能訪問不了,我總不能把如何FQ寫在這吧,

無標題

image-20220409210520668

WebDAV URL:http://主機地址:埠號

填入自己電腦上設定的用戶名與密碼,然后檢查同步配置,如果顯示“成功!同步配置看起來沒問題,”就 OK,

如果成功后依然沒有開始同步,一直轉圈,退出軟體重新進入,

其他人的使用心得

其他人的 Joplin 軟體使用心得:
https://www.zhihu.com/question/436251626/answer/1909305492
https://segmentfault.com/a/1190000038918737

打開擴展語法,在工具\選項\Markdown,根據需要勾選,詳細請看:https://lightzhan.xyz/index.php/2020/03/31/joplin-extension-usage/

如勾選啟用typographer支持,讓我試下:?(c)著作權所有人

1.7 MarkText 使用

是 Typora 的同型別產品,開源免費,

下載地址:https://marktext.app/

有時候可能打不開,https://github.com/marktext/marktext/tags

選擇版本后,Assets 下點擊 exe 檔案進行下載,

由于作者計劃 v1.0.0 以后支持其它語言(國際化),英語不好的,可以搜下漢化版,

如果 git 下載太慢:(慎用!!!)

作者:紫月java,https://www.cnblogs.com/ziyue7575/p/14157952.html

  • 安裝用戶腳本管理器:https://greasyfork.org/zh-CN/help/installing-user-scripts

  • 加速腳本:https://greasyfork.org/zh-CN/scripts/397419-fastgithub-鏡像加速訪問-克隆和下載

    螢屏截圖 2022-04-09 221050

    將 js 檔案拖入其中,重繪頁面,效果如圖:

image-20220410081922641

隨便點擊,開始下載吧,

1.7.1 編輯區域

查看源代碼:Ctrl + E

整體布局

正上方是 md 檔案的絕對路徑;

左上角 A 是總字符個數;點擊可以切換,

  • Words:單詞個數(一個漢字算一個單詞)
  • Characters:可見字符個數
  • Paragraphs:段落個數

右鍵標簽欄

Close:關閉檔案(未 Ctrl + S 保存會彈出提示)

Close others:關閉其它檔案

Close saved tabs:關閉已保存的檔案

Close all tabs:關閉所有檔案

Rename:重命名檔案

Copy path:復制檔案的絕對路徑

Show in folder:打開檔案所在目錄

段落快捷操作

當你每次移動游標時,當前段落對應的圖示(最左邊)就會顯示,點擊

image-20220410083416579

Duplicate:向下復制當前段落

Turn Into:變成?

  • Paragraph(Ctrl + 0):段落
  • Header 1(Ctrl + 1):h1 標題
  • Display Math(Alt + Ctrl + M):行內公式塊
  • HTML Block(Alt + Ctrl + J):div 標簽
  • Code Block(Alt + Ctrl + C):代碼塊
  • Quote Block(Alt + Ctrl + Q):參考
  • Order List(Alt + Ctrl + O):有序串列
  • Bullet List(Alt + Ctrl + U):無序串列
  • To-do List(Alt + Ctrl + X):任務復選框

New Paragraph:創建新的段落

Delete:洗掉當前段落

選中文字

從左至右依次是:粗(Ctrl + B)、斜(Ctrl + I)、下劃線(Ctrl + U)、洗掉線(Ctrl + D)、高亮(Ctrl + H)、代碼塊(Ctrl + `)、行內公式(Ctrl + M)、超鏈接(Ctrl + L)、插入圖片(Ctrl + Shift + I)、清除格式(Ctrl + Shift + R)

插入表情

Windows + 句號,或者 :a:,兩個冒號跟一個字母

1.7.2 偏好設定

Ctrl + 逗號

General

自動保存

Auto Save:

  • Automatically save document changes:更改時自動保存
  • Delay following document edit before automatically saving:延遲 ?ms 后保存

更改選單欄位置

Window:

Title bar style:

  • Custom:左上角
  • Native:正上方

Editor

字體樣式

Text editor settings:文本編輯設定

  • Font size:字體大小
  • Line height:行距
  • Font family:字體樣式
  • Maximum width of text editor:編輯器最大寬度,單位有:ch、px、%,例:輸入 100px;輸入錯誤會報紅,

Markdown

支持上下標

Markdown extensions:擴展語法

啟用 Enable Pandoc-style superscript and subscript

  • 5^3^:53
  • 5~3~:53

Spelling

Enable spell checker:開啟拼寫檢查

Default language for spell checker:檢查器的默認語言

Key Binding

更改操作的快捷鍵方式

image-20220410100837047

修改,重置,洗掉

每次修改后,需要翻到最下面保存

  • Save:保存
  • Restore default key bindings:恢復默認快捷鍵

1.7.3 圖片上傳

偏好設定/Image,

image-20220410103032577

Default action after an image is inserted from local folder or clipboard:插入圖片后的操作(只支持 macOS 和 Windows 系統)

  • Keep original location:保存在原位置

  • Copy image to designated relative assets or global local folder:復制圖片至指定位置(絕對或相對路徑)

  • Upload image to cloud using selected uploader(must be configured below):上傳至云端

Global or relative image folder:指定圖片保存的絕對路徑

Prefer relative assets folder:...相對路徑,開啟后,圖片會放在與 md 檔案的同級目錄下

  • Relative image folder name:目錄名稱,即圖片會放在此目錄下

說一下歷程吧,

之前不是使用 Typora 軟體時下載了 PicGo app 嘛,但是提示檢查不出來,說不存在;試著使用命令列方式吧(github 方式將來會廢棄),下拉串列切換為 Command line script,提示要安裝 PicGo-Core,于是先安裝 Node.js,打開 DOS 視窗,輸入 npm install picgo -g 命令,安裝位置:C:\Users\自己的用戶名\AppData\Roaming\npm\node_modules/

C:\Users\你的用戶名\.picgo 下創建了 config.json 檔案,復制了如下:

{
  "picBed": {
    "uploader": "smms", // 代表當前的默認上傳圖床為 SM.MS,
    "smms": {
      "token": "" // 從 https://sm.ms/home/apitoken 獲取的 token
    }
  },
  "picgoPlugins": {} // 為插件預留
}

PicGo-Core 指南:https://picgo.github.io/PicGo-Core-Doc/zh/guide/config.html#自動生成

用法:https://github.com/PicGo/PicGo-Core

如上傳檔案:picgo upload 檔案的絕對路徑

于是學了一下 Shell 腳本的語法,提示說輸入的唯一引數是圖片路徑,要求輸出圖片的 url 路徑;于是上網搜,如何接收第一個引數、輸出,分別是 $1、echo;嘗試程序中發現路徑必須以 / 分隔,而不是 \

export LANG="en_US.UTF-8"

str=$(picgo upload $1)
img=${str#*"[PicGo SUCCESS]: "}
echo $img

測驗中發現運行不了,需要環境,接著下載了 git,打開 bash 視窗使用 ./xxx.sh 命令運行此檔案,

正以為大功告成,可 MarkText 保存不了此 Shell 腳本的絕對路徑,沒有辦法,下載了 v0.16.3 版本覆寫安裝,偏好設定里 Image 下多了一項 Image Uploader

image-20220410110024054

選擇,點擊 Set as default,默認圖片上傳至 sm.ms,

然后下載新版本,再覆寫安裝一次,打開

eBxUcITybHdiZ39png

下拉框改為 Picgo 即可,

拖入圖片到視窗時,必須拖到當前段落(會顯示一條綠線),才會成功,

image-20220410111435947

點擊此圖片,可以修改圖片(查看是否為網路 URL)以及位置,

腳本:解釋性語言,且是文本格式,

1.7.4 File

英語不好,又沒有安裝漢化版的...下面是選單欄的各項,先從 File 開始:

New Tab(Ctrl + T):新建檔案

New Window(Ctrl + N):生成新視窗

Open File(Ctrl + O):打開檔案(可以直接將md 檔案拖入此視窗)

Open Folder(Ctrl + Shift + O):打開目錄(顯示目錄下的 md 檔案、查找、顯示文章中的標題)

Open Recent:打開最近檔案

  • Clear Recently Used:清空最近檔案(只是清除記錄)

Save(Ctrl + S):保存

Save As(Ctrl + Shift + S):另存

Auto Save:退出檔案前自動保存

Move To:將檔案移動至...

Rename:重命名

Export:匯出為

HTML

  • Page:設定頁面標題(title 標簽里的文本)

  • Style

    • Overwrite theme font settings:更改字體樣式、大小、行距

    • Auto numbering headings:自動為 h1 以下級別的標題編號

    • Show front matter:顯示前言

  • Theme:選擇主題

  • Table of Contents:目錄串列

PDF

  • Page

    • Page size:設定紙張大小

    • Landscape orientation:是否橫向

    • Page margin:頁邊距(毫米)

      • Top/Bottom:上下邊距

      • Left/Right:左右邊距

    • Header & Footer:頁眉頁腳

      • Header type:頁眉型別

        • Single cell:單(中間)

        • None:無

        • Three cells:三(左中右)

      • Customize style:定制風格

        • Header and footer font size:頁眉頁腳字體大小
  • Preferences(Ctrl + 逗號):偏好設定

  • Close Tab(Ctrl + W):關閉檔案

  • Close Window(Ctrl + Shift + W):關閉視窗

  • Quit(Ctrl + Q):關閉所有視窗

匯出時新增主題:https://github.com/marktext/marktext/blob/develop/docs/EXPORT_THEMES.md

1.7.5 Edit

Undo(Ctrl + Z):撤銷

Redo(Ctrl + Shift + Z):反撤銷

Cut(Ctrl + X):剪切

Copy(Ctrl + C):復制

Paste(Ctrl + V):粘貼

Copy as Markdown(Ctrl + Shift + C):以 Markdown 形式復制

Copy as HTML:以 HTML 標簽形式復制

Paste as Plain Text(Ctrl + Shift + V):純文本粘貼

Select All(Ctrl + A):選中所有

Duplicate(Alt + Ctrl + D):向下復制一行

Create Paragraph(Ctrl + Shift + N):創建新的段落

Delete Paragraph(Ctrl + Shift + D):洗掉當前段落

Find(Ctrl + F):查找

  • Case Sensitive:區分大小寫
  • Select whole word:選擇整個單詞,如查找 a,不會出現包含 a 的單詞如 puba,而是只有單獨的 a,
  • Use query as RegEx:使用正則運算式
  • Find Next(F3):往下找
  • Find Previous(Shift + F3):往上找

Replace(Ctrl + R):替換所有、一個個替換

Find in Folder(Ctrl + Shift + F):在目錄下的檔案中查找(首先得 Open Folder 打開目錄)

Line Ending:換行方式

  • Carriage return and line feed(CRLF):Windows 換行方式,即 \r\n

  • Line feed(LF):Linux換行方式,即 \n

1.7.6 Paragraph

Heading 1、2、...、6 為 H1、H2、...、H6 標題

Promote Heading(Ctrl + Shift + =、Ctrl + 加號):提升標題等級

Demote Heading(Ctrl + -):降低標題等級

Table(Ctrl + Shift + T):創建表格

Code Fences(Ctrl + Shift + K):代碼塊

Quote Block(Ctrl + Shift + Q):參考

Math Block(Alt + Ctrl + N):行內公式塊

HTML Block(Alt + Ctrl + H):HTML 標簽

Ordered List(Ctrl + G):有序串列

Bullet List(Ctrl + H):無序串列

Task List(Alt + Ctrl + X):復選框

Loose List Item(Alt + Ctrl + L):增加串列之間的距離

Paragraph(Ctrl + Shift + 0):段落

Horizontal Rule(Ctrl + Shift + U):分隔線

Front Matter(Alt + Ctrl + Y):前言

1.7.7 Format

Bold(Ctrl + B):粗體

Italic(Ctrl + I):斜體

Underline(Ctrl + U):下劃線

Superscript:上標

Subscript:下標

Highlight(Ctrl + Shift + H): 黃色高亮

Inline Code(Ctrl + `):單行代碼塊

Inline Math(Ctrl + Shift + M):單行行內公式

Strikethrough(Ctrl + D):洗掉線

Hyperlink(Ctrl + L):超鏈接

Image(Ctrl + Shift + I):圖片鏈接

Clear Formatting(Ctrl + Shift + R):清除格式

1.7.8 Window

Minimize(Ctrl + M):視窗最小化

Always on Top:總是顯示在最上層

Zoom In:放大

Zoom Out:縮小

Show in Full Screen(F11):全屏顯示

1.7.9 View

Command Palette(Ctrl + Shift + P):查看操作的快捷方式

Source Code Mode(Ctrl + E):查看源代碼

Typewriter Mode(Ctrl + Shift + G):打字機模式,保證游標在螢屏中間

Focus Mode(Ctrl + Shift + J):焦點模式,只關注當前輸入行

Show Sidebar(Ctrl + J):顯示側邊欄(目錄樹、查找、文章標題)

Show Tab Bar(Ctrl + Shift + B):顯示標簽欄(md 檔案名)

Toggle Table of Contents(Ctrl + K):跳轉至對應的 H 標題位置(點擊左邊側邊欄顯示的標題)

Reload Images(F5):重新加載圖片

1.7.a Help

Quick Start:快速開始

Markdown Reference:Markdown 語法

Changelog:更新日志

Donate via Open Collective:贊助

Feedback via Twitter:反饋(使用推特)

Report Issue or Request Feature:報告問題或請求功能

Website:網站

Watch on GitHub:查看 Github 專案

Follow us on GitHub:關注我們(GitHub)

Follow us on Twitter:關注我們(Twitter)

License:許可證

Check for updates:檢查更新

About MarkText:關于 MarkText

1.x 總結回顧

(不要驚訝怎么這么少,我說過別把大腦當成硬碟,記一個 cd 命令就足夠了,記得看完后休息一會,欲速則不達)

Java 介紹與下載

Java是最早由 SUN 公司的 James Gosling 開發的編程語言,

SUN 在 2009 年被 Oracle 收購;2014 年 3 月 19 日發布了 JDK8,

常用的 DOS 命令

cd 當前目錄下的檔案夾名 進入目錄

1.y 腦海練習

1.1 JDK 和 JRE 的區別?

1.2 什么是編程?

1.3 Swing 組件是什么?

1.4 JAR 包是什么?

1.5 軟體與程式指的是什么?

1.6 什么是編譯型語言和解釋型語言?

1.7 Java 語言特性?

1.8 能說下 JavaSE、JavaEE、JavaME 嗎?

第二章 撰寫第一個程式

內容導視:

  • 撰寫源代碼并運行
  • 代碼書寫規范
  • 注釋

2.1 撰寫源代碼并運行

內容導視:

  • 創建 .java 檔案撰寫原始碼
  • 配置環境變數
  • 查看命令使用幫助
  • 解釋代碼含義
  • 編譯與運行

2.1.1 創建 .java 檔案撰寫原始碼

我們要開始寫源代碼啦!但只是在 DOS 視窗中輸出一句話而已...

創建以 .java 結尾的檔案,如 Hello.java,(以后統稱為后綴或擴展名,打開檔案資源管理器,查看,勾上檔案擴展名)檔案右擊選擇打開一種打開方式,(EditPlus 或其他文本編輯器,找不到選擇其它應用,然后選中“始終使用此應用打開此型別的檔案”復選框)這樣你以后雙擊 .java 檔案就可以直接使用此軟體打開啦,

雙擊此檔案,輸入如下,還是直接復制、粘貼吧,記得保存,(Ctrl + S)

public class Hello {
	public static void main(String[] args) {
		System.out.println("hello world!");
	}
}

打開 DOS 視窗,使用 cd 命令切換到此檔案的所在目錄

(如果你在桌面上創建的檔案,路徑是 C:\Users\自己的用戶名\Desktop,你可以自己打開檔案資源管理器,點擊左邊的桌面圖示,在地址欄上輸入 cmd 后回車)

螢屏截圖 2022-03-22 113317

在 DOS 視窗中輸入 javac Hello.java,得到如下詭異的結果,

'javac' 不是內部或外部命令,也不是可運行的程式
或批處理檔案,

你可能會疑惑?怎么沒有找到這個命令,不是在 JDK 的安裝路徑\bin 目錄下有 javac.exe 命令嗎?你說找不到?那為什么之前 DOS 視窗查看 IP 時,也就是C:\Windows\System32下的 ipconfig 命令就可以執行?

此電腦右鍵/屬性/高級系統設定/環境變數/系統變數/Path 下看到了 %SystemRoot%\system32,即 C:\Windows\System32

(如果桌面上沒有此電腦圖示)

  • 打開檔案資源管理器,此電腦的圖示在左邊,
  • 或者 Windows + i打開設定,點擊系統/關于,往下翻,相關設定/高級系統設定,
  • 右鍵/個性化/主題/桌面圖示設定,勾選計算機圖示后點擊應用和確定,

猜想:難道系統只會在 Path 指定的路徑下尋找命令嗎?我隨手就刪了它(別試,否則手動還原),確定保存剛剛的修改操作,重新打開 DOS 視窗,再次執行 ipconfig,很明白了,

得出結論:執行的程式如果在當前目錄下不存在,系統會在名為 Path 的環境變數指定的目錄下查找

好的,大概明白了,但我的電腦上有多個用戶,那么為了不影響其他用戶,我只配置用戶變數的 Path,優先級當然沒有系統變數的高,(系統變數針對所有用戶生效)

2.1.2 配置環境變數

上節知道了 Path 變數的作用,現在該把命令地址添加到 Path 中了,

雙擊 Path,添加 javac 命令所在路徑,(如果你還記得 JDK 安裝的位置,打開 bin 目錄,復制地址欄上的地址)

如果這個 JDK 安裝目錄,以后會重復使用(不用懷疑,肯定了),為了方便,新建變數 JAVA_HOME 保存 JDK 安裝目錄,供其它地方使用,

再把之前的 javac 命令所在路徑替換成 %JAVA_HOME%\bin

%JAVA_HOME% 代表變數 JAVA_HOME 對應的值,以后 JavaEE、開發工具需要獲取 JDK 的安裝目錄,這樣就不需要再手動設定了,

有的人可能版本較老,Path 變數值在一行文本框上顯示,那么添加路徑時,注意路徑與路徑之前使用;分隔,注意這個分號是英文狀態下的半角符號,你按下 Shift,看看電腦右下角是否中英在切換,寫成就錯了,以后如果不說明,統一使用英文狀態下的符號,

例:

檢查自己是否配置好了:

打開 DOS 視窗,輸入 java -version 和 javac 等命令
如果顯示版本資訊,證明 java.exe 是可以用的

再輸入 echo %Path%
查看剛剛配置的 JDK的家\bin 路徑是否在其中

有的人可能有疑惑,明明自己沒配環境變數,為什么 java.exe 可以使用?

答:使用 exe 檔案安裝 JDK 后,會自動在系統變數 Path 添加如下圖路徑:

C:\Program Files (x86)\Common Files\Oracle\Java\javapath

所以沒有手動配置環境變數時,java 命令可以用,但 javac 不行,

每次改動,都需要重新打開 DOS 視窗,配置才能生效,輸入 javac Hello.java,如果你的語法正確,就會在當前路徑下生成 class(位元組碼)檔案,再輸入 java Hello ,此時別帶后綴,

有人就說了,每次運行 class 檔案,都要使用 cd 命令進入此目錄,再執行命令很麻煩,那么可以通過 classpath 變數指定位元組碼檔案所在位置,

新建環境變數 classpath:

.是英文輸入的句號,代表當前路徑,如果不寫就不會從當前路徑尋找 class 檔案,
由于我習慣把 class 檔案放在桌面上,于是新增了桌面的路徑,路徑和路徑直接使用;分隔,別使用中文的分號

這樣不管在任何地方,輸入 java Hello 就可以執行了,

總結

Path 是 Windows 查找 .exe 檔案的路徑;classpath 是 JVM 查找 .class 檔案的路徑;如果你以后學會了如何打 jar 包,假如它的絕對路徑為 E:\a\c\d\Tool.jar,如果想任何位置敲 java -jar Tool.jar 讓 jar 包執行,就可以把 E:\a\c\d\Tool.jar 加到 classpath 變數值里,

2.1.3 查看命令使用幫助

也許你總是會忘記,此命令應該攜帶什么引數...

想要執行的命令 -help,例舉了可加的引數,如 -encoding,(對不起,我要給你埋坑了,如果你事先不知道此引數的作用...)

javadoc -helpjavac -help,(其實不加 -help 也行)

看,這不就出來了:

image-20220322120929241

2.1.4 解釋代碼含義

看不懂很正常,學完面向物件就懂了,突然遇到看不懂的不要懷疑自己智力有問題,只是還沒到這步而已,大不了直接跳過,

public class Hello {
    // args 是變數名,可以根據識別符號的命名規則取名
	public static void main(String[] args) {
		System.out.println("hello world!");
	}
}

從頭開始說吧,

  • 關鍵字 public 是訪問修飾符,表明該類是一個公共類,可以控制其他物件對類成員的訪問,
  • 關鍵字 class 用于宣告一個類,其后所跟的 Hello 是類名,
  • Hello 后跟的 {} 稱為類體,包含了方法、欄位...
  • public static void main(String[] args) {}:這個是 main 方法,由于被 JVM 呼叫,也被稱為主方法、入口方法,所有 java 代碼都是最先從入口方法開始執行的,
    • main 后的 {} 稱為方法體,包含了 java 陳述句,
    • 關鍵字 static 表示該方法是一個靜態方法,無須創建類的實體即可呼叫,
    • 關鍵字 void 表示此方法沒有回傳值,
    • void 后面的是方法名 main,
    • main 后的括號包含一個形式引數,這個形參是 String 型別的陣列,引數名是 args,
    • System.out.println(""); 是 java 陳述句,代表列印(輸出)括號中的內容到控制臺(DOS 視窗),
    • "hello world!" 是一個字串,
    • ; 代表一條 java 陳述句的結束,

2.1.5 編譯與運行

(位元組碼檔案是 class 檔案,由源代碼中定義的 class 生成)

程序如下:

首先新建后綴為 java 的檔案,撰寫出符合語法規則的代碼,

編譯:經過 javac 源檔案名.java 命令編譯生成位元組碼檔案;

運行:使用 java 類名 命令在 JVM 虛擬機上運行此位元組碼檔案,JVM 會呼叫此類的 main 方法,

(補充:因為一個源檔案可以定義多個類,編譯后生成多個 class 檔案,所以 java 命令后面跟的不一定是源檔案名)

編譯

.java 檔案是 java 的源檔案,但是不能直接運行,必須先被編譯成為 .class 檔案才能夠執行,別問,問就是電腦太笨,看不懂,

class 檔案也稱為位元組碼檔案,上面的 javac 源檔案名.java 就是編譯的程序,

編譯期將原始碼交給編譯器,編譯成可以被 JVM 識別的位元組碼,如果源代碼不符合語法規則,就會報錯(錯誤提示很智能,可以根據報錯資訊相應找到原因,自己試試比如洗掉一個大括號、引號等,看看 javac 命令給你報什么錯)

運行

(當源檔案修改后,必須重新編譯才能生效)

編譯后生成 class 位元組碼檔案,使用 java class檔案名 運行,別加 .class 后綴,

運行期類加載器(Class Loader)找位元組碼檔案(如果沒有配 classpath,默認從當前路徑下找),找到了就加載位元組碼檔案到 JVM 虛擬機,JVM 啟動解釋器對位元組碼檔案進行解釋,生成的二進制碼讀到記憶體中,由作業系統進行二進制碼的執行,

位元組碼檔案是一種和任何具體機器環境及作業系統環境無關的中間代碼,編程人員和計算機都無法直接讀懂位元組碼檔案,它是一種二進制檔案,是 Java 源檔案由 Java 編譯器編譯后生成的目標代碼檔案,它必須由專用的 Java 解釋器來解釋執行,因此 Java 是一種在編譯基礎上進行解釋運行的語言,

C 語言中文網下的解釋,我覺得還行吧,我沒玩過 C 語言,說什么就先聽著,之后再忘掉就 OK 了,


1)將所有源代碼一次性轉換成二進制指令(也就是生成一個可執行程式,如 Windows 下的 .exe)
的轉換工具稱為編譯器

比如 C 語言、C++ 的 GCC、Golang 的 GCC GO 等,源代碼改動需要重新編譯一次,

2)翻譯一句,執行一句,不會生成可執行程式,
比如 Python 的 CPython 等,這種的轉換工具稱為解釋器,

3)Java 和 C# 是一種比較特殊的存在,
如 java 有編譯器 javac,但編譯后的 class 檔案計算機無法執行,還需要 java 解釋器進行翻譯,

它們的源代碼需要先轉換成一種中間檔案(位元組碼檔案),然后再將中間檔案拿到虛擬機中執行,
Java 引領了這種風潮,它的初衷是在跨平臺的同時兼顧執行效率;

C# 是后來的跟隨者,但是 C# 一直止步于 Windows 平臺,在其它平臺鮮有作為,


Java 解釋器負責將位元組碼檔案翻譯成具體硬體環境和作業系統平臺下的機器代碼,以便執行,因此 Java 程式不能直接運行在現有的作業系統平臺上,它必須運行在被稱為 Java 虛擬機的軟體平臺之上,

Java 虛擬機(JVM)是運行 Java 程式的軟體環境,Java 解釋器是 Java 虛擬機的一部分,在運行 Java 程式時,首先會啟動 JVM,然后由它來負責解釋執行 Java 的位元組碼程式,并且 Java 位元組碼程式只能運行于 JVM 之上,這樣利用 JVM 就可以把 Java 位元組碼程式和具體的硬體平臺以及作業系統環境分隔開來,只要在不同的計算機上安裝了針對特定平臺的 JVM,Java 程式就可以運行,而不用考慮當前具體的硬體平臺及作業系統環境,也不用考慮位元組碼檔案是在何種平臺上生成的,

JVM 把這種不同軟、硬體平臺的具體差別隱藏起來,從而實作了真正的二進制代碼級的跨平臺移植,JVM 是 Java 平臺架構的基礎,Java 的跨平臺特性正是通過在 JVM 中運行 Java 程式實作的,

Java 語言這種“一次撰寫,到處運行”的方式,有效地解決了目前大多數高級程式設計語言需要針對不同系統來編譯產生不同機器代碼的問題,即硬體環境和操作平臺的異構問題,大大降低了程式開發、維護和管理的開銷,

提示:Java 程式通過 JVM 可以實作跨平臺特性,但 JVM 是不跨平臺的,也就是說,不同作業系統之上的 JVM 是不同的,Windows 平臺之上的 JVM 不能用在 Linux 平臺,反之亦然,

2.2 代碼書寫規范

內容導視:

  • 代碼細節
  • 代碼規范
  • 識別符號與關鍵字

2.2.1 代碼書寫細節

看不懂沒關系,只挑能理解的,

1)字母嚴格區分大小寫,如 class 不等于 Class,

2)在 java 中任何有效的代碼必須寫在“類體”中,就是 public class Hello 后的一對大括號 {} 中,

3)大括號必須要成對寫,防止漏掉,

4)為了增加代碼的可讀性,大括號里的內容需要使用 tab 縮進,如 main 方法就比 class Hello 低一個層次,

class Hello {
    // 被 {} 包裹的部分選中,按下 tab
    public void some1() {
        // 被 {} 包裹的部分選中,按下 tab
        int i = 10;
        if (i > 10) {
            // 同理
            System.out.println("為何");
        }
    }
}

5)main 后的 {} 包裹的內容稱為方法體,由一行行的 java 陳述句構成,任何一條 java 陳述句必須以分號結尾;,若無特別說明,默認為英文狀態下的符號,

6)方法體中代碼遵循自上而下的順序依次逐行執行,不可隨意顛倒順序,

System.out.println(i);// 執行到這句時,還沒有 i 變數
int i = 10;

7)一個 java 源檔案可以定義多個類,編譯后,每一個類對應一個 class 檔案,如以下編譯后會生成 A.class、B.class、C.class 三個位元組碼檔案

class A {
}

class B {
}

class C {
}

8)有 public 修飾的類可以沒有,但如果有,被 public 修飾的類名必須與源檔案名一致
例:源檔案名為 Hello,則 public class 后的類名也應該為 Hello,

9)被 public 修飾的類如果有,則最多只能有一個,類似一個家只有一個主人吧,

10)運行時,只會呼叫對應類的入口方法里面的內容,入口方法有固定的書寫格式:

public static void main(String[] args) {}

那我偏不信邪,改下,再運行,

E:\cqh_demo\01-JavaSE>java A
錯誤: 在類 A 中找不到 main 方法, 請將 main 方法定義為:
   public static void main(String[] args)
否則 JavaFX 應用程式類必須擴展javafx.application.Application

好吧,再改回去了,

2.2.2 代碼規范

規范與規則不一樣,不是必須遵守,但是如果你不遵守,代碼可讀性會很差,反例如下,雖然可以通過編譯,但你看起來感覺如何?

class
Hello{
public
    static
void
    main
    (String a[]){
System.
       out. println("你好")
       ; 
    int i=2
        ;
    			if
                    (i>
                     1&&i
                     <29){
                    System.out.println("e");
                }
}
	}

1)類和方法上的注釋,以 javadoc 的方式,方便生成檔案注釋,

class Test {
    /**
     * 這個注釋下節有講,現在只是測驗
     *
     */
    public void some() {}
}

2)非 javadoc 注釋,用于給代碼的維護者和讀者看,(為什么這么寫,如何修改,注意事項)

// 這就是注釋,解釋下面是將 10 賦給了 int 型別的變數 i;
int i = 10;

3)運算子如 <、= 的兩邊使用空格與字符隔開,舉出正反例:

int a = 10;
int b=10;

if (a < 20 && b > 5) {}

if(a<20&&b>5){}

4)代碼撰寫使用次行風格或行尾風格,你可以理解為這就是對整齊風格的一種追求吧,

// 行尾風格
public void add(int num) {
    if (num < 0) {
        this.age = 3;
    } else if (num < 6) {
        this.age = 33;
    } else {
    	this.age = 333;
    }
}
// 次行風格
public void add(int num)
{
    if (num < 0)
    {
        this.age = 3;
    } else if (num < 6)
    {
        this.age = 33;
    } else
    {
    	this.age = 333;
    }
}

2.2.3 識別符號與關鍵字

宣告:由于每次使用 import、帶上完整類、main 方法比較繁瑣,于是進行了簡化,只提供關鍵部分,外面的類、方法等其它代碼以后自己加吧,別直接復制代碼,發現怎么跑不起來啊?

class Hello {
    public static void main(String[] args) {}
    
    public int add(int num1, int num2) {}
}

凡是程式員有權利命名的單詞都是識別符號

比如:類名、方法名、引數名、變數名、介面名、常量名,(這些是什么,以后就知道了,現在只是看看)

// add 是方法名有權利命名
public int add(int num1, int num2){
    // n 是變數名
    int n = num1;
}

你可以試試哪里可以修改,比如修改 public、int 等單詞,是否會報錯,你就明白,你可以動的地方有哪些,可以動而不報錯的那些單詞就是識別符號,不可以動的就是關鍵字,


切換到英文輸入,輸出下劃線、美元符號,

_:Shift 加 -
$:Shift + 4


命名規則

  • 識別符號只能由數字、字母、_、$ 組成,(識別符號中不能有空格)
  • 識別符號不能以數字開頭,
  • 關鍵字和保留字不能做識別符號,
  • 識別符號嚴格區分大小寫,理論上沒有長度限制,(如 Public 與 public 不一樣)

命名規范

A)見名知意,如 day 代表天數,

1)別用拼音與英語混合,那樣很難理解,

反例:tianKongBlue

2)杜絕完全不規范的英文縮寫,避免望文不知義,

反例:AbstractClass “縮寫”成 AbsClass;
condition “縮寫”成 condi;
Function “縮寫”成 Fu;
此類隨意縮寫嚴重降低了代碼的可閱讀性,

B)駝峰命名,多個單詞連在一起時,單詞首字母大寫,增加識別和可讀性,下面是阿里巴巴開發手冊(黃山版)詳細:

1)類名使用 UpperCamelCase 風格(首字母大寫,后面每個單詞首字母大寫),以下情形例外:DO / PO / DTO / BO / VO / UID 等,

正例:ForceCode / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion
反例:forcecode / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion

2)方法名、引數名、成員變數、區域變數都統一使用 lowerCamelCase 風格(首字母小寫,后面每個單詞首字母大寫),

正例:localValue / getHttpMessage() / inputUserId

C)其它命名風格

1)常量名全部大寫,單詞間用_連接,力求語意表達完整,不要嫌名字長,

正例:MAX_STOCK_COUNT / CACHE_EXPIRED_TIME
反例:MAX_COUNT / EXPIRED_TIME

列舉成員實際上也是常量,名稱需要全大寫,單詞間用_連接,

2)抽象類命名使用 Abstract 或 Base 開頭;例外類命名使用 Exception 結尾;測驗類命名以它要測驗的類的名稱開始,以 Test 結尾;列舉類名帶上 Enum 后綴,

3)介面和實作類的命名有兩套規則:

  • 對于 Service 和 DAO 類,基于 SOA 的理念,暴露出來的服務一定是介面,內部的實作類用 Impl 的后綴與介面區別,

    正例:CacheServiceImpl 實作 CacheService 介面, 
    
  • 如果是形容能力的介面名稱,取對應的形容詞為介面名(通常是 –able 結尾的形容詞),

    正例:AbstractTranslator 實作 Translatable 介面,
    

4)在常量與變數命名時,表示型別的名詞放在詞尾,以提升辨識度,

正例:startTime / workQueue / nameList / TERMINATED_THREAD_COUNT
反例:startedAt / QueueOfWork / listName / COUNT_TERMINATED_THREAD

5)如果模塊、介面、類、方法使用了設計模式,在命名時要體現出具體模式,

正例: 
public class OrderFactory;
public class LoginProxy;
public class ResourceObserver;

說明:將設計模式體現在名字中,有利于閱讀者快速理解架構設計思想,

6)各層命名規約:

? a)Service / DAO 層方法命名規約:

? ① 獲取單個物件的方法用 get 做前綴,

? ② 獲取多個物件的方法用 list 做前綴,復數結尾,如:listObjects

? ③ 獲取統計值的方法用 count 做前綴,

? ④ 插入的方法用 save / insert 做前綴,

? ⑤ 洗掉的方法用 remove / delete 做前綴,

? ⑥ 修改的方法用 update 做前綴,

? b)領域模型命名規約:

? ① 資料物件:xxxDO,xxx 即為資料表名,

? ② 資料傳輸物件:xxxDTO,xxx 為業務領域相關的名稱,

? ③ 展示物件:xxxVO,xxx 一般為網頁名稱,

? ④ POJO 是 DO / DTO / BO / VO 的統稱,禁止命名成 xxxPOJO,

7)POJO 類中定義的布爾型別的變數,不要加 is 前綴,否則部分框架決議會引起序列化錯誤,

備注:POJO(Plain Ordinary Java Object):普通的 Java 物件,

反例:定義為基本資料型別 Boolean isDeleted 的屬性,它的方法也是 isDeleted(),
框架在反向決議時,“誤以為”對應的屬性名稱是 deleted,導致屬性獲取不到,進而拋出例外,

說明:本文 MySQL 規約中的建表約定第 1 條,表達是與否的變數采用 is_xxx 的命名方式,
所以需要在設定從 is_xxx 到 xxx 的映射關系,

8)包名統一使用小寫,點分隔符之間有且僅有一個自然語意的英語單詞,包名統一使用單數形式,但是類名如果有復數含義,類名可以使用復數形式,

正例:應用工具類包名為 com.alibaba.ei.kunlun.aap.util;類名為 MessageUtils
(此規則參考 Spring 的框架結構),

9)陣列型別應與 [] 緊挨,以免看漏,認為是基本資料型別或 String 型別,

正例:定義整形陣列 int[] arrayDemo,
反例:在 main 引數中,使用 String args[] 來定義,

10)避免在子父類的成員變數之間、或者不同代碼塊的區域變數之間采用完全相同的命名,使可理解性降低,

// 反例
public class ConfusingName { 
    protected int stock; 
    protected String alibaba;
    // 非 setter/getter 的引數名稱,不允許與本類成員變數同名
    public void access(String alibaba) {
        if (condition) {
            final int money = 666;
            // ...
        }for (int i = 0; i < 10; i++) {
            // 在同一方法體中,不允許與其它代碼塊中的 money 命名相同
            final int money = 15978;
            // ...
        } } }
class Son extends ConfusingName {
    // 不允許與父類的成員變數名稱相同
    private int stock; 
}

說明:子類、父類成員變數名相同,即使是 public 也是能夠通過編譯,而區域變數在同一方法內的不同代碼塊中同名也是合法的,但是要避免使用,對于非 setter / getter 的引數名稱也要避免與成員變數名稱相同,

關鍵字

Java 關鍵字是對 Java 編譯器有特殊含義的字串,是編譯器和程式員的一個約定,程式員利用關鍵字來告訴編譯器其宣告的變數型別、類、方法特性等資訊,

關鍵字一律用小寫字母標識,按其用途劃分為如下幾組,

1)用于資料型別的關鍵字有:

boolean、byte、char、 double、 false、float、int、long、new、short、true、void、instanceof,

2)用于陳述句的關鍵字有:

break、case、 catch、 continue、 default 、do、else、 for、 if、return、switch、try、 while、finally、 throw、this、 super,

3)用于修飾的關鍵字有:

abstract、final、native、private、protected、public、static、synchronized、transient、 volatile,

4)用于方法、類、介面、包和例外的關鍵字有:

class、 extends、 implements、interface、 package、import、throws,

5)保留字:

cat、 future、 generic、inner、 operator、 outer、rest、var、goto、byValue、cast、const 等都是Java尚未使用,但以后可能會作為關鍵字使用,

另外,Java 還有3個保留字:true、false、null,它們不是關鍵字,而是文字,包含 Java 定義的值,和關鍵字一樣,它們也不可以作為識別符號使用,

2.3 注釋

內容導視:

  • 單行注釋
  • 多行注釋
  • 檔案注釋
  • IDEA 工具自動快捷鍵添加注釋
  • 使用 javac 命令編譯時出現的"錯誤: 編碼 GBK 的不可映射字符"
  • 淺入編碼
  • 查看系統編碼
  • 使用 API 檔案

注釋是對代碼的解釋說明,方便理解代碼的含義,提高代碼的可讀性,
注釋不是編程陳述句,因此被編譯器忽略,
如果不寫注釋,時間久了或代碼過長本人也看不懂,所以撰寫注釋是一個良好的習慣,

注釋有三種,依次介紹,

2.3.1 單行注釋

使用雙斜杠 //,// 后的就是注釋(僅一行),不會被編譯器當成 java 陳述句,

public class A {
	public static void main(String[] args) {
		// 列印()中的話到控制臺上,這個()中的字面量(資料)如果是字串型別,需要用""包裹起來
		System.out.println("Hello World A");
	}
}

2.3.2 多行注釋

對于很多內容,單行放不下,可以使用多行注釋,在 /**/ 里內寫下內容,星號別省略,

/*
	System 是類,
	通過類名.呼叫 out 這個靜態變數,
	這個靜態變數保存的是堆記憶體中的物件地址,被稱為物件參考
	再通過物件參考,呼叫物件的 println 方法
*/
System.out.println("Hello World A");

2.3.3 檔案注釋

下面看看就行,以后使用開發工具 IDE 自動生成,沒必要手動敲,

檔案注釋可以被 javadoc 命令決議,生成以網頁形式(html)顯示的 API 檔案,(Application Programming Interface:應用程式編程介面),

當類又多又雜,一個個找類、看注釋很麻煩,于是提取出來生成網頁,

用來說明類、成員變數和方法的功能,不用在一個一個 java 檔案中查看注釋,直接打開 html 查看想要的方法,

javadoc 默認只提取 public、protected 修飾的部分,javadoc -help 查看可加的選項,

檔案注釋必須寫在類、介面、方法、構造器、成員欄位前面,寫在其他位置無效,

檔案注釋中可以識別的標簽如下:

標簽 說明
@version 指定類的版本,用于類上
@author 標注類的作者
@since 從哪個版本起有了這個方法
@param 引數詳細資訊
@return 說明回傳值
@throws 可能拋出的例外
@deprecated 表示不建議使用
@see 另請參閱

檔案注釋的標簽區分大小寫,別寫錯了,也可以看看原始碼上的注釋是怎么寫的,(別省略 * 號,注意觀察下面的格式)

/**
 * @author 是在座的每一個人
 * @version 2.0.0
 */
public class Hello {

    /**
	 * 這個方法用來求兩數之和
	 *
     * @param  num1	第一個引數
	 * @param  num2	第二個引數
     * @return 回傳兩個數的和
     * @throws 測驗用而拋出的例外
     * @since  1.8.2
     */
    public int add(int num1, int num2) throws RuntimeException {
        return num1 + num2;
    }
} 

javadoc 命令只能提取檔案注釋,讓我們試試吧,

javadoc Hello.java -encoding UTF-8 -version -author -private -charset UTF-8 -docencoding GBK

當前目錄會生成 index.html 檔案,雙擊此檔案,交給瀏覽器決議(會自動打開瀏覽器),右鍵查看頁面源代碼,API 檔案里的資訊是讀取 Hello.java 檔案得來的,

使用此命令還可以追加其他 java 源檔案的檔案注釋,例:javadoc -encoding UTF-8 Hello.java H.java

javadoc 命令中的引數說明


-encoding 是告知 java 源代碼所用的字符編碼;
-version、-author 是顯示版本和作者;
-private 是顯示所有類和成員;(包括顯示私有,一般顯示 protected 以上級別就行,可以不加此選項)

-charset 是告知瀏覽器此檔案采用什么編碼方式讀取這個檔案;
即 html 檔案生成 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

-docencoding 是指定生成的 html 檔案的字符編碼,不寫此選項,默認 UTF-8,


由于檔案被保存時的編碼和讀取時采用的編碼不一致會出現亂碼,所以別掉坑,咳咳,你知道自己的檔案編碼嗎?在哪如何查看?編碼是什么?你可以先了解下相關知識,或者你之前已經掉坑了,不知道滿屏的 GBK 不可映射是啥意思,后面再講好嗎?

指定檔案生成的位置

使用 -d 指定檔案在 E:\a\b\c 下生成,很抱歉讓你的桌面生了一大堆 html 檔案,

javadoc Hello.java -d E:\a\b\c -version -author

代碼一改,注釋說明也得跟著改;為了避免無用功,代碼中給識別符號命名,見名知意,最好讓所有人看到這段代碼就知道它是干什么的,避免冗余無效注釋,

下面不用看,我怕你暈:

import java.nio.channels.ReadableByteChannel;
import java.nio.charset.CharsetDecoder;

/**
 * 這是測驗如何制作 API 檔案的類
 *
 * <p> p 標簽包圍的文字代表一段,ul 和 li 標簽是無序串列</p>
 * <ul>
 * <li>呵呵 {@code test} 呵呵</li>
 * <li>呵呵 <code>test</code> 呵呵</li>
 * <li>被上面 code 標簽包裹的內容會更顯眼,更細,一般用于識別符號</li>
 * <li>see 標簽另請參閱,格式:參考類的全類名#方法名(形參型別, 形參型別...)
 *     java.lang 包下的類可以省略包名,如果參考的類在 API 檔案上,點擊后會自動跳轉
 *     這個 H 類我也打包到了此檔案</li>
 * </ul>
 *
 * @author  cqh
 * @author  作者甲
 * @version 1.0.0
 * @see     Object#wait(long)
 * @see     Object#toString()
 * @see     StringBuffer
 * @see     H#hh()
 * @since   0.8.0
 */
public class Test {
    /**
     * 介紹屬性的作用
     *
     * @see java.util.Scanner#makeReadable(ReadableByteChannel, CharsetDecoder)
     * @since 0.8.1
     */
    public String[] name;

    /**
     * 說明方法的作用
     *
     * @param name 這個name是 {@code String} 型別
     *       	   see參閱本類中其它方法省略類名,link如
     *             {@link #getAge(int, int)}也可以跳轉,例
     *             {@link H#hh()},{@link H}
     * @return 回傳一個人名
     * @throws ArrayIndexOutOfBoundsException 下標越界拋出此例外
     * @see #getAge(int, int)
     * @see H
     * @since 0.8.1
     */
    public String getName(String name) throws ArrayIndexOutOfBoundsException{
        return name;
    }

    /**
     * 另一種格式,把解釋放到下一行 {@link java.lang.Object#notify()} 你好
     *
     * @param age
     *        這是人的年齡
     *
     * @param count
     *        總個數        
     *
     * @throws IndexOutOfBoundsException
     *         如果滿足如下幾種條件之一就拋出該例外
     *         <ul>
     *           <li> {@code age} 不是整數
     *           <li> {@code age} 沒有填入
     *           <li> {@code age+(end-begin)} 超過了 
     *                {@code name.length}
     *         </ul>
     */
    public void getAge(int age, int count) throws IndexOutOfBoundsException{

    }
}

2.3.4 IDEA 工具自動快捷鍵添加普通注釋

以后有了 IDEA 工具再試,現在不用看,直接跳過;放心 IDEA 工具中會更詳細地說明,

在 IDEA 中每創建一個類時,自動在類上加注釋

左上角 File/Settings/Editor/File and Code Templates,includes/File Header

里面粘貼

/**
 * 現在北京時間:${YEAR}/${MONTH}/${DAY} ${TIME}
 * 本類用于某某某
 *
 * @author  作者
 * @version 版本
 * @see     另請參閱
 * @since   從哪個版本有的
 */

點擊 apply 和 OK,

image-20220322171502796

在方法上加注釋

左上角 File/Settings/Editor/Live Templates

點擊加號 Template Group 自己創建個組后,再選擇你剛剛創建的組點擊加號 Live Template,

解釋:

Abbreviation:**

Description:解釋快捷鍵的描述,自己填寫

Options
Expand with Enter

Template text:
**
 *
 * @param   $param$
 * @return  
 * @throws
 */

當輸入 Abbreviation 所寫內容"**"時,按下 Enter 就把 ** 轉成 Template text 中的內容

被 $$ 包圍的變數需要點擊 Edit vaiables 設定,

選擇 Define 勾選 Java,就可以定義此模板只有在撰寫 java 檔案才能使用,

點擊 apply 和 OK,

然后我又定義了一個方法模板,縮寫詞:psvt;設定好后 OK 回傳,

image-20220322172330365

在 java 檔案輸入 psvt 后按下 Tab 鍵,游標停在 $VAR$ 等我們輸入;按下回車,游標到了 $END$ 處,

image-20220322172456942

image-20220322172627159

2.3.5 使用 javac 命令編譯時出現的"錯誤: 編碼 GBK 的不可映射字符"

內容如下:

  • 解決 GBK 亂碼問題
  • 普及編碼格式知識

本節片段提取:

友情提示,先復制文本,轉換后直接粘貼,目的是避免轉換編碼后造成中文亂碼,又得一個個改,

有 2 種方式解決:

1)檔案/另存為副本,更改編碼為 ANSI,(如果使用的是 notepad++,就在上方的工具列的編碼,轉成 ANSI 編碼)

image-20220322173042667

2)指定使用的編碼格式,(編碼格式在文本編輯器的右下方)-encoding UTF-8 是指定檔案編碼格式是 UTF-8,

螢屏截圖 2022-03-22 173317

正文如下:

可能編譯時由于代碼(包括注釋里面)中有中文,編譯時說什么含有 GBK 的不可映射字符,不讓通過,我相信新手的第一道關就卡在這,有人就干脆不寫中文了,

為何報錯

計算機只認得二進制數,也就是 0 和 1,存盤和讀取資料時都要使用二進制數表示,

0 和 1 可以有很多的組合,如 011、1001010 等等,可以用它們表示不同的資料,字符編碼就是人為定義的一套轉換表,規定一系列文字與二進制的映射關系,

(這里未區分字符集與字符編碼的概念)

有多種字符編碼,比如 ASCII 碼,一般是 8 位二進制表示一個字符,如字符 'a' 對應 01100001,這個二進制碼轉為十進制是 96;

學過概率的知道,8 位數,每位是 0 或 1,最多可以表示 2 ^ 8 = 256 個字符,應對 26 個英文字母綽綽有余,這 8 位稱為 1 個位元組(byte),單個位稱為 bit,

2 ^ 8 即 2 的 8 次方,只是為了方便表達,

ASCII 是美國人定義的,沒有考慮其它國家,但我們國家用的不是英文,有很多字符是 ASCII 碼沒有的,1個位元組也表示不了那么多的漢字,于是國人粗略規定了 GB2312,使用 2 個位元組(16位)表示一個漢字,

如在 GB2312 編碼中 "中國" 對應的二進制數 11010110 11010000 10111001 11111010,要是系統采用ASCII 碼讀取這段二進制,由于它們定義的字符的映射關系都不一樣,ASCII 編碼也不可能有中文對應的二進制碼,所以解碼不可能正確,決議不出來就會亂碼,

這里二進制數每 8 位隔開,只是方便你們觀看,實際使用時還是合在一起,

來,我們使用記事本試試看,此處檔案編碼為 ANSI,使用 ANSI 編碼讀取檔案,沒有亂碼,顯示 “天下”,

ANSI 代表系統默認編碼方式,在中國是 GBK,放心 GBK 兼容 GB2312,使用 GBK 可以決議 GB2312,

舉個例子,如果 ASCII 中所有字符對應的二進制碼,在 GBK 中,對應關系也同樣如此,就說明 GBK 兼容 ASCII 碼,說人話就是 01100001 在 ASCII 中表示 'a',在 GBK 中也表示 'a',那么使用 GBK 編碼讀取 ASCII 檔案沒有問題,反過來則不一定,因為 GBK 還多了 ASCII 中沒有的漢字,

螢屏截圖 2022-03-22 175428

讓我們把檔案編碼轉成 ISO-8859-1,也使用此編碼讀取檔案,

image-20220322181031033

image-20220322181046936

現在再看看,這不就亂碼了嗎?

所以解碼和編碼都要使用同一套字符編碼規則,notapad++ 可以使用不同的編碼方式決議,你測驗哪些編碼是兼容的,不會亂碼,

編碼:字符 -> 二進制碼

解碼:二進制碼 -> 字符

底層存盤的實際是二進制碼,

使用 javac 命令編譯時,如果不指定 -encoding 選項,一般默認采用作業系統的字符編碼方式,我們是 GBK,

在撰寫代碼時,文本編輯器的右下角會顯示當前檔案的編碼格式,編譯時,若與系統當前編碼不一致,不是同一套字符編碼規則,決議不出來,就會報錯;以后講 char 型別時還會深入,現在講的很淺顯,看不明白很正常,不是你的原因,(我移到擴充內容中了)

兩種方式解決

  • 告知此檔案的編碼方式,
    例:當前檔案的編碼格式是 UTF-8,檔案是 Hello.java,編譯時添加 -encoding 引數指定檔案編碼javac Hello.java -encoding UTF-8

  • 修改檔案編碼方式為 ANSI,檔案另存時可以看到編碼,(notepad++在工具列/編碼/轉為...記得先全選復制,改編碼后再粘貼,否則亂碼沒法撤回)

  • 所有檔案使用統一的編碼方式,如 UTF-8,新建環境變數 JAVA_TOOL_OPTIONS,值為 -Dfile.encoding=UTF-8,不建議,以后使用 IDE 工具統一使用 UTF-8 編碼,不需要自己在外面配,

  • 我不寫中文了,不建議,你是中國人,要不是英文通不過編譯,我還真想全部使用中文符號,

2.3.6 查看與修改系統編碼

通過 java 代碼查看

執行以下代碼查看系統默認編碼

public class Hello {
    public static void main(String[] args) {
        String encoding = System.getProperty("file.encoding");
		System.out.println(encoding);
    }
}

通過 DOS 視窗查看

打開 DOS 視窗(Windows + R,輸入 cmd 回車),點擊左上角圖示/屬性

看到了沒有,我沒有畫圈哦,當前代碼頁是 936,對應簡體中文編碼 GBK,

代碼頁是字符集編碼的別名,也稱內碼表,下面是代碼頁與編碼的對應關系:

代碼頁       國家(地區)或語言 
437          美國 
708          阿拉伯文(ASMO 708)
720          阿拉伯文(DOS)
850          多語言(拉丁文 I) 
852          中歐(DOS) - 斯拉夫語(拉丁文 II) 
855          西里爾文(俄語) 
857          土耳其語 
860          葡萄牙語 
861          冰島語 
862          希伯來文(DOS)
863          加拿大 - 法語 
865          日耳曼語 
866          俄語 - 西里爾文(DOS) 
869          現代希臘語
874          泰文(Windows)
932          日文(Shift-JIS)
936          中國 - 簡體中文(GB2312)現在是 GBK 了,GBK 是在國家標準 GB2312 基礎上擴容后兼容 GB2312 的標準,
949          韓文
950          繁體中文(Big5)
1200         Unicode        
1201         Unicode (Big-Endian)
1250         中歐(Windows)
1251         西里爾文(Windows)
1252         西歐(Windows)
1253         希臘文(Windows)
1254         土耳其文(Windows)
1255         希伯來文(Windows)
1256         阿拉伯文(Windows)
1257         波羅的海文(Windows)
1258         越南文(Windows)
20866        西里爾文(KOI8-R)
21866        西里爾文(KOI8-U)
28592        中歐(ISO)
28593        拉丁文 3 (ISO)
28594        波羅的海文(ISO)
28595        西里爾文(ISO)
28596        阿拉伯文(ISO)
28597        希臘文(ISO)
28598        希伯來文(ISO-Visual)
38598        希伯來文(ISO-Logical)
50000        用戶定義的
50001        自動選擇
50220        日文(JIS)
50221        日文(JIS-允許一個位元組的片假名)
50222        日文(JIS-允許一個位元組的片假名 - SO/SI)
50225        韓文(ISO)
50932        日文(自動選擇)
50949        韓文(自動選擇)
51932        日文(EUC)
51949        韓文(EUC)
52936        簡體中文(HZ)
65000        Unicode (UTF-7)
65001        Unicode (UTF-8)

也可通過 DOS 命令查看當前編碼:chcp

修改當前 DOS 視窗的編碼:chcp 對應編碼的代碼頁,如chcp 936,當控制臺不支持中文時,可以試試,(重新打開 DOS 視窗時會失效,恢復原來默認編碼)

修改系統編碼

如果是 Windows10,打開設定(Windows + i),時間和語言/語言/管理語言設定/更改系統區域設定,

老版本的使用控制面板/時鐘和區域/區域/管理/更改系統區域設定,

下面還有 beta 版(即測驗版),使用 UTF-8 編碼提供全球語言支持;但有些地方莫名其妙的亂碼,不建議嘗試,還是 GBK 靠譜,

作者:「已注銷」,內容:修改 cmd 控制臺默認代碼頁編碼的幾種方法【GBK、UTF-8】,https://blog.csdn.net/gulang03/article/details/81771343

2.3.7 使用 API 檔案

解決了中文亂碼后,來看看 rt.jar 包中的類、方法、欄位上的檔案注釋生成的 API 檔案,

JDK17 API檔案:https://docs.oracle.com/en/java/javase/17/docs/api/index.html

JDK8 API檔案:https://docs.oracle.com/javase/8/docs/api/

JDK8 API中文檔案:https://www.matools.com/api/java8

就是記不住方法名怎么辦,翻閱 API 檔案查看方法的作用,你得首先記住哪個類好像有這個方法,

Java 語言提供了大量可供使用的基礎類,Oracle 為這些類提供了對應的 API 檔案,告訴開發者如何使用此類,以及方法,

通過包名 -> 類名 -> 方法這樣的方式尋找,

以 JDK8 為例,哦,對了,將最上面的廣告關掉,

如果不知道類在哪個包下,點擊最上方的索引(INDEX)

如我要用 Math 類的求絕對值的方法,如果事先知道它在 java.lang 下(第一橫線處下翻),找到后點擊 java.lang,繼續下翻(第二個橫線處);找到后點擊 Math,再看右邊的頁面,下翻;點擊 abs 方法,就可以看到此方法的詳細說明,

image-20220318155351799

打開 rt.jar(jre 的 lib 下) 也可以看到 Math.class,(使如果你沒有軟體可以打開 zip,win-rar 解壓縮軟體下載地址在資源地址中)

image-20220318154136523

image-20220318154212941

image-20220318154252881

你說這是位元組碼檔案,肯本看不懂,要看原始碼上的檔案注釋,好吧,在 JDK 安裝目錄下,打開 src.zip\java\lang\Math.java,

image-20220318154851832

image-20220318155512159

以這種方式,的確沒有 API 檔案訪問方便不是嗎?(養成在方法上寫檔案注釋的好習慣,這樣方便提取出來)

這是谷歌翻譯:

回傳 {@code float} 值的絕對值,
* 如果引數不是負數,則回傳引數,
* 如果引數是否定的,則回傳引數的否定,
* 特別案例:
* <ul><li>如果引數是正零或負零,則
* 結果為正零,
* <li>如果引數為無窮大,則結果為正無窮大,
* <li>如果引數為 NaN,則結果為 NaN,</ul>
* 換句話說,結果與運算式的值相同:
* <p>{@code Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))}
*
* @param a 要確定其絕對值的引數
* @return 引數的絕對值,

2.x 總結回顧

編譯與運行

先編譯成 .class 檔案,后運行此類的 main 方法,

運行期類加載器(Class Loader)將 class 檔案加載到 JVM 中,JVM 啟動解釋器對 class 檔案解釋,生成的機器碼在記憶體中,由作業系統執行,

class 檔案是與平臺無關的中間代碼,下載對應平臺的 JVM,由它自帶的解釋器,將 class 檔案翻譯成當前作業系統可以執行的機器碼,做到一次撰寫,可以在不同的平臺上運行,但 JVM 不跨平臺,

程式員可以命名的單詞是識別符號,如類名、方法名、變數名、介面名、常量名,

命名規則

  • 只能由數字、字母、_、$組成,
  • 不能以數字開頭,
  • 不能以關鍵字作為識別符號,

命名規范

  • 類名、介面名首字母大寫,之后每個單詞首字母大寫,
  • 方法名、變數名首字母小寫,之后每個單詞首字母大寫,

注釋

合理使用注釋,解釋代碼含義,方便他人閱讀,

  • 類和方法上的注釋,使用檔案注釋,
  • 類中、代碼塊中使用多行或單行注釋,對難以理解的地方進行說明,
  • 不同邏輯的代碼之間空行隔開,

編碼

使用 UTF-8 格式撰寫源檔案更通用,

2.y 腦海練習

2.1 為什么 Java 代碼可以做到一次編譯,到處運行?

2.2 一個源檔案可以生成多個 class 檔案嗎?

2.3 Java 源檔案定義的類名必須與檔案名一致嗎?

第三章 變數

內容導視:

  • 變數
  • 資料型別
  • 型別轉換

3.1 變數

內容導視:

  • 字面量
  • 變數

3.1.1 字面量

值(資料)被稱為字面量,一眼就能看到值的量,如 3 是整數型字面量,'a' 是字符型字面量;有些人把它叫做常量,無可非議,

字面量型別如下:

1)整數型別:如 1、2、3...這些整數,
2)浮點型別:如 22.4、3.2...這些小數,
3)布爾型別:只有兩個值,true、false 分別代表真和假,
4)字符型別:'a'、'b'、'c'...用英文單引號括起來的單個字符
5)字串型別:"abc"、"b"、"北京歡迎你"...用英文雙引號括起來的是字串,

3.1.2 變數

使用如下方式,也不是不可以,但是你不怕一個個復制粘貼不小心漏了嗎?

System.out.println(327501510);
System.out.println(327501510 + 6);
System.out.println("我們的花園真漂亮");
System.out.println("我們的花園真漂亮");

為了使字面量得到重復利用,下面使用變數保存這些值,

內容如下:

  • 變數的宣告
  • 變數含義
  • 變數按宣告位置分類

變數宣告

每個變數都需要先宣告(定義)自己將要保存的資料的型別,后再給變數賦值,(放心,資料型別之后有講,現在先看看,別管 int、String 是什么)

例:想要保存整數型別的值,需要先宣告整數型別的變數,假如取名為 i:

int i;

再給變數賦一個整數值,

// 使用等號(賦值運算子)把等號右邊的字面量賦給左邊的變數
i = 327501510;

可以訪問這個變數保存的值,

System.out.println(i);// 此時 i 為 327501510

也可以重新給 i 變數賦值,把之前保存的值覆寫,

i = 6;// 把 6 賦給 i
System.out.println(i);// 此時 i 為 6

兩者結合,在宣告的同時,賦值,

int i = 327501510;

那么就可以把開頭的例子轉變了:

int num1 = 327501510;
int num2 = 6;
String str = "我們的花園真漂亮";

System.out.println(num1);
System.out.println(num1 + num2);
System.out.println(str);
System.out.println(str);

num1、num2、str 是變數名,作為識別符號,我們有權力命名,只要符合命名規則就行,

很明顯通過以上例子看到變數有三個要素:

  • 變數的資料型別,如 int
  • 變數名,如 num1
  • 變數值,如 327501510

資料型別 變數名 = 字面量;

如果不考慮型別轉換,那么變數的資料型別必須與字面量型別一致,

比如整數型的 int 型別不能保存浮點型的字面量,int i = 3.23; 是錯誤的寫法,由于現在還沒有講資料型別,聽著迷惑很正常,

變數含義

變數是記憶體中存盤資料的最基本的單元,任何變數都有資料型別,不同的資料型別在記憶體中分配的空間大小不同,

int a = 3; 在記憶體里分配 4 個位元組空間,空間存放著 3,a 就代表這個空間,

變數相當于記憶體中的一小塊資料存盤空間,通過變數名可以訪問到這個區域,可以把 a 理解成你家的門牌號,通過門牌號定位你家,

int 型別會被分配 4 個位元組大小的空間,1 個位元組(byte)= 8 個位元位(bit)

1 TB = 1024 GB
1 GB = 1024 MB
1 MB = 1024 KB
1 KB = 1024 Byte
1 Byte = 8 Bit
1 Bit = 0 或 1

利用 0 和 1 的不同的組合代表各式各樣的資料,等學到進制之間的轉換、原碼補碼就明白了,但你也可以跳過,節省時間,

變數按宣告位置分類

分為成員變數與區域變數,之間說過類名 Hello 后跟的 {} 是類體,方法名 main 后跟的 {} 是方法體,

public class Hello {
    // 方法體外、類體中宣告的變數是成員變數
    int a = 2;
    
    public static void main(String[] args) {
        // 方法體中宣告的變數是區域變數
        int b = 4;
        System.out.println(b);// 4
    }
}

值得注意的地方

1)區域變數必須賦值后才能訪問,錯誤示范:

public static void main(String[] args) {
    int i;
    System.out.println(i);
}

你得先給 i 賦值,比如 int i = 10; 后再訪問,

2)同一個域中,區域變數不能重復宣告,

域:{} 包起來的范圍,

// 錯誤示范
public static void main(String[] args) {
    int i = 3;
    int i = 6;
}

你得換個名字,以免沖突,比如把后面改成 int j = 6;

3)變數需要先宣告,后訪問,錯誤示范:

public static void main(String[] args) {
    System.out.println(i);
    int i = 3;
}

你應該把它倆的順序換過來,畢竟 java 陳述句是自上而下逐行執行的,

3.2 資料型別

內容導視:

  • 整數型別
  • 浮點型別
  • 字符型別
  • 布爾型別
  • 基本資料型別轉換
  • 基本資料型別與 String 型別的轉換

資料型別 變數名 = 字面量;...變數的資料型別必須與字面量型別一致?

字面量講了,變數名你可以隨便取,接下來該說一說資料型別了,

Java 支持的資料型別有兩種,基本資料型別參考資料型別

基本資料型別加上參考資料型別中的 String 類,正好與我們之前講的字面量型別一一對應,

基本資料型別

1)整數型別

  • byte(位元組):在記憶體中分配 1 個位元組的空間,(8 位)
  • short(短整型):在記憶體中分配 2 個位元組的空間,(16 位)
  • int(整型):在記憶體中分配 4 個位元組的空間,(32 位)
  • long(長整型):在記憶體中分配 8 個位元組的空間,(64 位)

2)浮點型別

  • float:在記憶體中分配 4 個位元組的空間,
  • double:在記憶體中分配 8 個位元組的空間,(double 精度比 float 更高)

3)布爾型別

  • boolean:在記憶體中分配 1 個位元組(陣列中)或 4 個位元組的空間(單個定義時),

4)字符型別

  • char:2 個位元組,

參考資料型別

1)類(class)包括列舉

  • JDK 自帶類別庫,如 java.lang.String、集合、包裝類...
  • 用戶自定義的型別,如我們之前寫的 class Hello...
  • 第三方類別庫

2)介面(interface)包括注解

3)陣列(array)

對于基本資料型別,如定義 int 型別的變數,就可以接收整數型的字面量:int i = 4;;定義 char 型別的變數,可以接收字符型的字面量:char c = '中';;定義 boolean 型別的變數可以接收 true 或 false:boolean b = true;...

對于參考型別的 String,定義 String 型別的變數,就可以接收字串型的字面量:String str = "我是什么樣";

正常情況下,占用位元組空間越大,表示的數越多;如整數型別的 byte 只占一個位元組,只能表示 -128 ~ 127 內的整數,所以才需要 int、long,用以存盤更大的整數,當然存盤的數很小時,沒必要使用 long,太浪費空間,

參考型別可以賦值 null;等面向物件時講,現在先看基本資料型別:

3.2.1 整數型別

整數型別用來存盤整數型別的字面量,

以 1 個位元組為例,1 個位元組 8 位,每位是 0 或 1,那么就是有 28 種可能,即表示 256 個數,

下面是不同整數型別的取值范圍:

型別 占用存盤空間 取值范圍
byte(位元組) 1 個位元組 [-128 ~ 127] 即 [-27 ~ 27 - 1]
short(短整型) 2 byte [-32768 ~ 32767] 即 [-215 ~ 215 - 1]
int(整型) 4 byte [-2147483648 ~ 2147483647] 即 [-231 ~ 231 - 1]
long(長整型) 8 byte [-263 ~ 263 - 1]

int i = 3;
byte b = 45;
b = 34;
System.out.println(i);

定義了 int 型別的變數,變數名為 i,保存的值為 3,

定義了 byte 型別的變數,變數名為 b,保存的值為 45,

把 34 賦給 b 變數,原來保存的 45 被修改了,

System.out.println(i);表示把 i 保存的值輸出到控制臺(目前是 DOS 視窗)上,

由于現在你們可能還不懂二進制,于是使用十進制表示,同時也是為了方便,避免寫太多的 0、1,


有人可能會問超過了整數型別的取值范圍會怎么樣?

byte b = 128;
Hello.java:4: 錯誤: 不兼容的型別: 從 int 轉換到 byte 可能會有損失
    byte b = 128;

這下就更疑惑了,什么叫 int 轉成 byte 會有損失?難道這個 128 也就是整數型字面量默認被當作 int 型別處理嗎?

讓我們試一試:

long num1 = 2147483648;

推測:就算 long 型別可以保存這么大的數,但如果后面的 2147483648 真的被當作 int 型別處理的話,那肯定由于超過 int 的范圍,會報錯,

Hello.java:4: 錯誤: 過大的整數: 2147483648
    long num1 = 2147483648;

好的,大概明白了,得出結論:

  • 整數型字面量默認被當作 int 型別處理,
  • 為了方便,當被當作 int 型別處理的字面量的值沒超過整數型別的范圍時,可以直接賦值,如 byte b = 1;

有人就問了,超出 int 范圍的值?那能不能讓整數型字面量被當作 long 型別處理?

答:在宣告整數型字面量時在其后加 l 或 L,

long num1 = 2147483648L;
long num2 = 2147483648l;

但是你也看見了,由于小寫的 l 感覺就像 1,為了避免混淆,統一使用大寫表示,

這里插一條概念:

值傳遞:把變數保存的值重新復制一份,傳遞給另一個變數;而另一個變數修改自己保存的值,不會影響原來變數保存的值,

值傳遞也稱值拷貝

int i1 = 100;
// 把 i1 保存的值 100 復制一份,傳給 i2,此時 i2 保存的值為 100
int i2 = i1;

// 修改 i2 保存的值,不會對 i1 有影響
i2 = 55;

System.out.println("i1 = " + i1);// i1 = 100
System.out.println("i2 = " + i2);// i2 = 55

好,有了這個概念,讓我們試著互換兩個變數保存的值,

大家想一想,如果現在有兩個杯子 a、b,都裝滿了水,該如何互換?

無標題

是不是要準備第 3 個杯子 c,先把 a 倒進 c 中,然后把 b 倒進 a 中,最后把 c 倒進 b 中,

int a = 22;
int b = 433;

int c = a;// c = 22
a = b;// a = 433
b = c;// b = 22

可以不借助第三個變數 c 嗎?

有聰明的小伙伴想到了:讓 a 保存兩值之和(a + b),讓 b = 兩值之和 - b = a;

int a = 22;
int b = 433;

a = a + b;// a = 22 + 433
b = a - b;// b = (22 + 433) - 433 = 22
a = a - b;// a = (22 + 433) - 22 = 433

3.2.2 浮點型別

浮點型別的變數可以接收一個小數,如 6.2、32.2,

由于使用指數的形式表示值,表示的數比相同位元組下的整數型別更大,但是精度有限,結果可能有誤差,無法精確表示,

現在看看浮點型別的取值范圍,的確比整數型別的取值范圍大多了:

型別 占用空間 范圍
float 4 個位元組 [1.4E-45 ~ 3.4028235E38] 即 [2-149 ~ 2128]
double 8 個位元組 [4.9E-324 ~ 1.7976931348623157E308] 即 [2-1074 ~ 21024]

這段內容可以不看:


科學計數法

由于數太大了,為了更好表示數值不浪費空間,使用科學計數法表示,這個 E 大寫小寫都可以,

1.4E-45 = 1.4 * 10-45

3.4028235E38 = 3.4028235 * 1038

有人說為何使用科學計數法表示?以 2 的冪表示,如 2-149 是不是更節省空間?

7777777 保留 2 位有效數字,使用科學計數法表示:7.78 * 106(7.78E6);你此時可能還在算它是 2 的幾次方吧?

Java 中,當小數超出 [-9999999,9999999] 范圍時,會使用科學計數法表示,

System.out.println(-10000000.0);

控制臺上會輸出 -1.0E7

有聰明的伙伴可能注意到了兩點,題干中的“小數”、字面量后的“.0”,注意啊這兩個條件不能丟,否則會被當作 int 型別處理,那么下面這道題就可能做錯:

思考控制臺輸出什么結果?

System.out.println(500e-2);

答:500e-2 = 500 * 10-2 = 500 / 102 = 5.0

別說結果是 5 啊,

下面呢?

System.out.println(-10000000);
System.out.println(500E-7);

第 1 個明顯不是小數,還是原樣輸出,第 2 個你可能會覺得這既然超過上述所說的范圍,那使用科學計數法表示,還是原樣輸出,

我留的坑啊,沒有使用這種方式 500E-7 表示的,而是 5.0E-5

舉個例子,a * 10n,那么 |a| 是 [1 ~ 10) 之間的數,

-78937935.2 ,一看超過了范圍,用科學計數法表示:-7.89379352E77.89379352 大于等于 1,小于 10,你要是這樣表示就錯了:-78.9379352E6


小數型別的字面量默認被當作什么型別處理?

回過頭來,小數型別的字面量又被當作什么型別處理?

做個實驗:

float f = 3.14;
Hello.java:8: 錯誤: 不兼容的型別: 從double轉換到float可能會有損失
   float f = 3.14;

看來默認被當作 double 型別處理,同樣想要指定字面量被當作 float 處理,需要在字面量后加上 f 或 F,

float f = 3.14F;

同理,指定字面量被當作 double 型別處理,(其實 D、d 去掉也可以,在基本型別的轉換中有講)

double d1 = 5D;
double d2 = 3d;

有時候你會看見這種寫法:double d = .12; 不要疑惑,這等同于 double d = 0.12 ,這個 0 可以省略不寫,但一般不要這么做,否則其他人可能會疑惑,

精度

浮點數存放形式:浮點數 = 符號位 + 指數位 + 尾數位,尾數部分很可能會丟失,造成精度損失,(小數都是近似值)(有興趣去擴充知識了解,這里不贅述)

System.out.println(0.11111111111111111111111111111F);
System.out.println(0.11111111111111111111111111111D);
0.11111111
0.1111111111111111

大概可以這么理解:

float 的精度是保留 8 位有效數字,

double 的精度是保留 16 位有效數字,通常使用 double 型別,

有效數字是一個數從左邊第一個不為 0 的數字起,直到末尾止的數字稱為有效數字,如 0.009210,有效數字 4 位:9、2、1、0,

保留兩位有效數字:0.0092,

由于浮點數運算得到的結果可能有誤差,所以如下就成了錯誤做法:

double d1 = 9.9 / 3;
double d2 = 3.3;

if (d1 == d2) {
  System.out.println("它們相等");  
}

上面的意思是:如果 d1 等于 d2,就輸出“它們相等”,

但試著運行,控制臺什么都沒有輸出...

此時再試下訪問 d1 的值:

System.out.println(d1);// 3.3000000000000003

看到沒有?9.9 / 3 不等于 3.3,而是十分接近 3.3 的小數,

當對運算結果是小數的進行相等判斷時,應該以兩個數的差值的絕對值,在某個精度范圍類判斷,這個精度由自己決定,如人民幣數值比較,人民幣最低面額 1 分 = 0.01 元,只要兩數差值小于 0.01,就認為它們相等,

現在該改一下了:

double d1 = 9.9 / 3;
double d2 = 3.3;

if (Math.abs(d1 - d2) < 1.0E-2) {
  System.out.println("它們相等");  
}

還記得如何查 API 檔案嗎?當匯入 java.lang 包下的類時,可以不用 import,哦,對了,你們還不懂,這節在面向物件的包機制中,

那我直接說含義,Math.abs(a):求 a 的絕對值,當 d1 - d2 的絕對值小于 0.01 時,我們姑且認為它們相等,

現在收尾,我還是說說怎么找吧:

打開 JDK API 檔案,如果知道 Math 在哪個包下,比如 Math 在 java.lang 包下,點擊 java.lang;

如果不知道,點擊索引找 M 開頭的類:

找到后點擊 Math,看看 abs 方法的介紹,

3.2.3 字符型別

輸出、列印是一個意思,

char 型別的變數可以保存單個字符,占用 2 個位元組,取值范圍:[0 ~ 65535] 即 [0 ~ 216 - 1],

char c1 = '中';
char c2 = 'a';

// 字符型別可以直接存放數字,當輸出 c2 時,會輸出 97 代表的字符,擴充內容中有講
char c2 = 97;

你們可能會在其他地方遇到如 char c = '\n';,這叫轉義字符

一般使用 \ 開頭,代表著將一個字符轉義,本質還是單個字符,


\n:換行
\t:制表符 tab
\r:回車
\u:把十六進制數轉成對應的字符


1)\n:

什么叫換行?

System.out.println("你好\n我好\n大家好\n");
char c = '\n';
System.out.println(c);
System.out.println(2);

這里不得不提一下 ln:

System.out.print(2);
System.out.print(1);
System.out.println();// 代表換行
System.out.print(7);
21
7

ln 表示當前行結束輸出,如果要繼續輸出,就要移到下行,

回過頭來,"你好"換行,"我好"換行,"大家好"換行,ln 代表換行,
System.out.println(c);,c 是 '\n',代表換行,ln 代表換行,
結果如下:

你好
我好
大家好



2

2)\t:

System.out.println("狗\t貓\t魚");
狗      貓      魚

可以看到狗與貓、魚之間隔了一個制表符的距離,

3)\r:

System.out.println("我是什么\r人呢");

回車:回到行首,輸出文本,由此產生分歧,有人認為一個 \n 足以表示回車加換行,兩個字符太浪費了,而 Windows 系統中還保留原來概念,Enter 鍵(我們通常叫回車鍵),實際用兩個字符表示:“\r\n”;對應的 ASCII 碼用十進制表示分別為 13、10,

Windows 系統換行 Carriage return and line feed(CRLF):回車加換行

Linux 系統換行 Line feed(LF):換行

回到這里,如果回車但不換行,\r 后的 “人呢” 還在同行首個位置上輸出,把 “我是” 覆寫,最后結果:"人呢什么",

4)\u:

System.out.println("\u5929");

16 進制的 5929 對應的字符為天,有興趣請在擴充內容中的字符編碼了解,

這個 \ 作用不止如此,

問想要使用 char 型別保存單個字符:英文單引號 ' 怎么做?

char c = ''';這樣?

Hello.java:4: 錯誤: 未結束的字符文字
                char c = ''';

像這類具有特殊含義的字符,需要使用 \ 轉成普通的字符,使其不再被認為是代表字符開始的單引號,

char c = '\'';

同理,列印 \、" 等特殊符號,都需要在字符前加上 \:

System.out.println("\"");
System.out.println("\\");

輸出結果:

"
\

3.2.4 布爾型別

boolean 型別只有兩個值:true 或 false,用于邏輯運算:2 < 3 為 true,

一般放在 if 、for 等陳述句的條件處,控制程式的流程,現在不用深究,

3.3 型別轉換

內容導視:

  • 基本資料型別轉換
  • 基本資料型別與 String 型別的轉換

3.3.1 基本資料型別轉換

緣起

double d = 3; 唉呀,字面量 3 不是被當作 int 型別處理嗎?怎么就可以賦給 double 型別的 d?別急,看完以下實驗就明白規則了,

boolean 除外,不同型別容量(取值范圍)按從小到大排列:

byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double

基本資料型別的轉換規則

前提:基本資料型別

當所賦值的字面量型別與變數的資料型別不一致時,會發生資料型別轉換,從一種資料型別轉成另一種資料型別,分為自動型別轉換強制型別轉換,除了 boolean 型別不能參與轉換,其他基本資料型別可以互相轉換,

小容量賦給大容量,會發生自動型別轉型,如 int 型別自動轉為 long 型別:

// int 型別自動轉換為 long
long l = 3;

// long 型別自動轉為 float
float d = 3L;
System.out.println(d);// 3.0

// char 自動轉 int
int i = '中';
System.out.println(i);// 20013

'中'在 Unicode 字庫的序號是 4E2D,使用 UTF-16 編碼存盤的二進制碼為 0100111000101101,即 20013,

大容量賦給小容量,自動轉換無法進行:

// 錯誤: 不兼容的型別: 從 double 轉換到 int 可能會有損失
int i = 3.13;
// 錯誤: 不兼容的型別: 從 long 轉換到 int 可能會有損失
i = 3L;
// 錯誤: 不兼容的型別: 從 int 轉換到 byte 可能會有損失
byte b = 532;

這時就需要強制轉換符(),但可能會有精度損失,

// 強制把 double 型別轉成 int
int i = (int)3.13;
System.out.println(i);// i = 3

// 強制把 long 型別轉成 int
i = (int)3L;
System.out.println(i);// i = 3

// 強制把 int 型別轉成 byte
byte b = (byte)532;
System.out.println(b);// b = 20

補充細節

1)如果字面量的值沒有超出 byte、short、char 的取值范圍,可以直接賦值給它們,(除了被當作 long 型別處理的字面量)

byte b = 3;
char c = 33;

byte b1 = 'a';// 'a' 表示 97
// 超出 byte 的取值范圍,從 char 轉換到 byte 可能會有損失
byte b2 = '中';// '中' 表示 20013

需要注意,我指的是以字面量形式賦值,而不是值傳遞,自己試試報什么錯?

int i1 = 3;
int i2 = 33;
char letter = 'a';

byte b = i1;
char c = i2;

byte b1 = letter;

之前有人問你怎么知道 'a' 代表的整數,我又不想了解 ASCII 碼,有什么簡單的方法嗎?這就是第 2 點,請看:

2)byte、short、char 型別的變數混算時,會自動升級到 int 型別,

怎么得出的這個結論?

byte b1 = 2;
byte b2 = 5;
byte b3 = b1 + b2;
Hello.java:6: 錯誤: 不兼容的型別: 從 int 轉換到 byte 可能會有損失
byte b3 = b1 + b2;

是吧,兩個 byte 型別的變數相加,竟然升級了,那我可以利用這一點,讓 char 型別的變數升級成 int 變數,自然就知道該字符對應的整數了,

char c = '中';
short s = 0;

System.out.println(c + s);// 20013
System.out.println('1' - 0);// 49

3)多種型別混算時,先把字面量轉成容量大的那種資料型別,再進行計算,

如果你不知道這點,以后計算很容易吃虧,比如 10 / 4,你本來想得到 2.5,但是這參與運算的數,容量最大的也只是 int 型別,而 int 型別只能保存整數,所以 2.5 被削去了小數,

int i = 10 / 4;
System.out.println(i);// i = 2

這時就需要浮點型別的參與,改一下:

double i = 10.0 / 4;
System.out.println(i);// i = 2.5

思考如下陳述句可以通過編譯嗎?

byte b = 10;
b = b * 2;

b 保存的 10 對應 byte 型別,2 對應 int 型別,這就是混算;讓 10 升級到 int 型別,與 2 相乘,結果還是 int 型別,再賦給 byte 型別的變數,報錯:從 int 轉換到 byte 可能會有損失

思考輸出什么?

double d = 1 / 4 * 4.0;
System.out.println(d);

有人說這不就是 1 嗎?有什么難的?當然也有其他人看出來了:1 / 4 是兩個 int 型別的字面量參與運算,結果為 0;(你難道忘了 int 型別只能保存整數嗎?)接著算,0 * 4.0 = 0.0;

所以結果為 0.0,(忘記帶小數,哪怕只是 .0,結果就完全不同)

你的原意可能是這:double d = 1.0 / 4 * 4.0;

3.3.2 基本資料型別與 String 型別的轉換

沒想到吧,"+" 號除了能計算兩數之和外,還能拼接字串,哦,我好像之前已經用過了,

String str1 = "我";
String str2 = "和";
String str3 = "你";

String str4 = str1 + str2 + str3;
System.out.println(str4);// 我和你

思考輸出什么?

System.out.println(4 + 3 * 2 + "2" + 5 * 5);

4 + 6 = 10;10 + "2" = "102";"102" + 25 = "10225";

沒看暈吧?從左至右,乘號優先;字串加誰,誰就被拼接在一起,那么就利用這個 "+",將基本資料型別轉成字串吧,

基本資料型別轉成字串

"" 代表空字串,輸出字串時,是不會輸出雙引號的,這你應該早就知道了,

long l = 3L;
int i = 3;
char c = '中';
double d = 3.243;

String str1 = l + "";
String str2 = i + "";
String str3 = c + "";
String str4 = d + "";

System.out.println(str1);// 3
System.out.println(str2);// 3
System.out.println(str3);// 中
System.out.println(str4);// 3.243

字串轉成基本資料型別

別看,等到包裝類時就懂了,(或者你會查 API 檔案,它們在 java.lang 包下)

String str = "123";

byte num1 = Byte.parseByte(str);
short num2 = Short.parseShort(str);
int num3 = Integer.parseInt(str);
long num4 = Long.parseLong(str);
float num5 = Float.parseFloat(str);
double num6 = Double.parseDouble(str);

/*
    取下標為 0 的字符(得到 str 的第一個字符)
	下標是從 0 開始,以 1 遞增,并不是從 1 開始哦
*/	
char num7 = str.charAt(0);

// 如果決議不是"true"的字串,那么回傳結果是 false
boolean num8 = Boolean.parseBoolean("true");

System.out.println(num1);// 123
System.out.println(num2);// 123
System.out.println(num3);// 123
System.out.println(num4);// 123
System.out.println(num5);// 123.0
System.out.println(num6);// 123.0
System.out.println(num7);// 1
System.out.println(num8);// true

注意不要想著把字串 "abc" 轉成整數,編譯雖然可以通過,但運行時會報 java.lang.NumberFormatException 例外(數字格式化例外),程式會在拋出例外的位置終止執行,(例外中有講)

編譯時只是檢查語法,并不會決議 "abc" 是否能夠轉成整數,

3.x 總結回顧

變數

資料型別 變數名 = 值; 先宣告后訪問,

資料型別

分為基本資料型別(byte、short、int、long、float、double、char、boolean)與參考資料型別(類、介面、陣列),

不能直接以雙等號判斷兩個浮點型別的值,應該讓兩數相減得到差值,如果差值在設定的精度范圍內就認為它們相等,

3.y 腦海練習

3.1 下面陳述句能夠通過編譯嗎?

1)

byte b = 2;
b = b * 2 + 10L;

2)

int i = 3;
float f = i + 2.22;

3)

int i = 21;
long l = 231;
double d = 3.23;

long l2 = i + l + d;

4)

int x = (int)3.14 * 3 + 6.2 * 10;

5)

short s1 = 34;
short s2 = s1 - 3;

6)

int i = 3;
char c = (char)i;

7)

byte b1 = 4 * 3;
byte b2 = b1 + (byte)4;

short s = b1 + b2;

8)

double d = 3;
float f = (float)d + .234F;

9)

long l = 3L;
double d = l + 3.24F;

3.2 下面輸出結果?

1)

int x = (int)3.14 * 3 + 6 * 10;
System.out.println(x);

2)

int x = (int)(3.14 * 3 + 6.2 * 10);
System.out.println(x);

3.3 想在控制臺上輸出 \,怎么寫?

3.4 想在控制臺上輸出如下,怎么寫?

第四章 運算子

內容導視:

  • 算術運算子
  • 賦值運算子
  • 關系運算子
  • 邏輯運算子
  • 條件運算子
  • 運算子優先級

4.1 算術運算子

內容導視:

  • 四則運算:+、-、*、/
  • 求余數:%
  • ++、--

4.1.1 四則運算:加減乘除

這個不用過多介紹,與初等數學一致,直接使用即可,

int a = 5;
int b = 2;

int add = a + b;
int sub = a - b;
int mult = a * b;
int divide = a / b;

7、3、10、2;注意 int 型別只能保存整數,會被削去小數部分,

此外 “+” 除了能夠計算加法,還能拼接字串,之前已經說過:

System.out.println(100 + 2 + "字串" + 3 * 8);

“102字串24”;從左至右,遇到字串就拼接,拼接后還是字串;記得乘法優先,

4.1.2 求余數:%

求余數也稱取模,得到的余數一定小于除數,

如 10 % 3 = 1、11 % 3 = 2、12 % 3 = 0;

int i = 11 % 4;

11 除以 4,商為 2,余數為 3;所以 i = 3,

% 的本質

a % b = a - a / b * b

知道了上面的式子,自己試著算一下吧:

System.out.println(-10 % 3);
System.out.println(10 % -3);
System.out.println(-10 % -3);

計算結果如下:

-10 % 3 = -10 - (-10) / 3 * 3
        = -10 - (-3) * 3
        = -1
        
10 % -3 = 10 - 10 / (-3) * (-3)
        = 10 - (-3) * (-3)
        = 1
        
-10 % -3 = -10 - (-10) / (-3) * (-3)
         = -10 - 3 * (-3)
         = -1

4.1.3 ++、--

++ 是讓變數保存的值,自加一,

int i = 10;
i++;
System.out.println(i);// i = 11
int i = 10;
++i;
System.out.println(i);// i = 11

++ 放在變數前后的區別

++ 放在變數前:

int i = 10;
int j = ++i;
System.out.println(j);// j = 11

等價于

int i = 10;
i = (int)(i + 1);// 先自加一,后賦值
int j = i;
System.out.println(j);// j = 11

++ 放在變數后:

int i = 10;
int j = i++;
System.out.println(j);// j = 10
int i = 10;
int j = i;// 先賦值,后自加一
i = (int)(i + 1);
System.out.println(j);// j = 10

結論:

當 ++ 出現在變數前,先自加一,再賦值;所以 i 自加一等于 11,再賦值給 j 為 11;

當 ++ 出現在變數后,會先賦值,再自加一;把 i 賦值給 j 即 10,再 i 自加 1,

反正 i 一定是 11;使用 ++ 或 -- 時,不會改變運算結果型別

例如:

byte b = 1;
b = b + 1;

會報錯從 int 轉成 byte 可能會有損失

換成如下就可以了,但是要注意別超了 byte 的取值范圍,否則強轉后會有精度損失,

byte b = 1;
b++;

-- 同理:

int i = 3;// i = 3
int j = i--;// j = 3、i = 2
int z = --j;// j = 2、z = 2

i = 2、j = 2、z = 2,

4.2 賦值運算子

內容導視:

  • 基本賦值運算子:=
  • 擴展賦值運算子:+=、-=、*=、/=、%=

4.2.1 基本賦值運算子:=

之前用過很多次了,通過 “=” 把字面量賦給變數、完成值傳遞,

int a = 10;// 10 被賦給了 int 型別的 a
int j = 10;
int i = j;// j 保存的 10 被賦給了 int 型別的 i

4.2.2 擴展賦值運算子:+=、-=、*=、/=、%=

只要學會了 +=,其它觸類旁通,

int x = 5;
x += 2;// x = 7

相當于將自保存的值加 2:

int x = 5;
x = (int)(x + 2);// x = 7

使用擴展運算子,不會改變運算結果型別,與 ++ 一樣,

看看下面的 i 的值為多少?

byte i = 8;
i *= 2;

i = (byte)(i * 2) = 16,

4.3 關系運算子

就是判斷對錯,判斷結果為真: true,假:false,

使用的符號都是英文半角符號,字符之間沒有空格,

!= != ! = 都錯,

4.3.1 >、<、<=、>=

大于號、小于號...如同初等數學使用即可,

boolean result1 = 6 > 3;
boolean result2 = 79 < 6;
    
System.out.println(result1);// true
System.out.println(result2);// false

4.3.2 ==

雙等號 “==” 是判斷保存的值是否相等,

boolean b1 = "你好" == "你好";
boolean b2 = 5 == 6;

System.out.println(b1);// true
System.out.println(b2);// false
System.out.println("你好" == "你");// false
System.out.println(5 == 5);// true

注意別把 “==” 與 “=” 混用了,我知道在日常生活中,使用 “=” 判斷是否相等,但是在程式里 “=” 是用來賦值的,“==” 才是用來判斷是否相等,

我舉個例子,if 旁邊的括號中的值只允許為 boolean 型別,當值為 true 時,才會執行 if {} 中的陳述句,

int i = 4;
if (i = 5) {
    System.out.println("Hello");
}

假如你的原意是想 i 等于 5 時,就輸出 “Hello”,但是由于你使用的是單等號,代表賦值,此時的 i = 5,所以原意成了

int i = 4;
if (5) {
    System.out.println("Hello");
}

在 Java 中,正好 boolean 型別不能參與轉換,所以編譯時直接報錯,你可以及時發現,但不是次次都是這么好運氣,

如下:

boolean b1 = false;
if (b1 = true) {
    System.out.println("Hello");// Hello
}
System.out.println(b1);// true

原意是當 b1 等于 true 時,輸出 “Hello”,但是你的意圖被扭曲了,這只是你不小心丟了一個等號而已,原意如下:

boolean b1 = false;
if (b1 == true) {
    System.out.println("Hello");
}
System.out.println(b1);// false

說了這么多,只為說一句:判斷兩個值是否相等,請用 “==”,

4.3.3 !=

判斷兩個值是否不相等,

System.out.println(5 != 4);// true
System.out.println("你好" != "你好");// false

5 的確不等于 4,判斷為真,所以為 true,

之所以把 “==”、“!=” 單獨拿出來,是因為它們與 “<”、“>=” 之類的符號不大一樣,“!=” 與 “==” 不僅可以判斷數值是否相等,還可以比較參考型別是否相等,

System.out.println("hel" != "hell");// true
System.out.println("u" == "u");// true
System.out.println("u" < "u");// 報錯,< 的兩邊只能為數值,如整數、小數

這里不得不提:'a' < 'b' 為什么可以編譯通過,因為這是 char 型別,可以轉成 int 型別,比較大小,

4.4 邏輯運算子

就是與或非邏輯,邏輯運算子的兩邊要求都是布爾型別,且最終的結果也是布爾型別,下面是我高中時記的口訣:

與(&):一假為假

或(|):一真為真

非(!):真即假,假即真

異或(^):不同為真

上面的符號還是位運算子,由于不常用,略去用法,

4.4.1 &

a & b:當 a 和 b 同時為 true 時,結果才為真,否則為 false,

boolean b1 = 5 > 3;
boolean b2 = 8 < 9;
System.out.println(b1 & b2);// true

翻譯成人話:5 大于 3 且 8 小于 9,命題為真,

需要注意的是,不同的運算子優先級不同,優先級高的先運算,之前通過乘法與加法的混合運算中就能看出來乘法優先,

思考如下輸出結果:

boolean b1 = 1 < 0;
boolean b2 = 79 > 99;
boolean b3 = "我" != "我";

System.out.println(b1 & b2 == b3);

b1、b2、b3 都為 false;b1 & b2 為 false,false 等于 b3,所以結果為 true?

但你沒有想到 “==” 的優先級高于 “&”,所以是 b2 == b3 先運算為 true,b1 & true,結果為 false,

上面的一句相當于:

System.out.println(b1 & (b2 == b3));// false

那該怎么辦?扭曲了原意!可以加小括號提升優先級:

System.out.println((b1 & b2) == b3);// true

短路與:&&

&& 相比于邏輯與,效率更高:如果整個運算式結果已經確定,剩下式子不再執行與判斷,

什么意思?

一假為假,當左邊的值為 false,還需要去執行去判斷右邊嗎?完全可以推出結果為 false,

int x = 3;
System.out.println((x < 2) & (++x > 3));
System.out.println(x);// 4
int x = 3;
System.out.println((x < 2) && (++x > 3));
System.out.println(x);// 3

x < 2 為 false,那么整個式子已經可以確定為 false,不需要再判斷,通過上面的例子可以看出,短路與并沒有去執行 ++x,所以 x 的結果不變,還是為 3.

4.4.2 |

a | b:當 a 和 b 同時為 false 時,結果才為 false,否則為 true,

System.out.println(8 < 1 | 9 > 3);// true

命題:8 小于 1 或者 9 大于 3,命題為真,

與 & 一樣的是,| 也有對應的短路或,

||

如果整個運算式的結果已經確定,后面不再執行判斷,

int x = 3;
System.out.println(8 < 9 | ++x == 8);
System.out.println(x);// 4
int x = 3;
System.out.println(8 < 9 || ++x == 8);
System.out.println(x);// 3

一般我們使用的是短路與和短路或,我幾乎沒有看見單個的,除非你想把所有的式子都執行一遍,

4.4.3 !

!a:對 a 取反;a 為 true,結果為 false;a 為 false,結果為 true,

System.out.println(!(3 < 5));// false

3 < 5 為 true,再取反為 false,

4.4.4 ^

a ^ b:當 a 不等于 b,結果為 true,否則為 false,

System.out.println(8 < 9 ^ 9 > 3);// false

8 < 9 為 true,9 > 3 為 true,它們相等,所以為 false,

4.5 條件運算子

算是條件陳述句的簡化版吧,可以根據運算式的真偽回傳不同的值,

4.5.1 三目運算子

語法:布林值 ? 值1 : 值2

當布林值為 true,回傳值1;為 false,回傳值2,

boolean isBoy = true;
char zhangSan = isBoy ? '男' : '女';

System.out.println(zhangSan);// 男
double scope = 99.5;
String evaluate = scope < 60 ? "不及格" : "及格";
System.out.println(evaluate);// 及格

很明顯 scope 小于 60 為 false,所以回傳值2:“及格”,

4.6 運算子優先級

優先級高的先運算,

優先級從高到低

. ()
++ -- ~ !						單目運算子
* / %							算術運算子
+ -	
<< >> >>>						位移運算子
< > <= >= instanceof			比較運算子
== !=							邏輯運算子
&
^
|
&&
||
? :								三目運算子
= *= /= %=						賦值運算子
+= -= <<= >>=
>>>= &= ^= |=

例如:int a = 1 + 2 * 1; 先算乘法,接著加法,最后賦值,

4.x 總結回顧

++、+= 等賦值運算子不會改變運算結果型別,(使用了強制轉換運算子)

判斷兩個值是否相等請用 “==”,

邏輯運算子中一般使用短路與、短路或,

4.y 實戰演練

4.1 double i = 5 / 2; 中的 i 的值為?

4.2 輸出什么?

1)

String s = "張三";
int i = 3;
System.out.println(s + i * 2 + "b");

2)

int x = 5;
int y = 5;
System.out.println(++x < 6);
System.out.println(y++ < 6);
System.out.println(y);

3)

int x = 10;
int a = x + (x++);
int b = x + (++x);
System.out.println(a);
System.out.println(b);
System.out.println(x);

4)

int i = 34;
int j = i--;
int z = --i;
System.out.println(i);
System.out.println(j);
System.out.println(z);

5)

int i = 2;
int j = 2 + i++;
System.out.println(i);
System.out.println(j);

6)

int i = 10;
i = ++i;
System.out.println(i);

7)

int i = 10;
i = i++;
System.out.println(i);

8)

byte b = 1;
byte b1 = b++;
byte b2 = --b;
System.out.println(b);
System.out.println(b1);
System.out.println(b2);

9)

boolean b = false;
System.out.println(b = true);
System.out.println(b == false);

10)

int x = 9;
int y = 12;

int z = x < y ? x + y : x - y;
System.out.println(z);

11)

int a = 10;
int b = 99;

int result = a > b ? a++ : b--;
System.out.println(result);
System.out.println(a);
System.out.println(b);

4.3 利用三目運算式求出三個數之間的最大數,

4.4 利用所學知識求出 33 天是多少個星期零幾天?

4.5 3 / 9 * (242.2 - 100) 的結果是什么?

4.6 下面代碼輸出什么?

1)

boolean x = true;
boolean y = false;

byte num = 2;

if ((num++ == 2) && (y = true)) {num++;}
if ((x = false) || (++num == 5)) {num++;}

System.out.println(num);
System.out.println(x);
System.out.println(y);

2)

int i = 342;
int b = ++i + i;

System.out.println(b);

3)

int i = 342;
int b = i++ + ++i;

System.out.println(i);
System.out.println(b);

第五章 流程控制陳述句

內容導視:

  • 輸入與輸出
  • 分支控制陳述句
  • 回圈控制陳述句
  • 轉向控制陳述句

5.1 輸入與輸出

內容導視:

  • 接收輸入
  • 普通輸出
  • 格式化輸出

5.1.1 接收輸入

我們需要用到 java.util 包下的 Scanner 類,非 lang 包下的類需要匯入,在首行加 import:

import java.util.Scanner;

public class Hello {
    public static void main(String[] args) {
        // 創建一個掃描儀實體,掃描指定輸入流產生的值
        Scanner scanner = new Scanner(System.in);
        
        System.out.print("等待你的輸入,請按下任意鍵:");
        
       	// 等待輸入字串,使用 String 型別的變數 name 接收
        String name = scanner.next();
        System.out.println("你輸入的字串為:" + name);
        
        System.out.print("等待你輸入整數:");
        
        // 等待輸入整數,使用 int 型別的變數 num 接收
        int num = scanner.nextInt();
        System.out.println("你輸入的整數為:" + num);
        
        /*
		scanner.nextDouble()是接收小數
        scanner.next().charAt(0)是接收字符
        */
    }
}

不想輸入,請按 Ctrl + C 結束程式,

注意,讓你輸入整數時,你卻輸入了其它字符,會報 java.util.InputMismatchException 輸入不匹配例外,

5.1.2 普通輸出

輸出與列印是一個意思,就是在控制臺上顯示一些文本資訊,

System.out.println("向控制臺輸出一些內容");

println 是 print line,即列印并換行:如果接著列印,內容會在下一行顯示;如果想下次列印時,文本在同一行,去掉 ln,

5.1.3 格式化輸出

就是把資料按指定格式輸出,使用 printf 配合占位符 %,先把地方占著,再接收資料填充上去;

由于沒有 ln,需要使用轉義字符 \n 手動換行,%d 是給整數占位置,%s 是給字串占位置,占位后,需要傳入值,從左至右,順序不可顛倒,資料型別必須要對應上,

下面是常用的占位符:

占位符 解釋
%d 給整數占位
%x 給整數占位,輸出的整數以十六進制顯示
%f 給小數占位
%e 給小數占位,輸出的小數以科學計數法顯示
%s 給字串占位
String ln = "\n";
System.out.println("班級人員詳情:");
String str = "序號:%d,姓名:%s" + ln;		

System.out.printf(str, 101, "張三");
System.out.printf(str, 102, "猛男");
System.out.printf(str, 103, "武丑");

System.out.println();

double num = 3.14256;
double num2 = 100123450.0;
int num3 = 15;
System.out.println("數字測驗:");
System.out.printf("這是小數:%f" + ln, num);
System.out.printf("%f 保留 2 位小數:%.2f" + ln, num, num);
System.out.printf("%f 的科學計數法顯示:%e" + ln, num2, num2);
System.out.printf("%d 對應的十六進制:%x" + ln, num3, num3);

5.2 分支控制陳述句

分支控制陳述句也稱選擇陳述句,

內容導視:

  • if else
  • switch case

程式一般自上而下,逐行執行,但是有時也需要特殊操作;比如根據條件選擇性地執行某段代碼、回圈執行某段代碼...

5.2.1 if else

if else 陳述句最多只會執行一條分支,類似走路遇見岔路,只能選一條通過,先從最簡單的 if 講起,

單條分支

語法:

if (布爾型別的值) {
    java 陳述句...
}

當布爾型別的值為 true 時,才會執行 {} 中的 java 陳述句,如下:

int age1 = 11;
int age2 = 8;
if (age1 > age2) {
    System.out.println("我比你大");// 此句話會輸出
}

當 {} 中只有一條陳述句時,可以省略 {};但是最好不要那么做,以免別人誤解,

if (age1 > age2) System.out.println("我比你大");

if else

語法:

if (布爾型別的值) {
    分支一...
} else {
    分支二...
}

布爾型別的值為 true,執行第一條分支;為 false,執行第二條分支,

char sex = '1';

if (sex == '0') {
    System.out.println("輸出女");
} else {
    System.out.println("輸出男");// 此句會輸出
}

多條分支

語法:

if (值1) {
    分支一...
} else if (值2) {
    分支二...
} else if (值3) {
    分支三...
} ...

從上至下,只執行第一個值為 true 的分支;else if 可以無限追加,

double scope = 100.0;

if (scope < 60) {
    System.out.println("你的成績不及格");
} else if (scope < 80) {
    System.out.println("你的成績一般");
} else if (scope < 90) {
    System.out.println("你的成績良好");
} else if (scope < 100) {
    System.out.println("你的成績優秀");
}

上面的分支都不會執行,因為從上至下,沒有布爾運算式為 true 的,

int age = 20;
if (age < 18) {
    System.out.println("未成年人");
} else if (age < 35) {
    System.out.println("青年人"); // 此句將會輸出
} else if (age < 50) {
    System.out.println("中年人");
}

執行第二條分支,

if else if ... else

語法:

if (值1) {
    分支一...
} else if (值2) {
    分支二...
} else if (值3) {
    分支三...
} ...
} else {
    最后的分支
}    

當所有分支括號里的值都為 false 時,執行最后的分支,

int age = 888;
if (age < 18) {
    System.out.println("未成年人");
} else if (age < 35) {
    System.out.println("青年人"); // 此句將會輸出
} else if (age < 50) {
    System.out.println("中年人");
} else if (age < 200) {
    System.out.println("老年人");
} else {
    System.out.println("妖怪吧!");// 由于上面分支都不滿足,執行此條分支
}

嵌套分支

if 陳述句中有 if 陳述句,

double scope = 120;

if (scope >= 0 && scope <= 100) {
    // 陳述句塊 1
    if (scope < 60) {
   		System.out.println("你的成績不及格");
	} else if (scope < 80) {
	    System.out.println("你的成績一般");
	} else if (scope < 90) {
   		System.out.println("你的成績良好");
	} else {
    	System.out.println("你的成績優秀");
	}
    
} else {
    // 陳述句塊 2
    System.out.println("這是人能考出的成績?");
}
/*
只有分數在 [0 ~ 100] 之間才會執行陳述句塊 1,否則執行陳述句塊 2
*/

嵌套最好不要超過三層,否則人容易迷惑,可讀性太差,

5.2.2 switch case

語法:

switch (值) {
	case 字面量1:
		陳述句塊1;
		break;
		
	case 字面量2:
    	陳述句塊2;
    	break;
    	
    case 字面量3:
    	陳述句塊3;
    	break;
    ...
    default:
    	陳述句塊4;
}

從上至下,執行字面量等于 switch 括號中的值的 case 分支陳述句,遇見 break 結束 switch 陳述句,

default 如同 else 一樣,可以不寫;當沒有一個匹配上,就執行此分支的陳述句,

char key = 's';

switch (key) {
    case 'w' :
        System.out.println("上");
        break;
    case 's' :
        System.out.println("下");// 此條將會被輸出
        break;   
    case 'a' :
        System.out.println("左");
        break;  
    case 'd' :
        System.out.println("右");
        break;  
    default:
        System.out.println("其它");
}

注意

  1. case 后的字面量對應的資料型別必須與 switch 括號中的值的型別一致,或者可以自動轉成此型別,
  2. case 后的字面量值不能重復,
  3. switch 括號中的值的資料型別只能是 int、String、Enum,(能夠自動轉換為這三種型別的也算)
  4. case 后的值不能是變數,只能是字面量與常量,

case 穿透現象

當執行某條 case 分支的陳述句時,如果沒有 break 陳述句結尾,直接順序執行之下的所有 case、default 分支的陳述句;因為只有執行了 break,才會退出 switch 陳述句,

看清楚了,我把 每條分支的 break 都略去了,

String weather = "sunny";

switch (weather) {
    case "cloudy" :
        System.out.println("陰天");
    case "sunny" :
        System.out.println("晴天");
    case "rain" :
        System.out.println("雨天");
    default:
        System.out.println("其它天氣");
}

當輸出 “晴天” 時,由于沒有遇到 break 陳述句,繼續執行之下陳述句,輸出 “雨天”、“其它天氣”,

打個比方吧:

在一個神奇的小區,房子一排排卻單向連通,一旦進入其中一家,便可以由內部通道去往下一家,有的住戶覺得很不安全,偷偷做了防范措施,

一個小偷撿到了一把鎖,嘗試著用它開啟一戶戶門,從巷頭走到巷尾,誒,有一扇門開了,進去拿了東西,但是主人安了警報鈴,小偷馬上 GG 了,另一個小偷也來了,也打開扇門,恰好主人家忽視了防護,小偷偷完這家后,直接順著通道前往下一家,居然都沒防范措施,直接全部偷完,
image-20220330215204967
case 合并

如果多個 case 分支執行的是相同的陳述句,可以將其合并:

char sex = '男';
switch (sex) {
    case '0' : case '女' :
        System.out.println("我有四個蛋");
        break;
    case '1' : case '男' :
        System.out.println("咖喱?什么咖喱?");
        System.out.println("快還給我!這是我的!");
        break;
    default:
        System.out.println("只想守護你");
}

當 sex 等于 '0' 或 '女' 時,執行第一條分支;sex 等于 '1' 或 '男' 執行第二條分支;都不滿足執行默認分支,

5.3 回圈控制陳述句

內容導視:

  • for
  • while

有些時候,我們需要重復執行某些事情...

5.3.1 for

語法:

for (初始化運算式; 布林值(回圈條件); 更新運算式) {
    回圈體中的陳述句
}

執行順序:

先執行初始化運算式,如果回圈條件為 true,執行回圈體中的陳述句;

執行完后,執行更新運算式,如果回圈條件為 true,執行回圈體中的陳述句...

直到回圈條件為 false,退出 for 陳述句,

示例:

for (int i = 0; i < 2; i++) {
    System.out.println("兩指夫人" + i);
}

分析:

i --> 0;
此時 i 小于 2,為 true,執行回圈體中的陳述句,輸出:兩指夫人0

執行更新運算式 i++
i --> 1;
此時 i 小于 2,為 true,執行回圈體中的陳述句,輸出:兩指夫人1

執行更新運算式 i++
i --> 2;
此時 i 小于 2 為 false,退出回圈

小技巧:

1)由于定義在 for () 中的變數的作用域僅在 for 回圈體內:

for (int i = 0; i < 2; i++) {}
System.out.println(i);
Hello.java:8: 錯誤: 找不到符號
System.out.println(i);

為了能夠在其它地方能夠訪問到此變數,可以將其提取出來,

int i = 0;
for (; i < 2; i++) {}
System.out.println(i);

2)初始化陳述句與更新運算式可以有多個,使用 , 隔開,

for (int i = 1, j = 2; i < 4 && j < 6; i++, j += 2) {
    System.out.println("i:" + i 
		+ ",j:" + j);
}

分析:

i --> 1,j --> 2
i < 4 && j < 6 為 true,執行回圈體,輸出:i:1,j:2

執行更新運算式:i++、j += 2
i --> 2,j --> 4
i < 4 && j < 6 為 true,執行回圈體,輸出:i:2,j:4

執行更新運算式:i++、j += 2
i --> 3,j --> 6
i < 4 && j < 6 為 false,結束 for 回圈

5.3.2 while

語法:

while (布林值(回圈條件)) {
    回圈體中的陳述句
}

如果布林值為 true,執行回圈體;執行結束后再判斷布林值...直到布林值為 false,退出回圈,

示例:

int i = 0;
while (i < 3) {
    System.out.println(i);
    i++;
}

輸出 0、1、2

do while

語法:

do {
    回圈體中的陳述句
} while (布林值);

先執行回圈體,執行結束后判斷布林值,如果為 true,執行回圈體,再判斷布林值...直到布林值為 false,退出回圈,

與 while 不同的是,do while 是先執行再判斷,所以一定會執行一次,

示例:

int i = 0;
do {
    System.out.println(i);
    i++;
} while (i < 3);

輸出 0、1、2

嵌套回圈

以 for 回圈為例,之前先講過嵌套,你就理解為套娃就行了,看到阿衰他媽給阿衰做了一籠包子,結果大臉妹打開包子一看,包子里有多個小包子,繼續打開,更小的包子...無窮盡也,很影響食欲,嵌套最好不要超過三層,怕人發昏,

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        System.out.println(j);
	}
}

分析:

當 i = 0 時,執行回圈體輸出 0、1、2,當 j = 3 時,不滿足條件,結束內層 for 回圈
當 i = 1 時,執行回圈體輸出 0、1、2...
當 i = 2 時,執行回圈體輸出 0、1、2...

當 i = 3 時,不滿足回圈條件,退出外層 for 回圈

外層的 for 一共回圈執行 3 次;每次外層回圈時,內層的 for 會回圈執行 3 次;也就是內層的回圈體中的陳述句一共執行 3 * 3 = 9 次,

5.4 轉向控制陳述句

內容導視:

  • break
  • continue
  • return

終止或跳過回圈...

5.4.1 break

break 代表終止陳述句塊的執行(不再執行),一般用于 switch case、for、while 中,

舉例:當 i = 2 時,終止回圈,

int i = 0;
while (i < 10) {
    if (i == 2) {
        System.out.println("終止了回圈");
        break;
    }
    System.out.println(i);
    i++;
}

輸出 0、1;當 i 等于 2 時,執行 if 陳述句,輸出 “終止了回圈”,接著執行 break 終止 for 回圈,

當 break 用在嵌套回圈中,默認終止最近的回圈體,

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
        if (j == 1) {
            break;
        }
        System.out.println(j);
    }
}

分析:

當 i = 0 時,輸出 0
當 i = 1 時,輸出 0
當 i = 2 時,輸出 0
因為當 j = 1 時,滿足了 if 條件,執行了 break,終止了里層的 for 回圈,
(只是代表里層的回圈執行結束,但外層回圈還在繼續執行)
當 i = 3 時,不滿足條件,退出外層回圈,

也可以自定義標簽,終止標簽對應的回圈,

key1: for (int i = 0; i < 3; i++) {
    key2: for (int j = 0; j < 2; j++) {
        if (j == 1) {          
            break key1;
        }
        System.out.println(j);
    }
}

輸出 0;當 j = 1 時,執行了 break,終止 key1 對應的 for 陳述句,

5.4.2 continue

跳過本次回圈,(提前結束本次回圈)

int i = 0;
while (i < 6){
    i++;
    if (i == 3){
        continue;
    }
    System.out.println(i);

}

當 i = 3 時,執行了 continue,跳過本次回圈,沒有執行輸出陳述句,直接進入下一次回圈,所以輸出 1、2、4、5、6,

需要注意的是,此時我把 “i++” 放在了前面;因為 i++ 如果在 continue 后,當 i = 3 時,跳過本次回圈,沒有執行 i++,下次回圈 i 還是 3,一直跳過,無限回圈,永遠執行不到 i++,

5.4.3 return

當方法沒有回傳值(void)時,使用 return; 代表結束當前方法,(在 main 方法中使用,代表結束程式)

public static void main(String[] args) {
    // for
    for (int i = 0; i < 6; i++) {
        System.out.println(i);
        if(i == 4) {
            return;
        }
	}
    // 其它陳述句
	System.out.println("代碼塊");
}

輸出 0、1、2、3、4 后,當 i = 4 時,執行 if 陳述句中的 return,結束 main 方法的執行,

如果把 return 換成 break,只結束了 for 回圈,接著還會輸出 “代碼塊”,

return 以后講方法回傳值時還會用到,現在只需了解它能夠終止方法執行即可,

5.x 總結回顧

switch case 陳述句注意 break 不可省略,以免出現 case 穿透現象,

for 與 while 回圈注意控制回圈結束條件,防止布林值一直為 true,避免無限回圈,

5.y 掀起波瀾

5.1 列印 [n,m] 之間的所有是 x 倍數的整數,統計個數及總和,

5.2 輸出 1 + (n - 1) = n、2 + (n - 2) = n...50 + (n - 50) = n,

5.3 列印九九乘法口訣表,

5.4 列印一個 n 層的空心金字塔,例:當 n = 5 是,輸出如下:

    *
   * *
  *   *
 *     *
*********

5.5 找出 3 位數的水仙花數,水仙花數是各位數的三次方之和等于此數,比如 153 = 13 + 53 + 33 = 153,

5.6 計算 1 - 1/2 + 1/3 - 1/4 +....- 1/100,

5.7 計算 1 + (1 + 2) + (1 + 2 + 3) +....+ (1 + 2 + 3 + 4 +...+ 100),

第六章 陣列

內容導視:

  • 一維陣列
  • 多維陣列
  • 排序
  • 查找

6.1 一維陣列

內容導視:

  • 陣列介紹
  • 一維陣列的宣告
  • 一維陣列的遍歷
  • 陣列元素默認值
  • 陣列賦值機制

6.1.1 陣列介紹

陣列是一種陣列結構,當成一個容器吧,只能存放同一型別的元素,如 int 陣列只能存放 int 型別的元素,(包括自動轉換成 int 的元素)

陣列一旦創建,長度不可變,如:

int[] arr = new int[5];

此陣列實體的長度被確定為 5 了,不可改變,

陣列中的元素的記憶體地址是連續的,陣列拿首元素的記憶體地址作為整個陣列的記憶體地址,

陣列物件都有 length 屬性,可以獲取陣列的長度,int length = arr.length;

每個元素都有下標,從 0 開始,以 1 遞增,如最后一個元素的下標是 length - 1,首元素的下標為 0,

下標也被稱為索引、index,

為什么陣列長度不可變

int[] arr = new int[3];
arr = new int[6];
/*
這并不是改變了原陣列的長度,而是重新在堆中創建了一個新的陣列實體
將地址重新賦給參考,原來的陣列實體由于沒有參考指向被回收
*/

堆是一塊記憶體空間,用來存放實體(我有時候也稱物件),參考是指保存了實體的記憶體地址的變數,可以通過參考操縱實體,如同遙控器控制電視一樣,

語言設計者對需要執行的任務分配給不同的結構,陣列具有固定長度,因為它旨在成為開發人員可以構建的低級別、簡單的實作,

計算機記憶體有限,如果可以延長陣列,但旁邊的記憶體已經存了另一個物件怎么辦?陣列各個元素是彼此相鄰存盤,延長不了,

固定長度后,如果陣列沒有足夠的空間存放元素,那么可以找到更大的空白空間創建一個新的更大的陣列存放原有陣列的資料,同時也可以騰出原陣列的空間,

如果不確定陣列長度多大,可以使用 List 集合存放資料,

集合底層已經實作好了,當陣列快裝滿時,會在更大的空白處創建一個長度更大的陣列,將原有資料復制到新陣列,不需要我們手動實作,

為什么陣列下標從 0 開始

  1. 歷史原因

    之前 C 語言陣列下標也是從 0 開始,沒有必要出一種語言就改一次下標,增加額外的學習和理解成本,

  2. 減少 CPU 指令運算

    1)下標從 0 開始,計算第 i 個元素的地址,arr[i] = 首地址 + i * 單個元素所占位元組,

    2)下標從 1 開始,計算第 i 個元素的地址,arr[i] = 首地址 + (i - 1) * 單個元素所占位元組,

    每次尋找地址時,多了一次 i - 1 即減法的指令運算,更加消耗CPU 資源,(把大腦想象成 CPU,每次尋址時多計算一次二進制的減法)

使用陣列存放元素的優點:根據下標查詢元素效率極高

  • 每個元素的記憶體地址在空間上是連續的,
  • 陣列中每個元素型別相同,占用空間大小一樣,
  • 知道首元素的記憶體地址、每個元素的占用空間大小,通過下標可以算出元素的記憶體地址,直接通過記憶體地址定位元素,

缺點

  • 由于保證陣列中每個元素的記憶體地址連續,隨機增刪元素時,會涉及到后面元素統一向后或向前位移的操作,效率較低,
  • 陣列不能存盤大資料量,因為很難在記憶體中找一塊特別的大的連續的空間,

簡化版本如下

陣列是什么

  • 存盤同一型別元素的容器,參考型別,

陣列的優缺點

  • 根據下標查詢元素效率極高
  • 隨機增刪元素效率低

為什么陣列下標從 0 開始

前提:

  • 陣列的每個元素的記憶體地址是連續的

  • 每個元素占用空間一樣

知道首元素記憶體地址,可以算出第 i 個下標的元素的記憶體地址,設元素是 int 型別:(首地址即第一個元素的記憶體地址)

  • 如果下標從 1 開始,arr[i] 的地址 = 首地址 + (i - 1) * 4
  • 如果下標從 0 開始,arr[i] 的地址 = 首地址 + i * 4

很明顯從 1 開始多算了一次減法,消耗的 CPU 更多,

為什么陣列長度不可變

  • 陣列是連續不斷的

    • 如果陣列可以延長,如果旁邊恰好存了一個物件怎么辦?
    • 如果陣列可以縮減,那么突然空出來了一小塊空間,別人如何利用?
  • 解決

    固定陣列長度,如果陣列滿了:

    另尋一個更大的空間創建更大的陣列,把原有資料填入新陣列,舊陣列無參考指向被當作垃圾回收,釋放空間,

6.1.2 一維陣列的宣告

靜態初始化

在宣告時,同時確定了元素的值,

int[] array = {1, 2, 92, 64, 90};
/*
也可以這么寫:
int[] array = new int[]{1, 2, 92, 64, 90};
有時候傳參,或者先宣告了 array,需要用到
*/

創建了一個 int 型別、長度為 5 的陣列,參考名為 array,存放了 5 個 int 型別的元素,分別為 1、2、92、64、90,

上面圖的元素,下標從左到右,依次為 0、1、2、3、4,

通過參考訪問下標對應的元素:

// 訪問第 1 個元素
int a1 = array[0];
// 訪問第 5 個元素
int a5 = array[4];
// 獲取陣列的長度
int length = array.length;

System.out.println(a1);// 1
System.out.println(a5);// 90
System.out.println(length);// 5

動態初始化

int[] array2 = new int[3];
/*
可以先宣告,后分配空間
int[] array2;
array2 = new int[3];
*/

創建了一個 int 型別、長度為 3 的陣列,參考名為 array2,存放了 3 個 int 型別的元素,值都默認為 0,

System.out.println(array2[0]);// 0

賦值

// 把 53 賦給下標為 0 的元素
array2[0] = 53;
array2[1] = 2;
array2[2] = 44;

System.out.println(array2[0]);// 53

int[] arr1;// 此變數沒有保存任何值,必須賦值(初始化)才能夠訪問
int[] arr2 = null;// 此變數保存了 null,代表空
int[] arr3 = {};// 創建了一個長度為 0 的陣列(陣列無元素),地址賦給了 arr3
int[] arr4 = new int[0];// 同上

6.1.3 一維陣列的遍歷

陣列中的元素下標從 0 到 length - 1,可以使用 for 回圈訪問每個元素,

int[] arr = {6, 2, 9};

for (int i = 0; i < arr.length; i++) {
    int num = arr[i];
    System.out.println(num);
}

注意:當訪問不存在的下標時,會報陣列索引越界例外,

int i = arr[3];
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
        at Hello.main(Hello.java:5)

6.1.4 陣列元素默認值

使用動態初始化時,不同型別的元素會有默認值,

資料型別 默認值
short、byte、int、long 0
float、double 0.0
boolean false
char '\u0000'
參考型別包括 String、陣列 null
long[] arr = new long[3];
byte b = arr[0];// 報錯:從 long 轉換到 byte 可能會有損失

特別說明一下:

char 的 '\u0000' 并不是空格,而是空字符,代表什么都沒有,

char[] arr = new char[3];
arr[1] = ' ';
System.out.println(arr[0] + 0);// 0
System.out.println(arr[1] + 0);// 32

'\u0000' 對應整數 0,另一種寫法 '\0',是字符的八進制表示,打個比方,'a' 對應的 8、10、16 進制分別為 0141、97、0x0061,如下都是一個意思,

char c1 = 97;
char c2 = 0141;
char c3 = 0x0061;
char c4 = '\141';
char c5 = 'a';

6.1.5 陣列賦值機制

int[] arr1 = {56, 6, 2};
// 將 arr1 保存的值拷貝一份,賦給 arr2
int[] arr2 = arr1;

arr1 保存的值為陣列實體的記憶體地址,假設為 0x1111,然后拷貝一份地址(創建副本)給 arr2,本質還是值傳遞,

修改 arr2 保存的值,arr1 不會受到影響,

arr2 = null;
System.out.println(arr1);// [I@15db9742(等同于實體的記憶體地址)

本來應該就此打住,但是有人可能還接觸過參考傳遞這個概念:

值傳遞(pass by value):賦值時將值拷貝一份賦給另一個變數,這樣在另一個變數中修改自己保存的值,不會影響到最初的變數;

類似 Ctrl + C、Ctrl + V,

參考傳遞(pass by reference):賦值時將值的地址賦給另一個變數,另一個變數通過記憶體地址定位到此值,如果修改此值,會影響原來變數保存的值;

類似 Windows 系統的創建桌面快捷方式,

值傳遞 參考傳遞
會創建副本 不會創建副本
無法改變原變數保存的值 可以改變原變數保存的值

有人就問了:

int[] arr1 = {6, 62, 2};
int[] arr2 = arr1;

// 使用 arr2 改變了陣列中第一個元素的值
arr2[0] = 99;
// 你看看,這不影響了 arr1 嗎?
System.out.println(arr1[0]);// 99

不不不,不是這個意思,把 arr1、arr2 當成兩個獨立的遙控器吧,電視只有一個,arr2 換臺,受影響的是電視,而不是 arr1,

這里修改的是陣列中的元素,而不是 arr1 保存的值,arr1 保存的值還是這個實體的地址,沒受影響,

結論:arr1 把自己保存的值拷貝一份賦給了arr2,只不過這個值恰好是地址,就當作是值傳遞吧,

陣列實體 {6, 62, 2} 把地址賦給 arr1,才有點參考傳遞的味道,

由于不能直接通過實體訪問到元素,必須借助參考;當沒有參考時,再也不可能訪問到此實體,等同于垃圾,

有人說,不對啊?必須借助參考訪問元素這我知道,如 arr[0];可當沒有參考時,我可以重新把這個實體的地址賦給另一個變數,又來了一個參考,這不就可以訪問到了嗎?

int[] arr1 = {5, 6, 2};// 保存實體的地址的變數稱為參考
// 現在 arr1 不是 {5, 6, 2} 的參考了
arr1 = null;

// 重新將此實體的地址賦給 arr2
int[] arr2 = {5, 6, 2};
// 我訪問到了!
System.out.println(arr2[1]);// 6

可是,你確定第 1 行與第 6 行的 {5, 6, 2} 是同一個實體嗎?

要想確認是否是同一個實體,需要借助參考修改這個實體的值,再看看實體是否被修改了,如果被修改了,說明是同一個實體,

int[] arr1 = {5, 6, 2};
int[] arr2 = {5, 6, 2};

// 修改 arr1 對應的實體第一個元素為 9
arr1[0] = 9;

// 訪問 arr2 對應的實體第一個元素,還是 5
System.out.println(arr2[0]);// 5

然而并沒有被修改,說明不是同一個實體,所以第 1 行的 {5, 6, 2} 永遠不可訪問到了,這種訪問不到的實體已經沒有用處,需要及時被垃圾回收器清理,

也可通過直接輸出參考、雙等號比較,查看是否是同一個實體:

int[] arr1 = {5, 6, 2};
int[] arr2 = arr1;
int[] arr3 = {5, 6, 2};

// arr1 與 arr2 保存的值一樣
System.out.println(arr1 == arr2);// true
// arr1 與 arr3 保存的值不一樣,說明保存的不是同一個實體的記憶體地址
System.out.println(arr1 == arr3);// false

System.out.println(arr1);// [I@15db9742
System.out.println(arr2);// [I@15db9742
System.out.println(arr3);// [I@6d06d69c

于是我們通常說:基本資料型別使用雙等號比較的是值,參考型別使用雙等號比較的是記憶體地址,

那如果有人只認為保存的內容相等就行,不在乎是否為不同實體,在源代碼最上面加入 import java.util.Arrays;

int[] arr1 = {5, 6, 2};
int[] arr2 = arr1;
int[] arr3 = {5, 6, 2};

// equals 比較內容
System.out.println(Arrays.equals(arr1, arr3));// true
System.out.println(arr1 == arr3);// false

6.2 多維陣列

內容導視:

  • 二維陣列宣告
  • 遍歷二維陣列
  • 靜態方法呼叫

6.2.1 二維陣列宣告

二維以上的陣列用的很少,故略去,

宣告二維陣列

int[][] arr1;
int arr2[][];
int []arr3[];

一般使用第一種,

靜態初始化

二維陣列由多個一維陣列組成(二維陣列的每一個元素是一維陣列),三維陣列有多個二維陣列組成...

int[] i1 = {5, 6, 7, 8};
int[] i2 = {63, 262, 2};
int[] i3 = {5, 2, 6};

int[][] arr1 = {i1, i2, i3};
int[][] arr2 = {
    {252, 26, 3},
    {1, 2, 3},
    {6, 4, 2}
};

動態初始化

語法:

資料型別[][] 陣列名 = new 資料型別[二維陣列的長度][一維陣列的長度];

例:

int[][] arr = new int[2][3];

代表創建了一個 int 型別、長度為 2 的二維陣列;(對于參考型別,只保存記憶體地址)

而二維陣列中的每個元素都保存著 int 型別、長度為 3 的一維陣列的記憶體地址,(但通常說二維陣列里的每個元素是 int 型別、長度為 3 的一維陣列)

訪問

// 二維陣列中的每一個元素都是一維陣列,如 arr[0] 是 int[] 型別
int[][] arr = new int[2][3];
// arr[0] 代表二維陣列中下標為 0 的元素,也就是一維陣列,把一維陣列的地址賦給 arr1
int[] arr1 = arr[0];

// 給 arr1 陣列的下標為 0 的元素賦值 67
arr1[0] = 67;

// 獲取 arr1 陣列下標為 0 的元素
int num1 = arr1[0];
System.out.println(num1);

合并

int[][] arr = new int[2][3];
// 下標為 0 就是陣列中的第一個元素
// 給 arr 下標為 0 的一維陣列中的下標為 0 的元素賦值 67
arr[0][0] = 67;

// 訪問 arr 下標為 0 的一維陣列中的下標為 0 的元素
int num1 = arr[0][0];
System.out.println(num1);

例子:

int[][] arr = new int[2][3];
// 賦值
arr[0][0] = 52;
arr[0][1] = 5;
arr[0][2] = 62;// 現在下標為 0 的一維陣列:{52, 5, 62}

arr[1][0] = 2;
arr[1][1] = 8;
arr[1][2] = 6;// 現在下標為 1 的一維陣列:{2, 8, 6}

// 訪問下標為 0 的陣列的所有元素
int n1 = arr[0][0];
int n2 = arr[0][1];
int n3 = arr[0][2];

// 訪問下標為 1 的陣列的所有元素
int m1 = arr[1][0];
int m2 = arr[1][1];
int m3 = arr[1][2];

// 注意二維陣列長度為 2,一維陣列長度為 3,下標別越界,(下標別超過 length - 1)

當一維陣列的長度不確定時,就不能使用上述方式動態初始化,

動態初始化 2

假如確定了二維陣列的長度為 4,

int[][] arr = new int[4][]; 此時記憶體圖如下:(因為一維陣列是參考型別,不賦值默認為 null)

System.out.println(arr[0]);// null
// 使用 null 獲取什么都會拋出 java.lang.NullPointerException 空指標例外
System.out.println(arr[0].length);

這類運行時例外,編譯時檢查不出來,

以后需要時再創建一維陣列:

arr[0] = new int[1];
arr[1] = new int[2];
arr[2] = new int[3];

6.2.2 遍歷二維陣列

先得到每一個元素,也就是一維陣列,再遍歷一維陣列:

int[][] total = new int[3][3];

for (int i = 0; i < total.length; i++) {
    int[] arr = total[i];
    for (int j = 0; j < arr.length; j++) {
        System.out.print(arr[j] + ",");
    }
    System.out.println("一維陣列遍歷完畢");
}

合并

int[][] total = new int[3][3];

for (int i = 0; i < total.length; i++) {
    for (int j = 0; j < total[i].length; j++) {
        System.out.print(total[i][j] + "\t");
    }
    System.out.println();
}

6.2.3 靜態方法呼叫

每次都是重復的代碼,有點厭倦了,所以需要方法封裝重復的代碼了;只講一點點,

class A {
    public static void f1(int[] arr) {}
    public static int sum(int a1, int a2) {return a1 + a2}
    
}

方法的第 3 個單詞如 void、int...代表回傳值,如果沒有回傳值就寫 void,有回傳值,就寫回傳值的型別,然后在方法結尾處寫上 return 要回傳的值;

f1、sum 是方法名,自己定義,符合識別符號規則就行,

方法名后的是形式引數串列,可以定義任意個變數,變數之間使用英文逗號分隔,將來呼叫時傳入實際引數,注意實際引數的個數和型別要與形式引數對應上,

如何使用方法?(呼叫方法)

在同一個類中,直接通過方法名(實參)呼叫,

class A {
    public static void main(String[] args) {
        // 使用 int 型別的變數接識訓傳值
        // int num1 = 4; int num2 = 5;
        int sum = sum(4, 5);
        System.out.println(sum);// 9
    }
    // 回傳 num1 + num2
    public static int sum(int num1, int num2) {
        return num1 + num2;
    }
}

在同一個包下(同級目錄),不同類中,使用類名.方法名(實參)呼叫:

class A {
    public static void main(String[] args) {
        System.out.println(B.f1());// 1
    }
}
class B {
    public static int f1() {return 1;}
}

不同包下的類需要匯入,如使用其它包下的 Arrays 類,關于方法詳細請看 API 檔案;如果以后編譯時說找不到符號,想一想自己匯入了此類沒有,

import java.util.Arrays;
class A {
    public static void main(String[] args) {
		int[] arr = {5, 26, 3};
        System.out.println(Arrays.toString(arr));// [5, 26, 3]
    }
}    

6.3 排序

內容導視:

  • 時間復雜度
  • 空間復雜度
  • 冒泡排序
  • 簡單選擇排序
  • 直接插入排序
  • 希爾排序
  • 堆排序
  • 歸并排序
  • 快速排序
  • 基數排序

我們知道了如何定義陣列來存放元素,那就試試對陣列中的元素排序吧,

排序:一組元素按指定順序排列的程序,生活中,排序無處不在,我會按照難度依次介紹(順序:從小到大排),對于初學者,只需要了解冒泡排序與簡單選擇排序,其它不用看,

排序演算法分為:

  • 插入排序
    • 直接插入排序
    • 希爾排序
  • 選擇排序
    • 簡單選擇排序
    • 堆排序
  • 交換排序
    • 冒泡排序
    • 快速排序
  • 歸并排序
  • 基數排序

在完成功能的情況下,我們需要考慮如何讓程式運行時間更短,占用空間更小,(你也不希望軟體卡半天沒回應,又特別占用記憶體,對吧)

由此引申出來時間復雜度與空間復雜度,接下來一一介紹,

6.3.1 時間復雜度

描述了解決特定問題的步驟稱為演算法,如排序演算法解決了元素無序的問題,只不過在計算機上,可以使用代碼描述,

解決問題的方法有多種,不同演算法的效率有高有低;最直觀的方法就是撰寫不同的程式實作不同的演算法,然后輸入不同資料,進行編譯,運行時對它們進行計時,用時最短的就是最好的,但這種事后測量的方法有很大的缺點與不確定性:

  • 實作不同程式需要耗費大量時間,而我們只需保留其中之一,
  • 資料的不同,可能對某個演算法更加有利;如使用順序與逆序查找,如果查找的數就在開頭,順序唰的一下找到了,就能說明順序一定比逆序好嗎?如何選擇測驗資料以及資料量的多少,才能能夠保證結果的公平性,很難判斷的,
  • 在不同的運行環境、硬體性能情況下得到的結果可能相差會很大;即使在同臺機器上,也有可能測驗時 CPU 負荷突然過高、運行記憶體忽高忽低、計算機電量不足...代碼運行速度慢了下來,你究竟要測驗幾次,在不同的機器上,配置一個怎么樣的的環境,才能得出令人信服的結果?

這時就需要我們自己在撰寫程式前,能夠粗略估計代碼的運行時間,(事前分析估算方法)

陳述句執行次數

也稱陳述句頻度、時間頻度,記為 T(n),n 代表資料的個數,假設運行一行基礎代碼就算執行一次陳述句,代碼花費的時間與陳述句執行次數成正比例,執行的陳述句越多,花費時間越多,

求 m1 方法內陳述句執行次數:

public static void m1(int[] arr) {
    System.out.println("你好");// 執行 1 次
    System.out.println("我餓了");// 執行 1 次
}

T(n) = 2;

此時陣列中元素的個數 n 不會對陳述句執行次數產生影響,也就是說無論 arr.length 有多大,陳述句執行次數也就是 2,

求 for 內的陳述句執行次數:

public static void m2(int[] arr) {
    int n = arr.length;
    // 從 0 到 n - 1,一共回圈 n 次,每次回圈執行 2 個陳述句
    for (int i = 0; i < n; i++) {
        System.out.println("我不想排序");// 一共執行 n 次
        System.out.println("我想睡覺");// 一共執行 n 次
    }
}

T(n) = 2n;

求 for 內的陳述句執行次數:

public static void m3(int[] arr) {
    int n = arr.length;
    for (int i = 1; i < n; i *= 2) {
        System.out.println("沒想到吧");
        System.out.println("還有乘等");
    }
}

for 回圈執行了幾次?

每次回圈 i *= 2
第 1 次回圈 i = 1 = 20;
第 2 次回圈 i = 2 = 21;
第 3 次回圈 i = 4 = 22;
...
第 x+1 次回圈 i = 2x;

假設第 x+1 次回圈時,i >= n,不滿足條件,退出回圈,得出不等式:
2x >= n
解出:x >= log2n

第 log2n + 1 次回圈時,i 正好等于 n,退出了回圈,這次不算,那么一共執行了 log2n 次回圈,每次回圈時執行 2 個陳述句,

T(n) = 2 * log2n;

若回圈次數不是整數,向上取整,如 2.321928 記作 3,

對數:https://baike.baidu.com/item/對數/91326

對數公式:https://baike.baidu.com/item/對數公式/5557846

求方法中輸出陳述句的執行次數:

public static void m4(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            System.out.println("i=" + i
                + ",j=" + j);
        }
    }
}

外層 for 一共回圈 n 次,里層 for 一共回圈 n 次,里面的輸出陳述句被執行了 n * n 次,

T(n) = n2;

有了陳述句執行次數的函式,難道就能比較不同代碼的運行時間嗎?

比如 T(n) = 100n + 1 與 T(n) = n2 + 7,依然無法清晰看出誰的運行時間更短,此時需要看運行時間如何隨 n 的增長而變化,選出增速最小的演算法,

引出漸進時間復雜度(asymptotic time complexity)這個概念:

漸進時間復雜度

簡稱時間復雜度,定義如下:

代碼執行陳述句次數記作 T(n);存在函式 f(n),當 n 趨近無窮大時,T(n) / f(n) 的比值為一個不等于 0 的常數,說明 f(n) 與 T(n) 的增長率相同,是同一量級;如 \(\lim\limits_{x \to \infty} \frac{2n + 10}{n}\) = 2,

記作 T(n) = O( f(n) ),稱 O( f(n) ) 為代碼的時間復雜度;時間復雜度描述了代碼執行時間隨資料量增長的變化趨勢,

如何推出 f(n)?

次數 n a:2n + 10 a`:n b:2n2 + 5 b`:n2
1 12 1 7 1
100 210 100 20005 10000
10000 20010 10000 200000005 100000000
1000000 2000010 1000000 2000000000005 1000000000000

當 n 越來越大時,常數、低次數項已經變得不太重要,如同 a 再怎么努力,也追不上 b,因此被可以省略,

  • 如果函式是常數,使用 1 代替
  • 若不是常數,只保留最高次數的那一項,并去除最高次數的系數

如 T(n) = 20,記作 T(n) = O(1);

T(n) = 2 * log2n + 98 = 2 * log2k * logkn + 98,只保留最高次數那項,且去掉系數,記作 T(n) = O(logkn);

設 k 為任意常數,由換底公式得:log2n = log2k * logkn

T(n) = 2n2 + 3n + 9,記作 T(n) = O(n2),

image-20220405141508691

很明顯隨著 n 的增大,O(n2) 的時間復雜度(增長速度)遠大于其它兩個,

常見的時間復雜度

從小到大排(n 趨向無窮大時):

常數時間:O(1)

對數時間:O(logkn)

線性時間:O(n)

線性對數時間:O(n * logkn)

平方時間:O(n2)

立方時間:O(n3)

指數時間:O(2n)

階乘時間:O(n!)

O(nn)

一般代碼的時間復雜度為指數階及以上,就不用考慮了,哪怕 n 只有 10000,結果也是天大的數字,除非你確定 n 十分的小,將來也不會增加,

計算 1 到 n 的數之和,來看看哪種演算法時間效率高:

普通人想到的是一個個累加,用代碼描述:

int n = 100;// 1
int sum = 0;// 1

for (int i = 1; i <= n; i++) {// n + 1
    sum += i;// n
}
System.out.println(sum);// 1

記錄所有陳述句執行次數:2n + 4,時間復雜度:O(n);

前 n 次順利通過 for 回圈的判斷條件,第 n + 1 次時判斷失敗,沒有進入,

高斯想到的是首尾相加 * 個數 / 2:

int n = 100;// 1
int sum = (1 + n) * n / 2;// 1
System.out.println(sum);// 1

時間復雜度:O(1);

很明顯高斯給出的演算法效率更高;那么如果在某個程式中,需要解決求和問題,就可以選擇此演算法;而不是等到程式寫好了,才掐著秒表,運行一下,一個個比哪個演算法用的時間少,

我們可以看到,執行的代碼就算有再多行,但如果與 n 的取值無關,通通記為 O(1),所以我只計算回圈內某段陳述句的執行次數(受 n 影響),如 sum += i,其外的忽略不計,這樣方便點,

演算法優劣、資料的不同、資料量決定了程式的運行時間長短,

當資料量很少時,如 n = 2,計算機運行速度很快的,時間差異幾乎是 0;使用事后計時的方法,是無法準確區分演算法優劣的,

備注,高斯思路描述如下:

sum =     1 +    2  + ... + 100

sum = 100 +  99  + ... +     1

2sum = 101 + 101 + ... + 101 = 101 * 100

sum = 2sum / 2 = 101 * 50 = 5050

6.3.2 空間復雜度

代碼耗費的存盤空間,記作 S(n),同樣也有 S(n) = O( f(n) ),O( f(n) ) 記為空間復雜度,

要求:記錄一張 n * n 棋盤上的黑白棋子,

image-20220405165947443

代碼 1:使用二維陣列記錄棋盤,空記為 0,黑記為 1,白記為 2;假設 n = 9:

int[][] arr = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 2, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 1, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 0, 0, 0, 0},
    {0, 2, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0},
};

陣列所占空間:一個 int 型別是 4 個位元組,S(n) = 4 * n2,空間復雜度為 O(n2);

想要獲取第 row 行、第 column 列的資訊:

public static void getState(int[][] arr, int row, int column) {
    // 注意下標從 0 開始,并不是 1,所以需要減去 1
    // 例:第 1 行第 1 列,即 arr[0][0]
    int data = https://www.cnblogs.com/cqhh/p/arr[row - 1][column - 1];
    System.out.println("第 " + row + " 行、第 " + column + " 列的棋子為:" + printChess(data));
}
public static String printChess(int data) {
    String state = "?";
    switch(data) {
        case 0 :
            state = "空";
            break;
        case 1 :
            state = "黑";
            break;
        case 2 :
            state = "白";
            break;
        default:
    }
	return state;
}

時間復雜度為 O(1),

代碼 2:創建二維陣列保存資料

第一行記錄陣列一共 i 行 j 列,有 count 個棋子(目前是 9、9、5);剩下 count 行記錄這些棋子的位置(下標從 0 開始)與保存的值;陣列長度為 1 + count,

int[][] arr = {
    {9, 9, 5},// 棋盤的總行、列數、棋子的個數
    {1, 3, 2},// 第一個棋子的行數 - 1、列數 - 1、保存的值
    {2, 5, 1},
    {4, 4, 1},
    {5, 1, 2},
    {6, 3, 1}
};

count 的范圍處于 [0, n2] 之間;

如果棋盤上沒有一個棋子,最好情況;只記錄棋盤幾行幾列、棋子的個數為 0,陣列所占空間:S(n) = 4 * 3 = 12,空間復雜度為 O(1);
如果棋盤上放滿了棋子,最差情況;需要記錄 n2 個棋子的位置,陣列所占空間:S(n) = 4 * 3 * (n2 + 1) = 12n2 + 12,空間復雜度為 O(n2),

獲取第 row 行、第 column 列的資訊,比如獲取第 3 行第 6 列的資訊,如果棋子存在,那么二維陣列中肯定記錄了 2、5、棋子保存的值,

我們需要從頭遍歷,找到開頭為 2、5 的一維陣列;如果找到,說明棋子存在,獲取這個一維陣列第 3 個元素(保存的值);

如果沒有找到,棋子不存在,記為空,

public static void getState(int[][] arr, int row, int column) {
    int i = row - 1;
    int j = column - 1;
    
    int data = https://www.cnblogs.com/cqhh/p/0;
    for(int m = 1; m < arr.length; m++) {
        if (arr[m][0] == i && arr[m][1] == j) {
            data = arr[m][2];
            break;
        }
    }
    System.out.println("第 " + row + " 行、第 " + column + " 列的棋子為:" + printChess(data));
}

這種方式時間復雜度十分不穩定,最好情況 count = 0,不需要遍歷,得到結果為空,時間復雜度為 O(1);最差情況 count = n2,且對應一維陣列在最后一個,時間復雜度為 O(n2),

當棋子較少時,使用代碼 2 更節省空間;想要獲取某行某列的資訊,使用代碼 1 時間效率更高,到底是用空間換時間,還是用時間換空間,憑自己取舍,

也可以組合:當用戶下棋時,為了提升時間效率,用空間換時間,使用代碼 1;退出棋盤時并不需要獲取某行某列的資訊,只需記錄棋盤位置,使用代碼 2 更節省空間,

6.3.3 冒泡排序

規定從小到大排序,那么小的要在前面,否則就需要交換,

Bubble Sort 演算法思路:比較相鄰元素,逆序就交換,

以 5,6,74,2,36,7 為例,每次比較中,我會用灰色標記大數,

第一輪:5,6,74,2,36,7

首先比較第 1 個與第 2 個元素的大小,5 < 6,不需要交換;
比較第 2 個與第 3 個,6 < 74,不需要交換;
比較第 3 個與第 4 個,74 > 2,需要交換,交換后:5,6,2,74,36,7
比較第 4 個與第 5 個,74 > 36,需要交換,交換后:5,6,2,36,74,7
比較第 5 個與第 6 個,74 > 7,需要交換,交換后:5,6,2,36,7,74

未命名檔案

可以看到第一輪只是把最大的數歸位了,繼續找出第二大數吧,

第二輪:5,6,2,36,7,74

比較第 1 個與第 2 個,5 < 6,不需要交換;
比較第 2 個與第 3 個,6 > 2,需要交換,交換后:5,2,6,36,7,74
比較第 3 個與第 4 個,6 < 36,不需要交換;
比較第 4 個與第 5 個,36 > 7,需要交換,交換后:5,2,6,7,36,74

未命名檔案 (1)

這一輪找出了第二大數 36,

有人這時可能會問,需不需要比較第 5 個與第 6 個?

要知道我們第一輪排序時,已經把最大的數放在了最后面,其它的數肯定不會大于最大數,所以沒有必要進行比較了,剩下幾輪同理,如下一輪只需比較到第 3 個與第 4 個,找出第三大數,

第三輪:5,2,6,7,36,74

比較第 1 個與第 2 個,5 > 2,需要交換,交換后:2,5,6,7,36,74
比較第 2 個與第 3 個,5 < 6,不需要交換;
比較第 3 個與第 4 個,6 < 7,不需要交換;

第三輪找出了第三大數 7,

未命名檔案 (2)

第四輪:2,5,6,7,36,74

比較第 1 個與第 2 個,2 < 5,不需要交換;
比較第 2 個與第 3 個,5 < 6,不需要交換;

未命名檔案 (3)

找出了第四大數 6,

第五輪:2,5,6,7,36,74

比較第 1 個與第 2 個,2 < 5,不需要交換;

未命名檔案 (4)

找出了第五大數 5,接下來就只剩 2,沒必要比了,到此結束,可以看出一個長度為 6 的陣列,需要 5 輪才能排好序,輪數正是陣列長度 - 1,

使用代碼實作:

之前在整數型別中講過兩數如何交換值,這里借助第三個變數 temp,

注意下標從 0 開始,如第一輪,arr[0] 與 arr[1] 比較、arr[1] 與 arr[2] 比較、...、arr[4] 與 arr[5] 比較,一共 5 次,那么定義一個變數從 0 到 4 即可,

int[] arr = {5, 6, 74, 2, 36, 7};
int temp = 0;

// 第一輪
for (int j = 0; j < 5; j++) {
    // 如果逆序就交換
    if (arr[j] > arr[j + 1]) {// 比較 5 次
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }
}
// 第二輪
for (int j = 0; j < 4; j++) {
    if (arr[j] > arr[j + 1]) {// 比較 4 次
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }    
}
// 第三輪
for (int j = 0; j < 3; j++) {
    if (arr[j] > arr[j + 1]) {// 比較 3 次
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }    
}
// 第四輪
for (int j = 0; j < 2; j++) {
    if (arr[j] > arr[j + 1]) {// 比較 2 次
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }    
}
// 第五輪
for (int j = 0; j < 1; j++) {
    if (arr[j] > arr[j + 1]) {// 比較 1 次,即 arr[0] 與 arr[1]
        temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
    }    
}

// 遍歷arr
for (int i = 0; i < arr.length; i++) {
    System.out.print(arr[i] + ",");
}

可是你發現了,每輪對應的 for 回圈都幾乎一模一樣,只是判斷條件從 j < 5,j < 4 ...到 j < 1,可以考慮使用外層回圈將其包裹,定義一個 i 從 5 到 1,讓 j < i,而這個 5 正是陣列的長度 - 1,

for (int i = arr.length - 1; i > 0; i--) {
    for (int j = 0; j < i; j++) {
        if (arr[j] > arr[j + 1]) {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }    
    } 
}

改進:

可以發現第三輪時就已經排好序了,再也沒有交換元素,剩下幾輪都是無用功,定義一個 boolean 變數,默認為 true,

如果交換了,說明還要繼續回圈,改為 true;如果沒有交換,證明已經排好序了,退出回圈,

boolean flag = true;
// flag 為 false 時,退出回圈
for (int i = arr.length - 1; i > 0 && flag; i--) {
    flag = false;
    for (int j = 0; j < i; j++) {
        // 逆序就交換
        if (arr[j] > arr[j + 1]) {
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
            // 還要繼續回圈
            flag = true;
        }    
    } 
}

改進后,設參與排序的陣列長度為 n;

最壞情況:陣列為逆序,每次比較都需要交換,比較次數為:\(\sum\limits_{i=1}^{n-1}i\) = 1 + 2 + ... + (n - 1) = n * (n - 1) / 2,時間復雜度為 O(n2);

最好情況:陣列為順序,當 i = n - 1 時,進入外回圈,里回圈 j 從 0 到 n - 2,一共 n - 1 次比較,沒有進入 if 陳述句內,flag = false,下一次外回圈直接退出,時間復雜度為 O(n),

空間復雜度為 O(1),

輸入的資料如陣列 arr,只取決于問題本身,與演算法無關,不計入空間復雜度,只需計入演算法實作所用的輔助空間,

包括輸出:查看陣列是否已經排序好了,都不計入,

6.3.4 簡單選擇排序

Simple Selection Sort 演算法思路:找出小數,放在前面;第 i 輪找出第 i 小數,放在第 i 個位置,

小數:兩數比較中,更小的數,我說的并不是 1.241 這種小數,

以 {5,2,6,252,1} 為例;小數使用灰色標記,

第一輪:5,2,6,252,1

比較第 1 個與第 2 個元素大小,5 > 2,小數為第 2 個;
比較第 2 個與第 3 個,2 < 6,小數為第 2 個;
比較第 2 個與第 4 個,2 < 252,小數為第 2 個;
比較第 2 個與第 5 個,2 > 1,小數為第 5 個;結束,

最小數在第 5 個位置上,應該放在第 1 個位置上,
交換第 5 個與第 1 個元素位置后:1,2,6,252,5

未命名檔案 (5)

第一輪,找出了最小數并放在了合適的位置,那么接著找第二小數,

第二輪:1,2,6,252,5

比較第 2 個與第 3 個,2 < 6,小數為第 2 個;
比較第 2 個與第 4 個,2 < 252,小數為第 2 個;
比較第 2 個與第 5 個,2 < 5,小數為第 2 個;結束,

第二小數在第 2 個位置上,正好合適,不需要交換:1,2,6,252,5

未命名檔案 (6)

不需要比較第 1 個與第 2 個,因為第 1 個是最小數,但我們找的是第二小數,下面同理,

第三輪:1,2,6,252,5

比較第 3 個與第 4 個,6 < 252,小數為第 3 個;
比較第 3 個與第 5 個,6 > 5,小數為第 5 個;結束,

第三小數在第 5 個位置上,應該放在第 3 個位置上,
交換第 5 個與第 3 個元素位置:1,2,5,252,6

未命名檔案 (7)

第四輪:1,2,5,252,6

比較第 4 個與第 5 個,252 > 6,小數為第 5 個;結束,

第四小數在第 5 個位置上,應該放在第 4 個位置上,
交換第 5 個與第 4 個元素位置:1,2,5,6,252

未命名檔案 (8)

5 個數,已經確定了 4 位,剩下一個數自動歸位;輪數為陣列長度 - 1,

使用代碼實作:

我們可以看到每輪都是拿小數與其它數進行比較,所以需要定義變數如 min,記錄小數的下標;設陣列長度為 n,

如第 1 輪假設最小數下標也就是 min 為 0,然后讓 arr[min] 與剩下的數,即與下標為 1、2、3 ... n - 1 的元素比較;期間,若發現更小數,將 min 替換為此數的下標,然后拿 arr[min] 繼續與其它數比較,

第 2 輪設 min 為 1;

第 3 輪設 min 為 2;

...

第 n - 1 輪設 min 為 n - 2,

int[] arr = {5, 2, 6, 252, 1};
int n = arr.length;// n = 5
int temp = 0;

// 第一輪:找最小數,假設最小數下標為 0
int min = 0;
// 下標為 0 的數,與下標為 1、2、3、4 的元素進行比較
for (int j = 1; j < n; j++) {

    // 比較程序中,發現有更小的,將 min 替換為此數下標,保證 min 一直記錄的是最小數的下標
    if (arr[j] < arr[min]) {// 比較 4 次
        min = j;
    }
}
// 如果 min 不等于 0,證明最小數的下標不是 0,需要將最小數與下標為 0 的元素交換位置
if (min != 0) {
    temp = arr[0];
    arr[0] = arr[min];
    arr[min] = temp;
}

// 第二輪:找出第二小數,假設第二小數下標為 1(因為下標為 0 的元素已經被確定為最小數,無需參與比較)
min = 1;
// 下標為 1 的數,與下標為 2、3、4 的元素進行比較
for (int j = 2; j < n; j++) {
    if (arr[j] < arr[min]) {// 比較 3 次
        min = j;
    }
}
if (min != 1) {
    temp = arr[1];
    arr[1] = arr[min];
    arr[min] = temp;
}

// 第三輪
min = 2;
for (int j = 3; j < n; j++) {
    if (arr[j] < arr[min]) {// 比較 2 次
        min = j;
    }
}
if (min != 2) {
    temp = arr[2];
    arr[2] = arr[min];
    arr[min] = temp;
}

// 第四輪
min = 3;
for (int j = 4; j < n; j++) {
    if (arr[j] < arr[min]) {// 比較 1 次
        min = j;
    }
}
if (min != 3) {
    temp = arr[3];
    arr[3] = arr[min];
    arr[min] = temp;
}
// 利用 Arrays 類的 toString 方法輸出 arr 的內容
System.out.println(Arrays.toString(arr));

每輪對應的 for 回圈幾乎一致,觀察每輪的變化之處:min = 0、1、2 ... n - 2,j = 1、2、3 ... n - 1,

考慮外層 for,定義 i 從 0 到 n - 2,讓 min = i,j = i + 1,

for (int i = 0; i < n - 1; i++) {
    int min = i;
    for (int j = i + 1; j < n; j++) {
        if (arr[j] < arr[min]) {
            min = j;
        }
    }
    if (min != i) {
        temp = arr[i];
        arr[i] = arr[min];
        arr[min] = temp;
    }
}

簡單選擇排序,比較時沒有交換元素,分開討論:

比較次數是固定的,一共為 1 + 2 + ... + (n - 1) = n * (n - 1) / 2,

交換次數,最好情況不用交換,次數為 0;最壞情況,每次位置都不對,需要交換,次數為 n - 1,

綜合,時間復雜度為 O(n2),空間復雜度為 O(1),

加載速度太慢,該分了

統領鏈接:cnblogs 1.1 語法入門-content

作者:藏取有道

出處:https://www.cnblogs.com/cqhh/p/16131275.html

本文來自博客園,商業轉載請聯系原作者獲得授權,非商業轉載請在文章頁面明顯位置給出原文鏈接,否則保留追究法律責任的權利,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/457971.html

標籤:Java

上一篇:1.1 語法入門-content

下一篇:java.net.ConnectException: Connect to XXXhost:XXXport failed: 拒絕連接 (Connection refused)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more