一:Java簡介
1. Java語言的介紹:Java是一門物件導向程式語言,具有功能強大和簡單易用兩個特徵。
2. Java語言的特點:簡單性、物件導向、分散式、健壯性、安全性、平臺獨立與可移植性、多執行緒、動態性等
3. Java語言的應用:編寫桌面應用程式、Web應用程式、分散式系統和嵌入式系統應用程式等
二:Java自學路線圖
三:Java基礎
一、識別符號和關鍵字
1. 識別符號
1. 在java語言中,用來標誌類名、物件名、變數名、方法名、型別名、陣列名、包名的有效字元序列,稱為“識別符號”;
2. 識別符號由字母、數字、下劃線、美元符號組成,且第一個字元不能是數字;
3. java語言區分大小寫;
4. 標誌符命名規則:類名首字母大寫,變數名和方法名採用駝峰標誌法,包名全小寫,常量全大寫,多個單詞之間用“_”隔開;
2. 關鍵字
1. 在java語言中,有一些專門的詞彙已經被賦予了特殊的含義,不能再使用這些詞彙來命名識別符號,這些專有詞彙,稱為“關鍵字”;
2. java有50個關鍵字和3個保留字,均不能用來命名識別符號;
3. true、false、null不是關鍵字,是保留字,但是仍不能用來命名識別符號;
二、資料型別
三、運算子與表示式
1. 算數運算子:加(+),減(-),乘(*),除(/),求餘(%)
2. 賦值運算子:=,+=,-=,*=,%=
3. 關係運算子:>,<,>=,<=,==,!=
4. 邏輯運算子:[&&,||](只有左側滿足才計算右側),!,[&,|](不管左側結果如何,都要計算右側)
5. 三目運算子:(表示式) ? 值1,值2;
四:流程控制語句
1. 條件分支語句:if語句,switch語句
2. 迴圈語句:while迴圈,do while迴圈,for迴圈,foreach迴圈
四:陣列
1. 宣告陣列:
1. 靜態初始化: 資料型別 [ ]... 陣列名 = {值1,值2,...}
2. 動態初始化:資料型別 [ ]... 陣列名 = new 資料型別[長度];
2. 列印陣列:foreach迴圈
3. 陣列排序:氣泡排序,選擇排序,反轉排序,插入排序
4. Arrays工具類:
1. 排序
1. 實現Comparable介面:Arrays.sort(要排序的陣列)
2. 實現Comparator介面:Arrays.sort(要排序的陣列,new Comparator);
2. 二分法查詢:binarySearch(要查詢的陣列,要查詢的值),必須提前拍好序
3. 陣列元素比較:Arrays.equals(陣列1,陣列2)
4. 陣列填充:Arrays.fill(要填充的陣列,值)
import java.util.Arrays; public class TestArray { public static void main(String[] args) { // 陣列的靜態初始化 int[] array1 = { 1, 3, 5, 6, 7, 2, 4, 10 }; // 陣列的動態初始化 int[] array2 = new int[5]; array2[0] = 1; array2[1] = 2; array2[2] = 7; array2[3] = 3; array2[4] = 4; // for迴圈列印陣列 for (int i = 0; i < array2.length; i++) { System.out.print (array2[i]); } // foreach列印陣列 for (int i : array2) { System.out.print(i); } // 排序 Arrays.sort(array2); for (int i : array2) { System.out.print(i); } // 二分法查詢 System.out.print(Arrays.binarySearch(array2, 3)); // 陣列元素比較 System.out.println(Arrays.equals(array1, array2)); // 陣列元素填充 Arrays.fill(array2, 1); for (int j : array2) { System.out.println(j); } } }
五:物件導向
一、封裝
1. 核心思想:隱藏細節,保護資料安全。
2. 訪問許可權
public class Encapsulation { // 1.成員屬性私有化 private String name; private String pwd; // 2.提供getter和setter方法來訪問 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } } class TestEncapsulation { public static void main(String[] args) { Encapsulation test = new Encapsulation(); // 3.通過setter方法設定屬性值 test.setName("封裝"); test.setPwd("666"); // 4.通過getter方法獲取值 System.out.println("姓名:" + test.getName() + " -- 密碼:" + test.getPwd()); } }
二、方法的過載和重寫
1. 方法的過載:方法名相同,引數列表不同
2. 方法的重寫:方法名、返回值型別、引數列表都相同,構造方法和使用final、static修飾的方法不能被重寫
三、繼承
1. 核心思想:解決程式碼冗餘,提高程式碼的複用性
2. 繼承關係:滿足is-a的關係,父類更通用,子類更具體。
/** * 1. 將類中重複的部分提取成為父類 */ public class Animal { private String name; private String food; public Animal(String name, String food) { this.name = name; this.food = food; } public void eat() { System.out.println(name + "正在吃" + food); } } /** * 2. 子類繼承父類,對父類進行擴充套件 */ public class Cat extends Animal { public Cat(String name, String food) { super(name, food); } } public class Dog extends Animal{ public Dog(String name, String food) { super(name, food); } } /** * 3. 測試 */ public class TestExtends{ public static void main(String[] args) { Animal cat = new Cat("三三", "魚"); cat.eat(); Animal dog = new Dog("二哈", "香腸"); cat.eat(); } }
四、多型
1. 核心思想:提高程式碼可維護性和可擴充套件性
2. 實現多型的三個必要條件:繼承、重寫、父類引用指向子類物件(向下轉型)
3. 多型的實現方式:重寫、介面、抽象類和抽象方法
/** * 1. 建立動物類,定義動物吃什麼的方法 */ class Animals { private String name; private String food; public Animals(String name, String food) { super(); this.name = name; this.food = food; } public void eat() { System.out.println(this.name + "會吃" + this.food); } } /** * 2. 建立Cat類來實現吃的功能 */ class Cat extends Animals{ public Cat(String name, String food) { super(name, food); } @Override public void eat() { super.eat(); } } /** * 3. 通過向上轉型和向下轉型實現多型 */ public class Test01 { public static void main(String[] args) { // 向下轉型 Animals animals = new Cat("三三", "魚"); animals.eat(); // 向上轉型 Cat cat = (Cat) animals; cat.eat(); } }
五、抽象類
1. 核心思想:讓程式碼有更強的可擴充套件性
2. 特點:
1. 抽象類不能例項化物件。
2. 如果一個類包含抽象方法,那麼該類必須是抽象類。
3. 任何子類必須重寫父類的抽象方法(具體實現),或者宣告自身為抽象類。
4. 抽象類中的抽象方法只有方法宣告,沒有方法體
5. 構造方法和static修飾的方法不能宣告為抽象方法
/** * 1. 建立員工抽象類 */ abstract class Employees { // 成員變數 private String name; private String address; private Integer number; // 構造方法 public Employees(String name, String address, Integer number) { System.out.println("Employees.Employees()"); this.name = name; this.address = address; this.number = number; } // 定義資訊抽象函式 public abstract void call(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Integer getNumber() { return number; } public void setNumber(Integer number) { this.number = number; } } class Salary extends Employees { private Double salary; public Salary(String name, String address, Integer number, Double salary) { super(name, address, number); this.salary = salary; System.out.println("Salary.Salary()"); } // 2. 重寫父類的抽象方法 @Override public void call() { System.out.println(super.getNumber() + "是" + super.getName() + "的電話,他住在" + super.getAddress() + "他現在的工資是" + this.salary); } } public class Test { public static void main(String[] args) { // 3. 抽象類的物件必須由子類去例項化 Employees emp = new Salary("孫悟空", "花果山", 1234, 222.66); emp.call(); } }
六、介面
1. 核心思想:讓程式碼有更強的可擴充套件性
2. 特點:
1. 介面不能例項化物件,沒有構造方法
2. 介面中的方法只能是抽象方法,預設使用public abstract修飾
3. 介面中的變數只能是常量,預設使用public static final修飾
4. 介面支援多繼承,但介面不是被繼承了,而是被實現了
3. 介面和抽象類的區別
1. 介面中的方法只能是抽象方法,而抽象類中的方法可以是普通方法,構造方法和抽象方法
2. 介面中的變數只能是常量,而抽象類中的方法可以是任意型別
3. 介面中不能含有靜態程式碼塊和靜態方法,而抽象類中可以有
4. 一個類可以實現多個介面,但一個類只能繼承一個抽象類
/** * 1. 建立Animal介面 */ interface Animal { // 定義睡覺抽象方法 void sleep(); // 定義吃飯抽象方法 void eat(); } /** * 2. 建立Dog介面繼承Animal介面 */ interface Dog extends Animal { // 定義游泳抽象方法 void swim(); } /** * 3. 建立HaShiQi介面繼承Dog和Animal介面,實現多繼承 */ interface HaShiQi extends Dog, Animal { // 定義拆家抽象方法 void demolishedFamily(); } /** * 4. 建立測試類來實現介面,並且複寫所有抽象方法 */ public class TestAnimal implements HaShiQi { @Override public void swim() { System.out.println("哈士奇會游泳"); } @Override public void sleep() { System.out.println("哈士奇會睡覺"); } @Override public void eat() { System.out.println("哈士奇喜歡吃苦瓜"); } @Override public void demolishedFamily() { System.out.println("哈士奇會拆家"); } public static void main(String[] args) { // 使用多型例項化物件 HaShiQi dog = new TestAnimal(); dog.eat(); dog.sleep(); dog.demolishedFamily(); dog.swim(); } }
六:集合
一、集合簡介
集合的主要作用是儲存引用型別資料,長度可以動態的改變,解決了儲存資料數量不確定的問題
二、Collection集合體系
一、Collection常用方法
二、不同集合的使用場景
import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 建立學生類 */ class Student { // 學號 private Integer id; // 姓名 private String name; public Student(Integer id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } } public class TestCollection { public static void main(String[] args) { // 1. 建立集合儲存String型別資料 List<String> list = new ArrayList<String>(); // 2.向集合中新增元素 list.add("豬豬俠"); list.add("超人強"); list.add("波比"); list.add("小菲菲"); // 3. 遍歷集合 // 3.1普通for迴圈 String[] strArray = new String[list.size()]; list.toArray(strArray); // 將集合轉換為陣列 for (int i = 0; i < strArray.length; i++) { System.out.println(strArray[i]); } // 3.2 foreach迴圈 for (String str : list) { System.out.println(str); } // 3.3 迭代器遍歷 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { // hasNext():判斷指標後是否有下一個元素 System.out.println(iterator.next()); // next():返回指標後的元素 } // 4. 判斷集合中是否包含某元素 System.out.println(list.contains("小菲菲")); // true // 5. 判斷集合是否為空 System.out.println(list.isEmpty()); // false // 6. 清除集合中所有元素 list.clear(); System.out.println(list.isEmpty()); // true System.out.println("---------------------------------------------------"); // 建立集合儲存物件型別資料 List<Student> list2 = new ArrayList<Student>(); // 向集合中新增物件型別資料 list2.add(new Student(1, "張三")); list2.add(new Student(2, "李四")); // foreach遍歷集合 for (Student student : list2) { System.out.println(student); } // 迭代器遍歷集合 Iterator<Student> iterator2 = list2.iterator(); while (iterator2.hasNext()) { Student student = iterator2.next(); System.out.println(student); } } }
三、Map集合體系
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.enterprise.inject.New; class Teacher { private String name; private Integer age; public Teacher(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Teacher [name=" + name + ", age=" + age + "]"; } } public class TestMap { public static void main(String[] args) { // 1. 建立Map集合儲存學號和姓名 Map<Integer, String> map = new HashMap<Integer, String>(); // 2. 向map集合中新增元素 map.put(1, "張三"); map.put(2, "李四"); map.put(3, "王五"); // 3. 遍歷map集合 // 3.1 通過map.keySet()遍歷集合 for (Integer key : map.keySet()) { System.out.println("key=" + key + " value=" + map.get(key)); } // 3.2 通過迭代器遍歷集合 Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Integer, String> entry = iterator.next(); System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); } // 3.3 通過map.entrySet()遍歷集合 for (Entry<Integer, String> entry : map.entrySet()) { System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); } // 4. 判斷集合中是否包含指定鍵 System.out.println(map.containsKey("1")); // true System.out.println(map.containsValue("list")); // false // 5. 判斷集合是否為空 System.out.println(map.isEmpty()); // false // 6. 清除集合中所有元素 map.clear(); System.out.println(map.isEmpty()); // true System.out.println("----------------------------------------"); // 1. 建立Map集合儲存物件型別資料 Map<Integer, Teacher> map2 = new HashMap<Integer, Teacher>(); // 2. 向Map集合中新增物件型別資料 map2.put(1, new Teacher("張三", 18)); map2.put(2, new Teacher("李四", 19)); map2.put(3, new Teacher("王五", 20)); // 3. 遍歷集合 // 3.1 通過map.keySet()遍歷 for (Integer key : map2.keySet()) { System.out.println("key=" + key + " value=" + map2.get(key)); } // 3.2 通過迭代器遍歷集合 Iterator<Entry<Integer, Teacher>> iterator2 = map2.entrySet().iterator(); while (iterator2.hasNext()) { Entry<Integer, Teacher> entry = iterator2.next(); System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); } // 3.3 通過map.entrySet()遍歷集合 for (Entry<Integer, Teacher> entry : map2.entrySet()) { System.out.println("key=" + entry.getKey() + " value=" + entry.getValue()); } } }
七:IO流
一、IO流簡介
1. 流的概念:流是有起點和終點的一組有順序的位元組集合,作用是進行資料傳輸
2. 流的分類:
1. 按照資料流向不同可以分為輸入輸出流;
2. 按照處理資料單位不同可以分為位元組流和字元流
3. 輸入流和輸出流的作用
1. 輸入流:程式從資料來源讀取資料
2. 輸出流:將資料從程式中寫入指定檔案
4. 位元組流和字元流的作用
1. 位元組流:以位元組為單位處理所有型別資料
2. 字元流:以字元為單位處理純文字檔案
二、IO流體系
三、IO流常用方法
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /** * 1. 文字檔案複製 * @author DELL * */ public class TestIO { public static void main(String[] args) { // 要讀取的檔案 String src = "E:/Workspaces1/Demo/src/TestFile.java"; // 要寫入的檔案 String dest = "d:/test.java"; // 1.1 一次複製一個位元組 copyFile1(src, dest); // 1.2 一次複製一個位元組陣列 copyFile2(src, dest); // 2.1 一次複製一個字元 copyFile3(src, dest); // 2.2 一次複製一個字元陣列 copyFile4(src, dest); } // 1. 一次複製一個位元組,異常處理,手動關閉流 public static void copyFile1(String srcFileName, String destFileName) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(srcFileName); fos = new FileOutputStream(destFileName); int cc = fis.read(); while (cc != -1) { // 一次寫入一個位元組 fos.write(cc); // 一次寫入一個位元組 cc = fis.read(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 2. 一次複製一個位元組陣列,異常處理,自動關閉流 public static void copyFile2(String srcFileName, String destFileName) { // 自動關閉流 try ( FileInputStream fis = new FileInputStream(srcFileName); FileOutputStream fos = new FileOutputStream(destFileName); ) { byte[] bytes = new byte[1024]; int len = fis.read(bytes); while (len != -1) { // 一次寫入一個位元組陣列 fos.write(bytes, 0, len); // 一次讀取一個位元組陣列 len = fis.read(bytes); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // 3. 一次複製一個字元,異常處理,自動關閉流 public static void copyFile3(String srcFileName, String destFileName) { try ( FileReader fr = new FileReader(srcFileName); FileWriter fw = new FileWriter(destFileName); ){ int cc = fr.read(); while (cc != -1) { // 一次寫入一個字元 fw.write(cc); // 一次讀取一個字元 cc = fr.read(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } // 4. 一次複製一個字元陣列,異常處理,手動關閉流 public static void copyFile4(String srcFileName, String destFileName) { FileReader fr = null; FileWriter fw = null; try { fr = new FileReader(srcFileName); fw = new FileWriter(destFileName); char[] cbuf = new char[1024]; int len = fr.read(cbuf); while (len != -1) { // 一次寫入一個字元陣列 fw.write(cbuf); // 一次讀取一個字元陣列 len = fr.read(cbuf); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fw != null) { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } if (fr != null) { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * 1. 序列化和反序列化的概念 * 1. 物件序列化:把物件轉換為位元組序列(二進位制資料)的過程 * 2. 物件反序列化:把位元組序列恢復為物件的過程 * * 2. 什麼情況下需要序列化: * 1. 將物件儲存到檔案或資料庫中時 * 2. 使用套接字在網上傳送物件時 * 3. 通過RMI傳輸物件時 * * 3. 如何實現序列化 * 1. 建立類實現Serializable介面 * 2. 指定serialVersionUID序列號 * 3. 使用物件輸出流(ObjectOutputStream)將物件儲存到指定位置 * 4. 使用writerObject()方法將物件寫入到檔案中 * * * 4. 哪些屬性不能被序列化 * 1. 使用transient修飾的屬性 * 2. 使用static修飾的屬性 * */ // 1. 建立類實現Serializable介面 class People implements Serializable { // 2. 指定序列號 private static final long serialVersionUID = 1L; // 靜態欄位 private static String id = "2019"; // transient關鍵字修飾的欄位 private transient String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "People [name=" + name + ", age=" + age + "]"; } } public class Test { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { serializePeople(); deserializePeople(); } /** * 序列化 */ public static void serializePeople() throws FileNotFoundException, IOException { People p = new People(); p.setName("張三"); p.setAge(18); // 3. 使用物件輸出流將物件儲存到指定位置 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:/test.txt"))); // 4. 將物件寫入檔案 oos.writeObject(p); System.out.println("物件序列化成功!!"); oos.close(); } /** * 反序列化 */ public static People deserializePeople() throws ClassNotFoundException, IOException { // 使用物件輸入流從指定位置讀取物件 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:/test.txt"))); // 讀取物件 People p = (People) ois.readObject(); System.out.println("物件反序列化成功!!"); return p; } }
四、File類常用方法
import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.text.SimpleDateFormat; public class TestFile { public static void main(String[] args) throws IOException { // 1. 構造方法指明檔案路徑以及格式 File file = new File("D:\\test2\\test.txt"); File file2 = new File("D:\\test2"); File file3 = new File("D:\\test3"); // 2.1 建立一個檔案 file.createNewFile(); // 2.2 建立一個單級目錄 file2.mkdir(); // 2.3 建立一個多級目錄 file3.mkdirs(); // 3.1 判斷檔案或資料夾是否存在 System.out.println(file.exists()); // true // 3.2 判斷是否為絕對路徑 System.out.println(file.isAbsolute()); // true // 3.3 判斷是否為檔案 System.out.println(file2.isFile()); // false // 3.4 判斷是否為目錄 System.out.println(file2.isDirectory()); // true // 3.5 判斷是否為隱藏檔案 System.out.println(file3.isHidden()); // false // 4.1 獲取檔案或目錄名稱 System.out.println(file.getName()); // 4.2 獲取檔案的絕對路徑 System.out.println(file.getAbsolutePath()); // 4.3 獲取檔案相對路徑 System.out.println(file.getPath()); // 4.4 獲取檔案父目錄 System.out.println(file.getParent()); // 4.5 獲取檔案大小 System.out.println(file.length()); // 4.6 獲取檔案最後一次被修改時間 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String updateTime = sdf.format(file.lastModified()); System.out.println(updateTime); // 5.1 返回此目錄下的所有檔案和目錄 String [] fileString = file2.list(); for (String str : fileString) { System.out.println(str); } // 5.2 返回此目錄下的所有檔案 File [] files = file2.listFiles(); for (File file4 : files) { System.out.println(file4.getName()); } // 5.3 返回所有根目錄 File [] files2 = File.listRoots(); for (File file4 : files2) { System.out.println(file4); } // 5.4 返回指定目錄中符合過濾條件的檔案和目錄 File [] files3 = file2.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { while ("a.txt".equals(pathname.getName())){ return true; } return false; } }); for (File file4 : files3) { System.out.println(file4.getName()); } } }
八:多執行緒
一、執行緒相關概念
1. 執行緒和程式
1. 程式:作業系統中的應用程式,一個程式就是一個應用程式
2. 執行緒:CPU排程的最小單元,程式的一個執行流
2. 上下文切換
1. 上下文切換:CPU從一個執行緒或程式切換到另一個程式或執行緒;
2. 多執行緒程式並不是同時進行的,由於CPU的執行速度太快,CPU會在不同的執行緒之間快速的切換執行;
二、多執行緒的三種實現方式及優缺點
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; /** * 1. 建立多執行緒的三種方式 * 1. 繼承Thread類 * * 2. 實現Runnable介面 * 1. 方式一:建立類實現Runnable介面 * 1. 建立類實現Runnable介面 * 2. 重寫run()方法 * 3. 使用Thread類的構造方法例項化實現Runnable介面的類物件 * 4. 開啟執行緒 * * 2. 方式二:使用匿名內部類 * 1. 使用Thread類的構造方法建立一個Runnable介面的代理物件 * 2. 重寫run()方法 * 2. 開啟執行緒 * * 3. 實現Callable介面 * 1. 方式一:建立類實現Callable介面 * 1. 建立類實現Callable介面 * 2. 重寫call()方法 * 3. 使用Thread類的構造方法例項化FutureTask物件 * 4. 使用FutureTask類的構造方法例項化實現了Callable介面的類物件 * 5. 開啟執行緒 * * 2. 方式二:使用匿名內部類 * 1. 使用Thread類的構造方法例項化FutureTask物件 * 2. 使用FutureTask類的構造方法建立Callable介面的代理物件 * 3. 重寫call()方法 * 4. 開啟執行緒 * * 2. 三種方式的優缺點 * 1. 繼承了Thread類 * 1. 優點:程式碼書寫簡單 * 2. 缺點:由於Java的單繼承性,程式碼的耦合度比較高 * * 2. 實現了Runnable介面和Callable介面 * 1. 方式一: * 1. 優點:程式碼的可擴充套件性更強 * 2. 缺點:沒有缺點 * * 2. 方式二: * 1. 優點:程式碼書寫簡單 * 2. 缺點:只適合執行緒使用一次的時候 */ /** * 1. 繼承Thread類 */ class Thread1 extends Thread{ public static void test() { for (int i = 0; i < 100; i++) { System.out.println("繼承Thread類執行的第" + i + "次"); } } } /** * 2. 實現Runnable介面 */ class Thread2 implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("實現Runnable介面方式一執行的第" + i + "次"); } } } /** * 3. 實現Callable介面 */ class Thread3 implements Callable<Integer>{ @Override public Integer call() throws Exception { int i = 0; for (; i < 100; i++) { System.out.println("實現Callable介面方式一執行的第" + i + "次"); } return i; } } public class TestThread { public static void main(String[] args) { // 1. 測試繼承Thread類 Thread1 thread1 = new Thread1(); thread1.start(); Thread1.test(); // 2. 測試實現Runnable介面 // 2.1 方式一 new Thread(new Thread2()).start(); // 2.2 方式二 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("實現Runnable介面方式一執行的第" + i + "次"); } } }).start(); // 3. 測試實現Callable介面 // 3.1 方式一 new Thread(new FutureTask<Integer>(new Thread3() { }), "方式三").start();; // 3.2 方式二 new Thread(new FutureTask<Integer>(new Callable<Integer>() { @Override public Integer call() throws Exception { int i = 0; for (; i < 100; i++) { System.out.println("實現Runnable介面方式二執行的第" + i + "次"); } return i; } })).start();; } }
三、多執行緒常用方法
public class TestThreadMethod { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { // 獲取正在執行的執行緒物件的引用 System.out.println(Thread.currentThread().getName() + "執行的第" + i + "次"); } } }); // 1. 開啟執行緒 thread.start(); // 2. 設定 // 2.1 設定該執行緒名稱 thread.setName("執行緒1號"); // 2.2 設定該執行緒為守護執行緒:main方法結束之後該執行緒停止 //thread.setDaemon(true); // 2.3 設定該執行緒的優先順序 thread.setPriority(7); // 3. 獲取 // 3.1 獲取執行緒名稱 System.out.println(thread.getName()); // 執行緒1號 // 3.2 獲取執行緒識別符號 System.out.println(thread.getId()); // 13 // 3.3 獲取執行緒優先順序 System.out.println(thread.getPriority()); // 7 // 3.4 獲取執行緒狀態 System.out.println(thread.getState()); // RUNNABLE // 3.5 獲取執行緒所線上程組 System.out.println(thread.getThreadGroup()); // java.lang.ThreadGroup[name=main,maxpri=10] // 4. 判斷 // 4.1 判斷執行緒是否中斷 System.out.println(thread.isInterrupted()); // false // 4.2 判斷執行緒是否為活動狀態 System.out.println(thread.isAlive()); // true // 4.3 判斷執行緒是否為守護執行緒 System.out.println(thread.isDaemon()); // false // 5. 停 // 5.1 讓執行緒休眠指定毫秒數 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "執行的第" + i + "次"); if (i == 25) { try { /** * 1. sleep()是靜態方法 * 2. sleep()使用時必須捕獲異常 * 3. sleep()執行時,只是讓該執行緒進入阻塞狀態,並不會釋放鎖 */ System.out.println("執行緒2號正在休眠"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } } },"執行緒2號").start(); // 5.2 暫停當前執行緒去執行其他執行緒 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "執行了" + i + "次"); if (i == 25) { /** * 1. yield()是靜態方法 * 2. yield()執行時,讓執行緒進入就緒狀態,重新爭搶CPU執行權,並不會釋放鎖 */ Thread.yield(); } } } },"執行緒3號").start(); // 5.3 等待執行緒銷燬 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { if (i == 50) { /** * 1. join()是物件方法 * 2. join()使用時必須捕獲異常 * 3. join()使用場景:一個執行完的執行緒需要另一個正在執行的執行緒的執行結果時 */ System.out.println("執行緒1號正在銷燬!!!!"); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("執行緒1號銷燬成功!!!!"); } } } },"執行緒4號").start(); } }
四、執行緒同步
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 1. 執行緒安全 * 1. 什麼是執行緒安全:當多個執行緒同時操作同一共享資料時,導致共享資料出錯 * 2. 怎樣解決:使用執行緒同步技術 * * 2. 執行緒同步:將多個執行緒的資料共享 * * 3. 實現執行緒同步的方式 * 1. 同步程式碼塊:有synchronized關鍵字修飾的語句塊 * 1. 例項程式碼塊:鎖物件是this或者任意物件 * 2. 靜態程式碼塊:鎖物件是當前類的位元組碼檔案 * * 2. 同步方法: 有synchronized關鍵字修飾的方法 * 1. 例項方法 * 2. 靜態方法 * * 3. 使用重入鎖 * 1. 宣告鎖物件 * 2. 給共享資料上鎖 * 3. 在finally中解鎖 * * 4. wait()和notify() * wait(): 執行緒等待,釋放鎖 * notify(): 喚醒等待狀態執行緒 */ class Bank{ // 例項賬戶 private Integer account1 = 100; // 靜態賬戶 private static Integer account2 = 100; // 1. 宣告鎖物件 private Lock lock = new ReentrantLock(); /** * 1. 同步程式碼塊 */ // 存錢1 public void save1(Integer money) { // 例項程式碼塊 synchronized (this) { account1 += money; } System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); } // 取錢1 public void draw1(Integer money) { // 例項程式碼塊 synchronized (this) { if (account1 - money < 0) { System.out.println("賬戶餘額不足"); return; } account1 -= money; System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); } } // 存錢2 public static void save2(Integer money) { // 靜態程式碼塊 synchronized (Bank.class) { account2 += money; } System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); } // 取錢2 public static void draw2(Integer money) { // 靜態程式碼塊 synchronized (Bank.class) { if (account2 - money < 0) { System.out.println("餘額不足"); return; } account2 -= money; System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); } } /** * 2. 同步方法 */ // 2.1 例項方法 public synchronized void save3(Integer money) { account1 += money; System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); } public synchronized void draw3(Integer money) { if (account1 - money < 0) { System.out.println("餘額不足"); return; } account1 -= money; System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); } // 2.2 靜態方法 public synchronized static void save4(Integer money) { account2 += money; System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); } public synchronized static void draw4(Integer money) { if (account2 - money < 0) { System.out.println("餘額不足"); return; } account2 -= money; System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); } /** * 3. 重入鎖 */ public void save5(Integer money) { // 2. 上鎖 lock.lock(); try { account1 += money; System.out.println(Thread.currentThread().getName() + "存入了" + money + "元"); } finally { // 3. 解鎖 lock.unlock(); } } public void draw5(Integer money) { // 2. 上鎖 lock.lock(); try { if (account1 - money < 0) { System.out.println("餘額不足"); return; } account1 -= money; System.out.println(Thread.currentThread().getName() + "取出了" + money + "元"); } finally { // 3. 解鎖 lock.unlock(); } } // 檢視賬戶餘額 public void show() { System.out.println("例項賬戶餘額" + account1); System.out.println("靜態賬戶餘額" + account2); } } class Demo implements Runnable{ private static Bank bank = new Bank(); @Override public void run() { /** * 1. 測試同步程式碼塊 */ // 1.1 例項程式碼塊 bank.save1(100); bank.show(); bank.draw1(20); bank.show(); // 1.2 靜態程式碼塊 Bank.save2(100); bank.show(); Bank.draw2(20); bank.show(); /** * 2. 測試同步方法 */ // 2.1 例項方法 bank.save3(100); bank.show(); bank.draw3(20); bank.show(); // 2.2 靜態方法 Bank.save4(100); bank.show(); Bank.draw4(20); bank.show(); /** * 3. 測試重入鎖 */ bank.save5(100); bank.show(); bank.draw5(20); bank.show(); } } public class TestSynchronized { public static void main(String[] args) { // 1. 測試同步例項程式碼塊 new Thread(new Demo(),"執行緒1號").start(); // 2. 測試同步靜態程式碼塊 new Thread(new Demo(),"執行緒2號").start(); // 2. 測試同步方法 // 2.1 例項方法 new Thread(new Demo(),"執行緒3號").start(); // 2.2 靜態方法 new Thread(new Demo(),"執行緒4號").start(); // 3. 測試衝入鎖 new Thread(new Demo(),"執行緒5號").start(); } }
五、執行緒控制(執行緒狀態轉換圖)
九:網路程式設計
一、網路程式設計概述
1. 計算機網路:多臺算機之間實現資訊傳遞和資源共享的的計算機系統
2. 網路程式設計:不同計算機之間使用網路進行資料交換
二、網路程式設計三要素
1. IP:每個裝置在網路中的唯一標識
2. 埠號:每個程式在裝置上的唯一標識
3. 協議:在網路中進行資料交換要遵守的規則
三、 UDP與TCP的區別
1. UDP:面向無連線,資料不可靠,速度快,適用於高速傳輸和對實時性要求較高
2. TCP:面向連線,資料可靠,速度略低,適用於可靠傳輸
四、網路程式設計常用方法
五、UDP傳輸
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /** * 1. 伺服器端實現步驟 * 1. 建立伺服器物件 * 2. 將接受到的資料打包 * 3. 將資料包儲存到伺服器物件 * 4. 列印資料 * 5. 關閉流通道 * * 2. 客戶端步驟實現 * 1. 建立客戶端物件 * 2. 將資料打包 * 3. 傳送資料包 * 4. 關閉流通道 * * @author 萌萌哥的春天 * */ /** * 伺服器端 */ public class Server { public static void main(String[] args) throws IOException { // 1. 建立伺服器物件 DatagramSocket ds = new DatagramSocket(9102); // 2. 將接收到的資料打包 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); // 3. 將資料包存入伺服器物件 ds.receive(dp); // 4. 列印資料 String IP = dp.getAddress().getHostAddress(); // IP地址 int port = dp.getPort(); String data = new String(dp.getData(), 0, dp.getLength()); // 將位元組陣列轉為字串 System.out.println(IP+": --" + data + "--" + port + ":"); // 5. 關閉流通道 ds.close(); } } /** * 客戶端 */ public class Client { public static void main(String[] args) throws IOException { // 1. 建立客戶端物件 DatagramSocket ds = new DatagramSocket(); // 2. 將資料打包 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 接受鍵盤輸入 byte[] bytes = br.toString().getBytes(); // 將字串轉換為位元組陣列 DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9102); // 3. 傳送資料包 ds.send(dp); // 4. 關閉流通道 ds.close(); } }
六、TCP傳輸
/** * 1. 伺服器端實現步驟 * 1. 建立伺服器物件 * 2. 偵聽客戶端連線 * 3. 使用輸入流讀取客戶端輸入 * 4. 使用輸出流寫入檔案 * 5. 使用輸出流通知客戶端 * 6. 關閉流通道 * * 2. 客戶端步驟實現 * 1. 建立客戶端物件 * 2. 使用輸出流傳送資料到伺服器 * 3. 使用輸入流讀取本地檔案 * 4. 使用輸入流接收伺服器反饋並列印到控制檯 * 5. 關閉流通道 * * @author 萌萌哥的春天 * */ import java.io.BufferedWriter; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; /** * 伺服器端 */ public class Server { private static ServerSocket server; private static Socket socket; private static InputStream in; private static OutputStream out; public static void main(String[] args) { try { // 1. 建立伺服器物件 server = new ServerSocket(9102); // 2. 偵聽客戶端連線 socket = server.accept(); // 3. 使用輸入流接收客戶端輸入 in = socket.getInputStream(); // 4. 使用輸出流寫入檔案 out = new FileOutputStream("D:/server.txt"); byte[] bytes = new byte[1024]; int len = 0; while ((len = in.read(bytes)) != -1) { out.write(bytes, 0, len); out.flush(); } // 5. 使用輸出流通知客戶端 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("檔案上傳成功"); bw.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 6. 關閉流通道 if (server != null) { try { server.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } } /** * 客戶端 */ public class Client { private static Socket socket; private static InputStream in; public static void main(String[] args) { try { // 1. 建立客戶端物件 socket = new Socket("localhost", 9102); // 2. 使用輸入流傳送資料到伺服器 OutputStream out = socket.getOutputStream(); // 3. 使用輸入流讀取本地檔案 in = new FileInputStream("D:/client.txt"); byte[] bytes = new byte[1024]; int len = 0; while ((len = in.read(bytes)) != -1) { out.write(bytes, 0, len); } // 4. 通知伺服器檔案已上傳 socket.shutdownOutput(); // 5. 使用輸出流接收伺服器反饋 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println(br.readLine()); } catch (UnknownHostException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 6. 關閉流通道 if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
十:反射
一、反射概述
1. 反射機制:動態獲取類的資訊和呼叫物件的方法的功能
2. 反射實現:獲取每個類的位元組碼檔案,也就是Class類物件
二、反射的三種方式
/** * 反射的三種方式:推薦2和3 * 1. Object類的getClass()方法 * 2. 實體類.class * 3. Class類的forName()方法 */ public class TestReflect { public static void main(String[] args) { // 1. 方式一:getClass()方法 Worker worker = new Worker(); Class<? extends Worker> class1 = worker.getClass(); System.out.println(class1.getName()); // Worker // 2. 方式二:實體類.class Class<Worker> class2 = Worker.class; System.out.println(class1 == class2); // true // 3. 方式三:Class類的forName()方法 try { Class<?> class3 = Class.forName("Worker"); System.out.println(class2 == class3); // true } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
三、Class常用方法
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; class Worker { // 私有屬性 private Integer id; private String name; // 公共屬性 Integer age; public Worker() { } public Worker(String name) { this.name = name; } protected Worker(Integer id, String name) { this.id = id; this.name = name; } private Worker(Integer id, String name, Integer age) { this.id = id; this.name = name; this.age = age; } // 繼承方法 @Override public String toString() { return "Worker [id=" + id + ", name=" + name + ", age=" + age + "]"; } // 私有方法 private void test() { System.out.println("這是私有方法"); } } public class TestReflect { public static void main(String[] args) { // 1. 建立Class物件 Class<Worker> class1 = Worker.class; Class<String> class2 = String.class; /** * 2. 類相關操作 */ // 2.1 獲取完整性類名 System.out.println(class2.getName()); // java.lang.String // 2.2 獲取類名 System.out.println(class2.getSimpleName()); // String // 2.3 獲取此類的包名 System.out.println(class2.getPackage()); // package java.lang // 2.4 獲取當前類所繼承父類的名字 System.out.println(class2.getSuperclass()); // class java.lang.Object // 2.5獲取當前類實現的介面 Class<?>[] interfaces = class2.getInterfaces(); for (Class<?> class3 : interfaces) { System.out.println(class3); // interface java.io.Serializable // interface java.lang.Comparable // interface java.lang.CharSequence } /** * 3. 類中屬性相關操作 */ // 3.1 獲取指定屬性 try { Field declaredField = class1.getDeclaredField("name"); System.out.println(declaredField); // private java.lang.String Worker.name } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } // 3.2 獲取所有屬性 Field[] declaredFields = class1.getDeclaredFields(); for (Field field : declaredFields) { System.out.println(field); // private java.lang.Integer Worker.id // private java.lang.String Worker.name // java.lang.Integer Worker.age } /** * 4. 類中構造方法相關操作 */ // 4.1 獲取引數列表匹配的構造方法 try { Constructor<Worker> declaredConstructor = class1.getDeclaredConstructor(Integer.class, String.class, Integer.class); System.out.println(declaredConstructor); // private Worker(java.lang.Integer,java.lang.String,java.lang.Integer) System.out.println(class1.getDeclaredConstructor(String.class)); // public Worker(java.lang.String) } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } // 4.2 獲取類中所有公共構造方法 Constructor<?>[] constructors = class1.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); // public Worker(java.lang.String) // public Worker() } // 4.3 獲取類中所有構造方法 Constructor<?>[] declaredConstructors = class1.getDeclaredConstructors(); for (Constructor<?> constructor : declaredConstructors) { System.out.println(constructor); // private Worker(java.lang.Integer,java.lang.String,java.lang.Integer) // protected Worker(java.lang.Integer,java.lang.String) // public Worker(java.lang.String) // public Worker() } /** * 5. 類中方法相關操作 */ // 5.1 獲取方法名和引數列表都匹配的方法 try { Method declaredMethod = class1.getDeclaredMethod("toString"); System.out.println(declaredMethod); // public java.lang.String Worker.toString() System.out.println(class1.getDeclaredMethod("test")); // //private void Worker.test() } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } // 5.2 獲取類中所有公共方法 Method[] methods = class1.getMethods(); for (Method method : methods) { System.out.println(method); // 當前類方法和它所繼承的類及其實現的介面中的所有公共方法 } // 5.3 獲取當前類中所有方法 Method[] declaredMethods = class1.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println(method); // public java.lang.String Worker.toString() // private void Worker.test() } } }
四、反射核心操作
import java.lang.reflect.Field; import java.lang.reflect.Method; class Worker { // 私有屬性 private Integer id; private String name; // 公共屬性 public Integer age; public Worker() { } @Override public String toString() { return "Worker [id=" + id + ", name=" + name + ", age=" + age + "]"; } // 私有方法 private void test() { System.out.println("這是私有方法"); } // 公共方法 public void show() { System.out.println("這是公共方法"); } } public class TestReflect { public static void main(String[] args) throws Exception { // 1. 建立Class物件 Class<?> class1 = Class.forName("Worker"); // 2. 通過構造方法例項化類物件 Object obj = class1.getConstructor().newInstance(); // 3. 給公共屬性設定值 Field field1 = class1.getField("age"); field1.set(obj, 18); // 4. 給私有屬性設定值 Field field = class1.getDeclaredField("name"); field.setAccessible(true); // 解除私有限定 field.set(obj, "張三"); // 為Worker類中的name屬性設定值 // 5. 呼叫公共成員方法 Method method1 = class1.getMethod("show"); method1.invoke(obj); // 6. 呼叫私有成員方法 Method method = class1.getDeclaredMethod("test"); method.setAccessible(true); method.invoke(obj); // 第一個引數是類物件,其餘的為實參 System.out.println(obj); } }