如果你不懂Java 并且想認真學習接觸了解一下Java的語法,建議把這篇文章收藏了,多看幾遍,應該可以初步掌握Java 大部分基礎的語法 。?
讓我們出發吧!ps:本文有點長,耐心閱讀 。
〇,編程環境
工程項目推薦使用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不允許在類和接口外面直接定義方法。
—?完—