一、Object類中的幾個(gè)常用方法:
1嗤练、toString
①作用:將對(duì)象轉(zhuǎn)化成字符串,一般都會(huì)重寫(xiě)該方法(默認(rèn)輸出:類名@對(duì)象內(nèi)存地址);
②直接輸出類會(huì)自動(dòng)調(diào)用toString方法丐怯;
System.out.println(cat); //輸出com.test.javase.Cat@1590164;
2翔横、equals
①作用:判斷兩個(gè)對(duì)象是否相等(默認(rèn)使用==判斷读跷,所以要重寫(xiě)該方法);
3禾唁、finalize
①作用:如果希望在對(duì)象銷毀時(shí)執(zhí)行一段代碼效览,可以將其寫(xiě)到finalize()方法當(dāng)中;
②源碼:protected void finalize() throws Throwable { }荡短;
③這個(gè)方法不需要程序員手動(dòng)調(diào)用丐枉,JVM垃圾回收器負(fù)責(zé)調(diào)用這個(gè)方法;
④執(zhí)行時(shí)機(jī):當(dāng)一個(gè)java對(duì)象即將被垃圾回收器回收的時(shí)候掘托,垃圾回收器負(fù)責(zé)調(diào)用finalize()方法
4瘦锹、hashCode
①作用:返回一個(gè)對(duì)象的哈希代碼值,通過(guò)將該對(duì)象的內(nèi)存地址轉(zhuǎn)換成一個(gè)整數(shù),函數(shù)返回一個(gè)int型數(shù)據(jù)
二弯院、數(shù)組
1辱士、一維數(shù)組初始化
靜態(tài)初始化:int[] a = {100, 200, 102};
動(dòng)態(tài)初始化:int[] a = new int[5]; //默認(rèn)值為0
或者[]放在后面:int a[] = new int[10];
2、數(shù)組拷貝
System.arraycopy(原數(shù)組听绳,拷貝開(kāi)始下標(biāo)颂碘,目標(biāo)數(shù)組,拷貝到目標(biāo)數(shù)組的下標(biāo)椅挣,拷貝長(zhǎng)度)
3头岔、二維數(shù)組初始化
靜態(tài)初始化:int[][] a = {{1,2,3},{4,5,6},{7,8,9}};
動(dòng)態(tài)初始化:int[][] a = new int[5][5];
4、Arrays工具類
排序:Arrays.sort
二分查找:Arrays.binarySearch
三鼠证、String類
1切油、字符串都是直接存儲(chǔ)在方法區(qū)的字符串常量池當(dāng)中的
視頻鏈接:https://www.bilibili.com/video/BV1Rx411876f?p=587&spm_id_from=pageDriver&vd_source=451d825d8e1ffcbfd124804db3810f11
"hello":java雙引號(hào)引起來(lái)都是一個(gè)字符串對(duì)象,都會(huì)在字符串常量池中創(chuàng)建一個(gè)新對(duì)象(相同的字符串只會(huì)創(chuàng)建一個(gè))名惩,當(dāng)用new創(chuàng)建String對(duì)象時(shí)澎胡,堆里面的String對(duì)象里面存放的是字符串常量池里面的內(nèi)存地址【兩個(gè)是兩種不同的對(duì)象】
①第一種初始化方式:String s1 = "hello";
String s1 = "hello";
String s2 = "hello";
System.out.println(b == c); 這里打印true
②第二種初始化方式:String x = new String("xyz");
String x = new String("xyz");
String y = new String("xyz");
System.out.println(b == c); 這里打印false
2、字符串比較時(shí)避免空指針異常
將username.equals("admin")修改為:
"admin".equals(username)
3娩鹉、String類構(gòu)造函數(shù)
①將byte數(shù)組全部轉(zhuǎn)化為字符串:String s = new String(bytes);
byte[] bytes = {97, 98, 99}; 97是a攻谁,98是b,99是c
String s = new String(bytes);
System.out.println(s); 輸出abc
②將char數(shù)組全部轉(zhuǎn)換為字符串:
char[] c = {'a', 'b', 'c'};
String s = new String(c);
System.out.println(s); 輸出abc
4弯予、String各類方法:
①equalsIgnoreCase()
"Abc".equalsIgnoreCase("abc"); true戚宦,【忽略大小寫(xiě)比較是否相等】
②getBytes()
byte[] b = "abcd".getBytes(); [97, 98, 99, 100] 【將字符串轉(zhuǎn)換為byte數(shù)組】
③String.valueOf()
String s1 = String.valueOf(true); 【靜態(tài)方法,可以將非字符串轉(zhuǎn)換成字符串锈嫩,true->"true"】
System.out.println(s1);
5受楼、StringBuffer(線程安全的)
作用:當(dāng)需要頻繁的拼接字符串時(shí),為了避免不斷的在字符串常量池當(dāng)中創(chuàng)建對(duì)象呼寸,可以使用StringBuffer艳汽。StringBuffer底層實(shí)際是一個(gè)byte[]數(shù)組,初始化容量是16对雪;
StringBuffer s = new StringBuffer();
s.append("a");
s.append("b");
s.append("c");
s.append(3.14);
s.append(8);
s.append(true);
System.out.println(s); 結(jié)果:abc3.148true
優(yōu)化:在創(chuàng)建StringBuffer的時(shí)候盡可能給定一個(gè)合適的初始化容量河狐,減少底層數(shù)組的擴(kuò)容次數(shù)。
6瑟捣、StringBuilder(非線程安全的)
StringBuilder跟StringBuffer區(qū)別:StringBuffer的方法都有synchronized關(guān)鍵字修飾馋艺,StringBuffer在多線程環(huán)境下運(yùn)行是安全的,而StringBuilder在多線程下是不安全的迈套。
四捐祠、八種包裝類
1、八種類
Byte桑李、Short踱蛀、Integer窿给、Long、Float星岗、Double填大、Boolean戒洼、Character
2俏橘、裝箱、拆箱
裝箱:基本數(shù)據(jù)類型轉(zhuǎn)換為包裝類
Integer i = new Integer(123);
插箱:包裝類轉(zhuǎn)換為基本數(shù)據(jù)類型
int relValue = i.intValue();
自動(dòng)裝箱:基本數(shù)據(jù)類型自動(dòng)轉(zhuǎn)換為包裝類
Integer i = 123; 【i中保存的還是指向?qū)ο蟮膬?nèi)存地址圈浇,并非123】
自動(dòng)插箱:包裝類自動(dòng)轉(zhuǎn)換為基本數(shù)據(jù)類型
int j = i;
3寥掐、注意點(diǎn)
java為了提高程序的執(zhí)行效率,將[-128到127]之間所有的包裝對(duì)象提前創(chuàng)建好磷蜀,放到一個(gè)方法區(qū)的“整數(shù)型常量池”當(dāng)中召耘,目的是只要用這個(gè)區(qū)間的數(shù)據(jù)不需要再new了,直接從整數(shù)型常量池當(dāng)中取出來(lái)褐隆。
例如:
Integer i = 127;
Integer j = 127;
System.out.println(i == j); true
Integer x = 128;
Integer y = 128;
System.out.println(x == y); false
圖解:
五污它、日期處理
1、格式化時(shí)間 SimpleDateFormat
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println(dateFormat.format(date)); 結(jié)果:2022-07-01 14:27:12 400
2庶弃、字符串轉(zhuǎn)換成Date類型 SimpleDateFormat
【字符串要保持與創(chuàng)建的SimpleDateFormat 格式一致】
String s = "2022-07-01 14:27:12 400";
Date date1 = dateFormat.parse(s);
System.out.println(date1);
3衫贬、System.currentTimeMillis() 獲取時(shí)間戳
六、數(shù)字處理
1歇攻、格式化數(shù)字
DecimalFormat df = new DecimalFormat("###,###.##");
System.out.println(df.format(3245.62)); 結(jié)果3,245.62
# 代表任意數(shù)字
, 代表千分位
. 代表小數(shù)點(diǎn)
0 代表不夠時(shí)補(bǔ)0
2固惯、高精度數(shù)字BigDecimal
專門用于財(cái)務(wù)軟件之中
BigDecimal d1 = new BigDecimal(100);
BigDecimal d2 = new BigDecimal(200);
System.out.println(d1.add(d2)); 結(jié)果:300
3、隨機(jī)數(shù)
Random r = new Random();
System.out.println(r.nextInt(101)); 結(jié)果:產(chǎn)生0-100(不包含101)的隨機(jī)整數(shù)
4缴守、枚舉enum
語(yǔ)法:
enum Color{ YELLOW, RED, BLACK, PINK, GREEN }
七葬毫、異常
1、java異常處理機(jī)制
①異常在java中以類和對(duì)象的形式存在屡穗,所有異常都是發(fā)生在運(yùn)行階段
②異常的繼承結(jié)構(gòu):
Object下面有Throwable
Throwable下面有兩個(gè)分支:Error(不可處理)和Exception(可處理)
Exception下面有兩個(gè)分支:
ExceptionSubClass:編譯時(shí)異常贴捡,要求在編寫(xiě)程序階段必須先對(duì)這些異常進(jìn)行處理,如果不處理編譯器會(huì)報(bào)錯(cuò)
RuntimeException:運(yùn)行時(shí)異常村砂,編寫(xiě)程序的時(shí)候可以不處理
③編譯時(shí)異常 和 運(yùn)行時(shí)異常的區(qū)別:
編譯時(shí)異常發(fā)生概率高
2栈暇、異常處理
第一種方式:在方法聲明的位置上,使用throws關(guān)鍵字箍镜,拋給上一級(jí)(拋給調(diào)用者源祈,調(diào)用者如果沒(méi)有處理就繼續(xù)上拋,直到拋給main函數(shù)色迂,main函數(shù)拋給JVM香缺,JVM檢查到異常則停止程序運(yùn)行)throw是手動(dòng)拋出異常;【異常上拋】
第二種方式:使用try...catch語(yǔ)句進(jìn)行異常捕捉 歇僧⊥颊牛【異常捕捉】
3锋拖、try...catch
①catch后面小括號(hào)中的類型可以是具體的異常類型,也可以是該異常類型的父類型
②catch可以寫(xiě)多個(gè)祸轮,建議catch的時(shí)候兽埃,精確的一個(gè)個(gè)處理,這樣有利于程序調(diào)試
③catch寫(xiě)多個(gè)的時(shí)候适袜,從上到下柄错,必須遵守從小到大。
4苦酱、異常對(duì)象的常用方法
e.printStackTrace(); 打印異常堆棧信息
String msg = e.getMessage(); 獲取異常簡(jiǎn)單描述信息
5售貌、finally
在finally字句中的代碼是最后執(zhí)行的,且一定會(huì)執(zhí)行疫萤,所以一般在finally語(yǔ)句塊中完成資源的釋放/關(guān)閉
①語(yǔ)法:
try{
}catch (Exception e){
}finally{
}
②面試問(wèn)題
第一種:
try {
System.out.println("try");
return;
} finally{
System.out.println("finally"); 會(huì)執(zhí)行
}
第二種:
try {
System.out.println("try");
System.exit(0); 退出JVM
} finally{
System.out.println("finally"); 不會(huì)執(zhí)行
}
第三種:
int i = 100;
try {
return i; i最后返回100
} finally{
i++;
}
6颂跨、final、finally扯饶、finalize的區(qū)別
final是一個(gè)關(guān)鍵字恒削,表示最終的、不變的尾序,無(wú)法繼承钓丰、無(wú)法覆蓋、無(wú)法重新賦值蹲诀;
finally也是一個(gè)關(guān)鍵字斑粱,與try聯(lián)合使用,使用在異常處理機(jī)制中脯爪,在finally語(yǔ)句塊中的代碼是一定會(huì)執(zhí)行的则北;
finalize()是Object類中的一個(gè)方法,作為方法名出現(xiàn)痕慢,當(dāng)一個(gè)java對(duì)象即將被垃圾回收器回收的時(shí)候尚揣,垃圾回收器負(fù)責(zé)調(diào)用finalize()方法。
7掖举、自定義異常
第一步:編寫(xiě)一個(gè)類繼承 Exception(編譯時(shí)異常) 或者 RuntimeException(運(yùn)行時(shí)異常)快骗;
第二步:提供兩個(gè)構(gòu)造方法,一個(gè)無(wú)參數(shù)的塔次,一個(gè)帶有String參數(shù)的方篮。
八、集合
1励负、集合中任何時(shí)候存儲(chǔ)的都是“引用”
集合不能直接存儲(chǔ)基本數(shù)據(jù)類型
2藕溅、List、Set接口(Map鍵值對(duì))
Collection接口下:
List
Set
①List继榆、Set區(qū)別
List:有序可重復(fù)巾表,有下標(biāo)
Set:無(wú)序不可重復(fù)汁掠,無(wú)下標(biāo)
②List接口的實(shí)現(xiàn)
ArrayList集合底層采用了數(shù)組(非線程安全)
LinkedList集合底層采用了雙向鏈表
Vector集合底層采用了數(shù)組(線程安全)
③Set接口的實(shí)現(xiàn)
HashSet集合底層采用了HashMap集合
TreeSet集合底層采用了TreeMap集合(TreeSet繼承自SortedSet)
HashMap底層是哈希表
TreeMap底層是二叉樹(shù)
3、Iterator迭代器
集合結(jié)構(gòu)只要發(fā)生改變集币,迭代器必須重新獲取
所以在迭代的過(guò)程中不能直接使用集合對(duì)象進(jìn)行刪除(改變了結(jié)構(gòu))考阱,而應(yīng)該使用迭代器提供的remove()方法,該方法刪除的是迭代器指向的當(dāng)前元素(迭代器迭代時(shí)是使用快照鞠苟,如果直接在對(duì)象上調(diào)用remove方法刪除乞榨,沒(méi)有通知迭代器,那么迭代器還是使用的原集合偶妖,就會(huì)報(bào)異常)
循環(huán)的三種方式:
List<String> arg = new ArrayList<String>();
arg.add("hello");
arg.add("Tong");
arg.add("Panda");
迭代器:
Iterator<String> it = arg.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
下標(biāo)方式:
for(int i = 0; i < arg.size(); i++){
System.out.println(arg.get(i));
}
增強(qiáng)for循環(huán):
for(String str : arg){
System.out.println(str);
}
4姜凄、ArrayList
- ArrayList集合初始化容量是10
- ArrayList集合底層是Object類型的數(shù)組Object[]
- 擴(kuò)容1.5倍
- 建議給定一個(gè)預(yù)估初始容量政溃,減少數(shù)組的擴(kuò)容操作
5趾访、泛型 ArrayList<obj>
- 泛型這種語(yǔ)法機(jī)制只在程序編譯階段起作用,只是給編譯器參考的(運(yùn)行階段泛型沒(méi)用)
- 使用了泛型之后集合中儲(chǔ)存的元素類型統(tǒng)一了
- 自定義泛型:
class Test<E> {
public void add(E a){
...
}
}
6董虱、增強(qiáng)for循環(huán):foreach(沒(méi)有下標(biāo))
int[] arr = {1,2,3,4,5};
for (int item : arr) {
System.out.println(item);
}
7扼鞋、Map鍵值對(duì)
- 注意點(diǎn):
①M(fèi)ap與Collection沒(méi)有繼承關(guān)系
②Map集合以key、value鍵值對(duì)的形式存儲(chǔ)數(shù)據(jù)
③key愤诱、value都是引用數(shù)據(jù)類型 - 常用方法:
containsKey云头、
containsValue、
get("key")淫半、
put("id", 123)溃槐、
remove("key")、
Set<K> keySet() 獲取Map集合所有的key科吭,返回一個(gè)Set
Collection<V> values() 獲取Map集合所有的value昏滴,返回一個(gè)Collection
Set<Map.Entry<K, V>> b = a.entrySet(); 將Map集合轉(zhuǎn)換成Set集合:變?yōu)閕d=123、age=19 - Map集合的遍歷:
①先用keySet()獲取到所有的key对人,然后通過(guò)key遍歷
Map<String, Integer> map = new HashMap<String, Integer>();
Set<String> keys = map.keySet();
for(String k : keys){
System.out.println(k + ":" + map.get(k));
}
②【效率高】先用entrySet()將Map轉(zhuǎn)成Set谣殊,再遍歷Set獲取到單個(gè)的Map.Entry<K, V>對(duì)象,調(diào)用對(duì)象的getKey()牺弄、getValue()方法獲取key姻几、value值,例:
Set<Map.Entry<String, Integer>> set = map.entrySet();
for(Map.Entry<String, Integer> item : set){
System.out.println(item.getKey()+ '=' + item.getValue());
}
- Properties
Properties是一個(gè)Map集合势告,繼承Hashtable蛇捌,Properties的key和value都是String類型;
Properties被稱為屬性類對(duì)象咱台;
Properties是線程安全的络拌;
Properties pro = new Properties();
pro.setProperty("url", "jdbc:mysql://localhost:3306");
pro.setProperty("username", "root");
pro.setProperty("password", "123456");
System.out.println(pro.getProperty("url"));
搭配FileReader 使用
//讀取xml配置文件
FileReader reader = new FileReader("xml");
Properties pro = new Properties(); //key value都是String
//將xml文件鍵值對(duì)加載到pro集合中
pro.load(reader);
//關(guān)閉流
reader.close();
//通過(guò)key獲取value
System.out.println(pro.getProperty("ClassName"));
8、TreeSet
TreeSet集合中的元素是可排序的
視頻鏈接:https://www.bilibili.com/video/BV1Rx411876f?p=709&vd_source=451d825d8e1ffcbfd124804db3810f11
九吵护、IO流
1盒音、IO流的分類:
輸出流
輸入流
字節(jié)流:可以讀任意類型的文件
字符流:只能讀純文本文件
2表鳍、流的四大家族:
java.io.InputStream 字節(jié)輸入流
java.io.OutputStream 字節(jié)輸出流
java.io.Reader 字符輸入流
java.io.Writer 字符輸出流
【注意】:
- 【類名以Stream結(jié)尾的都是字節(jié)流,以“Reader/Writer”結(jié)尾的都是字符流】
- 所有的輸出流都實(shí)現(xiàn)了java.io.Flushable接口祥诽,都是可刷新的譬圣,都有flush()方法,輸出流在輸出了之后一定要flush()刷新一下雄坪,將通道/管道中剩余未輸出的數(shù)據(jù)強(qiáng)行輸出(清空管道)厘熟;
如果沒(méi)有flush()可能會(huì)導(dǎo)致丟失數(shù)據(jù)。
3维哈、常用流
-
文件流:
FileInputStream【重點(diǎn)】
FileOutputStream【重點(diǎn)】
FileReader
FileWriter -
轉(zhuǎn)換流:(將字節(jié)流轉(zhuǎn)換成字符流)
InputStreamReader
OutputStreamWriter -
緩沖流:
BufferedReader
BufferedWriter
BufferedInputStream
BufferedOutputStream -
數(shù)據(jù)流:
DataInputStream
DataOutputStream -
標(biāo)準(zhǔn)輸出流:
PrintWriter
PrintStream【重點(diǎn)】 -
對(duì)象流:
ObjectInputStream【重點(diǎn)】
ObjectOutputStream【重點(diǎn)】
4绳姨、FileInputStream的常用方法:
①read():【不傳參默認(rèn)讀一個(gè)字節(jié)并返回該字節(jié);傳入byte數(shù)組則將字節(jié)存入byte數(shù)組中并返回成功讀取的字節(jié)數(shù)】
public static void main(String[] args){
FileInputStream fs = null;
try {
fs = new FileInputStream("C:\\Users\\Tong\\Desktop\\新建 文本文檔.txt");
byte[] bytes = new byte[4];
int readCount = 0; //初始化讀到的字節(jié)數(shù)
while((readCount = fs.read(bytes)) != -1){
System.out.print(new String(bytes, 0, readCount));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(fs != null){
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
②available():【返回流當(dāng)中剩余沒(méi)有讀到的字節(jié)數(shù)量】
fs = new FileInputStream("C:\\Users\\Tong\\Desktop\\新建 文本文檔.txt");
byte[] bytes = new byte[fs.available()]; //不適合大文件
fs.read(bytes);
System.out.print(new String(bytes));
③skip():【跳過(guò)幾個(gè)字節(jié)不讀】
5阔挠、FileOutputStream的常用方法
①構(gòu)造方法:
fs = new FileOutputStream("文本文檔");
fs = new FileOutputStream("文本文檔", true); 帶上true表示以追加的方式在文件末尾寫(xiě)入飘庄,不會(huì)覆蓋原文件內(nèi)容
②write():
fs = new FileOutputStream("文本文檔", true);
String str = "你好啊";
byte[] bytes = str.getBytes(); 將字符串轉(zhuǎn)換成byte數(shù)組
fs.write(bytes);
fs.flush();
③輸入輸出配合拷貝文件:
//創(chuàng)建一個(gè)輸入流對(duì)象
fis = new FileInputStream("C:\\Users\\Tong\\Desktop\\新建 文本文檔 (2).txt");
//創(chuàng)建一個(gè)輸出流對(duì)象
fos = new FileOutputStream("文本文檔", true);
byte[] bytes = new byte[1024*1024]; //一次最多拷貝1MB
int count = 0;
while((count = fis.read(bytes)) != -1){
fos.write(bytes, 0, count);
}
fos.flush();
6、FileReader
①文件字符輸入流购撼,只能讀取普通文本
②read方法傳入的是char數(shù)組
③搭配Properties使用
//讀取xml配置文件
FileReader reader = new FileReader("xml");
Properties pro = new Properties(); //key value都是String
//將xml文件鍵值對(duì)加載到pro集合中
pro.load(reader);
//關(guān)閉流
reader.close();
//通過(guò)key獲取value
System.out.println(pro.getProperty("ClassName"));
7跪削、BufferedReader
①緩沖流自帶緩沖區(qū),不需要借用byte或者char數(shù)組
②構(gòu)造函數(shù):必須要傳入一個(gè)Reader對(duì)象
FileReader reader = new FileReader("C:\\Users\\Tong\\Desktop\\新建 文本文檔 (2).txt");
BufferedReader buf = new BufferedReader(reader);
③readLine()方法:讀取一行不帶換行符
8迂求、節(jié)點(diǎn)流和包裝流
①概念:
節(jié)點(diǎn)流:當(dāng)一個(gè)流的構(gòu)造方法中需要一個(gè)流的時(shí)候碾盐,這個(gè)被傳進(jìn)來(lái)的流叫做:節(jié)點(diǎn)流
包裝流:外部負(fù)責(zé)包裝的這個(gè)流叫做:包裝流/處理流
上例中FileReader 就是一個(gè)節(jié)點(diǎn)流;BufferedReader 就是包裝流(處理流)
處理結(jié)束之后只用關(guān)閉處理流(處理流中的close方法會(huì)關(guān)閉節(jié)點(diǎn)流)
②字節(jié)流轉(zhuǎn)換成字符流:
使用InputStreamReader揩局,構(gòu)造方法傳入FileInputStream字節(jié)流對(duì)象毫玖,返回一個(gè)Reader字符流對(duì)象
FileInputStream in = new FileInputStream("C:\\Users\\Tong\\Desktop\\新建 文本文檔 (2).txt");
buf = new BufferedReader(new InputStreamReader(in));
9、數(shù)據(jù)流
DataOutputStream數(shù)據(jù)專屬流:可以將數(shù)據(jù)連同數(shù)據(jù)類型一并寫(xiě)入文件
DataInputStream:DataOutputStream寫(xiě)的文件只能使用DataInputStream去讀凌盯,并且讀的順序需要與寫(xiě)的順序保持一致付枫,才可以正常取出數(shù)據(jù)。
10十气、標(biāo)準(zhǔn)輸出流PrintStream 【日志工具的實(shí)現(xiàn)】
①PrintStream對(duì)象:
PrintStream pr = System.out; 【System.out是一個(gè)PrintStream對(duì)象】
標(biāo)準(zhǔn)輸出流不需要手動(dòng)關(guān)閉
②修改流的輸出方向:
不再打印到控制臺(tái)励背,而是指向“l(fā)og”文件
PrintStream pr = new PrintStream(new FileOutputStream("log.txt"));
System.setOut(pr); 【修改輸出方向,將輸出方向修改到log文件】
11砸西、對(duì)象流
①序列化叶眉、反序列化
序列化:serialize,將java對(duì)象存儲(chǔ)到文件中芹枷,將java對(duì)象的狀態(tài)保存下來(lái)的過(guò)程衅疙;
反序列化:deserialize,將硬盤上的數(shù)據(jù)重新恢復(fù)到內(nèi)存中鸳慈,恢復(fù)成java對(duì)象饱溢;
②參與序列化、反序列化的對(duì)象走芋,必須實(shí)現(xiàn)Serializable接口
③Serializable接口只是一個(gè)標(biāo)志接口绩郎,接口里面什么代碼都沒(méi)有
④標(biāo)志接口:里面都是空的潘鲫,沒(méi)有代碼,作用是給類添加一個(gè)標(biāo)志肋杖,java虛擬機(jī)在看到標(biāo)志后會(huì)分別作出不同處理
十溉仑、File類
File f = new File("C:\Users\Tong\Desktop\新建 文本文檔 (2).txt");
f.exists() 文件是否存在
f.createNewFile(); 創(chuàng)建文件
f.mkdir(); 創(chuàng)建目錄
f.mkdirs(); 創(chuàng)建多重目錄
f.getParent(); 獲取文件的父路徑String
f.getParentFile(); 獲取文件的父親File對(duì)象
f.getAbsolutePath(); 獲取文件的絕對(duì)路徑
f.getName(); 獲取文件名
f.isDirectory(); 判斷是否是目錄
f.isFile(); 判斷是否是文件
f.lastModified(); 獲取最后一次修改的時(shí)間戳
f.length(); 獲取文件大小(單位是字節(jié))
f.listFiles(); 獲取當(dāng)前目錄下所有的子文件
十一状植、多線程
視頻鏈接:https://www.bilibili.com/video/BV1Rx411876f?p=796&vd_source=451d825d8e1ffcbfd124804db3810f11
1浊竟、同一進(jìn)程的線程共享【堆內(nèi)存】、【方法區(qū)內(nèi)存】津畸;【棧內(nèi)存】獨(dú)立
2振定、實(shí)現(xiàn)多線程的三種方法:
①編寫(xiě)一個(gè)類,直接繼承java.lang.Tread肉拓,重寫(xiě)run方法:
public class MyThread extends Thread{
@Override
public void run(){
...
}
}
【如何使用】:在主函數(shù)中new出線程對(duì)象——>調(diào)用線程對(duì)象的start()方法
MyThread thread = new MyThread(); //創(chuàng)建線程對(duì)象
thread.start(); //啟動(dòng)線程
【start()方法的作用】:?jiǎn)?dòng)一個(gè)分支線程后频,在JVM中開(kāi)辟一個(gè)新的棧空間帝簇,只要椗枪空間開(kāi)出來(lái)靠益,start()方法就結(jié)束了丧肴,線程就啟動(dòng)成功了。啟動(dòng)成功的線程會(huì)自動(dòng)調(diào)用run方法胧后,并且將run方法壓入棧底部芋浮。
run方法在分支棧的棧底部,main方法在主棧的棧底部壳快,run和main是平級(jí)的纸巷。
②(使用較多)編寫(xiě)一個(gè)類,實(shí)現(xiàn)java.lang.Runnable接口眶痰,實(shí)現(xiàn)run方法:
public class MyThread implements Runnable{
@Override
public void run(){
...
}
}
【如何使用】:在主函數(shù)中new出Thread對(duì)象瘤旨,構(gòu)造函數(shù)中傳入一個(gè)Runnable對(duì)象——>調(diào)用Thread對(duì)象的start()方法
Thread s = new Thread(new MyThread()); //創(chuàng)建線程對(duì)象
s.start();
③實(shí)現(xiàn)Callable接口:【可以獲取到線程的返回值】
package com.test.javase;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) throws Exception{
//使用匿名內(nèi)部類的方式實(shí)現(xiàn)Callable接口
FutureTask task = new FutureTask(new Callable() {
//call()方法相當(dāng)于run()方法
public Object call() throws Exception {
Thread.sleep(1000);
int a = 3;
int b = 4;
return a + b;
}
});
//創(chuàng)建線程對(duì)象
Thread t = new Thread(task);
t.start();
//獲取到t線程的返回值
System.out.println(task.get()); //會(huì)阻塞當(dāng)前線程,因?yàn)橹挥挟?dāng)t線程執(zhí)行完才能夠拿到返回值
System.out.println(Thread.currentThread().getName());
}
}
3竖伯、線程生命周期:
start方法執(zhí)行完畢之后存哲,線程進(jìn)入就緒態(tài),開(kāi)始爭(zhēng)奪CPU時(shí)間片
JVM調(diào)度分配時(shí)間片
當(dāng)run方法使用完一個(gè)時(shí)間片后七婴,線程又進(jìn)入就緒態(tài)祟偷,等待JVM調(diào)度
當(dāng)run方法結(jié)束后進(jìn)入死亡狀態(tài)
4、線程對(duì)象的方法:
- setName("Thread-0") 設(shè)置線程名打厘;
- getName() 獲取線程名修肠;
- Thread.currentThread() 獲取當(dāng)前線程對(duì)象,這個(gè)方法出現(xiàn)在哪個(gè)線程的代碼中户盯,返回的就是哪個(gè)線程嵌施,類似于this饲化;
- Thread.sleep(1000L) 接收l(shuí)ong參數(shù),表示毫秒數(shù)吗伤;讓當(dāng)前線程進(jìn)入休眠(阻塞態(tài))滓侍,出現(xiàn)在哪個(gè)線程中,哪個(gè)線程就進(jìn)入休眠牲芋;
- interrupt() 中斷線程的休眠撩笆,喚醒線程(這種終斷睡眠的方式依靠了java的異常處理機(jī)制),會(huì)進(jìn)入sleep的catch語(yǔ)句塊中
- stop() 強(qiáng)制終止線程執(zhí)行缸浦,可能會(huì)導(dǎo)致丟失數(shù)據(jù)夕冲,不建議使用
- 合理結(jié)束線程:
package com.test.javase;
public class Test {
public static void main(String[] args) throws Exception{
MyThread t = new MyThread();
Thread s = new Thread(t);
s.start();
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
t.run = false; 手動(dòng)結(jié)束線程
}
}
class MyThread implements Runnable{
boolean run = true;
@Override
public void run(){
for(int i = 0; i < 10; i++){
if(run){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}else{
return就結(jié)束了,在結(jié)束前可以保存未保存的值
//終止當(dāng)前線程
return;
}
}
}
}
- setPriority() 設(shè)置線程優(yōu)先級(jí)裂逐,最高10歹鱼,最低1,默認(rèn)5卜高;
- getPriority() 獲取線程優(yōu)先級(jí)弥姻;
- Thread.yield() 暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程掺涛,會(huì)讓當(dāng)前進(jìn)程從運(yùn)行態(tài)進(jìn)入就緒態(tài)庭敦;
- t.join() 合并線程,當(dāng)前線程進(jìn)入阻塞薪缆,t線程執(zhí)行秧廉,直到t線程結(jié)束,當(dāng)前線程才可以繼續(xù)執(zhí)行拣帽;
- Thread.currentThread().getContextClassLoader().getResource("xml.txt").getPath() 獲取類路徑下xml.txt文件的絕對(duì)路徑
5疼电、java線程調(diào)度
java線程調(diào)度策略采用的是【優(yōu)先級(jí)搶占式調(diào)度】
6、線程安全
①java中保證線程安全的關(guān)鍵是使用【線程同步】
②局部變量永遠(yuǎn)不會(huì)存在線程安全的問(wèn)題减拭,因?yàn)榫植孔兞吭跅V胁还蚕肀尾颍粋€(gè)線程一個(gè)棧;實(shí)例變量(在堆中)和靜態(tài)變量(在方法區(qū))可能存在線程安全
③synchronized:
synchronized的用法:
synchronized (XX) { ... }
假設(shè)有[t1拧粪、t2修陡、t3、t4既们、t5]幾個(gè)線程濒析,此時(shí)希望t1、t2啥纸、t5同步進(jìn)行某項(xiàng)操作号杏,這時(shí)XX傳入的就是t1、t2、t5共享的一個(gè)對(duì)象盾致,希望同步執(zhí)行的代碼塊寫(xiě)入synchronized中主经,執(zhí)行時(shí)java會(huì)給該對(duì)象加對(duì)象鎖(只支持獨(dú)占式訪問(wèn))
- 同步的代碼塊越少,效率越高
- synchronized出現(xiàn)在實(shí)例方法上作為修飾關(guān)鍵字時(shí)庭惜,一定鎖的是this(括號(hào)中傳入的對(duì)象是this)罩驻,不能修改,所以這種方式不靈活护赊。同時(shí)整個(gè)方法體都需要同步惠遏,可能會(huì)無(wú)故擴(kuò)大同步范圍,導(dǎo)致程序的執(zhí)行效率降低骏啰。如果共享的對(duì)象就是this节吮,并且需要同步的代碼塊是整個(gè)方法體,建議使用這種方式判耕。
④synchronized的寫(xiě)法:
- 同步代碼塊
public void test(){
...
synchronized (XX) {
需要同步的代碼塊...
}
...
}
- 作為修飾關(guān)鍵字
public synchronized void test(){
需要同步的代碼塊...
}
- 在靜態(tài)方法上使用synchronized:
表示找類鎖透绩,類鎖永遠(yuǎn)只有一把,就算創(chuàng)建多個(gè)對(duì)象壁熄,類鎖也只有一把帚豪。
對(duì)象鎖:1個(gè)對(duì)象1把鎖
類鎖:類鎖只有一把,用于保證靜態(tài)變量的安全
public synchronized static void test(){
需要同步的代碼塊...
}
⑤死鎖:synchronized最好不要嵌套使用草丧,可能會(huì)引起死鎖
死鎖例子:
public class Test {
public static void main(String[] args) throws Exception{
Object o1 = new Object();
Object o2 = new Object();
MyThread1 t1 = new MyThread1(o1, o2);
MyThread2 t2 = new MyThread2(o1, o2);
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1, Object o2) {
super();
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (o2) {
}
}
}
}
class MyThread2 extends Thread{
Object o1;
Object o2;
public MyThread2(Object o1, Object o2) {
super();
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (o1) {
}
}
}
}
7狸臣、守護(hù)線程
①概念:
- java中線程分為兩大類:用戶線程、守護(hù)線程(后臺(tái)線程)
- 垃圾回收線程就是一個(gè)守護(hù)線程方仿,main方法是一個(gè)用戶線程固棚;
- 特點(diǎn):守護(hù)線程一般是一個(gè)死循環(huán),所有的用戶線程結(jié)束仙蚜,守護(hù)線程會(huì)自動(dòng)結(jié)束
- t.setDaemon(true):將一個(gè)用戶線程設(shè)置為守護(hù)線程
②定時(shí)器:
實(shí)現(xiàn)方式:
- 可以使用sleep方法,設(shè)置睡眠時(shí)間厂汗,每到這個(gè)時(shí)間點(diǎn)醒來(lái)委粉,執(zhí)行任務(wù)。這種方法是最原始的定時(shí)器娶桦;
- 在java類庫(kù)中已經(jīng)寫(xiě)好了一個(gè)定時(shí)器贾节,java.util.Timer呛梆,可以直接使用锡搜;
- 實(shí)際開(kāi)發(fā)中使用較多的是Spring框架中提供的SpringTask框架,這個(gè)框架只需要簡(jiǎn)單的配置就可以完成定時(shí)器的任務(wù)丹拯。
8祈争、wait斤程、notify方法
- wait、notify方法不是線程對(duì)象的方法菩混,是java對(duì)象都有的方法忿墅;
- wait扁藕、notify方法都建立在線程同步的基礎(chǔ)上,因?yàn)槎嗑€程要同時(shí)操作一個(gè)倉(cāng)庫(kù)疚脐,存在線程安全問(wèn)題亿柑;
- o.wait()方法讓正在o對(duì)象上活動(dòng)的線程t進(jìn)入等待狀態(tài),并且釋放t線程之前占有的o對(duì)象的鎖棍弄;
- 生產(chǎn)者望薄、消費(fèi)者模式:
package com.test.javase;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception{
List list = new ArrayList<Object>();
Thread t1 = new Thread(new Producer(list));
Thread t2 = new Thread(new Customer(list));
t1.start();
t2.start();
}
}
class Producer implements Runnable{
List list;
public Producer(List list) {
this.list = list;
}
@Override
public void run() {
while(true){
synchronized (list) {
if(list.size() > 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(new Object());
System.out.println("生產(chǎn)者生產(chǎn)了:"+list.get(0));
list.notify();
}
}
}
}
class Customer implements Runnable{
List list;
public Customer(List list) {
this.list = list;
}
@Override
public void run() {
while(true){
synchronized (list) {
if(list.size() == 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object obj = list.remove(0);
System.out.println("消費(fèi)者消費(fèi)了:"+obj);
list.notify();
}
}
}
}
十二、反射機(jī)制
視頻鏈接:https://www.bilibili.com/video/BV1Rx411876f?p=810
1呼畸、基礎(chǔ)概念
- 通過(guò)反射機(jī)制可以操作字節(jié)碼文件
- 通過(guò)使用反射機(jī)制可以直接用類名創(chuàng)建對(duì)象式矫,使程序變得更加靈活
- 反射機(jī)制的相關(guān)類在 java.lang.reflect.* 包下
- 反射機(jī)制相關(guān)的重要類:
java.lang.Class; 代表整個(gè)字節(jié)碼,整個(gè)類
java.lang.reflect.Method; 代表字節(jié)碼中的方法字節(jié)碼役耕。代表類中的方法
java.lang.reflect.Constructor; 代表字節(jié)碼中的構(gòu)造方法字節(jié)碼采转。代表類中的構(gòu)造函數(shù)
java.lang.reflect.Field; 代表字節(jié)碼中的屬性字節(jié)碼。代表類中的成員變量 - 如果只希望一個(gè)類的靜態(tài)代碼塊執(zhí)行瞬痘,其他代碼一律不執(zhí)行故慈,可以使用:
Class.forName("完整類名");
這個(gè)方法的執(zhí)行會(huì)導(dǎo)致類加載,類加載時(shí)框全,靜態(tài)代碼塊執(zhí)行察绷。
2、獲取Class的三種方式
-
Class.forName("完整類名");
Class c = Class.forName("java.lang.String"); -
對(duì)象.getClass();
String s = "abc";
Class c = s.getClass(); -
類.class;
Class c = String.class;
3津辩、通過(guò)讀屬性文件實(shí)例化對(duì)象
//獲取絕對(duì)路徑的方式
//String path = Thread.currentThread().getContextClassLoader().getResource("xml").getPath()
//FileReader reader = new FileReader(path);
//直接以流的形式返回
InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("xml");
Properties pro = new Properties(); //key value都是String
//將xml文件鍵值對(duì)加載到pro集合中
pro.load(reader);
//關(guān)閉流
reader.close();
//通過(guò)key獲取value
Class a = Class.forName(pro.getProperty("ClassName"));
//實(shí)例化對(duì)象
Object obj = a.newInstance();
4拆撼、資源綁定器
- java.util包下提供了一個(gè)資源綁定器,便于獲取【屬性配置文件】中的內(nèi)容喘沿;
- 資源綁定器只能綁定xxx.properties文件闸度,且該文件必須在類路徑下(bin或者src文件夾中);
- 在寫(xiě)路徑的時(shí)候蚜印,文件名不需要帶擴(kuò)展名莺禁;
- 例如:
ResourceBundle bundle = ResourceBundle.getBundle("xml");
String className = bundle.getString("ClassName");
System.out.println(className);
5、反射屬性Field
- ①獲取類的屬性Field:
Class studentClass = Student.class;
//只能獲取public修飾的field
Field[] fields = studentClass.getFields();
for(Field f : fields){
System.out.println(f.getName());
}
//獲取所有的field
Field[] allFields = studentClass.getDeclaredFields();
for(Field f : allFields){
System.out.println("屬性名:"+f.getName());
System.out.println("類型:"+f.getType().getSimpleName());
System.out.println("修飾符:"+Modifier.toString(f.getModifiers()));
System.out.println("---------");
}
- ②反編譯:
可以通過(guò)class文件反編譯出它含有的屬性窄赋、方法等 - ③通過(guò)反射機(jī)制訪問(wèn)對(duì)象屬性(賦值哟冬、取值):
Class studentClass = Student.class;
Object obj = studentClass.newInstance();
Field id = studentClass.getDeclaredField("id");
id.set(obj, "123k"); //給obj對(duì)象的id屬性賦值
System.out.println(id.get(obj)); //取出obj對(duì)象的id屬性值
- ④訪問(wèn)private私有變量:age.setAccessible(true);打破封裝
Field age = studentClass.getDeclaredField("age");
age.setAccessible(true);
age.set(obj, 12);
System.out.println(age.get(obj));
6、反射Method
①反編譯Method:
public static void main(String[] args) throws Exception{
Class studentClass = Student.class;
Method[] methods = studentClass.getDeclaredMethods();
for(Method m : methods){
System.out.println("修飾符:" + Modifier.toString(m.getModifiers()));
System.out.println("返回類型:" + m.getReturnType().getSimpleName());
System.out.println("方法名:" + m.getName());
StringBuffer s = new StringBuffer();
Class[] parameterTypes = m.getParameterTypes();
for(Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName() + " ");
}
System.out.println("參數(shù)類型列表:" + s);
System.out.println();
}
}
②反射機(jī)制調(diào)用方法:【*******五顆星重點(diǎn)*******】
視頻鏈接:https://www.bilibili.com/video/BV1Rx411876f?p=830&vd_source=451d825d8e1ffcbfd124804db3810f11
原類中的方法:
public int test2(int i, Boolean b){
System.out.println("測(cè)試方法2");
if(b) return 1;
return 0;
}
反射機(jī)制調(diào)用test2方法:
//獲得class
Class studentClass = Student.class;
//實(shí)例化對(duì)象
Object obj = studentClass.newInstance();
//反射Method:傳入方法名忆绰、方法參數(shù)類型浩峡,用以區(qū)分【方法重載】
Method method = studentClass.getDeclaredMethod("test2", int.class, Boolean.class);
反射機(jī)制調(diào)用方法
/*四要素:
method方法、
obj對(duì)象错敢、
1, true 實(shí)參
res返回值
*/
Object res = method.invoke(obj, 1, true);
System.out.println(res);
7翰灾、反射Constructor
反射機(jī)制調(diào)用構(gòu)造方法:
先獲取到有參數(shù)的構(gòu)造方法,調(diào)用構(gòu)造方法new對(duì)象
public static void main(String[] args) throws Exception{
Class studentClass = Student.class;
//無(wú)參數(shù)構(gòu)造函數(shù)
Object obj = studentClass.newInstance();
//獲取到帶參數(shù)構(gòu)造方法
Constructor con = studentClass.getDeclaredConstructor(String.class, String.class, int.class);
//使用該構(gòu)造方法new對(duì)象
Object newObj = con.newInstance("1120abc", "laowang", 23);
System.out.println(newObj.toString());
}
8、獲取父類和父接口
public static void main(String[] args) throws Exception{
Class studentClass = Student.class;
//獲取繼承的父接口
Class[] interfaces = studentClass.getInterfaces();
for(Class i : interfaces){
System.out.println(i.getSimpleName());
}
//獲取父類
Class superClass = studentClass.getSuperclass();
System.out.println(superClass.getSimpleName());
}
十三预侯、注解
①基礎(chǔ)概念:
注解Annotation是一種引用數(shù)據(jù)類型致开,編譯之后也是生成xxx.class文件;
②自定義注解:
[修飾符列表] @interface 注解類型名{
}
例如:
public @interface MyAnnotation {
}
③使用注解:
@注解名
注解可以出現(xiàn)在類上萎馅、屬性上双戳、方法上、變量上糜芳、注解上......
④JDK內(nèi)置的注解:
- @Deprecated:表示標(biāo)注的這個(gè)類飒货、方法等已過(guò)時(shí)
- @Override:只能注解方法。是給編譯器參考的峭竣,跟運(yùn)行階段沒(méi)關(guān)系塘辅;凡是java方法中帶有這個(gè)注釋的,編譯器都會(huì)進(jìn)行編譯檢查皆撩,如果這個(gè)方法不是重寫(xiě)父類的方法扣墩,編譯器會(huì)報(bào)錯(cuò)。
⑤元注解:
修飾注解的注解稱為元注解扛吞,例如:
- Target:用來(lái)標(biāo)注“被標(biāo)注的注解”可以出現(xiàn)在哪些位置上呻惕;
@Target(ElementType.METHOD):表示該注解只能出現(xiàn)在方法上; - Retention:用來(lái)標(biāo)注“被標(biāo)注的注解”最終保存在哪里滥比;
@Retention(RetentionPolicy.SOURCE):表示該注解只被保留在java源文件中亚脆;
@Retention(RetentionPolicy.CLASS):表示該注解被保存在calss文件中;
@Retention(RetentionPolicy.RUNTIME):表示該注解被保存在calss文件中盲泛,并且可以被反射機(jī)制讀取濒持。
⑥注解中定義屬性:
- 語(yǔ)法:
public @interface MyAnnotation {
//name屬性
String name();
int age() default 25; //指定默認(rèn)值
}
如果一個(gè)注解當(dāng)中有屬性,那么使用該注解時(shí)一定要給屬性賦值寺滚,除非有默認(rèn)值:
@MyAnnotation(屬性名=屬性值)如果屬性名是“value”并且只有一個(gè)屬性柑营,使用注解時(shí),屬性名可以省略:
定義:String value();
使用:@MyAnnotation("hello")注解中屬性允許的類型:
byte short int long float double boolean char String Class 枚舉
以及以上每一種的數(shù)組形式
⑦反射注解:
被反射的注解必須要被保存在class文件中玛迄,要能被反射機(jī)制讀取由境,即:
@Retention(RetentionPolicy.RUNTIME)反射機(jī)制獲取到注解對(duì)象的屬性:
Class stuClass = Student.class;
if(stuClass.isAnnotationPresent(MyAnnotation.class)){ //判斷是否存在該注解
MyAnnotation myAnnotation = (MyAnnotation)stuClass.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.age());
}