參考了廖雪峰老師的Java教程,以及網絡上的一些其他部落格,大概投入了50個小時的學習和整理,于是就有了本篇文章。
讓我們出發吧!
〇,程式設計環境
工程項目推薦使用IDEA.
入門學習推薦使用jupyter notebook.
安裝jupyter notebook的java插件 IJava 的方法如下:
1,下載下傳Java JDK >= 9.建議12
2,下載下傳ijava-1.3.0.zip,并解壓。
3,進入解壓後目錄,運作 python3 install.py --sys-prefix。
詳情參見:https://github.com/SpencerPark/IJava
也可以在以下網頁連結中直接嘗試IJava:
https://mybinder.org/v2/gh/SpencerPark/ijava-binder/master

一,算數運算
二,輸入輸出
輸入:System.in, java.io.InputStreamReader, java.util.Scanner
輸出:System.out.println, System.out.printf, System.out.print
讀檔案:java.io.FileInputStream
寫檔案:java.io.FileOutputStream
1,輸入
Scanner掃描輸入,遇到\n結束。
BufferedReader.read() 逐字元讀取。
BufferedReader.readLine() 逐行讀取。
2,輸出
print不換行,println換行,printf格式化輸出。
3,讀檔案
4,寫檔案
三,導入Package
java有以下一些導入包的方式:
1,導入包中某個對象:import java.text.SimpleDateFormat
2,導入包中全部對象: import java.util.*
3,導入包中的靜态字段和方法(較少使用): import static java.lang.System.*
4,預設導入: java預設導入了java.lang.*
四,文法規則
1,辨別符
辨別符由字母和數字組成,遵循駝峰命名規則。
類的名稱以大寫字母開頭。
方法的名稱以小寫字母開頭。
變量的名稱以小寫字母開頭。
2,注釋
單行注釋用//開頭。
多行注釋用結尾。
特殊多行注釋,以結束,如果有多行,每行通常以星号開頭。
這種特殊的多行注釋需要寫在類和方法的定義處,可以用于自動建立文檔。
3,資料類型
Java 的資料類型有兩大類,基本資料類型和引用資料類型。
基本資料類型相對非常底層,基本類型相同值的對象占有同樣的存儲單元,判斷是否相等可以用 ==。
引用資料類型本質上都是Class,相對抽象,引用類型相同值的對象占用不同的存儲單元,判斷是否相等應該用 equals方法。
基本資料類型包括:整型(byte,short,int,long),浮點型(float,double),布爾類型(boolean),字元類型(char)
引用資料類型包括:包裝類型(Integer,Double,Char,Boolean,……),字元串(String),數組(Array),以及各種容器類(List,Map,Set,Queue)。
使用者自定義的任何Class都可以看成是一種引用資料類型。
4,變量聲明
5,标點符号
Java 中常用的标點符号用法總結如下
- ()表示優先級或者函數參數清單
- []用于索引或數組聲明
- {}用于作用域
- <>用于泛型
- * 用于import包時的通配符
- @用于注解
五,編譯執行
1,程式結構
一個.java程式檔案中必須有且隻有一個public類,該類必須有一個聲明為main函數作為程式入口。
并且這個main函數需要聲明為 public static void 類型,即靜态的,公開的,傳回值為空的函數類型。
并且這個java程式的檔案名必須和這個public類名保持一緻。
将以上代碼拷貝到文本檔案中,命名為 Main.java。
2,編譯執行
Java是一種解釋型語言,其java源碼需要被編譯成class位元組碼運作在Java虛拟機上。
是以,執行Java程式分兩步:
(1),使用javac編譯指令将以.java結束的程式檔案編譯成以class結尾的位元組碼程式檔案。
javac Main.java 編譯後得到 Main.class檔案
(2),使用java 指令運作位元組碼程式。
java -classpath ./ Main 在JVM上執行Main.class檔案
編譯時,按下面的順序依次查找類:
(1)查找目前package是否存在這個class;
(2)查找import的包是否包含這個class;
(3)查找java.lang包是否包含這個class。
如果按照上面的規則還無法确定類名,則編譯報錯。
3,classpath和jar包
(1) classpath
classpath是JVM用到的一個環境變量,它用來訓示JVM如何搜尋class。
它其實就是一組目錄的集合,它設定的搜尋路徑與作業系統相關。
例如,在Windows系統上,用;分隔,可能長這樣。
C:\work\project1\bin;C:\shared;"D:\My Documents\project1\bin"
在Linux系統上,用:分隔,可能長這樣。
/usr/shared:/usr/local/bin:/home/liaoxuefeng/bin
如果JVM在某個路徑下找到了對應的class檔案,就不再往後繼續搜尋。如果所有路徑下都沒有找到,就報錯。
classpath的設定方法有兩種:
在系統環境變量中設定classpath環境變量,不推薦;
在啟動JVM時設定classpath變量,推薦。
我們強烈不推薦在系統環境變量中設定classpath,那樣會污染整個系統環境。在啟動JVM時設定classpath才是推薦的做法。實際上就是給java指令傳入-classpath或-cp參數:
java -classpath .;C:\work\project1\bin;C:\shared abc.xyz.Hello
但通常classpath這個參數不需要配置,其預設值為目前目錄 ./一般就夠用了。
(2) jar包
設想一下,如果有很多.class檔案,散落在各層目錄中,肯定不便于管理。
如果能把目錄打一個包,變成一個檔案,就友善多了。
jar包就是用來幹這個事的,它可以把package組織的目錄層級,以及各個目錄下的所有檔案(包括.class檔案和其他檔案)都打成一個jar檔案,這樣一來,無論是備份,還是發給客戶,就簡單多了。
jar包實際上就是一個zip格式的壓縮檔案,而jar包相當于目錄。如果我們要執行一個jar包的class,就可以把jar包放到classpath中:
java -cp ./hello.jar abc.xyz.Hello
jar包還可以包含一個特殊的/META-INF/MANIFEST.MF檔案,MANIFEST.MF是純文字,可以指定Main-Class和其它資訊。JVM會自動讀取這個MANIFEST.MF檔案。如果存在Main-Class,我們就不必在指令行指定啟動的類名,而是用更友善的指令:
java -jar hello.jar
jar包還可以包含其它jar包,這個時候,就需要在MANIFEST.MF檔案裡配置classpath了
4,maven項目管理工具
實際項目開發中,通常使用maven管理項目,并打成jar包。
maven使用POM檔案POM.xml指定項目的依賴和打包方式。
maven安裝後,将會在本地建立~/.m2/repository目錄,集中存放jar包作為本地倉庫。
maven搜尋并載入依賴的順序如下:本地倉庫->私人遠端倉庫->中央倉庫
常見的maven 指令如下:
- mvn clean 清理編譯打包輸出
- mvn compile 項目編譯
- mvn package 項目打包
- mvn install 安裝到本地倉庫
六,Java資料結構概述
Java中常用的資料結構主要包括字元串(String),數組(Array),枚舉(enum), 以及java.util中的各種容器類(通常被稱做集合)。
java.util中的這些容器類分成兩大類,一類是實作了Collection接口,另外一類實作了Map接口。
容器類中常用的資料結構包括:清單(List),映射(Map),集合(Set),隊列(Quene),堆棧(Stack)。
當然這些資料結構也都是接口,通過API封裝了特定的功能,下面還會有多種不同的實作。
可以用統一的Iterator方式對大多數容器類進行周遊,這種更加抽象的方式優于使用下标的方式進行周遊。
七,字元串String
Java 中的字元串和Scala中的字元串來源于同一個包,java.lang.String,兩者具有完全相同的方法。
以下為字元串一些常用操作。
八,數組Array
Java 中的數組和 C++中的數組很像,其長度是不可變的,但是數組中的元素内容是可以改變的。
數組是引用類型,一般是用花括号{}作為數組範圍辨別。
java.util.Arrays 類能友善地操作數組,它提供的所有方法都是靜态的。
1,建立Array
2,Array的常用操作
九,清單List
Java中的清單List是一種有序資料結構的接口。
它有兩種實作,一種是ArrayList,另外一種是LinkedList。前者是順序存儲,友善查詢和修改特定元素。後者是連結清單存儲,友善插入和删除元素。通常情況下我們使用ArrayList更多一些。
和數組Array不同,List的大小是可以改變的。
List的主要方法如下:(E是元素 e的類型)
- 在末尾添加一個元素:void add(E e)
- 在指定索引添加一個元素:void add(int index, E e)
- 删除指定索引的元素:int remove(int index)
- 删除某個元素:int remove(Object e)
- 擷取指定索引的元素:E get(int index)
- 擷取清單大小(包含元素的個數):int size()
1,建立List
2,List常用操作
十,映射Map
Map是一種無序資料結構的接口,存儲鍵值對(key,value)。
Map的常用實作是HashMap, LinkedHashMap, TreeMap。其中TreeMap是一種有序的Map.
Map的常用方法是put和get。如果想查詢某個key是否存在,可以調用containsKey.
Map中的key是唯一的,作為key的對象必須實作equals和hashCode方法。使用TreeMap時,放入的Key必須實作Comparable接口。
Map通常用來高效地進行查找。
1,建立Map
2,Map常用操作
十一,集合Set
Set用于存儲不重複的元素集合,它主要提供以下幾個方法:
- 将元素添加進Set:boolean add(E e)
- 将元素從Set删除:boolean remove(Object e)
- 判斷是否包含元素:boolean contains(Object e)
十二,疊代器
Java的容器類都可以使用for each循環,List、Set和Queue會疊代每個元素,Map會疊代每個key。
下面以List和Set的for each周遊為例。
實際上,Java編譯器并不知道如何周遊List和Set。
上述代碼能夠編譯通過,隻是因為編譯器把for each循環通過Iterator改寫為了普通的for循環:
Iterator是一種抽象的資料通路模型。使用Iterator模式進行疊代的好處有:
- 對任何容器都采用同一種通路模型;
- 調用者對容器内部結構一無所知;
- 容器類傳回的Iterator對象知道如何疊代。
如果我們自己編寫了一個容器類,想要使用for each循環,則該容器類要實作Iterable接口,并傳回一個Iterator對象,下面是一個範例。
十三,枚舉類enum
如果有一些相關的常量,如星期,月份,顔色,可以将其它們定義為枚舉類型。
枚舉類型常用的方法有name和ordinal。
- name():檢視枚舉常量值的名字。
- ordinal():檢視枚舉常量值的序号。
通過enum定義的枚舉類,其實也是一個class,隻不過它有以下幾個特點:
- 定義的enum類型總是繼承自java.lang.Enum,且無法被繼承;
- 隻能定義出enum的執行個體,而無法通過new操作符建立enum的執行個體;
- 定義的每個執行個體都是引用類型的唯一執行個體;
- 可以将enum類型用于switch語句。
因為枚舉類也是class, 是以我們可以定義private的構造方法,并且,給每個枚舉常量添加字段。
十四,選擇結構
Java的選擇結構主要有 if 語句和 switch語句。switch語句是多分支結構。
1,if 選擇語句
2,switch多分支結構
使用switch時不要忘記break,不要忘記default。
十五,循環結構
Java中的循環結構包括for循環,for each循環,while循環。
1,for循環
2,for each循環
for each循環可以對數組,字元串,各種容器類型進行周遊,其背後依賴于Iteratable接口。
3,while循環
4,流程控制continue、break
十六,異常處理
Java中的異常包括兩種體系:Error和Exception.
Error指的是嚴重的錯誤,程式一般對此無能為力。如:
- OutOfMemoryError:記憶體耗盡
- NoClassDefFoundError:無法加載某個Class
- StackOverflowError:棧溢出
而Exception則是運作時的錯誤,它可以被捕獲并處理。
某些異常是應用程式邏輯處理的一部分,應該捕獲并處理。例如:
- NumberFormatException:數值類型的格式錯誤
- FileNotFoundException:未找到檔案
- SocketException:讀取網絡失敗
還有一些異常是程式邏輯編寫不對造成的,應該修複程式本身。例如:
- NullPointerException:對某個null的對象調用方法或字段
- IndexOutOfBoundsException:數組索引越界
Exception又分為兩大類:
- RuntimeException以及它的子類;
- 非RuntimeException(包括IOException、ReflectiveOperationException等等)
Java規定:
- 必須捕獲的異常,包括Exception及其子類,但不包括RuntimeException及其子類,這種類型的異常稱為Checked Exception。
- 不需要捕獲的異常,包括Error及其子類,RuntimeException及其子類。
異常捕獲的語句是 try...catch...finally...此外還可以用throw抛出異常
如:throw new IllegalArgumentException。
十七,類的定義
Java中用關鍵字class定義普通類, 用enum定義枚舉類,用abstract class定義抽象類,用interface定義接口。
我們先看普通類的定義和執行個體化。
類的定義中可以用public聲明為公有屬性和公有方法,在類的内部和外部都可以被通路。
可以用private聲明為私有屬性和私有方法,隻允許在類的作用域通路,不允許在類的外部通路。
可以用protected聲明為受保護的屬性和方法,隻允許在類作用域及其子類作用域中通路。
不使用作用域關鍵字聲明的屬性和方法預設為為package作用域,在同一個package中的類可以通路。
十八,構造方法
構造方法是類的一個特殊的方法,構造方法名就是類名。
構造方法沒有return傳回值,也沒有void聲明。
如果一個類沒有定義任何構造方法,那麼編譯器會自動為我們生成一個預設構造方法,它沒有參數,也沒有執行語句。
如果我們已經定義了構造方法,那麼編譯器不會生成預設構造方法。
沒有在構造方法中初始化屬性時,引用類型的字段預設是null,int類型預設值是0,布爾類型預設值是false。
我們可以為一個類定義多個構造方法,使用時可以根據參數類型和數量自動進行比對。
這叫做構造方法的重載。
所有方法都支援方法重載。
十九,靜态屬性和靜态方法
通過static修飾的屬性為靜态屬性,通過static修飾的方法為靜态方法。
靜态屬性和靜态方法屬于類而不屬于特定的執行個體,在類的執行個體之間共享。
可以通過類名直接調用靜态屬性和靜态方法,也可以通過執行個體對象間接調用。
靜态方法中不能夠通過this關鍵字使用執行個體屬性。
二十,繼承
類和類之間有三種關系:A is B, A use B, A has B.
其中A is B 就是 繼承關系。如果A 的屬性中有 B的類型,叫做 A has B.如果A 的方法的參數中有 B的類型,叫做 A use B.
我們重點介紹繼承關系。
Java中用extends聲明繼承關系。public, protected聲明的屬性和方法可以被子類繼承,而private聲明的屬性和方法不可以被子類繼承。
二十一,多态
Java的執行個體方法調用是基于運作時的實際類型的動态調用,而非變量的聲明類型。
這個非常重要的特性在面向對象程式設計中稱之為多态。它的英文拼寫非常複雜:Polymorphic。
多态具有一個非常強大的功能,就是允許添加更多類型的子類實作功能擴充,卻不需要修改基于父類的代碼。
這就實作了面向對象程式設計非常著名的開閉原則:對擴充開放,對修改封閉。
二十二,抽象類
使用abstract聲明的方法為抽象類,抽象類隻能夠被繼承,不能夠建立抽象類的執行個體。
抽象類的方法可以被abstract聲明為抽象方法,抽象方法沒有執行語句。
抽象類的作用在于定義簽名規範,具體的業務實作留給子類去做。
二十三,接口
在抽象類中,抽象方法本質上是定義接口規範:即規定高層類的接口,進而保證所有子類都有相同的接口實作,這樣,多态就能發揮出威力。
如果一個抽象類沒有字段,所有方法全部都是抽象方法,那麼該抽象類就可以被改寫成接口(interface)。
Java 中的 interface具有和 Scala中的 trait相似的功能。
一個class隻能繼承自一個父類,但可以繼承自多個接口。
通過關鍵字 implements 聲明class和interface之間的繼承關系。
interface和interface之間也可以互相繼承,使用關鍵字 extends來表示這種擴充關系。
interface不能有執行個體屬性,但可以有靜态屬性。
interface中的所有方法都預設為抽象方法,是以無需關鍵字abstract聲明。
interface的非抽象方法用default關鍵字聲明,叫做default方法。
default方法中不能夠引用執行個體屬性,但可以調用抽象方法。
除了default方法和static聲明的靜态屬性,interface基本上可以看成是一個軀殼。
二十四,反射
通常我們通過類來建立執行個體,但反射機制讓我們能夠通過執行個體來擷取類的資訊。
包括類的名字,類的屬性和方法簽名,類的繼承關系等等。
當加載進一個class類檔案時,JVM會建立一個Class類型的執行個體來儲存類的資訊。
1,擷取Class類型執行個體
2,通路屬性
- Field getField(name):根據字段名擷取某個public的field(包括父類)
- Field getDeclaredField(name):根據字段名擷取目前類的某個field(不包括父類)
- Field[] getFields():擷取所有public的field(包括父類)
- Field[] getDeclaredFields():擷取目前類的所有field(不包括父類)
3,調用方法
- Method getMethod(name, Class...):擷取某個public的Method(包括父類)
- Method getDeclaredMethod(name, Class...):擷取目前類的某個Method(不包括父類)
- Method[] getMethods():擷取所有public的Method(包括父類)
- Method[] getDeclaredMethods():擷取目前類的所有Method(不包括父類)
4,調用構造方法
5,擷取繼承關系
二十五,泛型
泛型就是編寫模闆代碼來适應任意類型。Java的容器類中大量使用了泛型。
泛型的好處是使用時不必對類型進行強制轉換,它通過編譯器對類型進行檢查。
Java中泛型的實作是使用的擦拭法,編譯器編譯包含泛型的類時将泛型換成Object類型,
編譯器編譯泛型執行個體化的代碼時根據泛型的具體類型進行安全轉型,而JVM虛拟機對泛型一無所知。
是以泛型的類型不能是int,float,double等基本類型,并且不能夠擷取泛型的反射。
二十六,注解
Java中的注解是放在Java源碼的類、方法、屬性、參數前的一種特殊"注釋",以@開頭。
注解可以看成用作标注的一種"中繼資料"。
Java中有3中不同的注解:
- SOURCE類型的注解由編譯器使用,在編譯期被丢掉了,如@Override;
- CLASS類型的注解僅儲存在class檔案中,這類注解隻被一些底層庫使用,它們不會被加載進JVM;
- RUNTIME類型的注解會被加載進JVM,并且在運作期可以被程式讀取。
Java語言使用@interface文法來定義注解(Annotation),定義注解一般需要用到元注解。
元注解(meta annotation)就是可以用來修飾其它注解的注解。
Java标準庫已經定義了一些元注解,我們隻需要使用元注解,通常不需要自己去編寫元注解。
注解定義後也是一種class,所有的注解都繼承自java.lang.annotation.Annotation,是以,讀取注解,需要使用反射API。
RUNTIME類型的注解如何使用,完全由程式自己決定。
二十七,Scala和Java對比
Java發明于1995年,Scala發明于2003年。
Scala和Java都是JVM語言,兩者的源碼都将編譯成.class位元組碼在JVM虛拟機上執行。
是以Scala和Java可以無縫混編。
Scala在Java基礎上做了重大的改進,使其兼備靜态語言和腳本語言的特色。
下面列舉一些比較顯著的差異。
1,Scala比Java更加簡潔
Java 中列印用 System.out.println, 而Scala用 println,類似Python。
Java 許多地方語句中的分号”;“不能省略, 而Scala可以省略,類似Python。
Java 聲明變量時,先聲明類型,再聲明變量名,而Scala則先變量名,必要時用冒号說明類型,類似Python。
Java 定義方法無需關鍵字,Scala 定義方法用關鍵字 def,可讀性更強,類似Python.
Scala支援for推導式,類似Python.
Scala 支援類型推斷,Java 在後面的版本才增加了 var 關鍵字來支援類型推斷。
Scala 支援隐式類型轉換和隐式參數。
2,Scala比Java更加靈活
Java必須先編譯後才能執行,Scala解釋器可以直接運作Scala腳本。
Java程式設計風格統一為面向對象,Scala支援面向對象和函數式程式設計多種風格
Java中的多分支用switch, Scala使用match模式比對實作多分支。
Java中的類支援靜态屬性和靜态方法,Scala用伴生對象和伴生方法概念将靜态屬性和方法與執行個體屬性和方法分離。
Java的循環中支援break和continue關鍵字,Scala的循環中不支援。
3,常用标點符号差異
Java中導入全部對象用星号作為通配符,Scala中用下劃線作為通配符。
Java中用方括号來取索引,Scala中用圓括号來取索引。
Java中用尖括号來表示泛型,Scala中用方括号來表示泛型。
Java中的數組用花括号來表示,Scala中一般用工廠方法。
Java中可以用冒号來書寫for each語句,Scala中用
二十八,Java和C++的對比
C++發明于1983年,而Java發明于1995年。
C++代碼直接編譯成機器碼運作在裸機上,而Java代碼編譯成位元組碼運作在虛拟機上。
C++編譯的最終結果是一個程式生成一個exe檔案。Java編譯結果是一個程式中有多少類就生成多少個與類名相同的class檔案。
Java的文法大量借鑒了C++,但和C++相比,Java是一門純面向對象的語言,風格更加簡潔統一。
下面列舉一些兩者文法上的差異。
1,C++ 導入package使用 #include, 而 Java使用 import 關鍵字 。
2,C++ 支援指針直接操控記憶體,而 Java 抛棄了令人困惑的指針功能。
3,C++ 使用析構函數回收垃圾,Java自動回收(GC算法)。
4,C++ 支援直接多繼承性,Java用接口來實作多繼承性。
5,C++ 中可以在類的外部可以定義函數,而Java不允許在類和接口外面直接定義方法。
Ps:我在公衆号背景設定了一些關鍵詞自動回複,比如:Python、Java、算法、人工智能、C語言、軟考、英語等等關鍵詞 。背景回複都會自動給百度資源連結 。
擷取全部資源:關注公衆号并回複 資源 領取
覺得内容還不錯的話,給我點個“在看”呗