一:Java簡介html
1. Java語言的介紹:Java是一門面向對象編程語言,具備功能強大和簡單易用兩個特徵。前端
2. Java語言的特色:簡單性、面向對象、分佈式、健壯性、安全性、平臺獨立與可移植性、多線程、動態性等java
3. Java語言的應用:編寫桌面應用程序、Web應用程序、分佈式系統和嵌入式系統應用程序等web
二:Java自學路線圖數據庫
三:Java基礎
編程
1、標識符和關鍵字
數組
1. 標識符安全
1. 在java語言中,用來標誌類名、對象名、變量名、方法名、類型名、數組名、包名的有效字符序列,稱爲「標識符」;服務器
2. 標識符由字母、數字、下劃線、美圓符號組成,且第一個字符不能是數字;網絡
3. java語言區分大小寫;
4. 標誌符命名規則:類名首字母大寫,變量名和方法名採用駝峯標誌法,包名全小寫,常量全大寫,多個單詞之間用「_」隔開;
2. 關鍵字
1. 在java語言中,有一些專門的詞彙已經被賦予了特殊的含義,不能再使用這些詞彙來命名標識符,這些專有詞彙,稱爲「關鍵字」;
2. java有50個關鍵字和3個保留字,均不能用來命名標識符;
3. true、false、null不是關鍵字,是保留字,可是仍不能用來命名標識符;
2、數據類型
3、運算符與表達式
1. 算數運算符:加(+),減(-),乘(*),除(/),求餘(%)
2. 賦值運算符:=,+=,-=,*=,%=
3. 關係運算符:>,<,>=,<=,==,!=
4. 邏輯運算符:[&&,||](只有左側知足才計算右側),!,[&,|](無論左側結果如何,都要計算右側)
5. 三目運算符:(表達式) ? 值1,值2;
4、流程控制語句
1. 條件分支語句:if語句,switch語句
2. 循環語句:while循環,do while循環,for循環,foreach循環
四:數組
1、數組概述
1. 數組的概念:相同數據類型元素的集合
2. 數組的做用:用來存儲基本數據類型和引用數據類型的數據
2、數組的建立及排序
public class TestArray { public static void main(String[] args) { /** * 1. 數組的初始化 */ // 1.1 數組的靜態初始化 int[] array1 = { 1, 3, 5, 6, 7, 2, 4, 10 }; // 1.2 數組的動態初始化 int[] array2 = new int[5]; array2[0] = 1; array2[1] = 2; array2[2] = 7; array2[3] = 3; array2[4] = 4; /** * 2. 數組的遍歷 */ // 2.1 for循環打印數組 for (int i = 0; i < array2.length; i++) { System.out.print(array2[i]); } // 2.2 foreach打印數組 for (int i : array2) { System.out.print(i); } /** * 3. 數組排序 */ // 3.1 冒泡排序 for (int i = 0; i < array2.length; i++) { for (int j = i + 1; j < array2.length; j++) { // 1. 比較相鄰元素,將較大的數冒泡 if (array2[i] > array2[j]) { // 2. 交換 int temp = array2[i]; array2[i] = array2[j]; array2[j] = temp; } } } for (int i : array2) { System.out.println(i); } // 3.2 選擇排序 for (int i = 0; i < array2.length; i++) { int min = i; for (int j = i; j < array2.length; j++) { // 1. 找到最小的數 if (array2[j] < array2[min]) { // 2. 將最小的數賦值給min min = j; } } // 3. 交換兩個數的位置 int temp = array2[i]; array2[i] = array2[min]; array2[min] = temp; } for (int i : array2) { System.out.println(i); } // 3.3 反轉排序 for (int i = 0; i < array2.length / 2; i++) { // 將第i位元素與array2.length-1-i位元素交換 int temp = array2[i]; array2[i] = array2[array2.length - 1 - i]; array2[array2.length - 1 - i] = temp; } for (int i : array2) { System.out.println(i); } // 3.4 插入排序 for (int i = 0; i < array2.length; i++) { int j = i; int tmp = array2[i]; for (; j > 0 && tmp < array2[j - 1]; j--) { // 1. 將大於待排序的數向後移 array2[j] = array2[j - 1]; } // 2. 交換 array2[j] = tmp; } for (int i : array2) { System.out.println(i); } } }
3、Arrays工具類經常使用方法
import java.util.Arrays; public class TestArray { public static void main(String[] args) { int[] array1 = { 1, 3, 5, 2, 4 }; int[] array2 = {3,2}; // 1. 排序 Arrays.sort(array2); for (int i : array2) { System.out.print(i); } // 2. 二分法查找 System.out.print(Arrays.binarySearch(array2, 3)); // 3. 數組元素比較 System.out.println(Arrays.equals(array1, array2)); // 4. 數組元素填充 Arrays.fill(array2, 1); for (int j : array2) { System.out.println(j); } } }
五:面向對象
1、封裝
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()); } }
2、方法的重載和重寫
1. 方法的重載:方法名相同,參數列表不一樣
2. 方法的重寫:方法名、返回值類型、參數列表都相同,構造方法和使用final、static修飾的方法不能被重寫
3、繼承
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(); } }
4、多態
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(); } }
5、抽象類
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(); } }
6、接口
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(); } }
六:集合
1、集合簡介
集合的主要做用是存儲引用類型數據,長度能夠動態的改變,解決了存儲數據數量不肯定的問題
2、Collection集合體系
1、Collection經常使用方法
2、不一樣集合的使用場景
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); } } }
3、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流
1、IO流簡介
1. 流的概念:流是有起點和終點的一組有順序的字節集合,做用是進行數據傳輸
2. 流的分類:
1. 按照數據流向不一樣能夠分爲輸入輸出流;
2. 按照處理數據單位不一樣能夠分爲字節流和字符流
3. 輸入流和輸出流的做用
1. 輸入流:程序從數據源讀取數據
2. 輸出流:將數據從程序中寫入指定文件
4. 字節流和字符流的做用
1. 字節流:以字節爲單位處理全部類型數據
2. 字符流:以字符爲單位處理純文本文件
2、IO流體系
3、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; } }
4、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. 線程和進程
1. 進程:操做系統中的應用程序,一個進程就是一個應用程序
2. 線程:CPU調度的最小單元,進程的一個執行流
2. 上下文切換
1. 上下文切換:CPU從一個線程或進程切換到另外一個進程或線程;
2. 多線程程序並非同時進行的,因爲CPU的執行速度太快,CPU會在不一樣的線程之間快速的切換執行;
2、多線程的三種實現方式及優缺點
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();; } }
3、多線程經常使用方法
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(); } }
4、線程同步
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(); } }
5、線程控制(線程狀態轉換圖)
九:網絡編程
1、網絡編程概述
1. 計算機網絡:多臺算機之間實現信息傳遞和資源共享的的計算機系統
2. 網絡編程:不一樣計算機之間使用網絡進行數據交換
2、網絡編程三要素
1. IP:每一個設備在網絡中的惟一標識
2. 端口號:每一個程序在設備上的惟一標識
3. 協議:在網絡中進行數據交換要遵照的規則
3、 UDP與TCP的區別
1. UDP:面向無鏈接,數據不可靠,速度快,適用於高速傳輸和對實時性要求較高
2. TCP:面向鏈接,數據可靠,速度略低,適用於可靠傳輸
4、網絡編程經常使用方法
5、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(); } }
6、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、反射概述
1. 反射機制:動態獲取類的信息和調用對象的方法的功能
2. 反射實現:獲取每一個類的字節碼文件,也就是Class類對象
2、反射的三種方式
/** * 反射的三種方式:推薦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(); } } }
3、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() } } }
4、反射核心操做
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); } }