java基本介紹:
java可以簡單理解成爲編程語言或者開發工具。最終目的是編寫用於直接在機器上運行的程序。可跨平臺運行(虛擬機的作用)
java運行原理:
Java源程序經過編譯器編譯後變成字節碼,字節碼由虛擬機解釋執行,虛擬機將每一條要執行的字節碼送給解釋器,解釋器將其翻譯成特定機器上的機器碼,然後在特定的機器上運行。
類和對象
類是java中最基礎的組成單元
面向過程的編程:通過一個函數完成一件事,不會留下任何痕跡,是一次性的。
面向對象編程:時間完成後會將實體中對象抽象出來(類的概念)實體對象是可重複利用的。
類是一羣對象的模板,對象是類的實現。
類包含的基本內容:屬性和方法。
數據類型
標識符、關鍵字
標識符包括類名、方法名、變量名等。
標識符命名規則:
- 只能包含數字、字母(大小寫,Unicode字符)、下劃線 _、美元符$
- 不能以數字開頭
- 不是關鍵字
數據類型
數值型:
整數型:byte\short\int\long(int double使用較多)
浮點型:float\double
字符型:
char
boolean
在基本數據類型中可以進行類型之間的強制轉化。精度低的轉化爲高的沒有問題。精度高的轉爲低時會出現精度缺失或溢出。
變量
變量聲明語法:
數據類型 變量名
示例:
int a
變量賦值:
變量名 = 值;
示例:
a = 1;
簡寫:
int a = 1;
變量生命週期是在{}裏。
直接量
直接量是直接通過源代碼指定值。
例如:
int a = 1;
數字1就是直接量
java可定義的直接量包括:基本數據類型,字符串類型。null.
流程控制
順序結構
自上而下的運行過程
判斷(分支選擇)結構
包括if結構、switch結構
if結構:
if (logic expression) {
statement;
}
if (logic expression) {
statement;
} else {
statement;
}
if (logic expression) {
statement;
} else if (logic expression) {
statement;
} else {
statement;
}
switch結構(運用較少):
switch (expression) {
case condition1 : {
statement;
break;
}
case condition2 : {
statement;
break;
}
default : {
statement;
break;
}
}
在switch結構中要使用break關鍵字跳出
循環結構
在循環語句滿足條件下重複執行某段代碼
循環語句包括:
初始化語句:一條或多條語句用於完成初始化
循環條件:決定是否繼續執行循環體
循環體:條件允許,循環體反覆執行
迭代語句:控制循環
while結構
語法:
(init_statement);
while (test_expression) {
body_statement;
[iteration_statement];
}
do-while結構
語法:
(init_statement);
do {
body_statement;
[iteration_statement];
} whi
區別於while結構do-while結構至少會執行一次
for循環
語法:
for ([init_statement]; test_expression; [iteration_statement]) {
body_statement;
}
控制循環結構:
break:用於跳出整個循環
continue:用於跳出本次循環,條件符合循環還會繼續
數組結構
定義語法
type[] 變量名; // 建議用這種命名
type 變量名[];
數組的初始化
靜態初始化:顯式的指定每個數組元素的值,由系統來決定數組的大小。
- 列表內容
- 動態初始化:只需要指定數組的長度,通過程序動態的給每個元素賦值。
靜態初始化
語法:
type[] arrayName = {element1, element2,....};
type[] arrayName = new type[]{element1, element2,...};
示例:
int[] arrs2;
arrs2 = new int[]{1, 2 ,3 ,4};
int[] arrs = {1, 2, 3, 4};
動態初始化
語法:
type[] arrayName = new type[length];
foreach 遍歷數組
for (type element : array | collections) {
element...
}
面向對象編程
類和對象
類: 是一種自定義的數據類型。有時把這種數據類型也叫做「類類型」或者「引用數據類型」。「引用」就是內存地址的意思。
對象:
通過類創建的變量,或者叫類的實體。
類是一羣對象的特徵母版,對象是類的具體實例。
類是一羣對象的抽象。
類的定義
類所具備的最基本要素:(靜態)屬性、(動態)方法。
類的三大部件:成員變量、方法、構造器
語法:
[修飾符] class 類名 {
// 成員變量
[修飾符] 數據類型 成員變量1;
[修飾符] 數據類型 成員變量2;
...
// 方法
[修飾符] 返回值 方法名1([參數列表]) {
方法體語句;
}
[修飾符] 返回值 方法名2([參數列表]) {
方法體語句;
}
...
// 構造器:創建對象用的方法
[修飾符] 類名([參數列表1]) {
方法語句;
}
[修飾符] 類名([參數列表2]) {
方法語句;
}
}
構造器
語法:
[修飾符] 類名([參數列表]) {}
成員變量
語法
[修飾符] 數據類型 成員變量名 [= 默認值];
方法
語法:
[修飾符] 方法的返回值數據類型 方法名(形參列表) {
方法體語句;
}
static 關鍵字
用於修飾成員變量和方法,用 static 修飾的成員變量後者方法是屬於 類 的,而不屬於該類的實例(對象)。通常把 static 修飾的成員變量稱爲「類變量、靜態變量」,方法稱爲「類方法、靜態方法」
靜態的成員是不能訪問非靜態成員的;
靜態成員之間是可以互相訪問的。
使用一個對象的過程
定義類
構建和使用對象
語法:
類類型 對象名 = new 構造器方法();
在內存中的執行過程簡介:
1、在棧內存中,會存儲對象名,在沒有執行構造器創建對象並賦值時,此時對象名對應的值爲 null;
2、通過 new 關鍵字調用類的構造器在堆內存中分配了一塊對象區域;
3、通過賦值運算符 = ,將堆內存中的對象地址賦給棧內存中的變量名;
4、例如再次給對象的屬性賦值:通過棧內存定位到對象在堆內存中的地址,找到相應的成員變量,進行賦值操作。
this 關鍵字
Java 中使用 this 關鍵字,指向調用該方法的對象。根據 this 所在的位置,大致分爲兩種:
出現在構造器中:引用該構造器正在初始化的對象;
普通方法中:調用該方法的對象。
this 用於在類定義中,獲取當前對象的屬性,或者調用當前對象的方法。
用 static 修飾的方法中是不能使用 this 關鍵字的。
方法定義的語法
[修飾符] 返回值類型 方法名(形參列表) {
方法體
}
方法中參數傳遞的機制
參數的傳遞都是「值傳遞」,在調用方法的時候,參數會被創造出一個副本,原本的值是不會改變的。
基本數據類型,也稱爲「值類型」。
public class Demo11 {
void fun1(int i, int j) {
i = i + 5;
j = j + 5;
System.out.println("fun1-i:" + i);
System.out.println("fun1-j:" + j);
}
void fun1(P p) {
p.i = p.i + 5;
p.j = p.j + 5;
System.out.println("fun1-p-i:" + p.i);
System.out.println("fun1-p-j:" + p.j);
}
public static void main(String[] args) {
Demo11 demo11 = new Demo11();
int i = 10;
int j = 20;
demo11.fun1(i, j);
System.out.println("main-i:" + i);
System.out.println("main-j:" + j);
System.out.println("====================");
P p = new P();
p.i = 10;
p.j = 20;
demo11.fun1(p);
System.out.println("main-p-i:" + p.i);
System.out.println("main-p-j:" + p.j);
}
}
class P {
int i;
int j;
}
輸出:
fun1-i:15
fun1-j:25
main-i:10
main-j:20
====================
fun1-p-i:15
fun1-p-j:25
main-p-i:15
main-p-j:25
熟知理解上述代碼
變量
根據變量定義所在位置的不同,可以定義:
成員變量:在類中定義的變量,用 static 修飾的爲類變量,非 static 修飾的爲實例變量。
訪問變量的語法:
類.成員變量
實例(對象).成員變量
局部變量
局部變量按照定義的位置分爲:
在方法內部定義的變量;
在代碼塊中定義的變量,比如有循環體內部、判斷體內部;
形式參數:在方法定義的參數列表中定義的變量;
局部變量生命週期:從定義變量的位置開始,到定義位置所在花括號的結束位置結束。
要注意一般在 for 循環中我們的初始化條件裏面定義的變量,其生命週期在循環體內。
隱藏和封裝
封裝
封裝是面向對象編程的三大特性之一。
封裝目的:
隱藏類方法實現的細節;
讓使用者只能通過預先定義的方法來訪問數據,從而可以在方法中加入一些控制邏輯,限制對成員變量的不合理訪問。
簡單的理解就是把成員變量隱藏起來,暴露方法來提供成員的修改和訪問
Getter 和 Setter
把屬性定義爲 private 類型,即私有,向外部暴露其 get 和 set 方法。
訪問控制修飾符
訪問控制修飾符能修飾的對象包括:成員變量、方法、構造器
深入構造器
構造器的最大用處就是創建對象。
如果在類定義中沒有顯式的定義一個構造器,則編譯器在編譯源文件時,會創建一個沒有參數、沒有方法體執行語句的空的構造器。
如果顯式的定義了一個構造器,則上述的空的構造器則不會存在。
在調用構造器創建對象的時候,系統會爲每個對象的實例變量設置默認值
構造器重載
如果需要在構造器中調用另外一個構造器,可以使用 this(params);
在構造器中調用構造器,必須把this(params)放在有效的執行語句第一行,而且不允許出現兩條this(params)語句。
類的繼承
繼承是面向對象的三大特性之一,也是實現軟件複用的重要手段。
Java中是單繼承,每個子類只有一個直接父類。有的時候把父類也成爲基類或者超類。
繼承的特點
子類能繼承父類的方法
重寫父類的方法
在子類中包含與父類同方法簽名的現象稱爲「方法重寫(Override)」,有時也稱爲方法覆蓋。我們可以說子類重寫了父類的方法,也可以說子類覆蓋了父類的方法。
返回值和訪問控制修飾符可以不一樣,但是要符合“兩同兩小一大原則”
作爲兩同就是方法名和方法的參數列表相同
兩小:子類的返回值類型和拋出的異常類要比父類的返回值類型和拋出的異常類更小或者相等。這裏說的返回值類型小值得的是子類和父類的關係。
一大:子類的訪問權限要比父類的訪問權限要大或者相等
super限定
super的使用和this的使用很相似。
如果需要在子類中調用父類被覆蓋的方法,可以使用super關鍵字。
同樣也可以通過super.fun()調用沒有被覆蓋的方法,但是這樣寫沒有什麼特別的意義,因爲本身在子類中就可以直接調用,無需使用super關鍵字。
子類能夠繼承父類的信息包括:
沒有使用private修飾符修飾的成員變量和方法,子類都能夠繼承
子類重寫了父類的方法,則父類的方法會被隱藏,隱藏的方法或者成員變量可以通過super關鍵字進行訪問
引入super關鍵字的原因是可以訪問被隱藏的成員變量和屬性,而且super只能在子類的方法定義中使用。
調用父類的構造器
在子類的構造器中,無論如何在第一行語句中都會調用一次父類的構造器。
如果沒有顯式的調用,那麼會調用父類的沒有參數的構造器,如果父類沒有定義空參數的構造器,則此時會無法編譯。
super()必須出現在第一行,而且只能有一個。
this和super在同一構造器中只可能出現一次。
多態
ava引用類型變量有兩種類型:一種是編譯時的類型,一種是運行時的類型。
編譯的類型是由聲明變量的時候決定的。
運行時類型由實際賦給該變量的對象決定。
如果運行時的類型和編譯時的類型不一致就會出現所謂的多態
引用類型的強制類型轉換
強制類型轉換是把大的類型轉換爲小的類型。
在我們的引用數據裏,大的類型是父類,小的類型是子類。
只可能發生在子類和父類的關係中
instanceof運算符
instance運算符的前一個操作數一般是引用數據類型變量,後一個操作數是類名(接口),它是用於判斷前面的對象是否是後面的類、或者其子類。如果是的話,返回true。
包裝類
在Java中,基本數據類型本身不是對象,但是爲了面向對象設計語言的規範使用,Java對8大基本數據類型進行了包裝,提高了相應的構造器、方法以供使用。
基礎類型 | A包裝類型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
包裝類中一般會提供兩種構造器用於構建對象
使用基本數據類型的參數;
使用字符串類型的參數:對於此類參數,在實際創建對象的時候要注意輸入的值要滿足條件;
從基本數據轉成引用數據的方法:
從構造器創建
自動裝箱創建
final 修飾符
final 可以修飾在類、成員變量、方法
如果修飾類:則該類不會被繼承(一般在開發中很少使用);
如果修飾成員變量:一旦給成員變量賦值後就不允許修改其值,一般用在對常量的定義中。
如果修飾方法:
方法的重載和重寫
方法簽名:只包含了方法名和參數列表
重寫:發生在父類和子類之間,方法簽名必須是一樣的
重載:發生在本類中,方法名一樣,但是參數列表不一樣,重載可以是構造器的重載,也可以是方法的重載。
抽象類
抽象方法和抽象類
抽象方法和抽象類都是使用 abstract 修飾的
如果在一個類中定義了抽象方法,那麼這個類就是抽象類;
抽象類是無法實例化的,只能作爲父類被繼承使用;
抽象類的構造器只能用於被實現的子類的構造器調用。
抽象類的作用
抽象類一般只是定義需要使用的方法,把不能實現的部分抽象成抽象方法,留給子類去實現。
父類中可以有實現的方法,但是子類也是可以對已經實現的方法進行改造的(override),但是如果在子類中還需要調用父類的實現方法,可以使用 super 關鍵字。
接口
如果在一個類中,一個實現的方法都沒有,或者都是抽象方法,那麼,這樣的類,成爲接口。
接口定義使用 interface 定義
語法:
[修飾符] interface 接口名 extends 父接口1, 父接口2... {
0-N 個常量;
0-N個抽象方法;
}
接口的繼承
接口的繼承和類的繼承不一樣,接口支撐多繼承,使用 extends 關鍵字,之間用逗號隔開,繼承的內容包含了,常量和方法
接口的使用
接口是抽象類一樣,是不能被實例化的,但是接口可以用於聲明引用類型的變量,當使用接口來聲明變量時,該變量的運行時類型必須是該接口的實現類。
接口和抽象類
相同點:
都不能被實例化,位於繼承樹的頂端,是用於被其他類繼承或者實現的;
都可以包含抽象方法,子類都必須要實現抽象方法;
在實際的開發中,都是接口先行,一般都是先定義接口,然後開發人員實現接口,完成具體方法的實現。
抽象類是個半成品,可以作爲一個模板去使用。
不同點:
抽象類中可以定義普通方法,但是接口中都是抽象方法和靜態變量;
在抽象類是可以定義靜態方法的,接口中不能定義靜態方法的;
在抽象中可以定義構造器的,但是在接口中是不存在構造器這個概念的;
一個類最多只能有一個直接的父類或者抽象類,但是可以有多個接口的實現。
集合框架
在集合框架中,主要分爲 Collection 和 Map 兩大接口。
在 Collection 中又分爲 List (有序集合) 和 Set (無序集合)。List 和 Set 都是接口。
Map 存儲的 Key-Value 結構。
Collection
List
是實際開發中用的最多的一種數據結構,存儲的單個元素,使用泛型去強制約束 List 中存放的是一致的數據類型
插入元素
add()
遍歷元素
通過元素索引下標方式 for 循環
通過 foreach 循環
通過迭代器 Iterator
刪除元素
使用迭代器遍歷集合,調用 Iterator.remove() 方法刪除。
Map
類似的可以理解給集合元素中的值定義了一個 Key 鍵(遍歷),之後可以通過相關的方法快速的定位到具體的 Value 中。
獲取某個 key 的 value
Value get(Key)
遍歷 Map 結構
獲取 Map 的 Key 集合,通過遍歷 Key 集合,獲取 Value 值。
獲取 key 集合:map.keySet();
遍歷 Key 集合:iterator;
獲取 Value 值:get(key);
常用類
Object
toString() :直接打印對象調用該方法,一般在類中重寫(override)。
默認的 toString() 是打印類全名+hashcode
hashCode():返回該對象的哈希碼值,內存地址。
String
構建字符串的方式
String s1 = new String("hello");
char[] cs = {'h','e','l','l','o'};
String s2 = new String(cs);
String s3 = "hello"; // 最常用
常用的一些方法
charAt
replace
split
indexOf
substring
contains
示例:
public class Demo1 {
public static void main(String[] args) {
// 字符串的構建方式
String s1 = new String("hello");
char[] cs = { 'h', 'e', 'l', 'l', 'o' };
String s2 = new String(cs);
String s3 = "hello"; // 最常用
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s3.charAt(1));
String s4 = s3.concat(",world!");
System.out.println(s4);
System.out.println(s4.contains("world1"));
String s5 = "d:/a/index.js";
System.out.println(s5.endsWith(".js"));
// 對於字符串的比較操作,一般的場景都是比較字符串的內容是否一致
String s6 = "tom";
String s7 = new String("tom");
System.out.println(s6 == s7); // false
System.out.println(s6.equals(s7)); // true
String s8 = "hello,world!";
System.out.println(s8.indexOf("world")); // 6
String s9 = "a1a2a3b4a5";
System.out.println(s9.indexOf("a")); // 0
System.out.println(s9.indexOf("a", 1)); // 2
List<Integer> indexs = getIndexsOfStr("1a22a3444a4b", 'a');
for (Integer index : indexs) {
System.out.print(index + "\t");
}
// 打印文件的後綴
String s10 = "d:/a/index.js";
int s10_1 = s10.lastIndexOf(".") + 1;
String s10_2 = s10.substring(s10_1);
System.out.println(s10_2);
String s11 = "abcabcabc";
System.out.println(s11.replace("a", "A"));
System.out.println(s11.replaceFirst("a", "A"));
String s12 = "a-b-c-d-e-f";
String[] s12s = s12.split("-");
for (String s : s12s) {
System.out.println(s);
}
String s13 = "20171108001";
System.out.println(s13.startsWith("20171108"));
System.out.println(s12.toUpperCase());
String s14 = " hello,wolrd! ";
String s15 = s14.trim();
System.out.println("#"+s14+"#");
System.out.println("#"+s15+"#");
}
// 傳入一個字符串,輸出某個字符在傳入字符串中的所有位置
public static List<Integer> getIndexsOfStr(String src, char c) {
List<Integer> rs = new ArrayList<Integer>();
if (null != src) {
char[] cs = src.toCharArray();
for (int i = 0; i < cs.length; i++) {
if (cs[i] == c) {
rs.add(i);
}
}
}
return rs;
}
// 傳入一個字符串,輸出某個字符在傳入字符串中的所有位置
public static List<Integer> getIndexsOfStr(String src, String c) {
List<Integer> rs = new ArrayList<Integer>();
if (null != src) {
}
return rs;
}
}
**StringBuffer
在進行大數據的字符串拼接時使用 StringBuffer**
public class Demo3 {
public static void main(String[] args) {
Date d11 = new Date();
String s = "";
for (int i = 0; i < 100000; i++) {
s += 1;
}
Date d22 = new Date();
System.out.println(d22.getTime() - d11.getTime()); // 3418
Date d1 = new Date();
StringBuffer sb = new StringBuffer("");
for (int i = 0; i < 100000; i++) {
sb.append(i);
}
Date d2 = new Date();
System.out.println(d2.getTime() - d1.getTime()); // 16
}
}
日期 java.util.Date 和 Calendar
Date 和 SimpleDateFormat 的運用
public class Demo4 {
public static void main(String[] args) throws ParseException {
// 構建當前服務器的時間對象
Date now = new Date();
System.out.println(now);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
System.out.println(sdf.format(now)); // 格式化的目的是用於顯示
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
String dateStr = "2017/10/09 13:04:30";
Date now2 = sdf2.parse(dateStr); // 通過一個字符串解析成日期對象
System.out.println(now2.getYear()+1900);
}
}
Calendar 是更加先進的日期處理類
如果只是簡單的對日期進行輸入,用 Date 就可以了,但是如果要對日期進行復雜的運算,就要使用 Calendar 類,Calendar 和 Date 是可以互相轉化的。
Calendar 和 Date 的轉換
使用 Calendar 進行復雜的日期運算
Calendar 只是個工具,具體的日期還是要使用 Date 對象
public class Demo5 {
public static void main(String[] args) throws ParseException {
String dateStr = "2017/11/11";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = sdf.parse(dateStr);
Calendar rightNow = Calendar.getInstance();
rightNow.setTime(date);
rightNow.add(Calendar.DAY_OF_MONTH, 30);
rightNow.add(Calendar.MONTH, 1);
System.out.println(rightNow.get(Calendar.DAY_OF_MONTH));
System.out.println(rightNow.get(Calendar.MONTH));
rightNow.set(Calendar.YEAR, 2019);
rightNow.add(Calendar.DAY_OF_MONTH, -1);
System.out.println(sdf.format(rightNow.getTime()));
}
}
異常處理
如果不處理異常,一旦在出現異常的地方,程序就會被「異常指令流」直接終止,不再往下運行。
處理異常
使用 try catch
在 try catch 結構中,catch 是可以省略的,也可以多異常的捕獲,但是出現多異常的時候,父類異常只能出現在最下面。
在實際的開發中,一般最簡單的方式就是使用一個 Exception 直接處理。
finally
無論是否出現異常都會被執行,特別要注意的是,如果沒有寫 catch ,那麼 finally 是會被執行的,但是中斷後的語句是不會被執行的。
throws
在方法定義的後面顯式的聲明方法是有異常的,調用該方法的程序是要顯式的處理異常,後者也可以再次拋出。
throw
自定義的創建一個異常對象。在一般的異常發生時候,虛擬機會動態的創建一個「系統異常」拋出,和自定義使用 throw 拋出是一個概念。
異常堆棧信息
異常類
異常提示信息:getMessage()
異常所在的代碼位置:自下而上是異常出現的代碼所在方法的調用順序的先後。
單例模式
在實際的開發中,絕對部分的服務性質的類都會設計成單例模式
所謂的單例模式,就是類只有一個對象,外部要使用該類的對象,通過調用一個類方法實現。
/**
* 飽漢式單例模式
* @author lzq31
*
*/
public class Service2 {
private static Service2 service = new Service2();
private Service2() {
}
public static Service2 getInstance() {
return service;
}
}
/**
* 餓漢式單例模式
* @author lzq31
*
*/
public class Service {
private static Service service;
private Service() {
}
public static Service getInstance() {
if (null == service) {
service = new Service();
}
return service;
}
}