基本數據類型前端
引用數據類型java
注意mysql
switch (i % 2) { case 1: System.out.println("奇數"); break; case 0: System.out.println("偶數"); break; default: System.out.println("輸入不合法"); break; }
switch括號中得數據類型:
基本:byte/short/char/int 引用:String字符串/enum枚舉linux
動態初始化數組
int[] arrayA=new int[20];
靜態初始化數組
String[] arrayB={"hello","world","java"};程序員
數組的長度運行期間不可改變
正則表達式
方法覆蓋重寫的注意事項:spring
必須保證父子類之間方法的名稱相同,參數列表也相同。
@Override:寫在方法前面,用來檢測是否是有效的正確覆蓋重寫。
這個註解就算不寫,只要知足要求,也是正確的方法覆蓋重寫。sql
子類方法的返回值必須【小於等於】父類方法的返回值範圍。
小擴展提示:java.lang.Object類是全部類的公共最高父類(祖宗類),java.lang.String就是Object的子類。數據庫
子類方法的權限必須【大於等於】父類方法的權限修飾符。
小擴展提示:public > protected > (default) > private
備註:(default)不是關鍵字default,而是什麼都不寫,留空。編程
一旦使用static修飾成員方法,那麼這就成爲了靜態方法。靜態方法不屬於對象,而是屬於類的。
若是沒有static關鍵字,那麼必須首先建立對象,而後經過對象才能使用它。
若是有了static關鍵字,那麼不須要建立對象,直接就能經過類名稱來使用它。
不管是成員變量,仍是成員方法。若是有了static,都推薦使用類名稱進行調用。
靜態變量:類名稱.靜態變量
靜態方法:類名稱.靜態方法()
注意事項:
若是是Java 7,那麼接口中能夠包含的內容有:
若是是Java 8,還能夠額外包含有:
若是是Java 9,還能夠額外包含有:
小節一下類的權限修飾符:
public > protected > (default) > private
定義一個類的時候,權限修飾符規則:
局部內部類,若是但願訪問所在方法的局部變量,那麼這個局部變量必須是【有效final的】。
備註:從Java 8+開始,只要局部變量事實不變,那麼final關鍵字能夠省略。
緣由:
可是new出來的對象會在堆當中持續存在,直到垃圾回收消失。
public class MyOuter {
public void methodOuter() { int num = 10; // 所在方法的局部變量 class MyInner { public void methodInner() { System.out.println(num); } } }
}
package cn.itcast.day11.demo05; /* 若是接口的實現類(或者是父類的子類)只須要使用惟一的一次, 那麼這種狀況下就能夠省略掉該類的定義,而改成使用【匿名內部類】。 匿名內部類的定義格式: 接口名稱 對象名 = new 接口名稱() { // 覆蓋重寫全部抽象方法 }; 對格式「new 接口名稱() {...}」進行解析: 1. new表明建立對象的動做 2. 接口名稱就是匿名內部類須要實現哪一個接口 3. {...}這纔是匿名內部類的內容 另外還要注意幾點問題: 1. 匿名內部類,在【建立對象】的時候,只能使用惟一一次。 若是但願屢次建立對象,並且類的內容同樣的話,那麼就須要使用單獨定義的實現類了。 2. 匿名對象,在【調用方法】的時候,只能調用惟一一次。 若是但願同一個對象,調用屢次方法,那麼必須給對象起個名字。 3. 匿名內部類是省略了【實現類/子類名稱】,可是匿名對象是省略了【對象名稱】 強調:匿名內部類和匿名對象不是一回事!!! */ public class DemoMain { public static void main(String[] args) { // MyInterface obj = new MyInterfaceImpl(); // obj.method(); // MyInterface some = new MyInterface(); // 錯誤寫法! // 使用匿名內部類,但不是匿名對象,對象名稱就叫objA MyInterface objA = new MyInterface() { @Override public void method1() { System.out.println("匿名內部類實現了方法!111-A"); } @Override public void method2() { System.out.println("匿名內部類實現了方法!222-A"); } }; objA.method1(); objA.method2(); System.out.println("================="); // 使用了匿名內部類,並且省略了對象名稱,也是匿名對象 new MyInterface() { @Override public void method1() { System.out.println("匿名內部類實現了方法!111-B"); } @Override public void method2() { System.out.println("匿名內部類實現了方法!222-B"); } }.method1(); // 由於匿名對象沒法調用第二次方法,因此須要再建立一個匿名內部類的匿名對象 new MyInterface() { @Override public void method1() { System.out.println("匿名內部類實現了方法!111-B"); } @Override public void method2() { System.out.println("匿名內部類實現了方法!222-B"); } }.method2(); } }
Scanner sc=new Scanner(System.in); int i = sc.nextInt(); System.out.println(i); String next = sc.next(); System.out.println(next);
Random ran=new Random(); int in1 = ran.nextInt(); System.out.println(in1); System.out.println("---------"); for (int i = 0; i < 100; i++) { int in2 = ran.nextInt(10); System.out.print(in2+" "); }
1. public boolean add(E e):向集合當中添加元素,參數的類型和泛型一致。返回值表明添加是否成功。 2. public E get(int index):從集合當中獲取元素,參數是索引編號,返回值就是對應位置的元素。 3. public E remove(int index):從集合當中刪除元素,參數是索引編號,返回值就是被刪除掉的元素。 4. public int size():獲取集合的尺寸長度,返回值是集合中包含的元素個數。 5. public <T> T[] toArray(T[] a): 按適當順序(從第一個到最後一個元素)返回包含此列表中全部元素的數組;返回數組的運行時類型是指定數組的運行時類型。
java.lang.String類表明字符串。
API當中說:Java 程序中的全部字符串字面值(如 "abc" )都做爲此類的實例實現。
其實就是說:程序當中全部的雙引號字符串,都是String類的對象。(就算沒有new,也照樣是。)
字符串的特色:
建立字符串的常見3+1種方式。
三種構造方法:
public String():建立一個空白字符串,不含有任何內容。
public String(char[] array):根據字符數組的內容,來建立對應的字符串。
public String(byte[] array):根據字節數組的內容,來建立對應的字符串。
一種直接建立:
String str = "Hello"; // 右邊直接用雙引號
注意:直接寫上雙引號,就是字符串對象。
package cn.itcast.day08.demo01; /* 字符串常量池:程序當中直接寫上的雙引號字符串,就在字符串常量池中。 對於基本類型來講,==是進行數值的比較。 對於引用類型來講,==是進行【地址值】的比較。 */ public class Demo02StringPool { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc"; char[] charArray = {'a', 'b', 'c'}; String str3 = new String(charArray); System.out.println(str1 == str2); // true System.out.println(str1 == str3); // false System.out.println(str2 == str3); // false } }
1. boolean equals(Object anObject) 將此字符串與指定的對象比較。 2. boolean equalsIgnoreCase(String anotherString) 將此 String 與另外一個 String 比較,不考慮大小寫。 3. int length() 返回此字符串的長度。 4. String concat(String str) 將指定字符串鏈接到此字符串的結尾。 5. char charAt(int index) 返回指定索引處的 char 值。 6. int indexOf(String str) 返回指定子字符串在此字符串中第一次出現處的索引。 7. String substring(int beginIndex) 返回一個新的字符串,它是此字符串的一個子字符串。 8. String substring(int beginIndex, int endIndex) 返回一個新字符串,它是此字符串的一個子字符串。 9. char[] toCharArray() 將此字符串轉換爲一個新的字符數組。 10. byte[] getBytes() 使用平臺的默認字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。 11. replace(CharSequence target, CharSequence replacement) 使用指定的字面值替換序列替換此字符串全部匹配字面值目標序列的子字符串。 12. String[] split(String regex) 根據給定正則表達式的匹配拆分此字符串。 13. String trim() 返回字符串的副本,忽略前導空白和尾部空白。 14. String toLowerCase() 使用默認語言環境的規則將此 String 中的全部字符都轉換爲小寫。 15. String toUpperCase() 使用默認語言環境的規則將此 String 中的全部字符都轉換爲大寫。 16. boolean startsWith(String prefix) 測試此字符串是否以指定的前綴開始。 17. boolean startsWith(String prefix, int toffset) 測試此字符串從指定索引開始的子字符串是否以指定前綴開始。 18. boolean endsWith(String suffix) 測試此字符串是否以指定的後綴結束。 19. boolean contains(CharSequence s) 當且僅當此字符串包含指定的 char 值序列時,返回 true。
package cn.itcast.day08.demo04; import java.util.Arrays; /* java.util.Arrays是一個與數組相關的工具類,裏面提供了大量靜態方法,用來實現數組常見的操做。 public static String toString(數組):將參數數組變成字符串(按照默認格式:[元素1, 元素2, 元素3...]) public static void sort(數組):按照默認升序(從小到大)對數組的元素進行排序。 備註: 1. 若是是數值,sort默認按照升序從小到大 2. 若是是字符串,sort默認按照字母升序 3. 若是是自定義的類型,那麼這個自定義的類須要有Comparable或者Comparator接口的支持。 */ public class Demo01Arrays { public static void main(String[] args) { int[] intArray = {10, 20, 30}; // 將int[]數組按照默認格式變成字符串 String intStr = Arrays.toString(intArray); System.out.println(intStr); // [10, 20, 30] int[] array1 = {2, 1, 3, 10, 6}; Arrays.sort(array1); System.out.println(Arrays.toString(array1)); // [1, 2, 3, 6, 10] String[] array2 = {"bbb", "aaa", "ccc"}; Arrays.sort(array2); System.out.println(Arrays.toString(array2)); // [aaa, bbb, ccc] } }
package cn.itcast.day08.demo04; /* java.util.Math類是數學相關的工具類,裏面提供了大量的靜態方法,完成與數學運算相關的操做。 public static double abs(double num):獲取絕對值。有多種重載。 public static double ceil(double num):向上取整。 public static double floor(double num):向下取整。 public static long round(double num):四捨五入。 Math.PI表明近似的圓周率常量(double)。 */ public class Demo03Math { public static void main(String[] args) { // 獲取絕對值 System.out.println(Math.abs(3.14)); // 3.14 System.out.println(Math.abs(0)); // 0 System.out.println(Math.abs(-2.5)); // 2.5 System.out.println("================"); // 向上取整 System.out.println(Math.ceil(3.9)); // 4.0 System.out.println(Math.ceil(3.1)); // 4.0 System.out.println(Math.ceil(3.0)); // 3.0 System.out.println("================"); // 向下取整,抹零 System.out.println(Math.floor(30.1)); // 30.0 System.out.println(Math.floor(30.9)); // 30.0 System.out.println(Math.floor(31.0)); // 31.0 System.out.println("================"); System.out.println(Math.round(20.4)); // 20 System.out.println(Math.round(10.5)); // 11 } }
package com.itheima.demo07Integer; /* 裝箱:把基本類型的數據,包裝到包裝類中(基本類型的數據->包裝類) 構造方法: Integer(int value) 構造一個新分配的 Integer 對象,它表示指定的 int 值。 Integer(String s) 構造一個新分配的 Integer 對象,它表示 String 參數所指示的 int 值。 傳遞的字符串,必須是基本類型的字符串,不然會拋出異常 "100" 正確 "a" 拋異常 靜態方法: static Integer valueOf(int i) 返回一個表示指定的 int 值的 Integer 實例。 static Integer valueOf(String s) 返回保存指定的 String 的值的 Integer 對象。 拆箱:在包裝類中取出基本類型的數據(包裝類->基本類型的數據) 成員方法: int intValue() 以 int 類型返回該 Integer 的值。 */ public class Demo01Integer { public static void main(String[] args) { //裝箱:把基本類型的數據,包裝到包裝類中(基本類型的數據->包裝類) //構造方法 Integer in1 = new Integer(1);//方法上有橫線,說明方法過期了 System.out.println(in1);//1 重寫了toString方法 Integer in2 = new Integer("1"); System.out.println(in2);//1 //靜態方法 Integer in3 = Integer.valueOf(1); System.out.println(in3); //Integer in4 = Integer.valueOf("a");//NumberFormatException數字格式化異常 Integer in4 = Integer.valueOf("1"); System.out.println(in4); //拆箱:在包裝類中取出基本類型的數據(包裝類->基本類型的數據) int i = in1.intValue(); System.out.println(i); } } package com.itheima.demo07Integer; /* 基本類型與字符串類型之間的相互轉換 基本類型->字符串(String) 1.基本類型的值+"" 最簡單的方法(工做中經常使用) 2.包裝類的靜態方法toString(參數),不是Object類的toString() 重載 static String toString(int i) 返回一個表示指定整數的 String 對象。 3.String類的靜態方法valueOf(參數) static String valueOf(int i) 返回 int 參數的字符串表示形式。 字符串(String)->基本類型 使用包裝類的靜態方法parseXXX("字符串"); Integer類: static int parseInt(String s) Double類: static double parseDouble(String s) */ public class Demo03Integer { public static void main(String[] args) { //基本類型->字符串(String) int i1 = 100; String s1 = i1+""; System.out.println(s1+200);//100200 String s2 = Integer.toString(100); System.out.println(s2+200);//100200 String s3 = String.valueOf(100); System.out.println(s3+200);//100200 //字符串(String)->基本類型 int i = Integer.parseInt(s1); System.out.println(i-10); int a = Integer.parseInt("a");//NumberFormatException System.out.println(a); } }
package com.itheima.demo06StringBuilder; /* StringBuilder和String能夠相互轉換: String->StringBuilder:可使用StringBuilder的構造方法 StringBuilder(String str) 構造一個字符串生成器,並初始化爲指定的字符串內容。 StringBuilder->String:可使用StringBuilder中的toString方法 public String toString():將當前StringBuilder對象轉換爲String對象。 */ public class Demo03StringBuilder { public static void main(String[] args) { //String->StringBuilder String str = "hello"; System.out.println("str:"+str); StringBuilder bu = new StringBuilder(str); //往StringBuilder中添加數據 bu.append("world"); System.out.println("bu:"+bu); //StringBuilder->String String s = bu.toString(); System.out.println("s:"+s); } }
package com.itheima.demo02.Date; /* java.util.Date:表示日期和時間的類 類 Date 表示特定的瞬間,精確到毫秒。 毫秒:千分之一秒 1000毫秒=1秒 特定的瞬間:一個時間點,一剎那時間 2088-08-08 09:55:33:333 瞬間 2088-08-08 09:55:33:334 瞬間 2088-08-08 09:55:33:334 瞬間 ... 毫秒值的做用:能夠對時間和日期進行計算 2099-01-03 到 2088-01-01 中間一共有多少天 能夠日期轉換爲毫秒進行計算,計算完畢,在把毫秒轉換爲日期 把日期轉換爲毫秒: 當前的日期:2088-01-01 時間原點(0毫秒):1970 年 1 月 1 日 00:00:00(英國格林威治) 就是計算當前日期到時間原點之間一共經歷了多少毫秒 (3742767540068L) 注意: 中國屬於東八區,會把時間增長8個小時 1970 年 1 月 1 日 08:00:00 把毫秒轉換爲日期: 1 天 = 24 × 60 × 60 = 86400 秒 = 86400 x 1000 = 86400000毫秒 */ public class Demo01Date { public static void main(String[] args) { System.out.println(System.currentTimeMillis());//獲取當前系統時間到1970 年 1 月 1 日 00:00:00經歷了多少毫秒 } } package com.itheima.demo02.Date; import java.util.Date; public class Demo02Date { public static void main(String[] args) { demo03(); } /* long getTime() 把日期轉換爲毫秒值(至關於System.currentTimeMillis()方法) 返回自 1970 年 1 月 1 日 00:00:00 GMT 以來此 Date 對象表示的毫秒數。 */ private static void demo03() { Date date = new Date(); long time = date.getTime(); System.out.println(time);//3742777636267 } /* Date類的帶參數構造方法 Date(long date) :傳遞毫秒值,把毫秒值轉換爲Date日期 */ private static void demo02() { Date date = new Date(0L); System.out.println(date);// Thu Jan 01 08:00:00 CST 1970 date = new Date(3742767540068L); System.out.println(date);// Sun Aug 08 09:39:00 CST 2088 } /* Date類的空參數構造方法 Date() 獲取當前系統的日期和時間 */ private static void demo01() { Date date = new Date(); System.out.println(date);//Sun Aug 08 12:23:03 CST 2088 } }
package com.itheima.demo03.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /* java.text.DateFormat:是日期/時間格式化子類的抽象類 做用: 格式化(也就是日期 -> 文本)、解析(文本-> 日期) 成員方法: String format(Date date) 按照指定的模式,把Date日期,格式化爲符合模式的字符串 Date parse(String source) 把符合模式的字符串,解析爲Date日期 DateFormat類是一個抽象類,沒法直接建立對象使用,可使用DateFormat類的子類 java.text.SimpleDateFormat extends DateFormat 構造方法: SimpleDateFormat(String pattern) 用給定的模式和默認語言環境的日期格式符號構造 SimpleDateFormat。 參數: String pattern:傳遞指定的模式 模式:區分大小寫的 y 年 M 月 d 日 H 時 m 分 s 秒 S 毫秒 寫對應的模式,會把模式替換爲對應的日期和時間 "yyyy-MM-dd HH:mm:ss" 注意: 模式中的字母不能更改,鏈接模式的符號能夠改變 "yyyy年MM月dd日 HH時mm分ss秒" */ public class Demo01DateFormat { public static void main(String[] args) throws ParseException { demo02(); } /* 使用DateFormat類中的方法parse,把文本解析爲日期 使用步驟: 1.建立SimpleDateFormat對象,構造方法中傳遞指定的模式 2.調用SimpleDateFormat對象中的方法parse,把符合構造方法中模式的字符串,解析爲Date日期 注意: public Date parse(String source) throws ParseException parse方法聲明瞭一個異常叫ParseException 若是字符串和構造方法的模式不同,那麼程序就會拋出此異常 調用一個拋出了異常的方法,就必須的處理這個異常,要麼throws繼續拋出這個異常,要麼try catch本身處理 */ private static void demo02() throws ParseException { //1.建立SimpleDateFormat對象,構造方法中傳遞指定的模式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH時mm分ss秒"); //2.調用SimpleDateFormat對象中的方法parse,把符合構造方法中模式的字符串,解析爲Date日期 //Date parse(String source) 把符合模式的字符串,解析爲Date日期 Date date = sdf.parse("2088年08月08日 15時51分54秒"); System.out.println(date); } /* 使用DateFormat類中的方法format,把日期格式化爲文本 使用步驟: 1.建立SimpleDateFormat對象,構造方法中傳遞指定的模式 2.調用SimpleDateFormat對象中的方法format,按照構造方法中指定的模式,把Date日期格式化爲符合模式的字符串(文本) */ private static void demo01() { //1.建立SimpleDateFormat對象,構造方法中傳遞指定的模式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH時mm分ss秒"); //2.調用SimpleDateFormat對象中的方法format,按照構造方法中指定的模式,把Date日期格式化爲符合模式的字符串(文本) //String format(Date date) 按照指定的模式,把Date日期,格式化爲符合模式的字符串 Date date = new Date(); String d = sdf.format(date); System.out.println(date);//Sun Aug 08 15:51:54 CST 2088 System.out.println(d);//2088年08月08日 15時51分54秒 } }
package com.itheima.demo04.Calendar; import java.util.Calendar; /* java.util.Calendar類:日曆類 Calendar類是一個抽象類,裏邊提供了不少操做日曆字段的方法(YEAR、MONTH、DAY_OF_MONTH、HOUR ) Calendar類沒法直接建立對象使用,裏邊有一個靜態方法叫getInstance(),該方法返回了Calendar類的子類對象 static Calendar getInstance() 使用默認時區和語言環境得到一個日曆。 */ public class Demo01Calendar { public static void main(String[] args) { Calendar c = Calendar.getInstance();//多態 System.out.println(c); } } package com.itheima.demo04.Calendar; import java.util.Calendar; import java.util.Date; /* Calendar類的經常使用成員方法: public int get(int field):返回給定日曆字段的值。 public void set(int field, int value):將給定的日曆字段設置爲給定值。 public abstract void add(int field, int amount):根據日曆的規則,爲給定的日曆字段添加或減去指定的時間量。 public Date getTime():返回一個表示此Calendar時間值(從曆元到如今的毫秒偏移量)的Date對象。 成員方法的參數: int field:日曆類的字段,可使用Calendar類的靜態成員變量獲取 public static final int YEAR = 1; 年 public static final int MONTH = 2; 月 public static final int DATE = 5; 月中的某一天 public static final int DAY_OF_MONTH = 5;月中的某一天 public static final int HOUR = 10; 時 public static final int MINUTE = 12; 分 public static final int SECOND = 13; 秒 */ public class Demo02Calendar { public static void main(String[] args) { demo04(); } /* public Date getTime():返回一個表示此Calendar時間值(從曆元到如今的毫秒偏移量)的Date對象。 把日曆對象,轉換爲日期對象 */ private static void demo04() { //使用getInstance方法獲取Calendar對象 Calendar c = Calendar.getInstance(); Date date = c.getTime(); System.out.println(date); } /* public abstract void add(int field, int amount):根據日曆的規則,爲給定的日曆字段添加或減去指定的時間量。 把指定的字段增長/減小指定的值 參數: int field:傳遞指定的日曆字段(YEAR,MONTH...) int amount:增長/減小指定的值 正數:增長 負數:減小 */ private static void demo03() { //使用getInstance方法獲取Calendar對象 Calendar c = Calendar.getInstance(); //把年增長2年 c.add(Calendar.YEAR,2); //把月份減小3個月 c.add(Calendar.MONTH,-3); int year = c.get(Calendar.YEAR); System.out.println(year); int month = c.get(Calendar.MONTH); System.out.println(month);//西方的月份0-11 東方:1-12 //int date = c.get(Calendar.DAY_OF_MONTH); int date = c.get(Calendar.DATE); System.out.println(date); } /* public void set(int field, int value):將給定的日曆字段設置爲給定值。 參數: int field:傳遞指定的日曆字段(YEAR,MONTH...) int value:給指定字段設置的值 */ private static void demo02() { //使用getInstance方法獲取Calendar對象 Calendar c = Calendar.getInstance(); //設置年爲9999 c.set(Calendar.YEAR,9999); //設置月爲9月 c.set(Calendar.MONTH,9); //設置日9日 c.set(Calendar.DATE,9); //同時設置年月日,可使用set的重載方法 c.set(8888,8,8); int year = c.get(Calendar.YEAR); System.out.println(year); int month = c.get(Calendar.MONTH); System.out.println(month);//西方的月份0-11 東方:1-12 int date = c.get(Calendar.DATE); System.out.println(date); } /* public int get(int field):返回給定日曆字段的值。 參數:傳遞指定的日曆字段(YEAR,MONTH...) 返回值:日曆字段表明的具體的值 */ private static void demo01() { //使用getInstance方法獲取Calendar對象 Calendar c = Calendar.getInstance(); int year = c.get(Calendar.YEAR); System.out.println(year); int month = c.get(Calendar.MONTH); System.out.println(month);//西方的月份0-11 東方:1-12 //int date = c.get(Calendar.DAY_OF_MONTH); int date = c.get(Calendar.DATE); System.out.println(date); } }
package com.itheima.demo05.System; import java.util.Arrays; /* java.lang.System類中提供了大量的靜態方法,能夠獲取與系統相關的信息或系統級操做,在System類的API文檔中,經常使用的方法有: public static long currentTimeMillis():返回以毫秒爲單位的當前時間。 public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):將數組中指定的數據拷貝到另外一個數組中。 */ public class Demo01System { public static void main(String[] args) { demo02(); StringBuilder sb = new StringBuilder(); } /* public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):將數組中指定的數據拷貝到另外一個數組中。 參數: src - 源數組。 srcPos - 源數組中的起始位置(起始索引)。 dest - 目標數組。 destPos - 目標數據中的起始位置。 length - 要複製的數組元素的數量。 練習: 將src數組中前3個元素,複製到dest數組的前3個位置上 複製元素前: src數組元素[1,2,3,4,5],dest數組元素[6,7,8,9,10] 複製元素後: src數組元素[1,2,3,4,5],dest數組元素[1,2,3,9,10] */ private static void demo02() { //定義源數組 int[] src = {1,2,3,4,5}; //定義目標數組 int[] dest = {6,7,8,9,10}; System.out.println("複製前:"+ Arrays.toString(dest)); //使用System類中的arraycopy把源數組的前3個元素複製到目標數組的前3個位置上 System.arraycopy(src,0,dest,0,3); System.out.println("複製後:"+ Arrays.toString(dest)); } /* public static long currentTimeMillis():返回以毫秒爲單位的當前時間。 用來程序的效率 驗證for循環打印數字1-9999所須要使用的時間(毫秒) */ private static void demo01() { //程序執行前,獲取一次毫秒值 long s = System.currentTimeMillis(); //執行for循環 for (int i = 1; i <=9999 ; i++) { System.out.println(i); } //程序執行後,獲取一次毫秒值 long e = System.currentTimeMillis(); System.out.println("程序共耗時:"+(e-s)+"毫秒");//程序共耗時:106毫秒 } }
package com.itheima.demo01.Collection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /* java.util.Collection接口 全部單列集合的最頂層的接口,裏邊定義了全部單列集合共性的方法 任意的單列集合均可以使用Collection接口中的方法 共性的方法: public boolean add(E e): 把給定的對象添加到當前集合中 。 public void clear() :清空集合中全部的元素。 public boolean remove(E e): 把給定的對象在當前集合中刪除。 public boolean contains(E e): 判斷當前集合中是否包含給定的對象。 public boolean isEmpty(): 判斷當前集合是否爲空。 public int size(): 返回集合中元素的個數。 public Object[] toArray(): 把集合中的元素,存儲到數組中。 */ public class Demo01Collection { public static void main(String[] args) { //建立集合對象,可使用多態 //Collection<String> coll = new ArrayList<>(); Collection<String> coll = new HashSet<>(); System.out.println(coll);//重寫了toString方法 [] /* public boolean add(E e): 把給定的對象添加到當前集合中 。 返回值是一個boolean值,通常都返回true,因此能夠不用接收 */ boolean b1 = coll.add("張三"); System.out.println("b1:"+b1);//b1:true System.out.println(coll);//[張三] coll.add("李四"); coll.add("李四"); coll.add("趙六"); coll.add("田七"); System.out.println(coll);//[張三, 李四, 趙六, 田七] /* public boolean remove(E e): 把給定的對象在當前集合中刪除。 返回值是一個boolean值,集合中存在元素,刪除元素,返回true 集合中不存在元素,刪除失敗,返回false */ boolean b2 = coll.remove("趙六"); System.out.println("b2:"+b2);//b2:true boolean b3 = coll.remove("趙四"); System.out.println("b3:"+b3);//b3:false System.out.println(coll);//[張三, 李四, 田七] /* public boolean contains(E e): 判斷當前集合中是否包含給定的對象。 包含返回true 不包含返回false */ boolean b4 = coll.contains("李四"); System.out.println("b4:"+b4);//b4:true boolean b5 = coll.contains("趙四"); System.out.println("b5:"+b5);//b5:false //public boolean isEmpty(): 判斷當前集合是否爲空。 集合爲空返回true,集合不爲空返回false boolean b6 = coll.isEmpty(); System.out.println("b6:"+b6);//b6:false //public int size(): 返回集合中元素的個數。 int size = coll.size(); System.out.println("size:"+size);//size:3 //public Object[] toArray(): 把集合中的元素,存儲到數組中。 Object[] arr = coll.toArray(); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } //public void clear() :清空集合中全部的元素。可是不刪除集合,集合還存在 coll.clear(); System.out.println(coll);//[] System.out.println(coll.isEmpty());//true } }
package com.itheima.demo02.Iterator; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /* java.util.Iterator接口:迭代器(對集合進行遍歷) 有兩個經常使用的方法 boolean hasNext() 若是仍有元素能夠迭代,則返回 true。 判斷集合中還有沒有下一個元素,有就返回true,沒有就返回false E next() 返回迭代的下一個元素。 取出集合中的下一個元素 Iterator迭代器,是一個接口,咱們沒法直接使用,須要使用Iterator接口的實現類對象,獲取實現類的方式比較特殊 Collection接口中有一個方法,叫iterator(),這個方法返回的就是迭代器的實現類對象 Iterator<E> iterator() 返回在此 collection 的元素上進行迭代的迭代器。 迭代器的使用步驟(重點): 1.使用集合中的方法iterator()獲取迭代器的實現類對象,使用Iterator接口接收(多態) 2.使用Iterator接口中的方法hasNext判斷還有沒有下一個元素 3.使用Iterator接口中的方法next取出集合中的下一個元素 */ public class Demo01Iterator { public static void main(String[] args) { //建立一個集合對象 Collection<String> coll = new ArrayList<>(); //往集合中添加元素 coll.add("姚明"); coll.add("科比"); coll.add("麥迪"); coll.add("詹姆斯"); coll.add("艾弗森"); /* 1.使用集合中的方法iterator()獲取迭代器的實現類對象,使用Iterator接口接收(多態) 注意: Iterator<E>接口也是有泛型的,迭代器的泛型跟着集合走,集合是什麼泛型,迭代器就是什麼泛型 */ //多態 接口 實現類對象 Iterator<String> it = coll.iterator(); /* 發現使用迭代器取出集合中元素的代碼,是一個重複的過程 因此咱們可使用循環優化 不知道集合中有多少元素,使用while循環 循環結束的條件,hasNext方法返回false */ while(it.hasNext()){ String e = it.next(); System.out.println(e); } System.out.println("----------------------"); for(Iterator<String> it2 = coll.iterator();it2.hasNext();){ String e = it2.next(); System.out.println(e); } /* //2.使用Iterator接口中的方法hasNext判斷還有沒有下一個元素 boolean b = it.hasNext(); System.out.println(b);//true //3.使用Iterator接口中的方法next取出集合中的下一個元素 String s = it.next(); System.out.println(s);//姚明 b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b); s = it.next(); System.out.println(s); b = it.hasNext(); System.out.println(b);//沒有元素,返回false s = it.next();//沒有元素,在取出元素會拋出NoSuchElementException沒有元素異常 System.out.println(s);*/ } }
package com.itheima.demo02.Iterator; import java.util.ArrayList; /* 加強for循環:底層使用的也是迭代器,使用for循環的格式,簡化了迭代器的書寫 是JDK1.5以後出現的新特性 Collection<E>extends Iterable<E>:全部的單列集合均可以使用加強for public interface Iterable<T>實現這個接口容許對象成爲 "foreach" 語句的目標。 加強for循環:用來遍歷集合和數組 格式: for(集合/數組的數據類型 變量名: 集合名/數組名){ sout(變量名); } */ public class Demo02Foreach { public static void main(String[] args) { demo02(); } //使用加強for循環遍歷集合 private static void demo02() { ArrayList<String> list = new ArrayList<>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); list.add("ddd"); for(String s : list){ System.out.println(s); } } //使用加強for循環遍歷數組 private static void demo01() { int[] arr = {1,2,3,4,5}; for(int i:arr){ System.out.println(i); } } }
通配符高級使用----受限泛型 以前設置泛型的時候,其實是能夠任意設置的,只要是類就能夠設置。可是在JAVA的泛型中能夠指定一個泛型的上限和下限。 泛型的上限: 格式: 類型名稱 <? extends 類 > 對象名稱 意義: 只能接收該類型及其子類 泛型的下限: 格式: 類型名稱 <? super 類 > 對象名稱 意義: 只能接收該類型及其父類型 好比:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類 ~~~java public static void main(String[] args) { Collection list1 = new ArrayList(); Collection list2 = new ArrayList(); Collection list3 = new ArrayList(); Collection list4 = new ArrayList(); getElement(list1); getElement(list2);//報錯 getElement(list3); getElement(list4);//報錯 getElement2(list1);//報錯 getElement2(list2);//報錯 getElement2(list3); getElement2(list4); } // 泛型的上限:此時的泛型?,必須是Number類型或者Number類型的子類 public static void getElement1(Collection<? extends Number> coll){} // 泛型的下限:此時的泛型?,必須是Number類型或者Number類型的父類 public static void getElement2(Collection<? super Number> coll){} ~~~
package com.itheima.demo01.List; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /* java.util.List接口 extends Collection接口 List接口的特色: 1.有序的集合,存儲元素和取出元素的順序是一致的(存儲123 取出123) 2.有索引,包含了一些帶索引的方法 3.容許存儲重複的元素 List接口中帶索引的方法(特有) - public void add(int index, E element): 將指定的元素,添加到該集合中的指定位置上。 - public E get(int index):返回集合中指定位置的元素。 - public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。 - public E set(int index, E element):用指定元素替換集合中指定位置的元素,返回值的更新前的元素。 注意: 操做索引的時候,必定要防止索引越界異常 IndexOutOfBoundsException:索引越界異常,集合會報 ArrayIndexOutOfBoundsException:數組索引越界異常 StringIndexOutOfBoundsException:字符串索引越界異常 */ public class Demo01List { public static void main(String[] args) { //建立一個List集合對象,多態 List<String> list = new ArrayList<>(); //使用add方法往集合中添加元素 list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("a"); //打印集合 System.out.println(list);//[a, b, c, d, a] 不是地址重寫了toString //public void add(int index, E element): 將指定的元素,添加到該集合中的指定位置上。 //在c和d之間添加一個itheima list.add(3,"itheima");//[a, b, c, itheima, d, a] System.out.println(list); //public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。 //移除元素 String removeE = list.remove(2); System.out.println("被移除的元素:"+removeE);//被移除的元素:c System.out.println(list);//[a, b, itheima, d, a] //public E set(int index, E element):用指定元素替換集合中指定位置的元素,返回值的更新前的元素。 //把最後一個a,替換爲A String setE = list.set(4, "A"); System.out.println("被替換的元素:"+setE);//被替換的元素:a System.out.println(list);//[a, b, itheima, d, A] //List集合遍歷有3種方式 //使用普通的for循環 for(int i=0; i<list.size(); i++){ //public E get(int index):返回集合中指定位置的元素。 String s = list.get(i); System.out.println(s); } System.out.println("-----------------"); //使用迭代器 Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s); } System.out.println("-----------------"); //使用加強for for (String s : list) { System.out.println(s); } String r = list.get(5);//IndexOutOfBoundsException: Index 5 out-of-bounds for length 5 System.out.println(r); } }
package com.itheima.demo01.List; import java.util.LinkedList; /* java.util.LinkedList集合 implements List接口 LinkedList集合的特色: 1.底層是一個鏈表結構:查詢慢,增刪快 2.裏邊包含了大量操做首尾元素的方法 注意:使用LinkedList集合特有的方法,不能使用多態 - public void addFirst(E e):將指定元素插入此列表的開頭。 - public void addLast(E e):將指定元素添加到此列表的結尾。 - public void push(E e):將元素推入此列表所表示的堆棧。 - public E getFirst():返回此列表的第一個元素。 - public E getLast():返回此列表的最後一個元素。 - public E removeFirst():移除並返回此列表的第一個元素。 - public E removeLast():移除並返回此列表的最後一個元素。 - public E pop():今後列表所表示的堆棧處彈出一個元素。 - public boolean isEmpty():若是列表不包含元素,則返回true。 */ public class Demo02LinkedList { public static void main(String[] args) { show03(); } /* - public E removeFirst():移除並返回此列表的第一個元素。 - public E removeLast():移除並返回此列表的最後一個元素。 - public E pop():今後列表所表示的堆棧處彈出一個元素。此方法至關於 removeFirst */ private static void show03() { //建立LinkedList集合對象 LinkedList<String> linked = new LinkedList<>(); //使用add方法往集合中添加元素 linked.add("a"); linked.add("b"); linked.add("c"); System.out.println(linked);//[a, b, c] //String first = linked.removeFirst(); String first = linked.pop(); System.out.println("被移除的第一個元素:"+first); String last = linked.removeLast(); System.out.println("被移除的最後一個元素:"+last); System.out.println(linked);//[b] } /* - public E getFirst():返回此列表的第一個元素。 - public E getLast():返回此列表的最後一個元素。 */ private static void show02() { //建立LinkedList集合對象 LinkedList<String> linked = new LinkedList<>(); //使用add方法往集合中添加元素 linked.add("a"); linked.add("b"); linked.add("c"); //linked.clear();//清空集合中的元素 在獲取集合中的元素會拋出NoSuchElementException //public boolean isEmpty():若是列表不包含元素,則返回true。 if(!linked.isEmpty()){ String first = linked.getFirst(); System.out.println(first);//a String last = linked.getLast(); System.out.println(last);//c } } /* - public void addFirst(E e):將指定元素插入此列表的開頭。 - public void addLast(E e):將指定元素添加到此列表的結尾。 - public void push(E e):將元素推入此列表所表示的堆棧。此方法等效於 addFirst(E)。 */ private static void show01() { //建立LinkedList集合對象 LinkedList<String> linked = new LinkedList<>(); //使用add方法往集合中添加元素 linked.add("a"); linked.add("b"); linked.add("c"); System.out.println(linked);//[a, b, c] //public void addFirst(E e):將指定元素插入此列表的開頭。 //linked.addFirst("www"); linked.push("www"); System.out.println(linked);//[www, a, b, c] //public void addLast(E e):將指定元素添加到此列表的結尾。此方法等效於 add() linked.addLast("com"); System.out.println(linked);//[www, a, b, c, com] } }
package com.itheima.demo02.Set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /* java.util.Set接口 extends Collection接口 Set接口的特色: 1.不容許存儲重複的元素 2.沒有索引,沒有帶索引的方法,也不能使用普通的for循環遍歷 java.util.HashSet集合 implements Set接口 HashSet特色: 1.不容許存儲重複的元素 2.沒有索引,沒有帶索引的方法,也不能使用普通的for循環遍歷 3.是一個無序的集合,存儲元素和取出元素的順序有可能不一致 4.底層是一個哈希表結構(查詢的速度很是的快) */ public class Demo01Set { public static void main(String[] args) { Set<Integer> set = new HashSet<>(); //使用add方法往集合中添加元素 set.add(1); set.add(3); set.add(2); set.add(1); //使用迭代器遍歷set集合 Iterator<Integer> it = set.iterator(); while (it.hasNext()){ Integer n = it.next(); System.out.println(n);//1,2,3 } //使用加強for遍歷set集合 System.out.println("-----------------"); for (Integer i : set) { System.out.println(i); } } }
package com.itheima.demo02.Set; import java.util.HashSet; import java.util.LinkedHashSet; /* java.util.LinkedHashSet集合 extends HashSet集合 LinkedHashSet集合特色: 底層是一個哈希表(數組+鏈表/紅黑樹)+鏈表:多了一條鏈表(記錄元素的存儲順序),保證元素有序 */ public class Demo04LinkedHashSet { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("www"); set.add("abc"); set.add("abc"); set.add("itcast"); System.out.println(set);//[abc, www, itcast] 無序,不容許重複 LinkedHashSet<String> linked = new LinkedHashSet<>(); linked.add("www"); linked.add("abc"); linked.add("abc"); linked.add("itcast"); System.out.println(linked);//[www, abc, itcast] 有序,不容許重複 } }
package com.itheima.demo04.VarArgs; /* 可變參數:是JDK1.5以後出現的新特性 使用前提: 當方法的參數列表數據類型已經肯定,可是參數的個數不肯定,就可使用可變參數. 使用格式:定義方法時使用 修飾符 返回值類型 方法名(數據類型...變量名){} 可變參數的原理: 可變參數底層就是一個數組,根據傳遞參數個數不一樣,會建立不一樣長度的數組,來存儲這些參數 傳遞的參數個數,能夠是0個(不傳遞),1,2...多個 */ public class Demo01VarArgs { public static void main(String[] args) { //int i = add(); //int i = add(10); int i = add(10,20); //int i = add(10,20,30,40,50,60,70,80,90,100); System.out.println(i); method("abc",5.5,10,1,2,3,4); } /* 可變參數的注意事項 1.一個方法的參數列表,只能有一個可變參數 2.若是方法的參數有多個,那麼可變參數必須寫在參數列表的末尾 */ /*public static void method(int...a,String...b){ }*/ /*public static void method(String b,double c,int d,int...a){ }*/ //可變參數的特殊(終極)寫法 public static void method(Object...obj){ } /* 定義計算(0-n)整數和的方法 已知:計算整數的和,數據類型已經肯定int 可是參數的個數不肯定,不知道要計算幾個整數的和,就可使用可變參數 add(); 就會建立一個長度爲0的數組, new int[0] add(10); 就會建立一個長度爲1的數組,存儲傳遞來過的參數 new int[]{10}; add(10,20); 就會建立一個長度爲2的數組,存儲傳遞來過的參數 new int[]{10,20}; add(10,20,30,40,50,60,70,80,90,100); 就會建立一個長度爲2的數組,存儲傳遞來過的參數 new int[]{10,20,30,40,50,60,70,80,90,100}; */ public static int add(int...arr){ //System.out.println(arr);//[I@2ac1fdc4 底層是一個數組 //System.out.println(arr.length);//0,1,2,10 //定義一個初始化的變量,記錄累加求和 int sum = 0; //遍歷數組,獲取數組中的每個元素 for (int i : arr) { //累加求和 sum += i; } //把求和結果返回 return sum; } //定義一個方法,計算三個int類型整數的和 /*public static int add(int a,int b,int c){ return a+b+c; }*/ //定義一個方法,計算兩個int類型整數的和 /*public static int add(int a,int b){ return a+b; }*/ }
package com.itheima.demo05.Collections; import java.util.ArrayList; import java.util.Collections; /* - java.utils.Collections是集合工具類,用來對集合進行操做。部分方法以下: - public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。 - public static void shuffle(List<?> list) 打亂順序:打亂集合順序。 */ public class Demo01Collections { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); //往集合中添加多個元素 /*list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("e");*/ //public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。 Collections.addAll(list,"a","b","c","d","e"); System.out.println(list);//[a, b, c, d, e] //public static void shuffle(List<?> list) 打亂順序:打亂集合順序。 Collections.shuffle(list); System.out.println(list);//[b, d, c, a, e], [b, d, c, a, e] } }
package com.itheima.demo05.Collections; public class Person implements Comparable<Person>{ private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //重寫排序的規則 @Override public int compareTo(Person o) { //return 0;//認爲元素都是相同的 //自定義比較的規則,比較兩我的的年齡(this,參數Person) //return this.getAge() - o.getAge();//年齡升序排序 return o.getAge() - this.getAge();//年齡升序排序 } } package com.itheima.demo05.Collections; import java.util.ArrayList; import java.util.Collections; /* - java.utils.Collections是集合工具類,用來對集合進行操做。部分方法以下: public static <T> void sort(List<T> list):將集合中元素按照默認規則排序。 注意: sort(List<T> list)使用前提 被排序的集合裏邊存儲的元素,必須實現Comparable,重寫接口中的方法compareTo定義排序的規則 Comparable接口的排序規則: 本身(this)-參數:升序 */ public class Demo02Sort { public static void main(String[] args) { ArrayList<Integer> list01 = new ArrayList<>(); list01.add(1); list01.add(3); list01.add(2); System.out.println(list01);//[1, 3, 2] //public static <T> void sort(List<T> list):將集合中元素按照默認規則排序。 Collections.sort(list01);//默認是升序 System.out.println(list01);//[1, 2, 3] ArrayList<String> list02 = new ArrayList<>(); list02.add("a"); list02.add("c"); list02.add("b"); System.out.println(list02);//[a, c, b] Collections.sort(list02); System.out.println(list02);//[a, b, c] ArrayList<Person> list03 = new ArrayList<>(); list03.add(new Person("張三",18)); list03.add(new Person("李四",20)); list03.add(new Person("王五",15)); System.out.println(list03);//[Person{name='張三', age=18}, Person{name='李四', age=20}, Person{name='王五', age=15}] Collections.sort(list03); System.out.println(list03); } }
package com.itheima.demo05.Collections; public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } package com.itheima.demo05.Collections; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; /* - java.utils.Collections是集合工具類,用來對集合進行操做。部分方法以下: public static <T> void sort(List<T> list,Comparator<? super T> ):將集合中元素按照指定規則排序。 Comparator和Comparable的區別 Comparable:本身(this)和別人(參數)比較,本身須要實現Comparable接口,重寫比較的規則compareTo方法 Comparator:至關於找一個第三方的裁判,比較兩個 Comparator的排序規則: o1-o2:升序 */ public class Demo03Sort { public static void main(String[] args) { ArrayList<Integer> list01 = new ArrayList<>(); list01.add(1); list01.add(3); list01.add(2); System.out.println(list01);//[1, 3, 2] Collections.sort(list01, new Comparator<Integer>() { //重寫比較的規則 @Override public int compare(Integer o1, Integer o2) { //return o1-o2;//升序 return o2-o1;//降序 } }); System.out.println(list01); ArrayList<Student> list02 = new ArrayList<>(); list02.add(new Student("a迪麗熱巴",18)); list02.add(new Student("古力娜扎",20)); list02.add(new Student("楊冪",17)); list02.add(new Student("b楊冪",18)); System.out.println(list02); /*Collections.sort(list02, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { //按照年齡升序排序 return o1.getAge()-o2.getAge(); } });*/ //擴展:瞭解 Collections.sort(list02, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { //按照年齡升序排序 int result = o1.getAge()-o2.getAge(); //若是兩我的年齡相同,再使用姓名的第一個字比較 if(result==0){ result = o1.getName().charAt(0)-o2.getName().charAt(0); } return result; } }); System.out.println(list02); } }
package com.itheima.demo01.Map; import java.util.HashMap; import java.util.Map; /* java.util.Map<k,v>集合 Map集合的特色: 1.Map集合是一個雙列集合,一個元素包含兩個值(一個key,一個value) 2.Map集合中的元素,key和value的數據類型能夠相同,也能夠不一樣 3.Map集合中的元素,key是不容許重複的,value是能夠重複的 4.Map集合中的元素,key和value是一一對應 java.util.HashMap<k,v>集合 implements Map<k,v>接口 HashMap集合的特色: 1.HashMap集合底層是哈希表:查詢的速度特別的快 JDK1.8以前:數組+單向鏈表 JDK1.8以後:數組+單向鏈表|紅黑樹(鏈表的長度超過8):提升查詢的速度 2.hashMap集合是一個無序的集合,存儲元素和取出元素的順序有可能不一致 java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合 LinkedHashMap的特色: 1.LinkedHashMap集合底層是哈希表+鏈表(保證迭代的順序) 2.LinkedHashMap集合是一個有序的集合,存儲元素和取出元素的順序是一致的 */ public class Demo01Map { public static void main(String[] args) { show04(); } /* boolean containsKey(Object key) 判斷集合中是否包含指定的鍵。 包含返回true,不包含返回false */ private static void show04() { //建立Map集合對象 Map<String,Integer> map = new HashMap<>(); map.put("趙麗穎",168); map.put("楊穎",165); map.put("林志玲",178); boolean b1 = map.containsKey("趙麗穎"); System.out.println("b1:"+b1);//b1:true boolean b2 = map.containsKey("趙穎"); System.out.println("b2:"+b2);//b2:false } /* public V get(Object key) 根據指定的鍵,在Map集合中獲取對應的值。 返回值: key存在,返回對應的value值 key不存在,返回null */ private static void show03() { //建立Map集合對象 Map<String,Integer> map = new HashMap<>(); map.put("趙麗穎",168); map.put("楊穎",165); map.put("林志玲",178); Integer v1 = map.get("楊穎"); System.out.println("v1:"+v1);//v1:165 Integer v2 = map.get("迪麗熱巴"); System.out.println("v2:"+v2);//v2:null } /* public V remove(Object key): 把指定的鍵 所對應的鍵值對元素 在Map集合中刪除,返回被刪除元素的值。 返回值:V key存在,v返回被刪除的值 key不存在,v返回null */ private static void show02() { //建立Map集合對象 Map<String,Integer> map = new HashMap<>(); map.put("趙麗穎",168); map.put("楊穎",165); map.put("林志玲",178); System.out.println(map);//{林志玲=178, 趙麗穎=168, 楊穎=165} Integer v1 = map.remove("林志玲"); System.out.println("v1:"+v1);//v1:178 System.out.println(map);//{趙麗穎=168, 楊穎=165} //int v2 = map.remove("林志穎");//自動拆箱 NullPointerException Integer v2 = map.remove("林志穎"); System.out.println("v2:"+v2);//v2:null System.out.println(map);//{趙麗穎=168, 楊穎=165} } /* public V put(K key, V value): 把指定的鍵與指定的值添加到Map集合中。 返回值:v 存儲鍵值對的時候,key不重複,返回值V是null 存儲鍵值對的時候,key重複,會使用新的value替換map中重複的value,返回被替換的value值 */ private static void show01() { //建立Map集合對象,多態 Map<String,String> map = new HashMap<>(); String v1 = map.put("李晨", "范冰冰1"); System.out.println("v1:"+v1);//v1:null String v2 = map.put("李晨", "范冰冰2"); System.out.println("v2:"+v2);//v2:范冰冰1 System.out.println(map);//{李晨=范冰冰2} map.put("冷鋒","龍小云"); map.put("楊過","小龍女"); map.put("尹志平","小龍女"); System.out.println(map);//{楊過=小龍女, 尹志平=小龍女, 李晨=范冰冰2, 冷鋒=龍小云} } }
package com.itheima.demo01.Map; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /* Map集合的第一種遍歷方式:經過鍵找值的方式 Map集合中的方法: Set<K> keySet() 返回此映射中包含的鍵的 Set 視圖。 實現步驟: 1.使用Map集合中的方法keySet(),把Map集合全部的key取出來,存儲到一個Set集合中 2.遍歷set集合,獲取Map集合中的每個key 3.經過Map集合中的方法get(key),經過key找到value */ public class Demo02KeySet { public static void main(String[] args) { //建立Map集合對象 Map<String,Integer> map = new HashMap<>(); map.put("趙麗穎",168); map.put("楊穎",165); map.put("林志玲",178); //1.使用Map集合中的方法keySet(),把Map集合全部的key取出來,存儲到一個Set集合中 Set<String> set = map.keySet(); //2.遍歷set集合,獲取Map集合中的每個key //使用迭代器遍歷Set集合 Iterator<String> it = set.iterator(); while (it.hasNext()){ String key = it.next(); //3.經過Map集合中的方法get(key),經過key找到value Integer value = map.get(key); System.out.println(key+"="+value); } System.out.println("-------------------"); //使用加強for遍歷Set集合 for(String key : set){ //3.經過Map集合中的方法get(key),經過key找到value Integer value = map.get(key); System.out.println(key+"="+value); } System.out.println("-------------------"); //使用加強for遍歷Set集合 for(String key : map.keySet()){ //3.經過Map集合中的方法get(key),經過key找到value Integer value = map.get(key); System.out.println(key+"="+value); } } }
package com.itheima.demo01.Map; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /* Map集合遍歷的第二種方式:使用Entry對象遍歷 Map集合中的方法: Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射關係的 Set 視圖。 實現步驟: 1.使用Map集合中的方法entrySet(),把Map集合中多個Entry對象取出來,存儲到一個Set集合中 2.遍歷Set集合,獲取每個Entry對象 3.使用Entry對象中的方法getKey()和getValue()獲取鍵與值 */ public class Demo03EntrySet { public static void main(String[] args) { //建立Map集合對象 Map<String,Integer> map = new HashMap<>(); map.put("趙麗穎",168); map.put("楊穎",165); map.put("林志玲",178); //1.使用Map集合中的方法entrySet(),把Map集合中多個Entry對象取出來,存儲到一個Set集合中 Set<Map.Entry<String, Integer>> set = map.entrySet(); //2.遍歷Set集合,獲取每個Entry對象 //使用迭代器遍歷Set集合 Iterator<Map.Entry<String, Integer>> it = set.iterator(); while(it.hasNext()){ Map.Entry<String, Integer> entry = it.next(); //3.使用Entry對象中的方法getKey()和getValue()獲取鍵與值 String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key+"="+value); } System.out.println("-----------------------"); for(Map.Entry<String,Integer> entry:set){ //3.使用Entry對象中的方法getKey()和getValue()獲取鍵與值 String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key+"="+value); } } }
package com.itheima.demo03.Map; import java.util.HashMap; import java.util.LinkedHashMap; /* java.util.LinkedHashMap<K,V> entends HashMap<K,V> Map 接口的哈希表和連接列表實現,具備可預知的迭代順序。 底層原理: 哈希表+鏈表(記錄元素的順序) */ public class Demo01LinkedHashMap { public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); map.put("a","a"); map.put("c","c"); map.put("b","b"); map.put("a","d"); System.out.println(map);// key不容許重複,無序 {a=d, b=b, c=c} LinkedHashMap<String,String> linked = new LinkedHashMap<>(); linked.put("a","a"); linked.put("c","c"); linked.put("b","b"); linked.put("a","d"); System.out.println(linked);// key不容許重複,有序 {a=d, c=c, b=b} } }
package com.itheima.demo03.Map; import java.util.HashMap; import java.util.Hashtable; /* java.util.Hashtable<K,V>集合 implements Map<K,V>接口 Hashtable:底層也是一個哈希表,是一個線程安全的集合,是單線程集合,速度慢 HashMap:底層是一個哈希表,是一個線程不安全的集合,是多線程的集合,速度快 HashMap集合(以前學的全部的集合):能夠存儲null值,null鍵 Hashtable集合,不能存儲null值,null鍵 Hashtable和Vector集合同樣,在jdk1.2版本以後被更先進的集合(HashMap,ArrayList)取代了 Hashtable的子類Properties依然活躍在歷史舞臺 Properties集合是一個惟一和IO流相結合的集合 */ public class Demo02Hashtable { public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); map.put(null,"a"); map.put("b",null); map.put(null,null); System.out.println(map);//{null=null, b=null} Hashtable<String,String> table = new Hashtable<>(); //table.put(null,"a");//NullPointerException //table.put("b",null);//NullPointerException table.put(null,null);//NullPointerException } }
package com.itheima.demo03.Map; import java.util.HashMap; import java.util.Scanner; /* 練習: 計算一個字符串中每一個字符出現次數 分析: 1.使用Scanner獲取用戶輸入的字符串 2.建立Map集合,key是字符串中的字符,value是字符的個數 3.遍歷字符串,獲取每個字符 4.使用獲取到的字符,去Map集合判斷key是否存在 key存在: 經過字符(key),獲取value(字符個數) value++ put(key,value)把新的value存儲到Map集合中 key不存在: put(key,1) 5.遍歷Map集合,輸出結果 */ public class Demo03MapTest { public static void main(String[] args) { //1.使用Scanner獲取用戶輸入的字符串 Scanner sc = new Scanner(System.in); System.out.println("請輸入一個字符串:"); String str = sc.next(); //2.建立Map集合,key是字符串中的字符,value是字符的個數 HashMap<Character,Integer> map = new HashMap<>(); //3.遍歷字符串,獲取每個字符 for(char c :str.toCharArray()){ //4.使用獲取到的字符,去Map集合判斷key是否存在 if(map.containsKey(c)){ //key存在 Integer value = map.get(c); value++; map.put(c,value); }else{ //key不存在 map.put(c,1); } } //5.遍歷Map集合,輸出結果 for(Character key :map.keySet()){ Integer value = map.get(key); System.out.println(key+"="+value); } } }
package com.itheima.demo01.Exception; /* java.lang.Throwable:類是 Java 語言中全部錯誤或異常的超類。 Exception:編譯期異常,進行編譯(寫代碼)java程序出現的問題 RuntimeException:運行期異常,java程序運行過程當中出現的問題 異常就至關於程序得了一個小毛病(感冒,發燒),把異常處理掉,程序能夠繼續執行(吃點藥,繼續革命工做) Error:錯誤 錯誤就至關於程序得了一個沒法治癒的毛病(非典,艾滋).必須修改源代碼,程序才能繼續執行 */ public class Demo01Exception { public static void main(String[] args) /*throws ParseException*/ { //Exception:編譯期異常,進行編譯(寫代碼)java程序出現的問題 /*SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//用來格式化日期 Date date = null; try { date = sdf.parse("1999-0909");//把字符串格式的日期,解析爲Date格式的日期 } catch (ParseException e) { e.printStackTrace(); } System.out.println(date);*/ //RuntimeException:運行期異常,java程序運行過程當中出現的問題 /*int[] arr = {1,2,3}; //System.out.println(arr[0]); try { //可能會出現異常的代碼 System.out.println(arr[3]); }catch(Exception e){ //異常的處理邏輯 System.out.println(e); }*/ /* Error:錯誤 OutOfMemoryError: Java heap space 內存溢出的錯誤,建立的數組太大了,超出了給JVM分配的內存 */ //int[] arr = new int[1024*1024*1024]; //必須修改代碼,建立的數組小一點 int[] arr = new int[1024*1024]; System.out.println("後續代碼"); } }
package com.itheima.demo01.Exception; /* throw關鍵字 做用: 可使用throw關鍵字在指定的方法中拋出指定的異常 使用格式: throw new xxxException("異常產生的緣由"); 注意: 1.throw關鍵字必須寫在方法的內部 2.throw關鍵字後邊new的對象必須是Exception或者Exception的子類對象 3.throw關鍵字拋出指定的異常對象,咱們就必須處理這個異常對象 throw關鍵字後邊建立的是RuntimeException或者是 RuntimeException的子類對象,咱們能夠不處理,默認交給JVM處理(打印異常對象,中斷程序) throw關鍵字後邊建立的是編譯異常(寫代碼的時候報錯),咱們就必須處理這個異常,要麼throws,要麼try...catch */ public class Demo03Throw { public static void main(String[] args) { //int[] arr = null; int[] arr = new int[3]; int e = getElement(arr,3); System.out.println(e); } /* 定義一個方法,獲取數組指定索引處的元素 參數: int[] arr int index 之後(工做中)咱們首先必須對方法傳遞過來的參數進行合法性校驗 若是參數不合法,那麼咱們就必須使用拋出異常的方式,告知方法的調用者,傳遞的參數有問題 注意: NullPointerException是一個運行期異常,咱們不用處理,默認交給JVM處理 ArrayIndexOutOfBoundsException是一個運行期異常,咱們不用處理,默認交給JVM處理 */ public static int getElement(int[] arr,int index){ /* 咱們能夠對傳遞過來的參數數組,進行合法性校驗 若是數組arr的值是null 那麼咱們就拋出空指針異常,告知方法的調用者"傳遞的數組的值是null" */ if(arr == null){ throw new NullPointerException("傳遞的數組的值是null"); } /* 咱們能夠對傳遞過來的參數index進行合法性校驗 若是index的範圍不在數組的索引範圍內 那麼咱們就拋出數組索引越界異常,告知方法的調用者"傳遞的索引超出了數組的使用範圍" */ if(index<0 || index>arr.length-1){ throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數組的使用範圍"); } int ele = arr[index]; return ele; } }
package com.itheima.demo01.Exception; import java.util.Objects; /* Obects類中的靜態方法 public static <T> T requireNonNull(T obj):查看指定引用對象不是null。 源碼: public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } */ public class Demo04Objects { public static void main(String[] args) { method(null); } public static void method(Object obj){ //對傳遞過來的參數進行合法性判斷,判斷是否爲null /*if(obj == null){ throw new NullPointerException("傳遞的對象的值是null"); }*/ //Objects.requireNonNull(obj); Objects.requireNonNull(obj,"傳遞的對象的值是null"); } }
package com.itheima.demo01.Exception; import java.io.FileNotFoundException; import java.io.IOException; /* throws關鍵字:異常處理的第一種方式,交給別人處理 做用: 當方法內部拋出異常對象的時候,那麼咱們就必須處理這個異常對象 可使用throws關鍵字處理異常對象,會把異常對象聲明拋出給方法的調用者處理(本身不處理,給別人處理),最終交給JVM處理-->中斷處理 使用格式:在方法聲明時使用 修飾符 返回值類型 方法名(參數列表) throws AAAExcepiton,BBBExcepiton...{ throw new AAAExcepiton("產生緣由"); throw new BBBExcepiton("產生緣由"); ... } 注意: 1.throws關鍵字必須寫在方法聲明處 2.throws關鍵字後邊聲明的異常必須是Exception或者是Exception的子類 3.方法內部若是拋出了多個異常對象,那麼throws後邊必須也聲明多個異常 若是拋出的多個異常對象有子父類關係,那麼直接聲明父類異常便可 4.調用了一個聲明拋出異常的方法,咱們就必須的處理聲明的異常 要麼繼續使用throws聲明拋出,交給方法的調用者處理,最終交給JVM 要麼try...catch本身處理異常 */ public class Demo05Throws { /* FileNotFoundException extends IOException extends Excepiton 若是拋出的多個異常對象有子父類關係,那麼直接聲明父類異常便可 */ //public static void main(String[] args) throws FileNotFoundException,IOException { //public static void main(String[] args) throws IOException { public static void main(String[] args) throws Exception { readFile("c:\\a.tx"); System.out.println("後續代碼"); } /* 定義一個方法,對傳遞的文件路徑進行合法性判斷 若是路徑不是"c:\\a.txt",那麼咱們就拋出文件找不到異常對象,告知方法的調用者 注意: FileNotFoundException是編譯異常,拋出了編譯異常,就必須處理這個異常 可使用throws繼續聲明拋出FileNotFoundException這個異常對象,讓方法的調用者處理 */ public static void readFile(String fileName) throws FileNotFoundException,IOException{ if(!fileName.equals("c:\\a.txt")){ throw new FileNotFoundException("傳遞的文件路徑不是c:\\a.txt"); } /* 若是傳遞的路徑,不是.txt結尾 那麼咱們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對 */ if(!fileName.endsWith(".txt")){ throw new IOException("文件的後綴名不對"); } System.out.println("路徑沒有問題,讀取文件"); } }
package com.itheima.demo02.Exception; import java.io.IOException; /* try...catch:異常處理的第二種方式,本身處理異常 格式: try{ 可能產生異常的代碼 }catch(定義一個異常的變量,用來接收try中拋出的異常對象){ 異常的處理邏輯,異常異常對象以後,怎麼處理異常對象 通常在工做中,會把異常的信息記錄到一個日誌中 } ... catch(異常類名 變量名){ } 注意: 1.try中可能會拋出多個異常對象,那麼就可使用多個catch來處理這些異常對象 2.若是try中產生了異常,那麼就會執行catch中的異常處理邏輯,執行完畢catch中的處理邏輯,繼續執行try...catch以後的代碼 若是try中沒有產生異常,那麼就不會執行catch中異常的處理邏輯,執行完try中的代碼,繼續執行try...catch以後的代碼 */ public class Demo01TryCatch { public static void main(String[] args) { try{ //可能產生異常的代碼 readFile("d:\\a.tx"); System.out.println("資源釋放"); }catch (IOException e){//try中拋出什麼異常對象,catch就定義什麼異常變量,用來接收這個異常對象 //異常的處理邏輯,異常異常對象以後,怎麼處理異常對象 //System.out.println("catch - 傳遞的文件後綴不是.txt"); /* Throwable類中定義了3個異常處理的方法 String getMessage() 返回此 throwable 的簡短描述。 String toString() 返回此 throwable 的詳細消息字符串。 void printStackTrace() JVM打印異常對象,默認此方法,打印的異常信息是最全面的 */ //System.out.println(e.getMessage());//文件的後綴名不對 //System.out.println(e.toString());//重寫Object類的toString java.io.IOException: 文件的後綴名不對 //System.out.println(e);//java.io.IOException: 文件的後綴名不對 /* java.io.IOException: 文件的後綴名不對 at com.itheima.demo02.Exception.Demo01TryCatch.readFile(Demo01TryCatch.java:55) at com.itheima.demo02.Exception.Demo01TryCatch.main(Demo01TryCatch.java:27) */ e.printStackTrace(); } System.out.println("後續代碼"); } /* 若是傳遞的路徑,不是.txt結尾 那麼咱們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對 */ public static void readFile(String fileName) throws IOException { if(!fileName.endsWith(".txt")){ throw new IOException("文件的後綴名不對"); } System.out.println("路徑沒有問題,讀取文件"); } }
package com.kiramie.demo07; import java.io.IOException; /* finally代碼塊 格式: try{ 可能產生異常的代碼 }catch(定義一個異常的變量,用來接收try中拋出的異常對象){ 異常的處理邏輯,異常異常對象以後,怎麼處理異常對象 通常在工做中,會把異常的信息記錄到一個日誌中 } ... catch(異常類名 變量名){ }finally{ 不管是否出現異常都會執行 } 注意: 1.finally不能單獨使用,必須和try一塊兒使用 2.finally通常用於資源釋放(資源回收),不管程序是否出現異常,最後都要資源釋放(IO) */ public class Demo02TryCatchFinally { public static void main(String[] args) { try { //可能會產生異常的代碼 readFile("c:\\a.tx"); } catch (IOException e) { //異常的處理邏輯 e.printStackTrace(); } finally { //不管是否出現異常,都會執行 System.out.println("資源釋放"); } System.out.println("--------");//比finally先執行 } /* 若是傳遞的路徑,不是.txt結尾 那麼咱們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對 */ public static void readFile(String fileName) throws IOException { if(!fileName.endsWith(".txt")){ throw new IOException("文件的後綴名不對"); } System.out.println("路徑沒有問題,讀取文件"); } }
package com.itheima.demo03.Exception; import java.util.List; /* 異常的注意事項 */ public class Demo01Exception { public static void main(String[] args) { /* 多個異常使用捕獲又該如何處理呢? 1. 多個異常分別處理。 2. 多個異常一次捕獲,屢次處理。 3. 多個異常一次捕獲一次處理。 */ //1. 多個異常分別處理。 /* try { int[] arr = {1,2,3}; System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 }catch (ArrayIndexOutOfBoundsException e){ System.out.println(e); } try{ List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 }catch (IndexOutOfBoundsException e){ System.out.println(e); }*/ //2. 多個異常一次捕獲,屢次處理。 /*try { int[] arr = {1,2,3}; //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 }catch (ArrayIndexOutOfBoundsException e){ System.out.println(e); }catch (IndexOutOfBoundsException e){ System.out.println(e); }*/ /* 一個try多個catch注意事項: catch裏邊定義的異常變量,若是有子父類關係,那麼子類的異常變量必須寫在上邊,不然就會報錯 ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException */ /*try { int[] arr = {1,2,3}; //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 }catch (IndexOutOfBoundsException e){ System.out.println(e); }catch (ArrayIndexOutOfBoundsException e){ System.out.println(e); }*/ //3. 多個異常一次捕獲一次處理。 /*try { int[] arr = {1,2,3}; //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 }catch (Exception e){ System.out.println(e); }*/ //運行時異常被拋出能夠不處理。即不捕獲也不聲明拋出。 //默認給虛擬機處理,終止程序,何時不拋出運行時異常了,在來繼續執行程序 int[] arr = {1,2,3}; System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 System.out.println("後續代碼!"); } }
package com.itheima.demo03.Exception; /* 若是finally有return語句,永遠返回finally中的結果,避免該狀況,儘可能不要在finally中寫return語句. */ public class Demo02Exception { public static void main(String[] args) { int a = getA(); System.out.println(a); } //定義一個方法,返回變量a的值 public static int getA(){ int a = 10; try{ return a; }catch (Exception e){ System.out.println(e); }finally { //必定會執行的代碼 a = 100; return a; } } }
package com.itheima.demo03.Exception; /* 子父類的異常: - 若是父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。 - 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出 注意: 父類異常時什麼樣,子類異常就什麼樣 */ public class Fu { public void show01() throws NullPointerException,ClassCastException{} public void show02() throws IndexOutOfBoundsException{} public void show03() throws IndexOutOfBoundsException{} public void show04() throws Exception {} } class Zi extends Fu{ //子類重寫父類方法時,拋出和父類相同的異常 public void show01() throws NullPointerException,ClassCastException{} //子類重寫父類方法時,拋出父類異常的子類 public void show02() throws ArrayIndexOutOfBoundsException{} //子類重寫父類方法時,不拋出異常 public void show03() {} /* 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。 */ //public void show04() throws Exception{} //此時子類產生該異常,只能捕獲處理,不能聲明拋出 public void show04() { try { throw new Exception("編譯期異常"); } catch (Exception e) { e.printStackTrace(); } } }
package com.itheima.demo04.MyException; /* 自定義異常類: java提供的異常類,不夠咱們使用,須要本身定義一些異常類 格式: public class XXXExcepiton extends Exception | RuntimeException{ 添加一個空參數的構造方法 添加一個帶異常信息的構造方法 } 注意: 1.自定義異常類通常都是以Exception結尾,說明該類是一個異常類 2.自定義異常類,必須的繼承Exception或者RuntimeException 繼承Exception:那麼自定義的異常類就是一個編譯期異常,若是方法內部拋出了編譯期異常,就必須處理這個異常,要麼throws,要麼try...catch 繼承RuntimeException:那麼自定義的異常類就是一個運行期異常,無需處理,交給虛擬機處理(中斷處理) */ public class RegisterException extends /*Exception*/ RuntimeException{ //添加一個空參數的構造方法 public RegisterException(){ super(); } /* 添加一個帶異常信息的構造方法 查看源碼發現,全部的異常類都會有一個帶異常信息的構造方法,方法內部會調用父類帶異常信息的構造方法,讓父類來處理這個異常信息 */ public RegisterException(String message){ super(message); } } /*-------------------------------------------------------------------------------------------------------*/ package com.itheima.demo04.MyException; import java.util.Scanner; /* 要求:咱們模擬註冊操做,若是用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。 分析: 1.使用數組保存已經註冊過的用戶名(數據庫) 2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面) 3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷 遍歷存儲已經註冊過用戶名的數組,獲取每個用戶名 使用獲取到的用戶名和用戶輸入的用戶名比較 true: 用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊"; false: 繼續遍歷比較 若是循環結束了,尚未找到重複的用戶名,提示用戶"恭喜您,註冊成功!"; */ public class Demo01RegisterException { // 1.使用數組保存已經註冊過的用戶名(數據庫) static String[] usernames = {"張三","李四","王五"}; public static void main(String[] args) /*throws RegisterException*/ { //2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面) Scanner sc = new Scanner(System.in); System.out.println("請輸入您要註冊的用戶名:"); String username = sc.next(); checkUsername(username); } //3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷 public static void checkUsername(String username) /*throws RegisterException*/ { //遍歷存儲已經註冊過用戶名的數組,獲取每個用戶名 for (String name : usernames) { //使用獲取到的用戶名和用戶輸入的用戶名比較 if(name.equals(username)){ //true:用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊"; try { throw new RegisterException("親,該用戶名已經被註冊"); } catch (RegisterException e) { e.printStackTrace(); return; //結束方法 } } } //若是循環結束了,尚未找到重複的用戶名,提示用戶"恭喜您,註冊成功!"; System.out.println("恭喜您,註冊成功!"); } } /*-------------------------------------------------------------------------------------------------------*/ package com.itheima.demo04.MyException; import java.util.Scanner; /* 要求:咱們模擬註冊操做,若是用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。 分析: 1.使用數組保存已經註冊過的用戶名(數據庫) 2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面) 3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷 遍歷存儲已經註冊過用戶名的數組,獲取每個用戶名 使用獲取到的用戶名和用戶輸入的用戶名比較 true: 用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊"; false: 繼續遍歷比較 若是循環結束了,尚未找到重複的用戶名,提示用戶"恭喜您,註冊成功!"; */ public class Demo02RegisterException { // 1.使用數組保存已經註冊過的用戶名(數據庫) static String[] usernames = {"張三","李四","王五"}; public static void main(String[] args) { //2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面) Scanner sc = new Scanner(System.in); System.out.println("請輸入您要註冊的用戶名:"); String username = sc.next(); checkUsername(username); } //3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷 public static void checkUsername(String username) { //遍歷存儲已經註冊過用戶名的數組,獲取每個用戶名 for (String name : usernames) { //使用獲取到的用戶名和用戶輸入的用戶名比較 if(name.equals(username)){ //true:用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊"; throw new RegisterException("親,該用戶名已經被註冊");//拋出運行期異常,無需處理,交給JVM處理,中斷處理 } } //若是循環結束了,尚未找到重複的用戶名,提示用戶"恭喜您,註冊成功!"; System.out.println("恭喜您,註冊成功!"); } }
package com.itheima.demo06.Thread; //1.建立一個Thread類的子類 public class MyThread extends Thread{ //2.在Thread類的子類中重寫Thread類中的run方法,設置線程任務(開啓線程要作什麼?) @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println("run:"+i); } } } /*--------------------------------------------------------------------*/ package com.itheima.demo06.Thread; /* 建立多線程程序的第一種方式:建立Thread類的子類 java.lang.Thread類:是描述線程的類,咱們想要實現多線程程序,就必須繼承Thread類 實現步驟: 1.建立一個Thread類的子類 2.在Thread類的子類中重寫Thread類中的run方法,設置線程任務(開啓線程要作什麼?) 3.建立Thread類的子類對象 4.調用Thread類中的方法start方法,開啓新的線程,執行run方法 void start() 使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 結果是兩個線程併發地運行;當前線程(main線程)和另外一個線程(建立的新線程,執行其 run 方法)。 屢次啓動一個線程是非法的。特別是當線程已經結束執行後,不能再從新啓動。 java程序屬於搶佔式調度,那個線程的優先級高,那個線程優先執行;同一個優先級,隨機選擇一個執行 */ public class Demo01Thread { public static void main(String[] args) { //3.建立Thread類的子類對象 MyThread mt = new MyThread(); //4.調用Thread類中的方法start方法,開啓新的線程,執行run方法 mt.start(); for (int i = 0; i <20 ; i++) { System.out.println("main:"+i); } } }
package com.itheima.demo01.getName; /* 獲取線程的名稱: 1.使用Thread類中的方法getName() String getName() 返回該線程的名稱。 2.能夠先獲取到當前正在執行的線程,使用線程中的方法getName()獲取線程的名稱 static Thread currentThread() 返回對當前正在執行的線程對象的引用。 */ // 定義一個Thread類的子類 public class MyThread extends Thread{ //重寫Thread類中的run方法,設置線程任務 @Override public void run() { //獲取線程名稱 //String name = getName(); //System.out.println(name); //Thread t = Thread.currentThread(); //System.out.println(t);//Thread[Thread-0,5,main] //String name = t.getName(); //System.out.println(name); //鏈式編程 System.out.println(Thread.currentThread().getName()); } } /*---------------------------------------------------------------*/ package com.itheima.demo01.getName; /* 線程的名稱: 主線程: main 新線程: Thread-0,Thread-1,Thread-2 */ public class Demo01GetThreadName { public static void main(String[] args) { //建立Thread類的子類對象 MyThread mt = new MyThread(); //調用start方法,開啓新線程,執行run方法 mt.start(); new MyThread().start(); new MyThread().start(); //鏈式編程 System.out.println(Thread.currentThread().getName()); } }
package com.itheima.demo03.sleep; /* public static void sleep(long millis):使當前正在執行的線程以指定的毫秒數暫停(暫時中止執行)。 毫秒數結束以後,線程繼續執行 */ public class Demo01Sleep { public static void main(String[] args) { //模擬秒錶 for (int i = 1; i <=60 ; i++) { System.out.println(i); //使用Thread類的sleep方法讓程序睡眠1秒鐘 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
package com.itheima.demo04.Runnable; /* 建立多線程程序的第二種方式:實現Runnable接口 java.lang.Runnable Runnable 接口應該由那些打算經過某一線程執行其實例的類來實現。類必須定義一個稱爲 run 的無參數方法。 java.lang.Thread類的構造方法 Thread(Runnable target) 分配新的 Thread 對象。 Thread(Runnable target, String name) 分配新的 Thread 對象。 實現步驟: 1.建立一個Runnable接口的實現類 2.在實現類中重寫Runnable接口的run方法,設置線程任務 3.建立一個Runnable接口的實現類對象 4.建立Thread類對象,構造方法中傳遞Runnable接口的實現類對象 5.調用Thread類中的start方法,開啓新的線程執行run方法 實現Runnable接口建立多線程程序的好處: 1.避免了單繼承的侷限性 一個類只能繼承一個類(一我的只能有一個親爹),類繼承了Thread類就不能繼承其餘的類 實現了Runnable接口,還能夠繼承其餘的類,實現其餘的接口 2.加強了程序的擴展性,下降了程序的耦合性(解耦) 實現Runnable接口的方式,把設置線程任務和開啓新線程進行了分離(解耦) 實現類中,重寫了run方法:用來設置線程任務 建立Thread類對象,調用start方法:用來開啓新線程 */ public class Demo01Runnable { public static void main(String[] args) { //3.建立一個Runnable接口的實現類對象 RunnableImpl run = new RunnableImpl(); //4.建立Thread類對象,構造方法中傳遞Runnable接口的實現類對象 //Thread t = new Thread(run);//打印線程名稱 Thread t = new Thread(new RunnableImpl2());//打印HelloWorld //5.調用Thread類中的start方法,開啓新的線程執行run方法 t.start(); for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getName()+"-->"+i); } } } /*---------------------------------------------------------------*/ package com.itheima.demo04.Runnable; //1.建立一個Runnable接口的實現類 public class RunnableImpl implements Runnable{ //2.在實現類中重寫Runnable接口的run方法,設置線程任務 @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getName()+"-->"+i); } } } /*---------------------------------------------------------------*/ package com.itheima.demo04.Runnable; //1.建立一個Runnable接口的實現類 public class RunnableImpl2 implements Runnable{ //2.在實現類中重寫Runnable接口的run方法,設置線程任務 @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println("HelloWorld"+i); } } }
package com.itheima.demo05.InnerClassThread; /* 匿名內部類方式實現線程的建立 匿名:沒有名字 內部類:寫在其餘類內部的類 匿名內部類做用:簡化代碼 把子類繼承父類,重寫父類的方法,建立子類對象合一步完成 把實現類實現類接口,重寫接口中的方法,建立實現類對象合成一步完成 匿名內部類的最終產物:子類/實現類對象,而這個類沒有名字 格式: new 父類/接口(){ 重複父類/接口中的方法 }; */ public class Demo01InnerClassThread { public static void main(String[] args) { //線程的父類是Thread // new MyThread().start(); new Thread(){ //重寫run方法,設置線程任務 @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getName()+"-->"+"黑馬"); } } }.start(); //線程的接口Runnable //Runnable r = new RunnableImpl();//多態 Runnable r = new Runnable(){ //重寫run方法,設置線程任務 @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getName()+"-->"+"程序員"); } } }; new Thread(r).start(); //簡化接口的方式 new Thread(new Runnable(){ //重寫run方法,設置線程任務 @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getName()+"-->"+"傳智播客"); } } }).start(); } }
package com.itheima.demo06.ThreadSafe; /* 實現賣票案例 */ public class RunnableImpl implements Runnable{ //定義一個多個線程共享的票源 private int ticket = 100; //設置線程任務:賣票 @Override public void run() { //使用死循環,讓賣票操做重複執行 while(true){ //先判斷票是否存在 if(ticket>0){ //提升安全問題出現的機率,讓程序睡眠 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,賣票 ticket-- System.out.println(Thread.currentThread().getName()+"-->正在賣第"+ticket+"張票"); ticket--; } } } } /*-----------------------------------------------------------------------*/ package com.itheima.demo06.ThreadSafe; /* 模擬賣票案例 建立3個線程,同時開啓,對共享的票進行出售 */ public class Demo01Ticket { public static void main(String[] args) { //建立Runnable接口的實現類對象 RunnableImpl run = new RunnableImpl(); //建立Thread類對象,構造方法中傳遞Runnable接口的實現類對象 Thread t0 = new Thread(run); Thread t1 = new Thread(run); Thread t2 = new Thread(run); //調用start方法開啓多線程 t0.start(); t1.start(); t2.start(); } }
package com.itheima.demo07.Synchronized; /* 賣票案例出現了線程安全問題 賣出了不存在的票和重複的票 解決線程安全問題的一種方案:使用同步代碼塊 格式: synchronized(鎖對象){ 可能會出現線程安全問題的代碼(訪問了共享數據的代碼) } 注意: 1.經過代碼塊中的鎖對象,可使用任意的對象 2.可是必須保證多個線程使用的鎖對象是同一個 3.鎖對象做用: 把同步代碼塊鎖住,只讓一個線程在同步代碼塊中執行 */ public class RunnableImpl implements Runnable{ //定義一個多個線程共享的票源 private int ticket = 100; //建立一個鎖對象 Object obj = new Object(); //設置線程任務:賣票 @Override public void run() { //使用死循環,讓賣票操做重複執行 while(true){ //同步代碼塊 synchronized (obj){ //先判斷票是否存在 if(ticket>0){ //提升安全問題出現的機率,讓程序睡眠 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,賣票 ticket-- System.out.println(Thread.currentThread().getName()+"-->正在賣第"+ticket+"張票"); ticket--; } } } } } /*----------------------------------------------------------------------*/ package com.itheima.demo07.Synchronized; /* 模擬賣票案例 建立3個線程,同時開啓,對共享的票進行出售 */ public class Demo01Ticket { public static void main(String[] args) { //建立Runnable接口的實現類對象 RunnableImpl run = new RunnableImpl(); //建立Thread類對象,構造方法中傳遞Runnable接口的實現類對象 Thread t0 = new Thread(run); Thread t1 = new Thread(run); Thread t2 = new Thread(run); //調用start方法開啓多線程 t0.start(); t1.start(); t2.start(); } }
package com.itheima.demo08.Synchronized; /* 賣票案例出現了線程安全問題 賣出了不存在的票和重複的票 解決線程安全問題的二種方案:使用同步方法 使用步驟: 1.把訪問了共享數據的代碼抽取出來,放到一個方法中 2.在方法上添加synchronized修飾符 格式:定義方法的格式 修飾符 synchronized 返回值類型 方法名(參數列表){ 可能會出現線程安全問題的代碼(訪問了共享數據的代碼) } */ public class RunnableImpl implements Runnable{ //定義一個多個線程共享的票源 private static int ticket = 100; //設置線程任務:賣票 @Override public void run() { System.out.println("this:"+this);//this:com.itheima.demo08.Synchronized.RunnableImpl@58ceff1 //使用死循環,讓賣票操做重複執行 while(true){ payTicketStatic(); } } /* 靜態的同步方法 鎖對象是誰? 不能是this this是建立對象以後產生的,靜態方法優先於對象 靜態方法的鎖對象是本類的class屬性-->class文件對象(反射) */ public static /*synchronized*/ void payTicketStatic(){ synchronized (RunnableImpl.class){ //先判斷票是否存在 if(ticket>0){ //提升安全問題出現的機率,讓程序睡眠 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,賣票 ticket-- System.out.println(Thread.currentThread().getName()+"-->正在賣第"+ticket+"張票"); ticket--; } } } /* 定義一個同步方法 同步方法也會把方法內部的代碼鎖住 只讓一個線程執行 同步方法的鎖對象是誰? 就是實現類對象 new RunnableImpl() 也是就是this */ public /*synchronized*/ void payTicket(){ synchronized (this){ //先判斷票是否存在 if(ticket>0){ //提升安全問題出現的機率,讓程序睡眠 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,賣票 ticket-- System.out.println(Thread.currentThread().getName()+"-->正在賣第"+ticket+"張票"); ticket--; } } } } /*----------------------------------------------------------*/ package com.itheima.demo08.Synchronized; /* 模擬賣票案例 建立3個線程,同時開啓,對共享的票進行出售 */ public class Demo01Ticket { public static void main(String[] args) { //建立Runnable接口的實現類對象 RunnableImpl run = new RunnableImpl(); System.out.println("run:"+run);//run:com.itheima.demo08.Synchronized.RunnableImpl@58ceff1 //建立Thread類對象,構造方法中傳遞Runnable接口的實現類對象 Thread t0 = new Thread(run); Thread t1 = new Thread(run); Thread t2 = new Thread(run); //調用start方法開啓多線程 t0.start(); t1.start(); t2.start(); } }
package com.itheima.demo09.Lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* 賣票案例出現了線程安全問題 賣出了不存在的票和重複的票 解決線程安全問題的三種方案:使用Lock鎖 java.util.concurrent.locks.Lock接口 Lock 實現提供了比使用 synchronized 方法和語句可得到的更普遍的鎖定操做。 Lock接口中的方法: void lock()獲取鎖。 void unlock() 釋放鎖。 java.util.concurrent.locks.ReentrantLock implements Lock接口 使用步驟: 1.在成員位置建立一個ReentrantLock對象 2.在可能會出現安全問題的代碼前調用Lock接口中的方法lock獲取鎖 3.在可能會出現安全問題的代碼後調用Lock接口中的方法unlock釋放鎖 */ public class RunnableImpl implements Runnable{ //定義一個多個線程共享的票源 private int ticket = 100; //1.在成員位置建立一個ReentrantLock對象 Lock l = new ReentrantLock(); //設置線程任務:賣票 @Override public void run() { //使用死循環,讓賣票操做重複執行 while(true){ //2.在可能會出現安全問題的代碼前調用Lock接口中的方法lock獲取鎖 l.lock(); //先判斷票是否存在 if(ticket>0){ //提升安全問題出現的機率,讓程序睡眠 try { Thread.sleep(10); //票存在,賣票 ticket-- System.out.println(Thread.currentThread().getName()+"-->正在賣第"+ticket+"張票"); ticket--; } catch (InterruptedException e) { e.printStackTrace(); }finally { //3.在可能會出現安全問題的代碼後調用Lock接口中的方法unlock釋放鎖 l.unlock();//不管程序是否異常,都會把鎖釋放 } } } } /*//設置線程任務:賣票 @Override public void run() { //使用死循環,讓賣票操做重複執行 while(true){ //2.在可能會出現安全問題的代碼前調用Lock接口中的方法lock獲取鎖 l.lock(); //先判斷票是否存在 if(ticket>0){ //提升安全問題出現的機率,讓程序睡眠 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,賣票 ticket-- System.out.println(Thread.currentThread().getName()+"-->正在賣第"+ticket+"張票"); ticket--; } //3.在可能會出現安全問題的代碼後調用Lock接口中的方法unlock釋放鎖 l.unlock(); } }*/ } /*-----------------------------------------------------------*/ package com.itheima.demo09.Lock; /* 模擬賣票案例 建立3個線程,同時開啓,對共享的票進行出售 */ public class Demo01Ticket { public static void main(String[] args) { //建立Runnable接口的實現類對象 RunnableImpl run = new RunnableImpl(); //建立Thread類對象,構造方法中傳遞Runnable接口的實現類對象 Thread t0 = new Thread(run); Thread t1 = new Thread(run); Thread t2 = new Thread(run); //調用start方法開啓多線程 t0.start(); t1.start(); t2.start(); } }
概念:多個線程在處理同一個資源,可是處理的動做(線程的任務)卻不相同。
好比:線程A用來生成包子的,線程B用來吃包子的,包子能夠理解爲同一資源,線程A與線程B處理的動做,一個 是生產,一個是消費,那麼線程A與線程B之間就存在線程通訊問題。
爲何要處理線程間通訊:
多個線程併發執行時, 在默認狀況下CPU是隨機切換線程的,當咱們須要多個線程來共同完成一件任務,而且咱們 但願他們有規律的執行, 那麼多線程之間須要一些協調通訊,以此來幫咱們達到多線程共同操做一份數據。
如何保證線程間通訊有效利用資源:
多個線程在處理同一個資源,而且任務不一樣時,須要線程通訊來幫助解決線程之間對同一個變量的使用或操做。 就 是多個線程在操做同一份數據時, 避免對同一共享變量的爭奪。也就是咱們須要經過必定的手段使各個線程能有效 的利用資源。而這種手段即—— 等待喚醒機制。
package com.itheima.demo10.WaitAndNotify; /* 等待喚醒案例:線程之間的通訊 建立一個顧客線程(消費者):告知老闆要的包子的種類和數量,調用wait方法,放棄cpu的執行,進入到WAITING狀態(無限等待) 建立一個老闆線程(生產者):花了5秒作包子,作好包子以後,調用notify方法,喚醒顧客吃包子 注意: 顧客和老闆線程必須使用同步代碼塊包裹起來,保證等待和喚醒只能有一個在執行 同步使用的鎖對象必須保證惟一 只有鎖對象才能調用wait和notify方法 Obejct類中的方法 void wait() 在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法前,致使當前線程等待。 void notify() 喚醒在此對象監視器上等待的單個線程。 會繼續執行wait方法以後的代碼 */ public class Demo01WaitAndNotify { public static void main(String[] args) { //建立鎖對象,保證惟一 Object obj = new Object(); // 建立一個顧客線程(消費者) new Thread(){ @Override public void run() { //一直等着買包子 while(true){ //保證等待和喚醒的線程只能有一個執行,須要使用同步技術 synchronized (obj){ System.out.println("告知老闆要的包子的種類和數量"); //調用wait方法,放棄cpu的執行,進入到WAITING狀態(無限等待) try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //喚醒以後執行的代碼 System.out.println("包子已經作好了,開吃!"); System.out.println("---------------------------------------"); } } } }.start(); //建立一個老闆線程(生產者) new Thread(){ @Override public void run() { //一直作包子 while (true){ //花了5秒作包子 try { Thread.sleep(5000);//花5秒鐘作包子 } catch (InterruptedException e) { e.printStackTrace(); } //保證等待和喚醒的線程只能有一個執行,須要使用同步技術 synchronized (obj){ System.out.println("老闆5秒鐘以後作好包子,告知顧客,能夠吃包子了"); //作好包子以後,調用notify方法,喚醒顧客吃包子 obj.notify(); } } } }.start(); } }
package com.itheima.demo10.WaitAndNotify; /* 進入到TimeWaiting(計時等待)有兩種方式 1.使用sleep(long m)方法,在毫秒值結束以後,線程睡醒進入到Runnable/Blocked狀態 2.使用wait(long m)方法,wait方法若是在毫秒值結束以後,尚未被notify喚醒,就會自動醒來,線程睡醒進入到Runnable/Blocked狀態 喚醒的方法: void notify() 喚醒在此對象監視器上等待的單個線程。 void notifyAll() 喚醒在此對象監視器上等待的全部線程。 */ public class Demo02WaitAndNotify { public static void main(String[] args) { //建立鎖對象,保證惟一 Object obj = new Object(); // 建立一個顧客線程(消費者) new Thread(){ @Override public void run() { //一直等着買包子 while(true){ //保證等待和喚醒的線程只能有一個執行,須要使用同步技術 synchronized (obj){ System.out.println("顧客1告知老闆要的包子的種類和數量"); //調用wait方法,放棄cpu的執行,進入到WAITING狀態(無限等待) try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //喚醒以後執行的代碼 System.out.println("包子已經作好了,顧客1開吃!"); System.out.println("---------------------------------------"); } } } }.start(); // 建立一個顧客線程(消費者) new Thread(){ @Override public void run() { //一直等着買包子 while(true){ //保證等待和喚醒的線程只能有一個執行,須要使用同步技術 synchronized (obj){ System.out.println("顧客2告知老闆要的包子的種類和數量"); //調用wait方法,放棄cpu的執行,進入到WAITING狀態(無限等待) try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } //喚醒以後執行的代碼 System.out.println("包子已經作好了,顧客2開吃!"); System.out.println("---------------------------------------"); } } } }.start(); //建立一個老闆線程(生產者) new Thread(){ @Override public void run() { //一直作包子 while (true){ //花了5秒作包子 try { Thread.sleep(5000);//花5秒鐘作包子 } catch (InterruptedException e) { e.printStackTrace(); } //保證等待和喚醒的線程只能有一個執行,須要使用同步技術 synchronized (obj){ System.out.println("老闆5秒鐘以後作好包子,告知顧客,能夠吃包子了"); //作好包子以後,調用notify方法,喚醒顧客吃包子 //obj.notify();//若是有多個等待線程,隨機喚醒一個 obj.notifyAll();//喚醒全部等待的線程 } } } }.start(); } }
package com.itheima.demo01.WaitAndNotify; /* 資源類:包子類 設置包子的屬性 皮 陷 包子的狀態: 有 true,沒有 false */ public class BaoZi { //皮 String pi; //陷 String xian; //包子的狀態: 有 true,沒有 false,設置初始值爲false沒有包子 boolean flag = false; }
package com.itheima.demo01.WaitAndNotify; /* 生產者(包子鋪)類:是一個線程類,能夠繼承Thread 設置線程任務(run):生產包子 對包子的狀態進行判斷 true:有包子 包子鋪調用wait方法進入等待狀態 false:沒有包子 包子鋪生產包子 增長一些趣味性:交替生產兩種包子 有兩種狀態(i%2==0) 包子鋪生產好了包子 修改包子的狀態爲true有 喚醒吃貨線程,讓吃貨線程吃包子 注意: 包子鋪線程和包子線程關係-->通訊(互斥) 必須同時同步技術保證兩個線程只能有一個在執行 鎖對象必須保證惟一,可使用包子對象做爲鎖對象 包子鋪類和吃貨的類就須要把包子對象做爲參數傳遞進來 1.須要在成員位置建立一個包子變量 2.使用帶參數構造方法,爲這個包子變量賦值 */ public class BaoZiPu extends Thread{ //1.須要在成員位置建立一個包子變量 private BaoZi bz; //2.使用帶參數構造方法,爲這個包子變量賦值 public BaoZiPu(BaoZi bz) { this.bz = bz; } //設置線程任務(run):生產包子 @Override public void run() { //定義一個變量 int count = 0; //讓包子鋪一直生產包子 while(true){ //必須同時同步技術保證兩個線程只能有一個在執行 synchronized (bz){ //對包子的狀態進行判斷 if(bz.flag==true){ //包子鋪調用wait方法進入等待狀態 try { bz.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //被喚醒以後執行,包子鋪生產包子 //增長一些趣味性:交替生產兩種包子 if(count%2==0){ //生產 薄皮三鮮餡包子 bz.pi = "薄皮"; bz.xian = "三鮮餡"; }else{ //生產 冰皮 牛肉大蔥陷 bz.pi = "冰皮"; bz.xian = "牛肉大蔥陷"; } count++; System.out.println("包子鋪正在生產:"+bz.pi+bz.xian+"包子"); //生產包子須要3秒鐘 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } //包子鋪生產好了包子 //修改包子的狀態爲true有 bz.flag = true; //喚醒吃貨線程,讓吃貨線程吃包子 bz.notify(); System.out.println("包子鋪已經生產好了:"+bz.pi+bz.xian+"包子,吃貨能夠開始吃了"); } } } }
package com.itheima.demo01.WaitAndNotify; /* 消費者(吃貨)類:是一個線程類,能夠繼承Thread 設置線程任務(run):吃包子 對包子的狀態進行判斷 false:沒有包子 吃貨調用wait方法進入等待狀態 true:有包子 吃貨吃包子 吃貨吃完包子 修改包子的狀態爲false沒有 吃貨喚醒包子鋪線程,生產包子 */ public class ChiHuo extends Thread{ //1.須要在成員位置建立一個包子變量 private BaoZi bz; //2.使用帶參數構造方法,爲這個包子變量賦值 public ChiHuo(BaoZi bz) { this.bz = bz; } //設置線程任務(run):吃包子 @Override public void run() { //使用死循環,讓吃貨一直吃包子 while (true){ //必須同時同步技術保證兩個線程只能有一個在執行 synchronized (bz){ //對包子的狀態進行判斷 if(bz.flag==false){ //吃貨調用wait方法進入等待狀態 try { bz.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //被喚醒以後執行的代碼,吃包子 System.out.println("吃貨正在吃:"+bz.pi+bz.xian+"的包子"); //吃貨吃完包子 //修改包子的狀態爲false沒有 bz.flag = false; //吃貨喚醒包子鋪線程,生產包子 bz.notify(); System.out.println("吃貨已經把:"+bz.pi+bz.xian+"的包子吃完了,包子鋪開始生產包子"); System.out.println("----------------------------------------------------"); } } } }
package com.itheima.demo01.WaitAndNotify; /* 測試類: 包含main方法,程序執行的入口,啓動程序 建立包子對象; 建立包子鋪線程,開啓,生產包子; 建立吃貨線程,開啓,吃包子; */ public class Demo { public static void main(String[] args) { //建立包子對象; BaoZi bz =new BaoZi(); //建立包子鋪線程,開啓,生產包子; new BaoZiPu(bz).start(); //建立吃貨線程,開啓,吃包子; new ChiHuo(bz).start(); } }
概念:
咱們使用線程的時候就去建立一個線程,這樣實現起來很是簡便,可是就會有一個問題:
若是併發的線程數量不少,而且每一個線程都是執行一個時間很短的任務就結束了,這樣頻繁建立線程就會大大下降系統的效率,由於頻繁建立線程和銷燬線程須要時間。
其實就是一個容納多個線程的容器,其中的線程能夠反覆使用,省去了頻繁建立線程對象的操做,無需反覆建立線程而消耗過多資源。
原理:
合理利用線程池可以帶來三個好處:
提升線程的可管理性。能夠根據系統的承受能力,調整線程池中工做線線程的數目,防止由於消耗過多的內存,而把服務器累趴下(每一個線程須要大約1MB內存,線程開的越多,消耗的內存也就越大,最後死機)。
package com.itheima.demo02.ThreadPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /* 線程池:JDK1.5以後提供的 java.util.concurrent.Executors:線程池的工廠類,用來生成線程池 Executors類中的靜態方法: static ExecutorService newFixedThreadPool(int nThreads) 建立一個可重用固定線程數的線程池 參數: int nThreads:建立線程池中包含的線程數量 返回值: ExecutorService接口,返回的是ExecutorService接口的實現類對象,咱們可使用ExecutorService接口接收(面向接口編程) java.util.concurrent.ExecutorService:線程池接口 用來從線程池中獲取線程,調用start方法,執行線程任務 submit(Runnable task) 提交一個 Runnable 任務用於執行 關閉/銷燬線程池的方法 void shutdown() 線程池的使用步驟: 1.使用線程池的工廠類Executors裏邊提供的靜態方法newFixedThreadPool生產一個指定線程數量的線程池 2.建立一個類,實現Runnable接口,重寫run方法,設置線程任務 3.調用ExecutorService中的方法submit,傳遞線程任務(實現類),開啓線程,執行run方法 4.調用ExecutorService中的方法shutdown銷燬線程池(不建議執行) */ public class Demo01ThreadPool { public static void main(String[] args) { //1.使用線程池的工廠類Executors裏邊提供的靜態方法newFixedThreadPool生產一個指定線程數量的線程池 ExecutorService es = Executors.newFixedThreadPool(2); //3.調用ExecutorService中的方法submit,傳遞線程任務(實現類),開啓線程,執行run方法 es.submit(new RunnableImpl());//pool-1-thread-1建立了一個新的線程執行 //線程池會一直開啓,使用完了線程,會自動把線程歸還給線程池,線程能夠繼續使用 es.submit(new RunnableImpl());//pool-1-thread-1建立了一個新的線程執行 es.submit(new RunnableImpl());//pool-1-thread-2建立了一個新的線程執行 //4.調用ExecutorService中的方法shutdown銷燬線程池(不建議執行) es.shutdown(); es.submit(new RunnableImpl());//拋異常,線程池都沒有了,就不能獲取線程了 } } /*----------------------------------------------------------------------*/ package com.itheima.demo02.ThreadPool; /* 2.建立一個類,實現Runnable接口,重寫run方法,設置線程任務 */ public class RunnableImpl implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"建立了一個新的線程執行"); } }
Lambda的使用前提:
Lambda的語法很是簡潔,徹底沒有面向對象複雜的束縛。可是使用時有幾個問題須要特別注意:
Runnable
、Comparator
接口仍是自定義的接口,只有當接口中的抽象方法存在且惟一時,纔可使用Lambda。備註:有且僅有一個抽象方法的接口,稱爲「函數式接口」。
package com.itheima.demo03.Lambda; /* Lambda表達式的標準格式: 由三部分組成: a.一些參數 b.一個箭頭 c.一段代碼 格式: (參數列表) -> {一些重寫方法的代碼}; 解釋說明格式: ():接口中抽象方法的參數列表,沒有參數,就空着;有參數就寫出參數,多個參數使用逗號分隔 ->:傳遞的意思,把參數傳遞給方法體{} {}:重寫接口的抽象方法的方法體 */ public class Demo02Lambda { public static void main(String[] args) { //使用匿名內部類的方式,實現多線程 new Thread(new Runnable(){ @Override public void run() { System.out.println(Thread.currentThread().getName()+" 新線程建立了"); } }).start(); //使用Lambda表達式,實現多線程 new Thread(()->{ System.out.println(Thread.currentThread().getName()+" 新線程建立了"); } ).start(); //優化省略Lambda new Thread(()->System.out.println(Thread.currentThread().getName()+" 新線程建立了")).start(); } }
package com.itheima.demo07.Lambda; import java.util.ArrayList; /* Lambda表達式:是可推導,能夠省略 凡是根據上下文推導出來的內容,均可以省略書寫 能夠省略的內容: 1.(參數列表):括號中參數列表的數據類型,能夠省略不寫 2.(參數列表):括號中的參數若是隻有一個,那麼類型和()均可以省略 3.{一些代碼}:若是{}中的代碼只有一行,不管是否有返回值,均可以省略({},return,分號) 注意:要省略{},return,分號必須一塊兒省略 */ public class Demo01ArrayList { public static void main(String[] args) { //JDK1.7版本以前,建立集合對象必須把先後的泛型都寫上 ArrayList<String> list01 = new ArrayList<String>(); //JDK1.7版本以後,=號後邊的泛型能夠省略,後邊的泛型能夠根據前邊的泛型推導出來 ArrayList<String> list02 = new ArrayList<>(); } }
package com.itheima.demo01.File; import java.io.File; /* java.io.File類 文件和目錄路徑名的抽象表示形式。 java把電腦中的文件和文件夾(目錄)封裝爲了一個File類,咱們可使用File類對文件和文件夾進行操做 咱們可使用File類的方法 建立一個文件/文件夾 刪除文件/文件夾 獲取文件/文件夾 判斷文件/文件夾是否存在 對文件夾進行遍歷 獲取文件的大小 File類是一個與系統無關的類,任何的操做系統均可以使用這個類中的方法 重點:記住這三個單詞 file:文件 directory:文件夾/目錄 path:路徑 */ public class Demo01File { public static void main(String[] args) { /* static String pathSeparator 與系統有關的路徑分隔符,爲了方便,它被表示爲一個字符串。 static char pathSeparatorChar 與系統有關的路徑分隔符。 static String separator 與系統有關的默認名稱分隔符,爲了方便,它被表示爲一個字符串。 static char separatorChar 與系統有關的默認名稱分隔符。 操做路徑:路徑不能寫死了 C:\develop\a\a.txt windows C:/develop/a/a.txt linux "C:"+File.separator+"develop"+File.separator+"a"+File.separator+"a.txt" */ String pathSeparator = File.pathSeparator; System.out.println(pathSeparator);//路徑分隔符 windows:分號; linux:冒號: String separator = File.separator; System.out.println(separator);// 文件名稱分隔符 windows:反斜槓\ linux:正斜槓/ } }
package com.itheima.demo01.File; import java.io.File; /* 路徑: 絕對路徑:是一個完整的路徑 以盤符(c:,D:)開始的路徑 c:\\a.txt C:\\Users\itcast\\IdeaProjects\\shungyuan\\123.txt D:\\demo\\b.txt 相對路徑:是一個簡化的路徑 相對指的是相對於當前項目的根目錄(C:\\Users\itcast\\IdeaProjects\\shungyuan) 若是使用當前項目的根目錄,路徑能夠簡化書寫 C:\\Users\itcast\\IdeaProjects\\shungyuan\\123.txt-->簡化爲: 123.txt(能夠省略項目的根目錄) 注意: 1.路徑是不區分大小寫 2.路徑中的文件名稱分隔符windows使用反斜槓,反斜槓是轉義字符,兩個反斜槓表明一個普通的反斜槓 */ public class Demo02File { public static void main(String[] args) { /* File類的構造方法 */ //show02("c:\\","a.txt");//c:\a.txt //show02("d:\\","a.txt");//d:\a.txt show03(); File f = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan"); long length = f.length(); System.out.println(length); } /* File(File parent, String child) 根據 parent 抽象路徑名和 child 路徑名字符串建立一個新 File 實例。 參數:把路徑分紅了兩部分 File parent:父路徑 String child:子路徑 好處: 父路徑和子路徑,能夠單獨書寫,使用起來很是靈活;父路徑和子路徑均可以變化 父路徑是File類型,可使用File的方法對路徑進行一些操做,再使用路徑建立對象 */ private static void show03() { File parent = new File("c:\\"); File file = new File(parent,"hello.java"); System.out.println(file);//c:\hello.java } /* File(String parent, String child) 根據 parent 路徑名字符串和 child 路徑名字符串建立一個新 File 實例。 參數:把路徑分紅了兩部分 String parent:父路徑 String child:子路徑 好處: 父路徑和子路徑,能夠單獨書寫,使用起來很是靈活;父路徑和子路徑均可以變化 */ private static void show02(String parent, String child) { File file = new File(parent,child); System.out.println(file);//c:\a.txt } /* File(String pathname) 經過將給定路徑名字符串轉換爲抽象路徑名來建立一個新 File 實例。 參數: String pathname:字符串的路徑名稱 路徑能夠是以文件結尾,也能夠是以文件夾結尾 路徑能夠是相對路徑,也能夠是絕對路徑 路徑能夠是存在,也能夠是不存在 建立File對象,只是把字符串路徑封裝爲File對象,不考慮路徑的真假狀況 */ private static void show01() { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt"); System.out.println(f1);//重寫了Object類的toString方法 C:\Users\itcast\IdeaProjects\shungyuan\a.txt File f2 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan"); System.out.println(f2);//C:\Users\itcast\IdeaProjects\shungyuan File f3 = new File("b.txt"); System.out.println(f3);//b.txt } }
package com.itheima.demo01.File; import java.io.File; /* File類獲取功能的方法 - public String getAbsolutePath() :返回此File的絕對路徑名字符串。 - public String getPath() :將此File轉換爲路徑名字符串。 - public String getName() :返回由此File表示的文件或目錄的名稱。 - public long length() :返回由此File表示的文件的長度。 */ public class Demo03File { public static void main(String[] args) { show04(); } /* public long length() :返回由此File表示的文件的長度。 獲取的是構造方法指定的文件的大小,以字節爲單位 注意: 文件夾是沒有大小概念的,不能獲取文件夾的大小 若是構造方法中給出的路徑不存在,那麼length方法返回0 */ private static void show04() { File f1 = new File("C:\\develop\\a\\1.jpg"); long l1 = f1.length(); System.out.println(l1);//780831字節 File f2 = new File("C:\\develop\\a\\2.jpg"); System.out.println(f2.length());//0 File f3 = new File("C:\\develop\\a"); System.out.println(f3.length());//0 文件夾沒有大小概念的 } /* public String getName() :返回由此File表示的文件或目錄的名稱。 獲取的就是構造方法傳遞路徑的結尾部分(文件/文件夾) */ private static void show03() { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt"); String name1 = f1.getName(); System.out.println(name1);//a.txt File f2 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan"); String name2 = f2.getName(); System.out.println(name2);//shungyuan } /* public String getPath() :將此File轉換爲路徑名字符串。 獲取的構造方法中傳遞的路徑 toString方法調用的就是getPath方法 源碼: public String toString() { return getPath(); } */ private static void show02() { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt"); File f2 = new File("a.txt"); String path1 = f1.getPath(); System.out.println(path1);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt String path2 = f2.getPath(); System.out.println(path2);//a.txt System.out.println(f1);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt System.out.println(f1.toString());//C:\Users\itcast\IdeaProjects\shungyuan\a.txt } /* public String getAbsolutePath() :返回此File的絕對路徑名字符串。 獲取的構造方法中傳遞的路徑 不管路徑是絕對的仍是相對的,getAbsolutePath方法返回的都是絕對路徑 */ private static void show01() { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\a.txt"); String absolutePath1 = f1.getAbsolutePath(); System.out.println(absolutePath1);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt File f2 = new File("a.txt"); String absolutePath2 = f2.getAbsolutePath(); System.out.println(absolutePath2);//C:\Users\itcast\IdeaProjects\shungyuan\a.txt } }
package com.itheima.demo01.File; import java.io.File; /* File類判斷功能的方法 - public boolean exists() :此File表示的文件或目錄是否實際存在。 - public boolean isDirectory() :此File表示的是否爲目錄。 - public boolean isFile() :此File表示的是否爲文件。 */ public class Demo04File { public static void main(String[] args) { show02(); } /* public boolean isDirectory() :此File表示的是否爲目錄。 用於判斷構造方法中給定的路徑是否以文件夾結尾 是:true 否:false public boolean isFile() :此File表示的是否爲文件。 用於判斷構造方法中給定的路徑是否以文件結尾 是:true 否:false 注意: 電腦的硬盤中只有文件/文件夾,兩個方法是互斥 這兩個方法使用前提,路徑必須是存在的,不然都返回false */ private static void show02() { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shung"); //不存在,就沒有必要獲取 if(f1.exists()){ System.out.println(f1.isDirectory()); System.out.println(f1.isFile()); } File f2 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan"); if(f2.exists()){ System.out.println(f2.isDirectory());//true System.out.println(f2.isFile());//false } File f3 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\shungyuan.iml"); if(f3.exists()){ System.out.println(f3.isDirectory());//false System.out.println(f3.isFile());//true } } /* public boolean exists() :此File表示的文件或目錄是否實際存在。 用於判斷構造方法中的路徑是否存在 存在:true 不存在:false */ private static void show01() { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan"); System.out.println(f1.exists());//true File f2 = new File("C:\\Users\\itcast\\IdeaProjects\\shung"); System.out.println(f2.exists());//false File f3 = new File("shungyuan.iml");//相對路徑 C:\Users\itcast\IdeaProjects\shungyuan\shungyuan.iml System.out.println(f3.exists());//true File f4 = new File("a.txt"); System.out.println(f4.exists());//false } }
package com.itheima.demo01.File; import java.io.File; import java.io.IOException; /* File類建立刪除功能的方法 - public boolean createNewFile() :當且僅當具備該名稱的文件尚不存在時,建立一個新的空文件。 - public boolean delete() :刪除由此File表示的文件或目錄。 - public boolean mkdir() :建立由此File表示的目錄。 - public boolean mkdirs() :建立由此File表示的目錄,包括任何須需但不存在的父目錄。 */ public class Demo05File { public static void main(String[] args) throws IOException { show03(); } /* public boolean delete() :刪除由此File表示的文件或目錄。 此方法,能夠刪除構造方法路徑中給出的文件/文件夾 返回值:布爾值 true:文件/文件夾刪除成功,返回true false:文件夾中有內容,不會刪除返回false;構造方法中路徑不存在false 注意: delete方法是直接在硬盤刪除文件/文件夾,不走回收站,刪除要謹慎 */ private static void show03() { File f1 = new File("08_FileAndRecursion\\新建文件夾"); boolean b1 = f1.delete(); System.out.println("b1:"+b1); File f2 = new File("08_FileAndRecursion\\abc.txt"); System.out.println(f2.delete()); } /* public boolean mkdir() :建立單級空文件夾 public boolean mkdirs() :既能夠建立單級空文件夾,也能夠建立多級文件夾 建立文件夾的路徑和名稱在構造方法中給出(構造方法的參數) 返回值:布爾值 true:文件夾不存在,建立文件夾,返回true false:文件夾存在,不會建立,返回false;構造方法中給出的路徑不存在返回false 注意: 1.此方法只能建立文件夾,不能建立文件 */ private static void show02() { File f1 = new File("08_FileAndRecursion\\aaa"); boolean b1 = f1.mkdir(); System.out.println("b1:"+b1); File f2 = new File("08_FileAndRecursion\\111\\222\\333\\444"); boolean b2 = f2.mkdirs(); System.out.println("b2:"+b2); File f3 = new File("08_FileAndRecursion\\abc.txt"); boolean b3 = f3.mkdirs();//看類型,是一個文件 System.out.println("b3:"+b3); File f4 = new File("08_F\\ccc"); boolean b4 = f4.mkdirs();//不會拋出異常,路徑不存在,不會建立 System.out.println("b4:"+b4); } /* public boolean createNewFile() :當且僅當具備該名稱的文件尚不存在時,建立一個新的空文件。 建立文件的路徑和名稱在構造方法中給出(構造方法的參數) 返回值:布爾值 true:文件不存在,建立文件,返回true false:文件存在,不會建立,返回false 注意: 1.此方法只能建立文件,不能建立文件夾 2.建立文件的路徑必須存在,不然會拋出異常 public boolean createNewFile() throws IOException createNewFile聲明拋出了IOException,咱們調用這個方法,就必須的處理這個異常,要麼throws,要麼trycatch */ private static void show01() throws IOException { File f1 = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\08_FileAndRecursion\\1.txt"); boolean b1 = f1.createNewFile(); System.out.println("b1:"+b1); File f2 = new File("08_FileAndRecursion\\2.txt"); System.out.println(f2.createNewFile()); File f3 = new File("08_FileAndRecursion\\新建文件夾"); System.out.println(f3.createNewFile());//不要被名稱迷糊,要看類型 File f4 = new File("08_FileAndRecursi\\3.txt"); System.out.println(f4.createNewFile());//路徑不存在,拋出IOException } }
package com.itheima.demo01.File; import java.io.File; /* File類遍歷(文件夾)目錄功能 - public String[] list() :返回一個String數組,表示該File目錄中的全部子文件或目錄。 - public File[] listFiles() :返回一個File數組,表示該File目錄中的全部的子文件或目錄。 注意: list方法和listFiles方法遍歷的是構造方法中給出的目錄 若是構造方法中給出的目錄的路徑不存在,會拋出空指針異常 若是構造方法中給出的路徑不是一個目錄,也會拋出空指針異常 */ public class Demo06File { public static void main(String[] args) { show02(); } /* public File[] listFiles() :返回一個File數組,表示該File目錄中的全部的子文件或目錄。 遍歷構造方法中給出的目錄,會獲取目錄中全部的文件/文件夾,把文件/文件夾封裝爲File對象,多個File對象存儲到File數組中 */ private static void show02() { File file = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\08_FileAndRecursion"); File[] files = file.listFiles(); for (File f : files) { System.out.println(f); } } /* public String[] list() :返回一個String數組,表示該File目錄中的全部子文件或目錄。 遍歷構造方法中給出的目錄,會獲取目錄中全部文件/文件夾的名稱,把獲取到的多個名稱存儲到一個String類型的數組中 */ private static void show01() { //File file = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\08_FileAndRecursion\\1.txt");//NullPointerException //File file = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\08_Fi");//NullPointerException File file = new File("C:\\Users\\itcast\\IdeaProjects\\shungyuan\\08_FileAndRecursion"); String[] arr = file.list(); for (String fileName : arr) { System.out.println(fileName); } } }
package com.itheima.demo02.Recursion; /* 遞歸:方法本身調用本身 - 遞歸的分類: - 遞歸分爲兩種,直接遞歸和間接遞歸。 - 直接遞歸稱爲方法自身調用本身。 - 間接遞歸能夠A方法調用B方法,B方法調用C方法,C方法調用A方法。 - 注意事項: - 遞歸必定要有條件限定,保證遞歸可以中止下來,不然會發生棧內存溢出。 - 在遞歸中雖然有限定條件,可是遞歸次數不能太多。不然也會發生棧內存溢出。 - 構造方法,禁止遞歸 遞歸的使用前提: 當調用方法的時候,方法的主體不變,每次調用方法的參數不一樣,可使用遞歸 */ public class Demo01Recurison { public static void main(String[] args) { //a(); b(1); } /* 構造方法,禁止遞歸 編譯報錯:構造方法是建立對象使用的,一直遞歸會致使內存中有無數多個對象,直接編譯報錯 */ public Demo01Recurison() { //Demo01Recurison(); } /* 在遞歸中雖然有限定條件,可是遞歸次數不能太多。不然也會發生棧內存溢出。 11157 Exception in thread "main" java.lang.StackOverflowError */ private static void b(int i) { System.out.println(i); if(i==20000){ return; //結束方法 } b(++i); } /* 遞歸必定要有條件限定,保證遞歸可以中止下來,不然會發生棧內存溢出。 Exception in thread "main" java.lang.StackOverflowError */ private static void a() { System.out.println("a方法!"); a(); } }
package com.itheima.demo02.Recursion; /* 練習: 使用遞歸計算1-n之間的和 */ public class Demo02Recurison { public static void main(String[] args) { int s = sum(3); System.out.println(s); } /* 定義一個方法,使用遞歸計算1-n之間的和 1+2+3+...+n n+(n-1)+(n-2)+...+1 已知: 最大值:n 最小值:1 使用遞歸必須明確: 1.遞歸的結束條件 獲取到1的時候結束 2.遞歸的目的 獲取下一個被加的數字(n-1) */ public static int sum(int n){ //獲取到1的時候結束 if(n==1){ return 1; } //獲取下一個被加的數字(n-1) return n + sum(n-1); } }
package com.itheima.demo02.Recursion; import java.io.File; /* 練習: 遞歸打印多級目錄 需求: 遍歷c:\\abc文件夾,及abc文件夾的子文件夾 只要.java結尾的文件 c:\\abc c:\\abc\\abc.txt c:\\abc\\abc.java c:\\abc\\a c:\\abc\\a\\a.jpg c:\\abc\\a\\a.java c:\\abc\\b c:\\abc\\b\\b.java c:\\abc\\b\\b.txt */ public class Demo05Recurison { public static void main(String[] args) { File file = new File("c:\\abc"); getAllFile(file); } /* 定義一個方法,參數傳遞File類型的目錄 方法中對目錄進行遍歷 */ public static void getAllFile(File dir){ //System.out.println(dir);//打印被遍歷的目錄名稱 File[] files = dir.listFiles(); for (File f : files) { //對遍歷獲得的File對象f進行判斷,判斷是不是文件夾 if(f.isDirectory()){ //f是一個文件夾,則繼續遍歷這個文件夾 //咱們發現getAllFile方法就是傳遞文件夾,遍歷文件夾的方法 //因此直接調用getAllFile方法便可:遞歸(本身調用本身) getAllFile(f); }else{ //f是一個文件,直接打印便可 /* c:\\abc\\abc.java 只要.java結尾的文件 1.把File對象f,轉爲字符串對象 */ //String name = f.getName();//abc.java //String path = f.getPath();//c:\\abc\\abc.java //String s = f.toString();//c:\\abc\\abc.java //把字符串,轉換爲小寫 //s = s.toLowerCase(); //2.調用String類中的方法endsWith判斷字符串是不是以.java結尾 //boolean b = s.endsWith(".java"); //3.若是是以.java結尾的文件,則輸出 /*if(b){ System.out.println(f); }*/ if(f.getName().toLowerCase().endsWith(".java")){ System.out.println(f); } } } } }
原理:
package com.itheima.demo03Filter; import java.io.File; /* 需求: 遍歷c:\\abc文件夾,及abc文件夾的子文件夾 只要.java結尾的文件 c:\\abc c:\\abc\\abc.txt c:\\abc\\abc.java c:\\abc\\a c:\\abc\\a\\a.jpg c:\\abc\\a\\a.java c:\\abc\\b c:\\abc\\b\\b.java c:\\abc\\b\\b.txt 咱們可使用過濾器來實現 在File類中有兩個和ListFiles重載的方法,方法的參數傳遞的就是過濾器 File[] listFiles(FileFilter filter) java.io.FileFilter接口:用於抽象路徑名(File對象)的過濾器。 做用:用來過濾文件(File對象) 抽象方法:用來過濾文件的方法 boolean accept(File pathname) 測試指定抽象路徑名是否應該包含在某個路徑名列表中。 參數: File pathname:使用ListFiles方法遍歷目錄,獲得的每個文件對象 File[] listFiles(FilenameFilter filter) java.io.FilenameFilter接口:實現此接口的類實例可用於過濾器文件名。 做用:用於過濾文件名稱 抽象方法:用來過濾文件的方法 boolean accept(File dir, String name) 測試指定文件是否應該包含在某一文件列表中。 參數: File dir:構造方法中傳遞的被遍歷的目錄 String name:使用ListFiles方法遍歷目錄,獲取的每個文件/文件夾的名稱 注意: 兩個過濾器接口是沒有實現類的,須要咱們本身寫實現類,重寫過濾的方法accept,在方法中本身定義過濾的規則 */ public class Demo01Filter { public static void main(String[] args) { File file = new File("c:\\abc"); getAllFile(file); } /* 定義一個方法,參數傳遞File類型的目錄 方法中對目錄進行遍歷 */ public static void getAllFile(File dir){ File[] files = dir.listFiles(new FileFilterImpl());//傳遞過濾器對象 for (File f : files) { //對遍歷獲得的File對象f進行判斷,判斷是不是文件夾 if(f.isDirectory()){ //f是一個文件夾,則繼續遍歷這個文件夾 //咱們發現getAllFile方法就是傳遞文件夾,遍歷文件夾的方法 //因此直接調用getAllFile方法便可:遞歸(本身調用本身) getAllFile(f); }else{ //f是一個文件,直接打印便可 System.out.println(f); } } } }
package com.itheima.demo03Filter; import java.io.File; /* 需求: 遍歷c:\\abc文件夾,及abc文件夾的子文件夾 只要.java結尾的文件 c:\\abc c:\\abc\\abc.txt c:\\abc\\abc.java c:\\abc\\a c:\\abc\\a\\a.jpg c:\\abc\\a\\a.java c:\\abc\\b c:\\abc\\b\\b.java c:\\abc\\b\\b.txt 咱們可使用過濾器來實現 在File類中有兩個和ListFiles重載的方法,方法的參數傳遞的就是過濾器 File[] listFiles(FileFilter filter) java.io.FileFilter接口:用於抽象路徑名(File對象)的過濾器。 做用:用來過濾文件(File對象) 抽象方法:用來過濾文件的方法 boolean accept(File pathname) 測試指定抽象路徑名是否應該包含在某個路徑名列表中。 參數: File pathname:使用ListFiles方法遍歷目錄,獲得的每個文件對象 File[] listFiles(FilenameFilter filter) java.io.FilenameFilter接口:實現此接口的類實例可用於過濾器文件名。 做用:用於過濾文件名稱 抽象方法:用來過濾文件的方法 boolean accept(File dir, String name) 測試指定文件是否應該包含在某一文件列表中。 參數: File dir:構造方法中傳遞的被遍歷的目錄 String name:使用ListFiles方法遍歷目錄,獲取的每個文件/文件夾的名稱 注意: 兩個過濾器接口是沒有實現類的,須要咱們本身寫實現類,重寫過濾的方法accept,在方法中本身定義過濾的規則 */ public class Demo02Filter { public static void main(String[] args) { File file = new File("c:\\abc"); getAllFile(file); } /* 定義一個方法,參數傳遞File類型的目錄 方法中對目錄進行遍歷 */ public static void getAllFile(File dir){ //傳遞過濾器對象 使用匿名內部類 /*File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { //過濾規則,pathname是文件夾或者是.java結尾的文件返回true return pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java"); } });*/ //使用Lambda表達式優化匿名內部類(接口中只有一個抽象方法) /*File[] files = dir.listFiles((File pathname)->{ return pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java"); });*/ File[] files = dir.listFiles(pathname->pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java")); /*File[] files = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { //過濾規則,pathname是文件夾或者是.java結尾的文件返回true return new File(dir,name).isDirectory() || name.toLowerCase().endsWith(".java"); } });*/ //使用Lambda表達式優化匿名內部類(接口中只有一個抽象方法) /*File[] files = dir.listFiles((File d, String name)->{ //過濾規則,pathname是文件夾或者是.java結尾的文件返回true return new File(d,name).isDirectory() || name.toLowerCase().endsWith(".java"); });*/ //File[] files = dir.listFiles((d,name)->new File(d,name).isDirectory() || name.toLowerCase().endsWith(".java")); for (File f : files) { //對遍歷獲得的File對象f進行判斷,判斷是不是文件夾 if(f.isDirectory()){ //f是一個文件夾,則繼續遍歷這個文件夾 //咱們發現getAllFile方法就是傳遞文件夾,遍歷文件夾的方法 //因此直接調用getAllFile方法便可:遞歸(本身調用本身) getAllFile(f); }else{ //f是一個文件,直接打印便可 System.out.println(f); } } } }
package com.itheima.demo01.OutputStream; import java.io.FileOutputStream; import java.io.IOException; /* java.io.OutputStream:字節輸出流 此抽象類是表示輸出字節流的全部類的超類。 定義了一些子類共性的成員方法: - public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。 - public void flush() :刷新此輸出流並強制任何緩衝的輸出字節被寫出。 - public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。 - public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。 - public abstract void write(int b) :將指定的字節輸出流。 java.io.FileOutputStream extends OutputStream FileOutputStream:文件字節輸出流 做用:把內存中的數據寫入到硬盤的文件中 構造方法: FileOutputStream(String name)建立一個向具備指定名稱的文件中寫入數據的輸出文件流。 FileOutputStream(File file) 建立一個向指定 File 對象表示的文件中寫入數據的文件輸出流。 參數:寫入數據的目的 String name:目的地是一個文件的路徑 File file:目的地是一個文件 構造方法的做用: 1.建立一個FileOutputStream對象 2.會根據構造方法中傳遞的文件/文件路徑,建立一個空的文件 3.會把FileOutputStream對象指向建立好的文件 寫入數據的原理(內存-->硬盤) java程序-->JVM(java虛擬機)-->OS(操做系統)-->OS調用寫數據的方法-->把數據寫入到文件中 字節輸出流的使用步驟(重點): 1.建立一個FileOutputStream對象,構造方法中傳遞寫入數據的目的地 2.調用FileOutputStream對象中的方法write,把數據寫入到文件中 3.釋放資源(流使用會佔用必定的內存,使用完畢要把內存清空,提供程序的效率) */ public class Demo01OutputStream { public static void main(String[] args) throws IOException { //1.建立一個FileOutputStream對象,構造方法中傳遞寫入數據的目的地 FileOutputStream fos = new FileOutputStream("09_IOAndProperties\\a.txt"); //2.調用FileOutputStream對象中的方法write,把數據寫入到文件中 //public abstract void write(int b) :將指定的字節輸出流。 fos.write(97); //3.釋放資源(流使用會佔用必定的內存,使用完畢要把內存清空,提供程序的效率) //fos.close(); } }
package com.itheima.demo01.OutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; /* 一次寫多個字節的方法: - public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。 - public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。 */ public class Demo02OutputStream { public static void main(String[] args) throws IOException { //建立FileOutputStream對象,構造方法中綁定要寫入數據的目的地 FileOutputStream fos = new FileOutputStream(new File("09_IOAndProperties\\b.txt")); //調用FileOutputStream對象中的方法write,把數據寫入到文件中 //在文件中顯示100,寫個字節 fos.write(49); fos.write(48); fos.write(48); /* public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。 一次寫多個字節: 若是寫的第一個字節是正數(0-127),那麼顯示的時候會查詢ASCII表 若是寫的第一個字節是負數,那第一個字節會和第二個字節,兩個字節組成一箇中文顯示,查詢系統默認碼錶(GBK) */ byte[] bytes = {65,66,67,68,69};//ABCDE //byte[] bytes = {-65,-66,-67,68,69};//烤紻E fos.write(bytes); /* public void write(byte[] b, int off, int len) :把字節數組的一部分寫入到文件中 int off:數組的開始索引 int len:寫幾個字節 */ fos.write(bytes,1,2);//BC /* 寫入字符的方法:可使用String類中的方法把字符串,轉換爲字節數組 byte[] getBytes() 把字符串轉換爲字節數組 */ byte[] bytes2 = "你好".getBytes(); System.out.println(Arrays.toString(bytes2));//[-28, -67, -96, -27, -91, -67] fos.write(bytes2); //釋放資源 fos.close(); } }
package com.itheima.demo01.OutputStream; import java.io.FileOutputStream; import java.io.IOException; /* 追加寫/續寫:使用兩個參數的構造方法 FileOutputStream(String name, boolean append)建立一個向具備指定 name 的文件中寫入數據的輸出文件流。 FileOutputStream(File file, boolean append) 建立一個向指定 File 對象表示的文件中寫入數據的文件輸出流。 參數: String name,File file:寫入數據的目的地 boolean append:追加寫開關 true:建立對象不會覆蓋源文件,繼續在文件的末尾追加寫數據 false:建立一個新文件,覆蓋源文件 寫換行:寫換行符號 windows:\r\n linux:/n mac:/r */ public class Demo03OutputStream { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("09_IOAndProperties\\c.txt",true); for (int i = 1; i <=10 ; i++) { fos.write("你好".getBytes()); fos.write("\r\n".getBytes()); } fos.close(); } }
package com.itheima.demo02.InputStream; import java.io.FileInputStream; import java.io.IOException; /* java.io.InputStream:字節輸入流 此抽象類是表示字節輸入流的全部類的超類。 定義了全部子類共性的方法: int read()從輸入流中讀取數據的下一個字節。 int read(byte[] b) 從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 b 中。 void close() 關閉此輸入流並釋放與該流關聯的全部系統資源。 java.io.FileInputStream extends InputStream FileInputStream:文件字節輸入流 做用:把硬盤文件中的數據,讀取到內存中使用 構造方法: FileInputStream(String name) FileInputStream(File file) 參數:讀取文件的數據源 String name:文件的路徑 File file:文件 構造方法的做用: 1.會建立一個FileInputStream對象 2.會把FileInputStream對象指定構造方法中要讀取的文件 讀取數據的原理(硬盤-->內存) java程序-->JVM-->OS-->OS讀取數據的方法-->讀取文件 字節輸入流的使用步驟(重點): 1.建立FileInputStream對象,構造方法中綁定要讀取的數據源 2.使用FileInputStream對象中的方法read,讀取文件 3.釋放資源 */ public class Demo01InputStream { public static void main(String[] args) throws IOException { //1.建立FileInputStream對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("09_IOAndProperties\\c.txt"); //2.使用FileInputStream對象中的方法read,讀取文件 //int read()讀取文件中的一個字節並返回,讀取到文件的末尾返回-1 /*int len = fis.read(); System.out.println(len);//97 a len = fis.read(); System.out.println(len);// 98 b len = fis.read(); System.out.println(len);//99 c len = fis.read(); System.out.println(len);//-1 len = fis.read(); System.out.println(len);//-1*/ /* 發現以上讀取文件是一個重複的過程,因此可使用循環優化 不知道文件中有多少字節,使用while循環 while循環結束條件,讀取到-1的時候結束 布爾表達式(len = fis.read())!=-1 1.fis.read():讀取一個字節 2.len = fis.read():把讀取到的字節賦值給變量len 3.(len = fis.read())!=-1:判斷變量len是否不等於-1 */ int len = 0; //記錄讀取到的字節 while((len = fis.read())!=-1){ System.out.print(len);//abc } //3.釋放資源 fis.close(); } }
package com.itheima.demo02.InputStream; import java.io.FileInputStream; import java.io.IOException; /* 字節輸入流一次讀取多個字節的方法: int read(byte[] b) 從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 b 中。 明確兩件事情: 1.方法的參數byte[]的做用? 起到緩衝做用,存儲每次讀取到的多個字節 數組的長度一把定義爲1024(1kb)或者1024的整數倍 2.方法的返回值int是什麼? 每次讀取的有效字節個數 String類的構造方法 String(byte[] bytes) :把字節數組轉換爲字符串 String(byte[] bytes, int offset, int length) 把字節數組的一部分轉換爲字符串 offset:數組的開始索引 length:轉換的字節個數 */ public class Demo02InputStream { public static void main(String[] args) throws IOException { //建立FileInputStream對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("09_IOAndProperties\\b.txt"); //使用FileInputStream對象中的方法read讀取文件 //int read(byte[] b) 從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 b 中。 /*byte[] bytes = new byte[2]; int len = fis.read(bytes); System.out.println(len);//2 //System.out.println(Arrays.toString(bytes));//[65, 66] System.out.println(new String(bytes));//AB len = fis.read(bytes); System.out.println(len);//2 System.out.println(new String(bytes));//CD len = fis.read(bytes); System.out.println(len);//1 System.out.println(new String(bytes));//ED len = fis.read(bytes); System.out.println(len);//-1 System.out.println(new String(bytes));//ED*/ /* 發現以上讀取時一個重複的過程,可使用循環優化 不知道文件中有多少字節,因此使用while循環 while循環結束的條件,讀取到-1結束 */ byte[] bytes = new byte[1024];//存儲讀取到的多個字節 int len = 0; //記錄每次讀取的有效字節個數 while((len = fis.read(bytes))!=-1){ //String(byte[] bytes, int offset, int length) 把字節數組的一部分轉換爲字符串 offset:數組的開始索引 length:轉換的字節個數 System.out.println(new String(bytes,0,len)); } //釋放資源 fis.close(); } }
package com.itheima.demo03.CopyFile; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* 文件複製練習:一讀一寫 明確: 數據源: c:\\1.jpg 數據的目的地: d:\\1.jpg 文件複製的步驟: 1.建立一個字節輸入流對象,構造方法中綁定要讀取的數據源 2.建立一個字節輸出流對象,構造方法中綁定要寫入的目的地 3.使用字節輸入流對象中的方法read讀取文件 4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中 5.釋放資源 */ public class Demo01CopyFile { public static void main(String[] args) throws IOException { long s = System.currentTimeMillis(); //1.建立一個字節輸入流對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("c:\\1.jpg"); //2.建立一個字節輸出流對象,構造方法中綁定要寫入的目的地 FileOutputStream fos = new FileOutputStream("d:\\1.jpg"); //一次讀取一個字節寫入一個字節的方式 //3.使用字節輸入流對象中的方法read讀取文件 /*int len = 0; while((len = fis.read())!=-1){ //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中 fos.write(len); }*/ //使用數組緩衝讀取多個字節,寫入多個字節 byte[] bytes = new byte[1024]; //3.使用字節輸入流對象中的方法read讀取文件 int len = 0;//每次讀取的有效字節個數 while((len = fis.read(bytes))!=-1){ //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中 fos.write(bytes,0,len); } //5.釋放資源(先關寫的,後關閉讀的;若是寫完了,確定讀取完畢了) fos.close(); fis.close(); long e = System.currentTimeMillis(); System.out.println("複製文件共耗時:"+(e-s)+"毫秒"); } }
package com.itheima.Demo04.Reader; import java.io.FileReader; import java.io.IOException; /* java.io.Reader:字符輸入流,是字符輸入流的最頂層的父類,定義了一些共性的成員方法,是一個抽象類 共性的成員方法: int read() 讀取單個字符並返回。 int read(char[] cbuf)一次讀取多個字符,將字符讀入數組。 void close() 關閉該流並釋放與之關聯的全部資源。 java.io.FileReader extends InputStreamReader extends Reader FileReader:文件字符輸入流 做用:把硬盤文件中的數據以字符的方式讀取到內存中 構造方法: FileReader(String fileName) FileReader(File file) 參數:讀取文件的數據源 String fileName:文件的路徑 File file:一個文件 FileReader構造方法的做用: 1.建立一個FileReader對象 2.會把FileReader對象指向要讀取的文件 字符輸入流的使用步驟: 1.建立FileReader對象,構造方法中綁定要讀取的數據源 2.使用FileReader對象中的方法read讀取文件 3.釋放資源 */ public class Demo02Reader { public static void main(String[] args) throws IOException { //1.建立FileReader對象,構造方法中綁定要讀取的數據源 FileReader fr = new FileReader("09_IOAndProperties\\c.txt"); //2.使用FileReader對象中的方法read讀取文件 //int read() 讀取單個字符並返回。 /*int len = 0; while((len = fr.read())!=-1){ System.out.print((char)len); }*/ //int read(char[] cbuf)一次讀取多個字符,將字符讀入數組。 char[] cs = new char[1024];//存儲讀取到的多個字符 int len = 0;//記錄的是每次讀取的有效字符個數 while((len = fr.read(cs))!=-1){ /* String類的構造方法 String(char[] value) 把字符數組轉換爲字符串 String(char[] value, int offset, int count) 把字符數組的一部分轉換爲字符串 offset數組的開始索引 count轉換的個數 */ System.out.println(new String(cs,0,len)); } //3.釋放資源 fr.close(); } }
package com.itheima.Demo05Writer; import java.io.FileWriter; import java.io.IOException; /* java.io.Writer:字符輸出流,是全部字符輸出流的最頂層的父類,是一個抽象類 共性的成員方法: - void write(int c) 寫入單個字符。 - void write(char[] cbuf)寫入字符數組。 - abstract void write(char[] cbuf, int off, int len)寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。 - void write(String str)寫入字符串。 - void write(String str, int off, int len) 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。 - void flush()刷新該流的緩衝。 - void close() 關閉此流,但要先刷新它。 java.io.FileWriter extends OutputStreamWriter extends Writer FileWriter:文件字符輸出流 做用:把內存中字符數據寫入到文件中 構造方法: FileWriter(File file)根據給定的 File 對象構造一個 FileWriter 對象。 FileWriter(String fileName) 根據給定的文件名構造一個 FileWriter 對象。 參數:寫入數據的目的地 String fileName:文件的路徑 File file:是一個文件 構造方法的做用: 1.會建立一個FileWriter對象 2.會根據構造方法中傳遞的文件/文件的路徑,建立文件 3.會把FileWriter對象指向建立好的文件 字符輸出流的使用步驟(重點): 1.建立FileWriter對象,構造方法中綁定要寫入數據的目的地 2.使用FileWriter中的方法write,把數據寫入到內存緩衝區中(字符轉換爲字節的過程) 3.使用FileWriter中的方法flush,把內存緩衝區中的數據,刷新到文件中 4.釋放資源(會先把內存緩衝區中的數據刷新到文件中) */ public class Demo01Writer { public static void main(String[] args) throws IOException { //1.建立FileWriter對象,構造方法中綁定要寫入數據的目的地 FileWriter fw = new FileWriter("09_IOAndProperties\\d.txt"); //2.使用FileWriter中的方法write,把數據寫入到內存緩衝區中(字符轉換爲字節的過程) //void write(int c) 寫入單個字符。 fw.write(97); //3.使用FileWriter中的方法flush,把內存緩衝區中的數據,刷新到文件中 //fw.flush(); //4.釋放資源(會先把內存緩衝區中的數據刷新到文件中) fw.close(); } }
package com.itheima.Demo05Writer; import java.io.FileWriter; import java.io.IOException; /* flush方法和close方法的區別 - flush :刷新緩衝區,流對象能夠繼續使用。 - close: 先刷新緩衝區,而後通知系統釋放資源。流對象不能夠再被使用了。 */ public class Demo02CloseAndFlush { public static void main(String[] args) throws IOException { //1.建立FileWriter對象,構造方法中綁定要寫入數據的目的地 FileWriter fw = new FileWriter("09_IOAndProperties\\e.txt"); //2.使用FileWriter中的方法write,把數據寫入到內存緩衝區中(字符轉換爲字節的過程) //void write(int c) 寫入單個字符。 fw.write(97); //3.使用FileWriter中的方法flush,把內存緩衝區中的數據,刷新到文件中 fw.flush(); //刷新以後流能夠繼續使用 fw.write(98); //4.釋放資源(會先把內存緩衝區中的數據刷新到文件中) fw.close(); //close方法以後流已經關閉了,已經從內存中消失了,流就不能再使用了 fw.write(99);//IOException: Stream closed } }
package com.itheima.Demo05Writer; import java.io.FileWriter; import java.io.IOException; /* 字符輸出流寫數據的其餘方法 - void write(char[] cbuf)寫入字符數組。 - abstract void write(char[] cbuf, int off, int len)寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。 - void write(String str)寫入字符串。 - void write(String str, int off, int len) 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。 */ public class Demo03Writer { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("09_IOAndProperties\\f.txt"); char[] cs = {'a','b','c','d','e'}; //void write(char[] cbuf)寫入字符數組。 fw.write(cs);//abcde //void write(char[] cbuf, int off, int len)寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。 fw.write(cs,1,3);//bcd //void write(String str)寫入字符串。 fw.write("傳智播客");//傳智播客 //void write(String str, int off, int len) 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。 fw.write("黑馬程序員",2,3);//程序員 fw.close(); } }
package com.itheima.Demo05Writer; import java.io.FileWriter; import java.io.IOException; /* 續寫和換行 續寫,追加寫:使用兩個參數的構造方法 FileWriter(String fileName, boolean append) FileWriter(File file, boolean append) 參數: String fileName,File file:寫入數據的目的地 boolean append:續寫開關 true:不會建立新的文件覆蓋源文件,能夠續寫; false:建立新的文件覆蓋源文件 換行:換行符號 windows:\r\n linux:/n mac:/r */ public class Demo04Writer { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("09_IOAndProperties\\g.txt",true); for (int i = 0; i <10 ; i++) { fw.write("HelloWorld"+i+"\r\n"); } fw.close(); } }
package com.itheima.demo06.trycatch; import java.io.FileWriter; import java.io.IOException; /* 在jdk1.7以前使用try catch finally 處理流中的異常 格式: try{ 可能會產出異常的代碼 }catch(異常類變量 變量名){ 異常的處理邏輯 }finally{ 必定會指定的代碼 資源釋放 } */ public class Demo01TryCatch { public static void main(String[] args) { //提升變量fw的做用域,讓finally可使用 //變量在定義的時候,能夠沒有值,可是使用的時候必須有值 //fw = new FileWriter("09_IOAndProperties\\g.txt",true); 執行失敗,fw沒有值,fw.close會報錯 FileWriter fw = null; try{ //可能會產出異常的代碼 fw = new FileWriter("w:\\09_IOAndProperties\\g.txt",true); for (int i = 0; i <10 ; i++) { fw.write("HelloWorld"+i+"\r\n"); } }catch(IOException e){ //異常的處理邏輯 System.out.println(e); }finally { //必定會指定的代碼 //建立對象失敗了,fw的默認值就是null,null是不能調用方法的,會拋出NullPointerException,須要增長一個判斷,不是null在把資源釋放 if(fw!=null){ try { //fw.close方法聲明拋出了IOException異常對象,因此咱們就的處理這個異常對象,要麼throws,要麼try catch fw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
package com.itheima.demo06.trycatch; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* JDK7的新特性 在try的後邊能夠增長一個(),在括號中能夠定義流對象 那麼這個流對象的做用域就在try中有效 try中的代碼執行完畢,會自動把流對象釋放,不用寫finally 格式: try(定義流對象;定義流對象....){ 可能會產出異常的代碼 }catch(異常類變量 變量名){ 異常的處理邏輯 } */ public class Demo02JDK7 { public static void main(String[] args) { try(//1.建立一個字節輸入流對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("c:\\1.jpg"); //2.建立一個字節輸出流對象,構造方法中綁定要寫入的目的地 FileOutputStream fos = new FileOutputStream("d:\\1.jpg");){ //可能會產出異常的代碼 //一次讀取一個字節寫入一個字節的方式 //3.使用字節輸入流對象中的方法read讀取文件 int len = 0; while((len = fis.read())!=-1){ //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中 fos.write(len); } }catch (IOException e){ //異常的處理邏輯 System.out.println(e); } } }
package com.itheima.demo06.trycatch; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* JDK9新特性 try的前邊能夠定義流對象 在try後邊的()中能夠直接引入流對象的名稱(變量名) 在try代碼執行完畢以後,流對象也能夠釋放掉,不用寫finally 格式: A a = new A(); B b = new B(); try(a,b){ 可能會產出異常的代碼 }catch(異常類變量 變量名){ 異常的處理邏輯 } */ public class Demo03JDK9 { public static void main(String[] args) throws IOException { //1.建立一個字節輸入流對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("c:\\1.jpg"); //2.建立一個字節輸出流對象,構造方法中綁定要寫入的目的地 FileOutputStream fos = new FileOutputStream("d:\\1.jpg"); try(fis;fos){ //一次讀取一個字節寫入一個字節的方式 //3.使用字節輸入流對象中的方法read讀取文件 int len = 0; while((len = fis.read())!=-1){ //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中 fos.write(len); } }catch (IOException e){ System.out.println(e); } //fos.write(1);//Stream Closed } }
package com.itheima.demo07.Prop; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Set; /* java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v> Properties 類表示了一個持久的屬性集。Properties 可保存在流中或從流中加載。 Properties集合是一個惟一和IO流相結合的集合 可使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲 可使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用 屬性列表中每一個鍵及其對應值都是一個字符串。 Properties集合是一個雙列集合,key和value默認都是字符串 */ public class Demo01Properties { public static void main(String[] args) throws IOException { show03(); } /* 可使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用 void load(InputStream inStream) void load(Reader reader) 參數: InputStream inStream:字節輸入流,不能讀取含有中文的鍵值對 Reader reader:字符輸入流,能讀取含有中文的鍵值對 使用步驟: 1.建立Properties集合對象 2.使用Properties集合對象中的方法load讀取保存鍵值對的文件 3.遍歷Properties集合 注意: 1.存儲鍵值對的文件中,鍵與值默認的鏈接符號可使用=,空格(其餘符號) 2.存儲鍵值對的文件中,可使用#進行註釋,被註釋的鍵值對不會再被讀取 3.存儲鍵值對的文件中,鍵與值默認都是字符串,不用再加引號 */ private static void show03() throws IOException { //1.建立Properties集合對象 Properties prop = new Properties(); //2.使用Properties集合對象中的方法load讀取保存鍵值對的文件 prop.load(new FileReader("09_IOAndProperties\\prop.txt")); //prop.load(new FileInputStream("09_IOAndProperties\\prop.txt")); //3.遍歷Properties集合 Set<String> set = prop.stringPropertyNames(); for (String key : set) { String value = prop.getProperty(key); System.out.println(key+"="+value); } } /* 可使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲 void store(OutputStream out, String comments) void store(Writer writer, String comments) 參數: OutputStream out:字節輸出流,不能寫入中文 Writer writer:字符輸出流,能夠寫中文 String comments:註釋,用來解釋說明保存的文件是作什麼用的 不能使用中文,會產生亂碼,默認是Unicode編碼 通常使用""空字符串 使用步驟: 1.建立Properties集合對象,添加數據 2.建立字節輸出流/字符輸出流對象,構造方法中綁定要輸出的目的地 3.使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲 4.釋放資源 */ private static void show02() throws IOException { //1.建立Properties集合對象,添加數據 Properties prop = new Properties(); prop.setProperty("趙麗穎","168"); prop.setProperty("迪麗熱巴","165"); prop.setProperty("古力娜扎","160"); //2.建立字節輸出流/字符輸出流對象,構造方法中綁定要輸出的目的地 //FileWriter fw = new FileWriter("09_IOAndProperties\\prop.txt"); //3.使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲 //prop.store(fw,"save data"); //4.釋放資源 //fw.close(); prop.store(new FileOutputStream("09_IOAndProperties\\prop2.txt"),""); } /* 使用Properties集合存儲數據,遍歷取出Properties集合中的數據 Properties集合是一個雙列集合,key和value默認都是字符串 Properties集合有一些操做字符串的特有方法 Object setProperty(String key, String value) 調用 Hashtable 的方法 put。 String getProperty(String key) 經過key找到value值,此方法至關於Map集合中的get(key)方法 Set<String> stringPropertyNames() 返回此屬性列表中的鍵集,其中該鍵及其對應值是字符串,此方法至關於Map集合中的keySet方法 */ private static void show01() { //建立Properties集合對象 Properties prop = new Properties(); //使用setProperty往集合中添加數據 prop.setProperty("趙麗穎","168"); prop.setProperty("迪麗熱巴","165"); prop.setProperty("古力娜扎","160"); //prop.put(1,true); //使用stringPropertyNames把Properties集合中的鍵取出,存儲到一個Set集合中 Set<String> set = prop.stringPropertyNames(); //遍歷Set集合,取出Properties集合的每個鍵 for (String key : set) { //使用getProperty方法經過key獲取value String value = prop.getProperty(key); System.out.println(key+"="+value); } } }
package com.itheima.demo01.BufferedStream;
import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; /* java.io.BufferedOutputStream extends OutputStream BufferedOutputStream:字節緩衝輸出流 繼承自父類的共性成員方法: - public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。 - public void flush() :刷新此輸出流並強制任何緩衝的輸出字節被寫出。 - public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。 - public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。 - public abstract void write(int b) :將指定的字節輸出流。 構造方法: BufferedOutputStream(OutputStream out) 建立一個新的緩衝輸出流,以將數據寫入指定的底層輸出流。 BufferedOutputStream(OutputStream out, int size) 建立一個新的緩衝輸出流,以將具備指定緩衝區大小的數據寫入指定的底層輸出流。 參數: OutputStream out:字節輸出流 咱們能夠傳遞FileOutputStream,緩衝流會給FileOutputStream增長一個緩衝區,提升FileOutputStream的寫入效率 int size:指定緩衝流內部緩衝區的大小,不指定默認 使用步驟(重點) 1.建立FileOutputStream對象,構造方法中綁定要輸出的目的地 2.建立BufferedOutputStream對象,構造方法中傳遞FileOutputStream對象對象,提升FileOutputStream對象效率 3.使用BufferedOutputStream對象中的方法write,把數據寫入到內部緩衝區中 4.使用BufferedOutputStream對象中的方法flush,把內部緩衝區中的數據,刷新到文件中 5.釋放資源(會先調用flush方法刷新數據,第4部能夠省略) */ public class Demo01BufferedOutputStream { public static void main(String[] args) throws IOException { //1.建立FileOutputStream對象,構造方法中綁定要輸出的目的地 FileOutputStream fos = new FileOutputStream("10_IO\\a.txt"); //2.建立BufferedOutputStream對象,構造方法中傳遞FileOutputStream對象對象,提升FileOutputStream對象效率 BufferedOutputStream bos = new BufferedOutputStream(fos); //3.使用BufferedOutputStream對象中的方法write,把數據寫入到內部緩衝區中 bos.write("我把數據寫入到內部緩衝區中".getBytes()); //4.使用BufferedOutputStream對象中的方法flush,把內部緩衝區中的數據,刷新到文件中 bos.flush(); //5.釋放資源(會先調用flush方法刷新數據,第4部能夠省略) bos.close(); } }
package com.itheima.demo01.BufferedStream; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; /* java.io.BufferedInputStream extends InputStream BufferedInputStream:字節緩衝輸入流 繼承自父類的成員方法: int read()從輸入流中讀取數據的下一個字節。 int read(byte[] b) 從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 b 中。 void close() 關閉此輸入流並釋放與該流關聯的全部系統資源。 構造方法: BufferedInputStream(InputStream in) 建立一個 BufferedInputStream 並保存其參數,即輸入流 in,以便未來使用。 BufferedInputStream(InputStream in, int size) 建立具備指定緩衝區大小的 BufferedInputStream 並保存其參數,即輸入流 in,以便未來使用。 參數: InputStream in:字節輸入流 咱們能夠傳遞FileInputStream,緩衝流會給FileInputStream增長一個緩衝區,提升FileInputStream的讀取效率 int size:指定緩衝流內部緩衝區的大小,不指定默認 使用步驟(重點): 1.建立FileInputStream對象,構造方法中綁定要讀取的數據源 2.建立BufferedInputStream對象,構造方法中傳遞FileInputStream對象,提升FileInputStream對象的讀取效率 3.使用BufferedInputStream對象中的方法read,讀取文件 4.釋放資源 */ public class Demo02BufferedInputStream { public static void main(String[] args) throws IOException { //1.建立FileInputStream對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("10_IO\\a.txt"); //2.建立BufferedInputStream對象,構造方法中傳遞FileInputStream對象,提升FileInputStream對象的讀取效率 BufferedInputStream bis = new BufferedInputStream(fis); //3.使用BufferedInputStream對象中的方法read,讀取文件 //int read()從輸入流中讀取數據的下一個字節。 /*int len = 0;//記錄每次讀取到的字節 while((len = bis.read())!=-1){ System.out.println(len); }*/ //int read(byte[] b) 從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 b 中。 byte[] bytes =new byte[1024];//存儲每次讀取的數據 int len = 0; //記錄每次讀取的有效字節個數 while((len = bis.read(bytes))!=-1){ System.out.println(new String(bytes,0,len)); } //4.釋放資源 bis.close(); } }
package com.itheima.demo01.BufferedStream; import java.io.*; import java.util.HashMap; /* 練習: 對文本的內容進行排序 按照(1,2,3....)順序排序 分析: 1.建立一個HashMap集合對象,能夠:存儲每行文本的序號(1,2,3,..);value:存儲每行的文本 2.建立字符緩衝輸入流對象,構造方法中綁定字符輸入流 3.建立字符緩衝輸出流對象,構造方法中綁定字符輸出流 4.使用字符緩衝輸入流中的方法readline,逐行讀取文本 5.對讀取到的文本進行切割,獲取行中的序號和文本內容 6.把切割好的序號和文本的內容存儲到HashMap集合中(key序號是有序的,會自動排序1,2,3,4..) 7.遍歷HashMap集合,獲取每個鍵值對 8.把每個鍵值對,拼接爲一個文本行 9.把拼接好的文本,使用字符緩衝輸出流中的方法write,寫入到文件中 10.釋放資源 */ public class Demo05Test { public static void main(String[] args) throws IOException { //1.建立一個HashMap集合對象,能夠:存儲每行文本的序號(1,2,3,..);value:存儲每行的文本 HashMap<String,String> map = new HashMap<>(); //2.建立字符緩衝輸入流對象,構造方法中綁定字符輸入流 BufferedReader br = new BufferedReader(new FileReader("10_IO\\in.txt")); //3.建立字符緩衝輸出流對象,構造方法中綁定字符輸出流 BufferedWriter bw = new BufferedWriter(new FileWriter("10_IO\\out.txt")); //4.使用字符緩衝輸入流中的方法readline,逐行讀取文本 String line; while((line = br.readLine())!=null){ //5.對讀取到的文本進行切割,獲取行中的序號和文本內容 String[] arr = line.split("\\."); //6.把切割好的序號和文本的內容存儲到HashMap集合中(key序號是有序的,會自動排序1,2,3,4..) map.put(arr[0],arr[1]); } //7.遍歷HashMap集合,獲取每個鍵值對 for(String key : map.keySet()){ String value = map.get(key); //8.把每個鍵值對,拼接爲一個文本行 line = key + "." + value; //9.把拼接好的文本,使用字符緩衝輸出流中的方法write,寫入到文件中 bw.write(line); bw.newLine();//寫換行 } //10.釋放資源 bw.close(); br.close(); } }
計算機中儲存的信息都是用二進制數表示的,而咱們在屏幕上看到的數字、英文、標點符號、漢字等字符是二進制數轉換以後的結果。按照某種規則,將字符存儲到計算機中,稱爲編碼 。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱爲解碼 。好比說,按照A規則存儲,一樣按照A規則解析,那麼就能顯示正確的文本符號。反之,按照A規則存儲,再按照B規則解析,就會致使亂碼現象。
編碼:字符(能看懂的)--字節(看不懂的)
解碼:字節(看不懂的)-->字符(能看懂的)
字符編碼Character Encoding
: 就是一套天然語言的字符與二進制數之間的對應規則。
編碼表:生活中文字和計算機中二進制的對應規則
Charset
:也叫編碼表。是一個系統支持的全部字符的集合,包括各國家文字、標點符號、圖形符號、數字等。計算機要準確的存儲和識別各類字符集符號,須要進行字符編碼,一套字符集必然至少有一套字符編碼。常見字符集有ASCII字符集、GBK字符集、Unicode字符集等。
可見,當指定了編碼,它所對應的字符集天然就指定了,因此編碼纔是咱們最終要關心的。
在IDEA中,使用FileReader
讀取項目中的文本文件。因爲IDEA的設置,都是默認的UTF-8
編碼,因此沒有任何問題。可是,當讀取Windows系統中建立的文本文件時,因爲Windows系統的默認是GBK編碼,就會出現亂碼。
```java public class ReaderDemo { public static void main(String[] args) throws IOException { FileReader fileReader = new FileReader("E:\\File_GBK.txt"); int read; while ((read = fileReader.read()) != -1) { System.out.print((char)read); } fileReader.close(); } } 輸出結果: ��� ```
package com.itheima.demo03.ReverseStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; /* java.io.OutputStreamWriter extends Writer OutputStreamWriter: 是字符流通向字節流的橋樑:可以使用指定的 charset 將要寫入流中的字符編碼成字節。(編碼:把能看懂的變成看不懂) 繼續自父類的共性成員方法: - void write(int c) 寫入單個字符。 - void write(char[] cbuf)寫入字符數組。 - abstract void write(char[] cbuf, int off, int len)寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。 - void write(String str)寫入字符串。 - void write(String str, int off, int len) 寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。 - void flush()刷新該流的緩衝。 - void close() 關閉此流,但要先刷新它。 構造方法: OutputStreamWriter(OutputStream out)建立使用默認字符編碼的 OutputStreamWriter。 OutputStreamWriter(OutputStream out, String charsetName) 建立使用指定字符集的 OutputStreamWriter。 參數: OutputStream out:字節輸出流,能夠用來寫轉換以後的字節到文件中 String charsetName:指定的編碼表名稱,不區分大小寫,能夠是utf-8/UTF-8,gbk/GBK,...不指定默認使用UTF-8 使用步驟: 1.建立OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱 2.使用OutputStreamWriter對象中的方法write,把字符轉換爲字節存儲緩衝區中(編碼) 3.使用OutputStreamWriter對象中的方法flush,把內存緩衝區中的字節刷新到文件中(使用字節流寫字節的過程) 4.釋放資源 */ public class Demo02OutputStreamWriter { public static void main(String[] args) throws IOException { //write_utf_8(); write_gbk(); } /* 使用轉換流OutputStreamWriter寫GBK格式的文件 */ private static void write_gbk() throws IOException { //1.建立OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\gbk.txt"),"GBK"); //2.使用OutputStreamWriter對象中的方法write,把字符轉換爲字節存儲緩衝區中(編碼) osw.write("你好"); //3.使用OutputStreamWriter對象中的方法flush,把內存緩衝區中的字節刷新到文件中(使用字節流寫字節的過程) osw.flush(); //4.釋放資源 osw.close(); } /* 使用轉換流OutputStreamWriter寫UTF-8格式的文件 */ private static void write_utf_8() throws IOException { //1.建立OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱 //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\utf_8.txt"),"utf-8"); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\utf_8.txt"));//不指定默認使用UTF-8 //2.使用OutputStreamWriter對象中的方法write,把字符轉換爲字節存儲緩衝區中(編碼) osw.write("你好"); //3.使用OutputStreamWriter對象中的方法flush,把內存緩衝區中的字節刷新到文件中(使用字節流寫字節的過程) osw.flush(); //4.釋放資源 osw.close(); } }
package com.itheima.demo03.ReverseStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; /* java.io.InputStreamReader extends Reader InputStreamReader:是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。(解碼:把看不懂的變成能看懂的) 繼承自父類的共性成員方法: int read() 讀取單個字符並返回。 int read(char[] cbuf)一次讀取多個字符,將字符讀入數組。 void close() 關閉該流並釋放與之關聯的全部資源。 構造方法: InputStreamReader(InputStream in) 建立一個使用默認字符集的 InputStreamReader。 InputStreamReader(InputStream in, String charsetName) 建立使用指定字符集的 InputStreamReader。 參數: InputStream in:字節輸入流,用來讀取文件中保存的字節 String charsetName:指定的編碼表名稱,不區分大小寫,能夠是utf-8/UTF-8,gbk/GBK,...不指定默認使用UTF-8 使用步驟: 1.建立InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱 2.使用InputStreamReader對象中的方法read讀取文件 3.釋放資源 注意事項: 構造方法中指定的編碼表名稱要和文件的編碼相同,不然會發生亂碼 */ public class Demo03InputStreamReader { public static void main(String[] args) throws IOException { //read_utf_8(); read_gbk(); } /* 使用InputStreamReader讀取GBK格式的文件 */ private static void read_gbk() throws IOException { //1.建立InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱 //InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\gbk.txt"),"UTF-8");//??? InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\gbk.txt"),"GBK");//你好 //2.使用InputStreamReader對象中的方法read讀取文件 int len = 0; while((len = isr.read())!=-1){ System.out.println((char)len); } //3.釋放資源 isr.close(); } /* 使用InputStreamReader讀取UTF-8格式的文件 */ private static void read_utf_8() throws IOException { //1.建立InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱 //InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\utf_8.txt"),"UTF-8"); InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\utf_8.txt"));//不指定默認使用UTF-8 //2.使用InputStreamReader對象中的方法read讀取文件 int len = 0; while((len = isr.read())!=-1){ System.out.println((char)len); } //3.釋放資源 isr.close(); } }
package com.itheima.demo04.ObjectStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; /* java.io.ObjectOutputStream extends OutputStream ObjectOutputStream:對象的序列化流 做用:把對象以流的方式寫入到文件中保存 構造方法: ObjectOutputStream(OutputStream out) 建立寫入指定 OutputStream 的 ObjectOutputStream。 參數: OutputStream out:字節輸出流 特有的成員方法: void writeObject(Object obj) 將指定的對象寫入 ObjectOutputStream。 使用步驟: 1.建立ObjectOutputStream對象,構造方法中傳遞字節輸出流 2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中 3.釋放資源 */ public class Demo01ObjectOutputStream { public static void main(String[] args) throws IOException { //1.建立ObjectOutputStream對象,構造方法中傳遞字節輸出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("10_IO\\person.txt")); //2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中 oos.writeObject(new Person("小美女",18)); //3.釋放資源 oos.close(); } }
package com.itheima.demo04.ObjectStream; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; /* java.io.ObjectInputStream extends InputStream ObjectInputStream:對象的反序列化流 做用:把文件中保存的對象,以流的方式讀取出來使用 構造方法: ObjectInputStream(InputStream in) 建立從指定 InputStream 讀取的 ObjectInputStream。 參數: InputStream in:字節輸入流 特有的成員方法: Object readObject() 從 ObjectInputStream 讀取對象。 使用步驟: 1.建立ObjectInputStream對象,構造方法中傳遞字節輸入流 2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件 3.釋放資源 4.使用讀取出來的對象(打印) readObject方法聲明拋出了ClassNotFoundException(class文件找不到異常) 當不存在對象的class文件時拋出此異常 反序列化的前提: 1.類必須實現Serializable 2.必須存在類對應的class文件 */ public class Demo02ObjectInputStream { public static void main(String[] args) throws IOException, ClassNotFoundException { //1.建立ObjectInputStream對象,構造方法中傳遞字節輸入流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10_IO\\person.txt")); //2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件 Object o = ois.readObject(); //3.釋放資源 ois.close(); //4.使用讀取出來的對象(打印) System.out.println(o); Person p = (Person)o; System.out.println(p.getName()+p.getAge()); } }
package com.itheima.demo04.ObjectStream; import java.io.Serializable; /* 序列化和反序列化的時候,會拋出NotSerializableException沒有序列化異常 類經過實現 java.io.Serializable 接口以啓用其序列化功能。未實現此接口的類將沒法使其任何狀態序列化或反序列化。 Serializable接口也叫標記型接口 要進行序列化和反序列化的類必須實現Serializable接口,就會給類添加一個標記 當咱們進行序列化和反序列化的時候,就會檢測類上是否有這個標記 有:就能夠序列化和反序列化 沒有:就會拋出 NotSerializableException異常 去市場買肉-->肉上有一個藍色章(檢測合格)-->放心購買-->買回來怎麼吃隨意 static關鍵字:靜態關鍵字 靜態優先於非靜態加載到內存中(靜態優先於對象進入到內存中) 被static修飾的成員變量不能被序列化的,序列化的都是對象 private static int age; oos.writeObject(new Person("小美女",18)); Object o = ois.readObject(); Person{name='小美女', age=0} transient關鍵字:瞬態關鍵字 被transient修飾成員變量,不能被序列化 private transient int age; oos.writeObject(new Person("小美女",18)); Object o = ois.readObject(); Person{name='小美女', age=0} */ public class Person implements Serializable{ private static final long serialVersionUID = 1L; private String name; //private static int age; //private transient int age; public int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package com.itheima.demo04.ObjectStream; import java.io.*; import java.util.ArrayList; /* 練習:序列化集合 當咱們想在文件中保存多個對象的時候 能夠把多個對象存儲到一個集合中 對集合進序列化和反序列化 分析: 1.定義一個存儲Person對象的ArrayList集合 2.往ArrayList集合中存儲Person對象 3.建立一個序列化流ObjectOutputStream對象 4.使用ObjectOutputStream對象中的方法writeObject,對集合進行序列化 5.建立一個反序列化ObjectInputStream對象 6.使用ObjectInputStream對象中的方法readObject讀取文件中保存的集合 7.把Object類型的集合轉換爲ArrayList類型 8.遍歷ArrayList集合 9.釋放資源 */ public class Demo03Test { public static void main(String[] args) throws IOException, ClassNotFoundException { //1.定義一個存儲Person對象的ArrayList集合 ArrayList<Person> list = new ArrayList<>(); //2.往ArrayList集合中存儲Person對象 list.add(new Person("張三",18)); list.add(new Person("李四",19)); list.add(new Person("王五",20)); //3.建立一個序列化流ObjectOutputStream對象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("10_IO\\list.txt")); //4.使用ObjectOutputStream對象中的方法writeObject,對集合進行序列化 oos.writeObject(list); //5.建立一個反序列化ObjectInputStream對象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10_IO\\list.txt")); //6.使用ObjectInputStream對象中的方法readObject讀取文件中保存的集合 Object o = ois.readObject(); //7.把Object類型的集合轉換爲ArrayList類型 ArrayList<Person> list2 = (ArrayList<Person>)o; //8.遍歷ArrayList集合 for (Person p : list2) { System.out.println(p); } //9.釋放資源 ois.close(); oos.close(); } }
package com.itheima.demo05.PrintStream; import java.io.FileNotFoundException; import java.io.PrintStream; /* java.io.PrintStream:打印流 PrintStream 爲其餘輸出流添加了功能,使它們可以方便地打印各類數據值表示形式。 PrintStream特色: 1.只負責數據的輸出,不負責數據的讀取 2.與其餘輸出流不一樣,PrintStream 永遠不會拋出 IOException 3.有特有的方法,print,println void print(任意類型的值) void println(任意類型的值並換行) 構造方法: PrintStream(File file):輸出的目的地是一個文件 PrintStream(OutputStream out):輸出的目的地是一個字節輸出流 PrintStream(String fileName) :輸出的目的地是一個文件路徑 PrintStream extends OutputStream 繼承自父類的成員方法: - public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。 - public void flush() :刷新此輸出流並強制任何緩衝的輸出字節被寫出。 - public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。 - public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。 - public abstract void write(int b) :將指定的字節輸出流。 注意: 若是使用繼承自父類的write方法寫數據,那麼查看數據的時候會查詢編碼表 97->a 若是使用本身特有的方法print/println方法寫數據,寫的數據原樣輸出 97->97 */ public class Demo01PrintStream { public static void main(String[] args) throws FileNotFoundException { //System.out.println("HelloWorld"); //建立打印流PrintStream對象,構造方法中綁定要輸出的目的地 PrintStream ps = new PrintStream("10_IO\\print.txt"); //若是使用繼承自父類的write方法寫數據,那麼查看數據的時候會查詢編碼表 97->a ps.write(97); //若是使用本身特有的方法print/println方法寫數據,寫的數據原樣輸出 97->97 ps.println(97); ps.println(8.8); ps.println('a'); ps.println("HelloWorld"); ps.println(true); //釋放資源 ps.close(); } }
package com.itheima.demo05.PrintStream; import java.io.FileNotFoundException; import java.io.PrintStream; /* 能夠改變輸出語句的目的地(打印流的流向) 輸出語句,默認在控制檯輸出 使用System.setOut方法改變輸出語句的目的地改成參數中傳遞的打印流的目的地 static void setOut(PrintStream out) 從新分配「標準」輸出流。 */ public class Demo02PrintStream { public static void main(String[] args) throws FileNotFoundException { System.out.println("我是在控制檯輸出"); PrintStream ps = new PrintStream("10_IO\\目的地是打印流.txt"); System.setOut(ps);//把輸出語句的目的地改變爲打印流的目的地 System.out.println("我在打印流的目的地中輸出"); ps.close(); } }
通訊的協議仍是比較複雜的,java.net
包中包含的類和接口,它們提供低層次的通訊細節。咱們能夠直接使用這些類和接口,來專一於網絡程序開發,而不用考慮通訊的細節。
java.net
包中提供了兩種常見的網絡協議的支持:
UDP:用戶數據報協議(User Datagram Protocol)。UDP是無鏈接通訊協議,即在數據傳輸時,數據的發送端和接收端不創建邏輯鏈接。簡單來講,當一臺計算機向另一臺計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,一樣接收端在收到數據時,也不會向發送端反饋是否收到數據。
因爲使用UDP協議消耗資源小,通訊效率高,因此一般都會用於音頻、視頻和普通數據的傳輸例如視頻會議都使用UDP協議,由於這種狀況即便偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。
可是在使用UDP協議傳送數據時,因爲UDP的面向無鏈接性,不能保證數據的完整性,所以在傳輸重要數據時不建議使用UDP協議。UDP的交換過程以下圖所示。
特色:數據被限制在64kb之內,超出這個範圍就不能發送了。
數據報(Datagram):網絡傳輸的基本單位
TCP:傳輸控制協議 (Transmission Control Protocol)。TCP協議是面向鏈接的通訊協議,即傳輸數據以前,在發送端和接收端創建邏輯鏈接,而後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。
在TCP鏈接中必需要明確客戶端與服務器端,由客戶端向服務端發出鏈接請求,每次鏈接的建立都須要通過「三次握手」。
完成三次握手,鏈接創建後,客戶端和服務器就能夠開始進行數據傳輸了。因爲這種面向鏈接的特性,TCP協議能夠保證傳輸數據的安全,因此應用十分普遍,例以下載文件、瀏覽網頁等。
IP地址分類
IPv4:是一個32位的二進制數,一般被分爲4個字節,表示成a.b.c.d
的形式,例如192.168.65.100
。其中a、b、c、d都是0~255之間的十進制整數,那麼最多能夠表示42億個。
IPv6:因爲互聯網的蓬勃發展,IP地址的需求量越來越大,可是網絡地址資源有限,使得IP的分配愈加緊張。
爲了擴大地址空間,擬經過IPv6從新定義地址空間,採用128位地址長度,每16個字節一組,分紅8組十六進制數,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
,號稱能夠爲全世界的每一粒沙子編上一個網址,這樣就解決了網絡地址資源數量不夠的問題。
經常使用命令
ipconfig
ping 空格 IP地址 ping 220.181.57.216
特殊的IP地址
127.0.0.1
、localhost
。網絡的通訊,本質上是兩個進程(應用程序)的通訊。每臺計算機都有不少的進程,那麼在網絡通訊時,如何區分這些進程呢?
若是說IP地址能夠惟一標識網絡中的設備,那麼端口號就能夠惟一標識設備中的進程(應用程序)了。
利用協議
+IP地址
+端口號
三元組合,就能夠標識網絡中的進程了,那麼進程間的通訊就能夠利用這個標識與其它進程進行交互。
package com.itheima.demo01.TCP; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /* TCP通訊的客戶端:向服務器發送鏈接請求,給服務器發送數據,讀取服務器回寫的數據 表示客戶端的類: java.net.Socket:此類實現客戶端套接字(也能夠就叫「套接字」)。套接字是兩臺機器間通訊的端點。 套接字:包含了IP地址和端口號的網絡單位 構造方法: Socket(String host, int port) 建立一個流套接字並將其鏈接到指定主機上的指定端口號。 參數: String host:服務器主機的名稱/服務器的IP地址 int port:服務器的端口號 成員方法: OutputStream getOutputStream() 返回此套接字的輸出流。 InputStream getInputStream() 返回此套接字的輸入流。 void close() 關閉此套接字。 實現步驟: 1.建立一個客戶端對象Socket,構造方法綁定服務器的IP地址和端口號 2.使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象 3.使用網絡字節輸出流OutputStream對象中的方法write,給服務器發送數據 4.使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象 5.使用網絡字節輸入流InputStream對象中的方法read,讀取服務器回寫的數據 6.釋放資源(Socket) 注意: 1.客戶端和服務器端進行交互,必須使用Socket中提供的網絡流,不能使用本身建立的流對象 2.當咱們建立客戶端對象Socket的時候,就會去請求服務器和服務器通過3次握手創建鏈接通路 這時若是服務器沒有啓動,那麼就會拋出異常ConnectException: Connection refused: connect 若是服務器已經啓動,那麼就能夠進行交互了 */ public class TCPClient { public static void main(String[] args) throws IOException { //1.建立一個客戶端對象Socket,構造方法綁定服務器的IP地址和端口號 Socket socket = new Socket("127.0.0.1",8888); //2.使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象 OutputStream os = socket.getOutputStream(); //3.使用網絡字節輸出流OutputStream對象中的方法write,給服務器發送數據 os.write("你好服務器".getBytes()); //4.使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象 InputStream is = socket.getInputStream(); //5.使用網絡字節輸入流InputStream對象中的方法read,讀取服務器回寫的數據 byte[] bytes = new byte[1024]; int len = is.read(bytes); System.out.println(new String(bytes,0,len)); //6.釋放資源(Socket) socket.close(); } }
package com.itheima.demo01.TCP; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /* TCP通訊的服務器端:接收客戶端的請求,讀取客戶端發送的數據,給客戶端回寫數據 表示服務器的類: java.net.ServerSocket:此類實現服務器套接字。 構造方法: ServerSocket(int port) 建立綁定到特定端口的服務器套接字。 服務器端必須明確一件事情,必須的知道是哪一個客戶端請求的服務器 因此可使用accept方法獲取到請求的客戶端對象Socket 成員方法: Socket accept() 偵聽並接受到此套接字的鏈接。 服務器的實現步驟: 1.建立服務器ServerSocket對象和系統要指定的端口號 2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端對象Socket 3.使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象 4.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端發送的數據 5.使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象 6.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫數據 7.釋放資源(Socket,ServerSocket) */ public class TCPServer { public static void main(String[] args) throws IOException { //1.建立服務器ServerSocket對象和系統要指定的端口號 ServerSocket server = new ServerSocket(8888); //2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端對象Socket Socket socket = server.accept(); //3.使用Socket對象中的方法getInputStream()獲取網絡字節輸入流InputStream對象 InputStream is = socket.getInputStream(); //4.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端發送的數據 byte[] bytes = new byte[1024]; int len = is.read(bytes); System.out.println(new String(bytes,0,len)); //5.使用Socket對象中的方法getOutputStream()獲取網絡字節輸出流OutputStream對象 OutputStream os = socket.getOutputStream(); //6.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫數據 os.write("收到謝謝".getBytes()); //7.釋放資源(Socket,ServerSocket) socket.close(); server.close(); } }
package com.itheima.demo02.FileUpload; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /* 文件上傳案例的客戶端:讀取本地文件,上傳到服務器,讀取服務器回寫的數據 明確: 數據源:c:\\1.jpg 目的地:服務器 實現步驟: 1.建立一個本地字節輸入流FileInputStream對象,構造方法中綁定要讀取的數據源 2.建立一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號 3.使用Socket中的方法getOutputStream,獲取網絡字節輸出流OutputStream對象 4.使用本地字節輸入流FileInputStream對象中的方法read,讀取本地文件 5.使用網絡字節輸出流OutputStream對象中的方法write,把讀取到的文件上傳到服務器 6.使用Socket中的方法getInputStream,獲取網絡字節輸入流InputStream對象 7.使用網絡字節輸入流InputStream對象中的方法read讀取服務回寫的數據 8.釋放資源(FileInputStream,Socket) */ public class TCPClient { public static void main(String[] args) throws IOException { //1.建立一個本地字節輸入流FileInputStream對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("c:\\1.jpg"); //2.建立一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號 Socket socket = new Socket("127.0.0.1",8888); //3.使用Socket中的方法getOutputStream,獲取網絡字節輸出流OutputStream對象 OutputStream os = socket.getOutputStream(); //4.使用本地字節輸入流FileInputStream對象中的方法read,讀取本地文件 int len = 0; byte[] bytes = new byte[1024]; while((len = fis.read(bytes))!=-1){ //5.使用網絡字節輸出流OutputStream對象中的方法write,把讀取到的文件上傳到服務器 os.write(bytes,0,len); } /* 解決:上傳完文件,給服務器寫一個結束標記 void shutdownOutput() 禁用此套接字的輸出流。 對於 TCP 套接字,任何之前寫入的數據都將被髮送,而且後跟 TCP 的正常鏈接終止序列。 */ socket.shutdownOutput(); //6.使用Socket中的方法getInputStream,獲取網絡字節輸入流InputStream對象 InputStream is = socket.getInputStream(); System.out.println("333333333333333333333"); //7.使用網絡字節輸入流InputStream對象中的方法read讀取服務回寫的數據 while((len = is.read(bytes))!=-1){ System.out.println(new String(bytes,0,len)); } System.out.println("444444444444444444 while死循環打印不到"); //8.釋放資源(FileInputStream,Socket) fis.close(); socket.close(); } }
package com.itheima.demo02.FileUpload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /* 文件上傳案例服務器端:讀取客戶端上傳的文件,保存到服務器的硬盤,給客戶端回寫"上傳成功" 明確: 數據源:客戶端上傳的文件 目的地:服務器的硬盤 d:\\upload\\1.jpg 實現步驟: 1.建立一個服務器ServerSocket對象,和系統要指定的端口號 2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端Socket對象 3.使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象 4.判斷d:\\upload文件夾是否存在,不存在則建立 5.建立一個本地字節輸出流FileOutputStream對象,構造方法中綁定要輸出的目的地 6.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端上傳的文件 7.使用本地字節輸出流FileOutputStream對象中的方法write,把讀取到的文件保存到服務器的硬盤上 8.使用Socket對象中的方法getOutputStream,獲取到網絡字節輸出流OutputStream對象 9.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫"上傳成功" 10.釋放資源(FileOutputStream,Socket,ServerSocket) */ public class TCPServer { public static void main(String[] args) throws IOException { //1.建立一個服務器ServerSocket對象,和系統要指定的端口號 ServerSocket server = new ServerSocket(8888); //2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端Socket對象 Socket socket = server.accept(); //3.使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象 InputStream is = socket.getInputStream(); //4.判斷d:\\upload文件夾是否存在,不存在則建立 File file = new File("d:\\upload"); if(!file.exists()){ file.mkdirs(); } //5.建立一個本地字節輸出流FileOutputStream對象,構造方法中綁定要輸出的目的地 FileOutputStream fos = new FileOutputStream(file+"\\1.jpg"); //6.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端上傳的文件 System.out.println("11111111111111111111"); int len =0; byte[] bytes = new byte[1024]; while((len = is.read(bytes))!=-1){ //7.使用本地字節輸出流FileOutputStream對象中的方法write,把讀取到的文件保存到服務器的硬盤上 fos.write(bytes,0,len); } System.out.println("22222222222222222222222 while死循環打印不到"); //8.使用Socket對象中的方法getOutputStream,獲取到網絡字節輸出流OutputStream對象 //9.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫"上傳成功" socket.getOutputStream().write("上傳成功".getBytes()); //10.釋放資源(FileOutputStream,Socket,ServerSocket) fos.close(); socket.close(); server.close(); } }
package com.itheima.demo03.FileUpload; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /* 文件上傳案例的客戶端:讀取本地文件,上傳到服務器,讀取服務器回寫的數據 明確: 數據源:c:\\1.jpg 目的地:服務器 實現步驟: 1.建立一個本地字節輸入流FileInputStream對象,構造方法中綁定要讀取的數據源 2.建立一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號 3.使用Socket中的方法getOutputStream,獲取網絡字節輸出流OutputStream對象 4.使用本地字節輸入流FileInputStream對象中的方法read,讀取本地文件 5.使用網絡字節輸出流OutputStream對象中的方法write,把讀取到的文件上傳到服務器 6.使用Socket中的方法getInputStream,獲取網絡字節輸入流InputStream對象 7.使用網絡字節輸入流InputStream對象中的方法read讀取服務回寫的數據 8.釋放資源(FileInputStream,Socket) */ public class TCPClient { public static void main(String[] args) throws IOException { //1.建立一個本地字節輸入流FileInputStream對象,構造方法中綁定要讀取的數據源 FileInputStream fis = new FileInputStream("c:\\1.jpg"); //2.建立一個客戶端Socket對象,構造方法中綁定服務器的IP地址和端口號 Socket socket = new Socket("127.0.0.1",8888); //3.使用Socket中的方法getOutputStream,獲取網絡字節輸出流OutputStream對象 OutputStream os = socket.getOutputStream(); //4.使用本地字節輸入流FileInputStream對象中的方法read,讀取本地文件 int len = 0; byte[] bytes = new byte[1024]; while((len = fis.read(bytes))!=-1){ //5.使用網絡字節輸出流OutputStream對象中的方法write,把讀取到的文件上傳到服務器 os.write(bytes,0,len); } /* 解決:上傳完文件,給服務器寫一個結束標記 void shutdownOutput() 禁用此套接字的輸出流。 對於 TCP 套接字,任何之前寫入的數據都將被髮送,而且後跟 TCP 的正常鏈接終止序列。 */ socket.shutdownOutput(); //6.使用Socket中的方法getInputStream,獲取網絡字節輸入流InputStream對象 InputStream is = socket.getInputStream(); //7.使用網絡字節輸入流InputStream對象中的方法read讀取服務回寫的數據 while((len = is.read(bytes))!=-1){ System.out.println(new String(bytes,0,len)); } //8.釋放資源(FileInputStream,Socket) fis.close(); socket.close(); } }
package com.itheima.demo03.FileUpload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Random; /* 文件上傳案例服務器端:讀取客戶端上傳的文件,保存到服務器的硬盤,給客戶端回寫"上傳成功" 明確: 數據源:客戶端上傳的文件 目的地:服務器的硬盤 d:\\upload\\1.jpg 實現步驟: 1.建立一個服務器ServerSocket對象,和系統要指定的端口號 2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端Socket對象 3.使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象 4.判斷d:\\upload文件夾是否存在,不存在則建立 5.建立一個本地字節輸出流FileOutputStream對象,構造方法中綁定要輸出的目的地 6.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端上傳的文件 7.使用本地字節輸出流FileOutputStream對象中的方法write,把讀取到的文件保存到服務器的硬盤上 8.使用Socket對象中的方法getOutputStream,獲取到網絡字節輸出流OutputStream對象 9.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫"上傳成功" 10.釋放資源(FileOutputStream,Socket,ServerSocket) */ public class TCPServer { public static void main(String[] args) throws IOException { //1.建立一個服務器ServerSocket對象,和系統要指定的端口號 ServerSocket server = new ServerSocket(8888); //2.使用ServerSocket對象中的方法accept,獲取到請求的客戶端Socket對象 /* 讓服務器一直處於監聽狀態(死循環accept方法) 有一個客戶端上傳文件,就保存一個文件 */ while(true){ Socket socket = server.accept(); /* 使用多線程技術,提升程序的效率 有一個客戶端上傳文件,就開啓一個線程,完成文件的上傳 */ new Thread(new Runnable() { //完成文件的上傳 @Override public void run() { try { //3.使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象 InputStream is = socket.getInputStream(); //4.判斷d:\\upload文件夾是否存在,不存在則建立 File file = new File("d:\\upload"); if(!file.exists()){ file.mkdirs(); } /* 自定義一個文件的命名規則:防止同名的文件被覆蓋 規則:域名+毫秒值+隨機數 */ String fileName = "itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg"; //5.建立一個本地字節輸出流FileOutputStream對象,構造方法中綁定要輸出的目的地 //FileOutputStream fos = new FileOutputStream(file+"\\1.jpg"); FileOutputStream fos = new FileOutputStream(file+"\\"+fileName); //6.使用網絡字節輸入流InputStream對象中的方法read,讀取客戶端上傳的文件 int len =0; byte[] bytes = new byte[1024]; while((len = is.read(bytes))!=-1){ //7.使用本地字節輸出流FileOutputStream對象中的方法write,把讀取到的文件保存到服務器的硬盤上 fos.write(bytes,0,len); } //8.使用Socket對象中的方法getOutputStream,獲取到網絡字節輸出流OutputStream對象 //9.使用網絡字節輸出流OutputStream對象中的方法write,給客戶端回寫"上傳成功" socket.getOutputStream().write("上傳成功".getBytes()); //10.釋放資源(FileOutputStream,Socket,ServerSocket) fos.close(); socket.close(); }catch (IOException e){ System.out.println(e); } } }).start(); } //服務器就不用關閉 //server.close(); } }
測試分類:
1. 黑盒測試:不須要寫代碼,給輸入值,看程序是否可以輸出指望的值。
2. 白盒測試:須要寫代碼的。關注程序具體的執行流程。
修飾的方法會在測試方法執行以後自動被執行
package cn.itcast.junit;
/**計算器類
*/
public class Calculator {
@return
*/
public int add (int a , int b){
//int i = 3/0;
return a - b;
}
}
package cn.itcast.junit; public class CalculatorTest { public static void main(String[] args) { //建立對象 Calculator c = new Calculator(); //調用 /* int result = c.add(1, 2); System.out.println(result);*/ int result = c.sub(1, 1); System.out.println(result); String str = "abc"; } }
package cn.itcast.test; import cn.itcast.junit.Calculator; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class CalculatorTest { /** * 初始化方法: * 用於資源申請,全部測試方法在執行以前都會先執行該方法 */ @Before public void init(){ System.out.println("init..."); } /** * 釋放資源方法: * 在全部測試方法執行完後,都會自動執行該方法 */ @After public void close(){ System.out.println("close..."); } /** * 測試add方法 */ @Test public void testAdd(){ // System.out.println("我被執行了"); //1.建立計算器對象 System.out.println("testAdd..."); Calculator c = new Calculator(); //2.調用add方法 int result = c.add(1, 2); //System.out.println(result); //3.斷言 我斷言這個結果是3 Assert.assertEquals(3,result); } @Test public void testSub(){ //1.建立計算器對象 Calculator c = new Calculator(); int result = c.sub(1, 2); System.out.println("testSub...."); Assert.assertEquals(-1,result); } }
在java的世界裏,一切皆對象。其實從某種意義上說,在java中有兩種對象:實例對象和Class對象。實例對象就是咱們日常定義的一個類的實例
而Class對象是沒辦法用new關鍵字獲得的,由於它是jvm生成用來保存對應類的信息的,換句話說,當咱們定義好一個類文件並編譯成.class字節碼後,編譯器同時爲咱們建立了一個Class對象並將它保存.class文件中。我不知道這樣描述是否穩當,由於我也見過某些書上直接把.class文件稱之爲Class對象。同時在jvm內部有一個類加載機制,即在須要的時候(懶加載)將.class文件和對應的Class對象加載到內存中。總之要有這樣一個意識,Person.java文件編譯成Person.class的同時也會產生一個對應的Class對象。
Field getField(String name) 獲取指定名稱的 public修飾的成員變量
Constructor
Method getMethod(String name, 類<?>... parameterTypes)
Method getDeclaredMethod(String name, 類<?>... parameterTypes)
setAccessible(true):暴力反射
package cn.itcast.domain;
public class Person {
private String name;
private int age;
public String a; protected String b; String c; private String d; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + ", d='" + d + '\'' + '}'; } public void eat(){ System.out.println("eat..."); } public void eat(String food){ System.out.println("eat..."+food); }
}
package cn.itcast.reflect; import cn.itcast.domain.Person; import cn.itcast.domain.Student; public class ReflectDemo1 { /** 獲取Class對象的方式: 1. Class.forName("全類名"):將字節碼文件加載進內存,返回Class對象 2. 類名.class:經過類名的屬性class獲取 3. 對象.getClass():getClass()方法在Object類中定義着。 */ public static void main(String[] args) throws Exception { //1.Class.forName("全類名") Class cls1 = Class.forName("cn.itcast.domain.Person"); System.out.println(cls1); //2.類名.class Class cls2 = Person.class; System.out.println(cls2); //3.對象.getClass() Person p = new Person(); Class cls3 = p.getClass(); System.out.println(cls3); //== 比較三個對象 System.out.println(cls1 == cls2);//true System.out.println(cls1 == cls3);//true Class c = Student.class; System.out.println(c == cls1); } }
package cn.itcast.reflect; import cn.itcast.domain.Person; import java.lang.reflect.Field; public class ReflectDemo2 { /** Class對象功能: * 獲取功能: 1. 獲取成員變量們 * Field[] getFields() * Field getField(String name) * Field[] getDeclaredFields() * Field getDeclaredField(String name) 2. 獲取構造方法們 * Constructor<?>[] getConstructors() * Constructor<T> getConstructor(類<?>... parameterTypes) * Constructor<T> getDeclaredConstructor(類<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors() 3. 獲取成員方法們: * Method[] getMethods() * Method getMethod(String name, 類<?>... parameterTypes) * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 類<?>... parameterTypes) 4. 獲取類名 * String getName() */ public static void main(String[] args) throws Exception { //0.獲取Person的Class對象 Class personClass = Person.class; /* 1. 獲取成員變量們 * Field[] getFields() * Field getField(String name) * Field[] getDeclaredFields() * Field getDeclaredField(String name) */ //1.Field[] getFields()獲取全部public修飾的成員變量 Field[] fields = personClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("------------"); //2.Field getField(String name) Field a = personClass.getField("a"); //獲取成員變量a 的值 Person p = new Person(); Object value = a.get(p); System.out.println(value); //設置a的值 a.set(p,"張三"); System.out.println(p); System.out.println("==================="); //Field[] getDeclaredFields():獲取全部的成員變量,不考慮修飾符 Field[] declaredFields = personClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } //Field getDeclaredField(String name) Field d = personClass.getDeclaredField("d"); //忽略訪問權限修飾符的安全檢查 d.setAccessible(true);//暴力反射 Object value2 = d.get(p); System.out.println(value2); } }
T newInstance(Object... initargs)
若是使用空參數構造方法建立對象,操做能夠簡化:Class對象的newInstance方法
package cn.itcast.reflect; import cn.itcast.domain.Person; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class ReflectDemo3 { /** Class對象功能: * 獲取功能: 1. 獲取成員變量們 * Field[] getFields() * Field getField(String name) * Field[] getDeclaredFields() * Field getDeclaredField(String name) 2. 獲取構造方法們 * Constructor<?>[] getConstructors() * Constructor<T> getConstructor(類<?>... parameterTypes) * Constructor<T> getDeclaredConstructor(類<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors() 3. 獲取成員方法們: * Method[] getMethods() * Method getMethod(String name, 類<?>... parameterTypes) * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 類<?>... parameterTypes) 4. 獲取類名 * String getName() */ public static void main(String[] args) throws Exception { //0.獲取Person的Class對象 Class personClass = Person.class; /* 2. 獲取構造方法們 * Constructor<?>[] getConstructors() * Constructor<T> getConstructor(類<?>... parameterTypes) * Constructor<T> getDeclaredConstructor(類<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors() */ //Constructor<T> getConstructor(類<?>... parameterTypes) Constructor constructor = personClass.getConstructor(String.class, int.class); System.out.println(constructor); //建立對象 Object person = constructor.newInstance("張三", 23); System.out.println(person); System.out.println("----------"); Constructor constructor1 = personClass.getConstructor(); System.out.println(constructor1); //建立對象 Object person1 = constructor1.newInstance(); System.out.println(person1); Object o = personClass.newInstance(); System.out.println(o); //constructor1.setAccessible(true); } }
package cn.itcast.reflect; import cn.itcast.domain.Person; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ReflectDemo4 { /** Class對象功能: * 獲取功能: 1. 獲取成員變量們 * Field[] getFields() * Field getField(String name) * Field[] getDeclaredFields() * Field getDeclaredField(String name) 2. 獲取構造方法們 * Constructor<?>[] getConstructors() * Constructor<T> getConstructor(類<?>... parameterTypes) * Constructor<T> getDeclaredConstructor(類<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors() 3. 獲取成員方法們: * Method[] getMethods() * Method getMethod(String name, 類<?>... parameterTypes) * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 類<?>... parameterTypes) 4. 獲取類名 * String getName() */ public static void main(String[] args) throws Exception { //0.獲取Person的Class對象 Class personClass = Person.class; /* 3. 獲取成員方法們: * Method[] getMethods() * Method getMethod(String name, 類<?>... parameterTypes) * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 類<?>... parameterTypes) */ //獲取指定名稱的方法 Method eat_method = personClass.getMethod("eat"); Person p = new Person(); //執行方法 eat_method.invoke(p); Method eat_method2 = personClass.getMethod("eat", String.class); //執行方法 eat_method2.invoke(p,"飯"); System.out.println("-----------------"); //獲取全部public修飾的方法 Method[] methods = personClass.getMethods(); for (Method method : methods) { System.out.println(method); String name = method.getName(); System.out.println(name); //method.setAccessible(true); } //獲取類名 String className = personClass.getName(); System.out.println(className);//cn.itcast.domain.Person } }
* 概念:說明程序的。給計算機看的 * 註釋:用文字描述程序的。給程序員看的 * 定義:註解(Annotation),也叫元數據。一種代碼級別的說明。它是JDK1.5及之後版本引入的一個特性,與類、接口、枚舉是在同一個層次。它能夠聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,註釋。 * 概念描述: * JDK1.5以後的新特性 * 說明程序的 * 使用註解:@註解名稱 * 做用分類: ①編寫文檔:經過代碼裏標識的註解生成文檔【生成文檔doc文檔】 ②代碼分析:經過代碼裏標識的註解對代碼進行分析【使用反射】 ③編譯檢查:經過代碼裏標識的註解讓編譯器可以實現基本的編譯檢查【Override】 * JDK中預約義的一些註解 * @Override :檢測被該註解標註的方法是不是繼承自父類(接口)的 * @Deprecated:該註解標註的內容,表示已過期 * @SuppressWarnings:壓制警告 * 通常傳遞參數all @SuppressWarnings("all") * 自定義註解 * 格式: 元註解 public @interface 註解名稱{ 屬性列表; } * 本質:註解本質上就是一個接口,該接口默認繼承Annotation接口 * public interface MyAnno extends java.lang.annotation.Annotation {} * 屬性:接口中的抽象方法 * 要求: 1. 屬性的返回值類型有下列取值 * 基本數據類型 * String * 枚舉 * 註解 * 以上類型的數組 2. 定義了屬性,在使用時須要給屬性賦值 1. 若是定義屬性時,使用default關鍵字給屬性默認初始化值,則使用註解時,能夠不進行屬性的賦值。 2. 若是隻有一個屬性須要賦值,而且屬性的名稱是value,則value能夠省略,直接定義值便可。 3. 數組賦值時,值使用{}包裹。若是數組中只有一個值,則{}能夠省略 * 元註解:用於描述註解的註解 * @Target:描述註解可以做用的位置 * ElementType取值: * TYPE:能夠做用於類上 * METHOD:能夠做用於方法上 * FIELD:能夠做用於成員變量上 * @Retention:描述註解被保留的階段 * @Retention(RetentionPolicy.RUNTIME):當前被描述的註解,會保留到class字節碼文件中,並被JVM讀取到 * @Documented:描述註解是否被抽取到api文檔中 * @Inherited:描述註解是否被子類繼承 * 在程序使用(解析)註解:獲取註解中定義的屬性值 1. 獲取註解定義的位置的對象 (Class,Method,Field) 2. 獲取指定的註解 * getAnnotation(Class) //其實就是在內存中生成了一個該註解接口的子類實現對象 public class ProImpl implements Pro{ public String className(){ return "cn.itcast.annotation.Demo1"; } public String methodName(){ return "show"; } } 3. 調用註解中的抽象方法獲取配置的屬性值 * 案例:簡單的測試框架 * 小結: 1. 之後大多數時候,咱們會使用註解,而不是自定義註解 2. 註解給誰用? 1. 編譯器 2. 給解析程序用 3. 註解不是程序的一部分,能夠理解爲註解就是一個標籤
1. 數據庫的英文單詞: DataBase 簡稱 : DB 2. 什麼數據庫? * 用於存儲和管理數據的倉庫。 3. 數據庫的特色: 1. 持久化存儲數據的。其實數據庫就是一個文件系統 2. 方便存儲和管理數據 3. 使用了統一的方式操做數據庫 -- SQL 4. 常見的數據庫軟件 * 參見《MySQL基礎.pdf》
1. 安裝 * 參見《MySQL基礎.pdf》 2. 卸載 1. 去mysql的安裝目錄找到my.ini文件 * 複製 datadir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/" 2. 卸載MySQL 3. 刪除C:/ProgramData目錄下的MySQL文件夾。 3. 配置 * MySQL服務啓動 1. 手動。 2. cmd--> services.msc 打開服務的窗口 3. 使用管理員打開cmd * net start mysql : 啓動mysql的服務 * net stop mysql:關閉mysql服務 * MySQL登陸 1. mysql -uroot -p密碼 2. mysql -hip -uroot -p鏈接目標的密碼 3. mysql --host=ip --user=root --password=鏈接目標的密碼 * MySQL退出 1. exit 2. quit * MySQL目錄結構 1. MySQL安裝目錄:basedir="D:/develop/MySQL/" * 配置文件 my.ini 2. MySQL數據目錄:datadir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/" * 幾個概念 * 數據庫:文件夾 * 表:文件 * 數據:數據
1.什麼是SQL? Structured Query Language:結構化查詢語言 其實就是定義了操做全部關係型數據庫的規則。每一種數據庫操做的方式存在不同的地方,稱爲「方言」。 2.SQL通用語法 1. SQL 語句能夠單行或多行書寫,以分號結尾。 2. 可以使用空格和縮進來加強語句的可讀性。 3. MySQL 數據庫的 SQL 語句不區分大小寫,關鍵字建議使用大寫。 4. 3 種註釋 * 單行註釋: -- 註釋內容 或 # 註釋內容(mysql 特有) * 多行註釋: /* 註釋 */ 3. SQL分類 1) DDL(Data Definition Language)數據定義語言 用來定義數據庫對象:數據庫,表,列等。關鍵字:create, drop,alter 等 2) DML(Data Manipulation Language)數據操做語言 用來對數據庫中表的數據進行增刪改。關鍵字:insert, delete, update 等 3) DQL(Data Query Language)數據查詢語言 用來查詢數據庫中表的記錄(數據)。關鍵字:select, where 等 4) DCL(Data Control Language)數據控制語言(瞭解) 用來定義數據庫的訪問權限和安全級別,及建立用戶。關鍵字:GRANT, REVOKE 等
1. 操做數據庫:CRUD 1. C(Create):建立 * 建立數據庫: * create database 數據庫名稱; * 建立數據庫,判斷不存在,再建立: * create database if not exists 數據庫名稱; * 建立數據庫,並指定字符集 * create database 數據庫名稱 character set 字符集名; * 練習: 建立db4數據庫,判斷是否存在,並制定字符集爲gbk * create database if not exists db4 character set gbk; 2. R(Retrieve):查詢 * 查詢全部數據庫的名稱: * show databases; * 查詢某個數據庫的字符集:查詢某個數據庫的建立語句 * show create database 數據庫名稱; 3. U(Update):修改 * 修改數據庫的字符集 * alter database 數據庫名稱 character set 字符集名稱; 4. D(Delete):刪除 * 刪除數據庫 * drop database 數據庫名稱; * 判斷數據庫存在,存在再刪除 * drop database if exists 數據庫名稱; 5. 使用數據庫 * 查詢當前正在使用的數據庫名稱 * select database(); * 使用數據庫 * use 數據庫名稱; 2. 操做表 1. C(Create):建立 1. 語法: create table 表名( 列名1 數據類型1, 列名2 數據類型2, .... 列名n 數據類型n ); * 注意:最後一列,不須要加逗號(,) * 數據庫類型: 1. int:整數類型 * age int, 2. double:小數類型 * score double(5,2) 3. date:日期,只包含年月日,yyyy-MM-dd 4. datetime:日期,包含年月日時分秒 yyyy-MM-dd HH:mm:ss 5. timestamp:時間錯類型 包含年月日時分秒 yyyy-MM-dd HH:mm:ss * 若是未來不給這個字段賦值,或賦值爲null,則默認使用當前的系統時間,來自動賦值 6. varchar:字符串 * name varchar(20):姓名最大20個字符 * zhangsan 8個字符 張三 2個字符 * 建立表 create table student( id int, name varchar(32), age int , score double(4,1), birthday date, insert_time timestamp ); * 複製表: * create table 表名 like 被複制的表名; 2. R(Retrieve):查詢 * 查詢某個數據庫中全部的表名稱 * show tables; * 查詢表結構 * desc 表名; 3. U(Update):修改 1. 修改表名 alter table 表名 rename to 新的表名; 2. 修改表的字符集 alter table 表名 character set 字符集名稱; 3. 添加一列 alter table 表名 add 列名 數據類型; 4. 修改列名稱 類型 alter table 表名 change 列名 新列別 新數據類型; alter table 表名 modify 列名 新數據類型; 5. 刪除列 alter table 表名 drop 列名; 4. D(Delete):刪除 * drop table 表名; * drop table if exists 表名 ;
1. 添加數據: * 語法: * insert into 表名(列名1,列名2,...列名n) values(值1,值2,...值n); * 注意: 1. 列名和值要一一對應。 2. 若是表名後,不定義列名,則默認給全部列添加值 insert into 表名 values(值1,值2,...值n); 3. 除了數字類型,其餘類型須要使用引號(單雙均可以)引發來 2. 刪除數據: * 語法: * delete from 表名 [where 條件] * 注意: 1. 若是不加條件,則刪除表中全部記錄。 2. 若是要刪除全部記錄 1. delete from 表名; -- 不推薦使用。有多少條記錄就會執行多少次刪除操做 2. TRUNCATE TABLE 表名; -- 推薦使用,效率更高 先刪除表,而後再建立一張同樣的表。 3. 修改數據: * 語法: * update 表名 set 列名1 = 值1, 列名2 = 值2,... [where 條件]; * 注意: 1. 若是不加任何條件,則會將表中全部記錄所有修改。
* select * from 表名; 1. 語法: select 字段列表 from 表名列表 where 條件列表 group by 分組字段 having 分組以後的條件 order by 排序 limit 分頁限定 2. 基礎查詢 1. 多個字段的查詢 select 字段名1,字段名2... from 表名; * 注意: * 若是查詢全部字段,則可使用*來替代字段列表。 2. 去除重複: * distinct 3. 計算列 * 通常可使用四則運算計算一些列的值。(通常只會進行數值型的計算) * ifnull(表達式1,表達式2):null參與的運算,計算結果都爲null * 表達式1:哪一個字段須要判斷是否爲null * 若是該字段爲null後的替換值。 4. 起別名: * as:as也能夠省略 3. 條件查詢 1. where子句後跟條件 2. 運算符 * > 、< 、<= 、>= 、= 、<> * BETWEEN...AND * IN( 集合) * LIKE:模糊查詢 * 佔位符: * _:單個任意字符 * %:多個任意字符 * IS NULL * and 或 && * or 或 || * not 或 ! -- 查詢年齡大於20歲 SELECT * FROM student WHERE age > 20; SELECT * FROM student WHERE age >= 20; -- 查詢年齡等於20歲 SELECT * FROM student WHERE age = 20; -- 查詢年齡不等於20歲 SELECT * FROM student WHERE age != 20; SELECT * FROM student WHERE age <> 20; -- 查詢年齡大於等於20 小於等於30 SELECT * FROM student WHERE age >= 20 && age <=30; SELECT * FROM student WHERE age >= 20 AND age <=30; SELECT * FROM student WHERE age BETWEEN 20 AND 30; -- 查詢年齡22歲,18歲,25歲的信息 SELECT * FROM student WHERE age = 22 OR age = 18 OR age = 25 SELECT * FROM student WHERE age IN (22,18,25); -- 查詢英語成績爲null SELECT * FROM student WHERE english = NULL; -- 不對的。null值不能使用 = (!=) 判斷 SELECT * FROM student WHERE english IS NULL; -- 查詢英語成績不爲null SELECT * FROM student WHERE english IS NOT NULL; -- 查詢姓馬的有哪些? like SELECT * FROM student WHERE NAME LIKE '馬%'; -- 查詢姓名第二個字是化的人 SELECT * FROM student WHERE NAME LIKE "_化%"; -- 查詢姓名是3個字的人 SELECT * FROM student WHERE NAME LIKE '___'; -- 查詢姓名中包含德的人 SELECT * FROM student WHERE NAME LIKE '%德%';
1. 排序查詢 * 語法:order by 子句 * order by 排序字段1 排序方式1 , 排序字段2 排序方式2... * 排序方式: * ASC:升序,默認的。 * DESC:降序。 * 注意: * 若是有多個排序條件,則當前邊的條件值同樣時,纔會判斷第二條件。 2. 聚合函數:將一列數據做爲一個總體,進行縱向的計算。 1. count:計算個數 1. 通常選擇非空的列:主鍵 2. count(*) 2. max:計算最大值 3. min:計算最小值 4. sum:計算和 5. avg:計算平均值 * 注意:聚合函數的計算,排除null值。 解決方案: 1. 選擇不包含非空的列進行計算 2. IFNULL函數 3. 分組查詢: 1. 語法:group by 分組字段; 2. 注意: 1. 分組以後查詢的字段:分組字段、聚合函數 2. where 和 having 的區別? 1. where 在分組以前進行限定,若是不知足條件,則不參與分組。having在分組以後進行限定,若是不知足結果,則不會被查詢出來 2. where 後不能夠跟聚合函數,having能夠進行聚合函數的判斷。 -- 按照性別分組。分別查詢男、女同窗的平均分 SELECT sex , AVG(math) FROM student GROUP BY sex; -- 按照性別分組。分別查詢男、女同窗的平均分,人數 SELECT sex , AVG(math),COUNT(id) FROM student GROUP BY sex; -- 按照性別分組。分別查詢男、女同窗的平均分,人數 要求:分數低於70分的人,不參與分組 SELECT sex , AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex; -- 按照性別分組。分別查詢男、女同窗的平均分,人數 要求:分數低於70分的人,不參與分組,分組以後。人數要大於2我的 SELECT sex , AVG(math),COUNT(id) FROM student WHERE math > 70 GROUP BY sex HAVING COUNT(id) > 2; SELECT sex , AVG(math),COUNT(id) 人數 FROM student WHERE math > 70 GROUP BY sex HAVING 人數 > 2; 4. 分頁查詢 1. 語法:limit 開始的索引,每頁查詢的條數; 2. 公式:開始的索引 = (當前的頁碼 - 1) * 每頁顯示的條數 -- 每頁顯示3條記錄 SELECT * FROM student LIMIT 0,3; -- 第1頁 SELECT * FROM student LIMIT 3,3; -- 第2頁 SELECT * FROM student LIMIT 6,3; -- 第3頁 3. limit 是一個MySQL"方言"
* 概念: 對錶中的數據進行限定,保證數據的正確性、有效性和完整性。 * 分類: 1. 主鍵約束:primary key 2. 非空約束:not null 3. 惟一約束:unique 4. 外鍵約束:foreign key * 非空約束:not null,值不能爲null 1. 建立表時添加約束 CREATE TABLE stu( id INT, NAME VARCHAR(20) NOT NULL -- name爲非空 ); 2. 建立表完後,添加非空約束 ALTER TABLE stu MODIFY NAME VARCHAR(20) NOT NULL; 3. 刪除name的非空約束 ALTER TABLE stu MODIFY NAME VARCHAR(20); * 惟一約束:unique,值不能重複 1. 建立表時,添加惟一約束 CREATE TABLE stu( id INT, phone_number VARCHAR(20) UNIQUE -- 添加了惟一約束 ); * 注意mysql中,惟一約束限定的列的值能夠有多個null 2. 刪除惟一約束 ALTER TABLE stu DROP INDEX phone_number; 3. 在建立表後,添加惟一約束 ALTER TABLE stu MODIFY phone_number VARCHAR(20) UNIQUE; * 主鍵約束:primary key。 1. 注意: 1. 含義:非空且惟一 2. 一張表只能有一個字段爲主鍵 3. 主鍵就是表中記錄的惟一標識 2. 在建立表時,添加主鍵約束 create table stu( id int primary key,-- 給id添加主鍵約束 name varchar(20) ); 3. 刪除主鍵 -- 錯誤 alter table stu modify id int ; ALTER TABLE stu DROP PRIMARY KEY; 4. 建立完表後,添加主鍵 ALTER TABLE stu MODIFY id INT PRIMARY KEY; 5. 自動增加: 1. 概念:若是某一列是數值類型的,使用 auto_increment 能夠來完成值得自動增加 2. 在建立表時,添加主鍵約束,而且完成主鍵自增加 create table stu( id int primary key auto_increment,-- 給id添加主鍵約束 name varchar(20) ); 3. 刪除自動增加 ALTER TABLE stu MODIFY id INT; 4. 添加自動增加 ALTER TABLE stu MODIFY id INT AUTO_INCREMENT; * 外鍵約束:foreign key,讓表於表產生關係,從而保證數據的正確性。 1. 在建立表時,能夠添加外鍵 * 語法: create table 表名( .... 外鍵列 constraint 外鍵名稱 foreign key (外鍵列名稱) references 主表名稱(主表列名稱) ); 2. 刪除外鍵 ALTER TABLE 表名 DROP FOREIGN KEY 外鍵名稱; 3. 建立表以後,添加外鍵 ALTER TABLE 表名 ADD CONSTRAINT 外鍵名稱 FOREIGN KEY (外鍵字段名稱) REFERENCES 主表名稱(主表列名稱); 4. 級聯操做 1. 添加級聯操做 語法:ALTER TABLE 表名 ADD CONSTRAINT 外鍵名稱 FOREIGN KEY (外鍵字段名稱) REFERENCES 主表名稱(主表列名稱) ON UPDATE CASCADE ON DELETE CASCADE ; 2. 分類: 1. 級聯更新:ON UPDATE CASCADE 2. 級聯刪除:ON DELETE CASCADE
1. 多表之間的關係 1. 分類: 1. 一對一(瞭解): * 如:人和身份證 * 分析:一我的只有一個身份證,一個身份證只能對應一我的 2. 一對多(多對一): * 如:部門和員工 * 分析:一個部門有多個員工,一個員工只能對應一個部門 3. 多對多: * 如:學生和課程 * 分析:一個學生能夠選擇不少門課程,一個課程也能夠被不少學生選擇 2. 實現關係: 1. 一對多(多對一): * 如:部門和員工 * 實現方式:在多的一方創建外鍵,指向一的一方的主鍵。 2. 多對多: * 如:學生和課程 * 實現方式:多對多關係實現須要藉助第三張中間表。中間表至少包含兩個字段,這兩個字段做爲第三張表的外鍵,分別指向兩張表的主鍵 3. 一對一(瞭解): * 如:人和身份證 * 實現方式:一對一關係實現,能夠在任意一方添加惟一外鍵指向另外一方的主鍵。 3. 案例 -- 建立旅遊線路分類表 tab_category -- cid 旅遊線路分類主鍵,自動增加 -- cname 旅遊線路分類名稱非空,惟一,字符串 100 CREATE TABLE tab_category ( cid INT PRIMARY KEY AUTO_INCREMENT, cname VARCHAR(100) NOT NULL UNIQUE ); -- 建立旅遊線路表 tab_route /* rid 旅遊線路主鍵,自動增加 rname 旅遊線路名稱非空,惟一,字符串 100 price 價格 rdate 上架時間,日期類型 cid 外鍵,所屬分類 */ CREATE TABLE tab_route( rid INT PRIMARY KEY AUTO_INCREMENT, rname VARCHAR(100) NOT NULL UNIQUE, price DOUBLE, rdate DATE, cid INT, FOREIGN KEY (cid) REFERENCES tab_category(cid) ); /*建立用戶表 tab_user uid 用戶主鍵,自增加 username 用戶名長度 100,惟一,非空 password 密碼長度 30,非空 name 真實姓名長度 100 birthday 生日 sex 性別,定長字符串 1 telephone 手機號,字符串 11 email 郵箱,字符串長度 100 */ CREATE TABLE tab_user ( uid INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(100) UNIQUE NOT NULL, PASSWORD VARCHAR(30) NOT NULL, NAME VARCHAR(100), birthday DATE, sex CHAR(1) DEFAULT '男', telephone VARCHAR(11), email VARCHAR(100) ); /* 建立收藏表 tab_favorite rid 旅遊線路 id,外鍵 date 收藏時間 uid 用戶 id,外鍵 rid 和 uid 不能重複,設置複合主鍵,同一個用戶不能收藏同一個線路兩次 */ CREATE TABLE tab_favorite ( rid INT, -- 線路id DATE DATETIME, uid INT, -- 用戶id -- 建立複合主鍵 PRIMARY KEY(rid,uid), -- 聯合主鍵 FOREIGN KEY (rid) REFERENCES tab_route(rid), FOREIGN KEY(uid) REFERENCES tab_user(uid) ); 2. 數據庫設計的範式 * 概念:設計數據庫時,須要遵循的一些規範。要遵循後邊的範式要求,必須先遵循前邊的全部範式要求 設計關係數據庫時,聽從不一樣的規範要求,設計出合理的關係型數據庫,這些不一樣的規範要求被稱爲不一樣的範式,各類範式呈遞次規範,越高的範式數據庫冗餘越小。 目前關係數據庫有六種範式:第一範式(1NF)、第二範式(2NF)、第三範式(3NF)、巴斯-科德範式(BCNF)、第四範式(4NF)和第五範式(5NF,又稱完美範式)。 * 分類: 1. 第一範式(1NF):每一列都是不可分割的原子數據項 2. 第二範式(2NF):在1NF的基礎上,非碼屬性必須徹底依賴於碼(在1NF基礎上消除非主屬性對主碼的部分函數依賴) * 幾個概念: 1. 函數依賴:A-->B,若是經過A屬性(屬性組)的值,能夠肯定惟一B屬性的值。則稱B依賴於A 例如:學號-->姓名。 (學號,課程名稱) --> 分數 2. 徹底函數依賴:A-->B, 若是A是一個屬性組,則B屬性值得肯定須要依賴於A屬性組中全部的屬性值。 例如:(學號,課程名稱) --> 分數 3. 部分函數依賴:A-->B, 若是A是一個屬性組,則B屬性值得肯定只須要依賴於A屬性組中某一些值便可。 例如:(學號,課程名稱) -- > 姓名 4. 傳遞函數依賴:A-->B, B -- >C . 若是經過A屬性(屬性組)的值,能夠肯定惟一B屬性的值,在經過B屬性(屬性組)的值能夠肯定惟一C屬性的值,則稱 C 傳遞函數依賴於A 例如:學號-->系名,系名-->系主任 5. 碼:若是在一張表中,一個屬性或屬性組,被其餘全部屬性所徹底依賴,則稱這個屬性(屬性組)爲該表的碼 例如:該表中碼爲:(學號,課程名稱) * 主屬性:碼屬性組中的全部屬性 * 非主屬性:除過碼屬性組的屬性 3. 第三範式(3NF):在2NF基礎上,任何非主屬性不依賴於其它非主屬性(在2NF基礎上消除傳遞依賴)
1. 命令行: * 語法: * 備份: mysqldump -u用戶名 -p密碼 數據庫名稱 > 保存的路徑 * 還原: 1. 登陸數據庫 2. 建立數據庫 3. 使用數據庫 4. 執行文件。source 文件路徑 2. 圖形化工具:
* 查詢語法: select 列名列表 from 表名列表 where.... * 準備sql # 建立部門表 CREATE TABLE dept( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO dept (NAME) VALUES ('開發部'),('市場部'),('財務部'); # 建立員工表 CREATE TABLE emp ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), gender CHAR(1), -- 性別 salary DOUBLE, -- 工資 join_date DATE, -- 入職日期 dept_id INT, FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外鍵,關聯部門表(部門表的主鍵) ); INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孫悟空','男',7200,'2013-02-24',1); INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('豬八戒','男',3600,'2010-12-02',2); INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2); INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3); INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1); * 笛卡爾積: * 有兩個集合A,B .取這兩個集合的全部組成狀況。 * 要完成多表查詢,須要消除無用的數據 * 多表查詢的分類: 1. 內鏈接查詢: 1. 隱式內鏈接:使用where條件消除無用數據 * 例子: -- 查詢全部員工信息和對應的部門信息 SELECT * FROM emp,dept WHERE emp.`dept_id` = dept.`id`; -- 查詢員工表的名稱,性別。部門表的名稱 SELECT emp.name,emp.gender,dept.name FROM emp,dept WHERE emp.`dept_id` = dept.`id`; SELECT t1.name, -- 員工表的姓名 t1.gender,-- 員工表的性別 t2.name -- 部門表的名稱 FROM emp t1, dept t2 WHERE t1.`dept_id` = t2.`id`; 2. 顯式內鏈接: * 語法: select 字段列表 from 表名1 [inner] join 表名2 on 條件 * 例如: * SELECT * FROM emp INNER JOIN dept ON emp.`dept_id` = dept.`id`; * SELECT * FROM emp JOIN dept ON emp.`dept_id` = dept.`id`; 3. 內鏈接查詢: 1. 從哪些表中查詢數據 2. 條件是什麼 3. 查詢哪些字段 2. 外連接查詢: 1. 左外鏈接: * 語法:select 字段列表 from 表1 left [outer] join 表2 on 條件; * 查詢的是左表全部數據以及其交集部分。 * 例子: -- 查詢全部員工信息,若是員工有部門,則查詢部門名稱,沒有部門,則不顯示部門名稱 SELECT t1.*,t2.`name` FROM emp t1 LEFT JOIN dept t2 ON t1.`dept_id` = t2.`id`; 2. 右外鏈接: * 語法:select 字段列表 from 表1 right [outer] join 表2 on 條件; * 查詢的是右表全部數據以及其交集部分。 * 例子: SELECT * FROM dept t2 RIGHT JOIN emp t1 ON t1.`dept_id` = t2.`id`; 3. 子查詢: * 概念:查詢中嵌套查詢,稱嵌套查詢爲子查詢。 -- 查詢工資最高的員工信息 -- 1 查詢最高的工資是多少 9000 SELECT MAX(salary) FROM emp; -- 2 查詢員工信息,而且工資等於9000的 SELECT * FROM emp WHERE emp.`salary` = 9000; -- 一條sql就完成這個操做。子查詢 SELECT * FROM emp WHERE emp.`salary` = (SELECT MAX(salary) FROM emp); * 子查詢不一樣狀況 1. 子查詢的結果是單行單列的: * 子查詢能夠做爲條件,使用運算符去判斷。 運算符: > >= < <= = * -- 查詢員工工資小於平均工資的人 SELECT * FROM emp WHERE emp.salary < (SELECT AVG(salary) FROM emp); 2. 子查詢的結果是多行單列的: * 子查詢能夠做爲條件,使用運算符in來判斷 -- 查詢'財務部'和'市場部'全部的員工信息 SELECT id FROM dept WHERE NAME = '財務部' OR NAME = '市場部'; SELECT * FROM emp WHERE dept_id = 3 OR dept_id = 2; -- 子查詢 SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME = '財務部' OR NAME = '市場部'); 3. 子查詢的結果是多行多列的: * 子查詢能夠做爲一張虛擬表參與查詢 -- 查詢員工入職日期是2011-11-11日以後的員工信息和部門信息 -- 子查詢 SELECT * FROM dept t1 ,(SELECT * FROM emp WHERE emp.`join_date` > '2011-11-11') t2 WHERE t1.id = t2.dept_id; -- 普通內鏈接 SELECT * FROM emp t1,dept t2 WHERE t1.`dept_id` = t2.`id` AND t1.`join_date` > '2011-11-11' * 多表查詢練習 -- 部門表 CREATE TABLE dept ( id INT PRIMARY KEY PRIMARY KEY, -- 部門id dname VARCHAR(50), -- 部門名稱 loc VARCHAR(50) -- 部門所在地 ); -- 添加4個部門 INSERT INTO dept(id,dname,loc) VALUES (10,'教研部','北京'), (20,'學工部','上海'), (30,'銷售部','廣州'), (40,'財務部','深圳'); -- 職務表,職務名稱,職務描述 CREATE TABLE job ( id INT PRIMARY KEY, jname VARCHAR(20), description VARCHAR(50) ); -- 添加4個職務 INSERT INTO job (id, jname, description) VALUES (1, '董事長', '管理整個公司,接單'), (2, '經理', '管理部門員工'), (3, '銷售員', '向客人推銷產品'), (4, '文員', '使用辦公軟件'); -- 員工表 CREATE TABLE emp ( id INT PRIMARY KEY, -- 員工id ename VARCHAR(50), -- 員工姓名 job_id INT, -- 職務id mgr INT , -- 上級領導 joindate DATE, -- 入職日期 salary DECIMAL(7,2), -- 工資 bonus DECIMAL(7,2), -- 獎金 dept_id INT, -- 所在部門編號 CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id), CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id) ); -- 添加員工 INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES (1001,'孫悟空',4,1004,'2000-12-17','8000.00',NULL,20), (1002,'盧俊義',3,1006,'2001-02-20','16000.00','3000.00',30), (1003,'林沖',3,1006,'2001-02-22','12500.00','5000.00',30), (1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20), (1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30), (1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30), (1007,'劉備',2,1009,'2001-09-01','24500.00',NULL,10), (1008,'豬八戒',4,1004,'2007-04-19','30000.00',NULL,20), (1009,'羅貫中',1,NULL,'2001-11-17','50000.00',NULL,10), (1010,'吳用',3,1006,'2001-09-08','15000.00','0.00',30), (1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20), (1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30), (1013,'小白龍',4,1004,'2001-12-03','30000.00',NULL,20), (1014,'關羽',4,1007,'2002-01-23','13000.00',NULL,10); -- 工資等級表 CREATE TABLE salarygrade ( grade INT PRIMARY KEY, -- 級別 losalary INT, -- 最低工資 hisalary INT -- 最高工資 ); -- 添加5個工資等級 INSERT INTO salarygrade(grade,losalary,hisalary) VALUES (1,7000,12000), (2,12010,14000), (3,14010,20000), (4,20010,30000), (5,30010,99990); -- 需求: -- 1.查詢全部員工信息。查詢員工編號,員工姓名,工資,職務名稱,職務描述 /* 分析: 1.員工編號,員工姓名,工資,須要查詢emp表 職務名稱,職務描述 須要查詢job表 2.查詢條件 emp.job_id = job.id */ SELECT t1.`id`, -- 員工編號 t1.`ename`, -- 員工姓名 t1.`salary`,-- 工資 t2.`jname`, -- 職務名稱 t2.`description` -- 職務描述 FROM emp t1, job t2 WHERE t1.`job_id` = t2.`id`; -- 2.查詢員工編號,員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置 /* 分析: 1. 員工編號,員工姓名,工資 emp 職務名稱,職務描述 job 部門名稱,部門位置 dept 2. 條件: emp.job_id = job.id and emp.dept_id = dept.id */ SELECT t1.`id`, -- 員工編號 t1.`ename`, -- 員工姓名 t1.`salary`,-- 工資 t2.`jname`, -- 職務名稱 t2.`description`, -- 職務描述 t3.`dname`, -- 部門名稱 t3.`loc` -- 部門位置 FROM emp t1, job t2,dept t3 WHERE t1.`job_id` = t2.`id` AND t1.`dept_id` = t3.`id`; -- 3.查詢員工姓名,工資,工資等級 /* 分析: 1.員工姓名,工資 emp 工資等級 salarygrade 2.條件 emp.salary >= salarygrade.losalary and emp.salary <= salarygrade.hisalary emp.salary BETWEEN salarygrade.losalary and salarygrade.hisalary */ SELECT t1.ename , t1.`salary`, t2.* FROM emp t1, salarygrade t2 WHERE t1.`salary` BETWEEN t2.`losalary` AND t2.`hisalary`; -- 4.查詢員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置,工資等級 /* 分析: 1. 員工姓名,工資 emp , 職務名稱,職務描述 job 部門名稱,部門位置,dept 工資等級 salarygrade 2. 條件: emp.job_id = job.id and emp.dept_id = dept.id and emp.salary BETWEEN salarygrade.losalary and salarygrade.hisalary */ SELECT t1.`ename`, t1.`salary`, t2.`jname`, t2.`description`, t3.`dname`, t3.`loc`, t4.`grade` FROM emp t1,job t2,dept t3,salarygrade t4 WHERE t1.`job_id` = t2.`id` AND t1.`dept_id` = t3.`id` AND t1.`salary` BETWEEN t4.`losalary` AND t4.`hisalary`; -- 5.查詢出部門編號、部門名稱、部門位置、部門人數 /* 分析: 1.部門編號、部門名稱、部門位置 dept 表。 部門人數 emp表 2.使用分組查詢。按照emp.dept_id完成分組,查詢count(id) 3.使用子查詢將第2步的查詢結果和dept表進行關聯查詢 */ SELECT t1.`id`,t1.`dname`,t1.`loc` , t2.total FROM dept t1, (SELECT dept_id,COUNT(id) total FROM emp GROUP BY dept_id) t2 WHERE t1.`id` = t2.dept_id; -- 6.查詢全部員工的姓名及其直接上級的姓名,沒有領導的員工也須要查詢 /* 分析: 1.姓名 emp, 直接上級的姓名 emp * emp表的id 和 mgr 是自關聯 2.條件 emp.id = emp.mgr 3.查詢左表的全部數據,和 交集數據 * 使用左外鏈接查詢 */ /* select t1.ename, t1.mgr, t2.`id`, t2.ename from emp t1, emp t2 where t1.mgr = t2.`id`; */ SELECT t1.ename, t1.mgr, t2.`id`, t2.`ename` FROM emp t1 LEFT JOIN emp t2 ON t1.`mgr` = t2.`id`;
1. 事務的基本介紹 1. 概念: * 若是一個包含多個步驟的業務操做,被事務管理,那麼這些操做要麼同時成功,要麼同時失敗。 2. 操做: 1. 開啓事務: start transaction; 2. 提交:commit; 3. 回滾:rollback; 3. 例子: CREATE TABLE account ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), balance DOUBLE ); -- 添加數據 INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000); SELECT * FROM account; UPDATE account SET balance = 1000; -- 張三給李四轉帳 500 元 -- 0. 開啓事務 START TRANSACTION; -- 1. 張三帳戶 -500 UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan'; -- 2. 李四帳戶 +500 -- 出錯了... UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi'; -- 發現執行沒有問題,提交事務 COMMIT; -- 發現出問題了,回滾事務 ROLLBACK; 4. MySQL數據庫中事務默認自動提交 * 事務提交的兩種方式: * 自動提交: * mysql就是自動提交的 * 一條DML(增刪改)語句會自動提交一次事務。 * 手動提交: * Oracle 數據庫默認是手動提交事務 * 須要先開啓事務,再提交 * 修改事務的默認提交方式: * 查看事務的默認提交方式:SELECT @@autocommit; -- 1 表明自動提交 0 表明手動提交 * 修改默認提交方式: set @@autocommit = 0; 2. 事務的四大特徵: 1. 原子性:是不可分割的最小操做單位,要麼同時成功,要麼同時失敗。 2. 持久性:當事務提交或回滾後,數據庫會持久化的保存數據。 3. 隔離性:多個事務之間。相互獨立。 4. 一致性:事務操做先後,數據總量不變 3. 事務的隔離級別(瞭解) * 概念:多個事務之間隔離的,相互獨立的。可是若是多個事務操做同一批數據,則會引起一些問題,設置不一樣的隔離級別就能夠解決這些問題。 * 存在問題: 1. 髒讀:一個事務,讀取到另外一個事務中沒有提交的數據 2. 不可重複讀(虛讀):在同一個事務中,兩次讀取到的數據不同。 3. 幻讀:一個事務操做(DML)數據表中全部記錄,另外一個事務添加了一條數據,則第一個事務查詢不到本身的修改。 * 隔離級別: 1. read uncommitted:讀未提交 * 產生的問題:髒讀、不可重複讀、幻讀 2. read committed:讀已提交 (Oracle) * 產生的問題:不可重複讀、幻讀 3. repeatable read:可重複讀 (MySQL默認) * 產生的問題:幻讀 4. serializable:串行化 * 能夠解決全部的問題 * 注意:隔離級別從小到大安全性愈來愈高,可是效率愈來愈低 * 數據庫查詢隔離級別: * select @@tx_isolation; * 數據庫設置隔離級別: * set global transaction isolation level 級別字符串; * 演示: set global transaction isolation level read uncommitted; start transaction; -- 轉帳操做 update account set balance = balance - 500 where id = 1; update account set balance = balance + 500 where id = 2;
* SQL分類: 1. DDL:操做數據庫和表 2. DML:增刪改表中數據 3. DQL:查詢表中數據 4. DCL:管理用戶,受權 * DBA:數據庫管理員 * DCL:管理用戶,受權 1. 管理用戶 1. 添加用戶: * 語法:CREATE USER '用戶名'@'主機名' IDENTIFIED BY '密碼'; 2. 刪除用戶: * 語法:DROP USER '用戶名'@'主機名'; 3. 修改用戶密碼: UPDATE USER SET PASSWORD = PASSWORD('新密碼') WHERE USER = '用戶名'; UPDATE USER SET PASSWORD = PASSWORD('abc') WHERE USER = 'lisi'; SET PASSWORD FOR '用戶名'@'主機名' = PASSWORD('新密碼'); SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123'); * mysql中忘記了root用戶的密碼? 1. cmd -- > net stop mysql 中止mysql服務 * 須要管理員運行該cmd 2. 使用無驗證方式啓動mysql服務: mysqld --skip-grant-tables 3. 打開新的cmd窗口,直接輸入mysql命令,敲回車。就能夠登陸成功 4. use mysql; 5. update user set password = password('你的新密碼') where user = 'root'; 6. 關閉兩個窗口 7. 打開任務管理器,手動結束mysqld.exe 的進程 8. 啓動mysql服務 9. 使用新密碼登陸。 4. 查詢用戶: -- 1. 切換到mysql數據庫 USE myql; -- 2. 查詢user表 SELECT * FROM USER; * 通配符: % 表示能夠在任意主機使用用戶登陸數據庫 2. 權限管理: 1. 查詢權限: -- 查詢權限 SHOW GRANTS FOR '用戶名'@'主機名'; SHOW GRANTS FOR 'lisi'@'%'; 2. 授予權限: -- 授予權限 grant 權限列表 on 數據庫名.表名 to '用戶名'@'主機名'; -- 給張三用戶授予全部權限,在任意數據庫任意表上 GRANT ALL ON *.* TO 'zhangsan'@'localhost'; 3. 撤銷權限: -- 撤銷權限: revoke 權限列表 on 數據庫名.表名 from '用戶名'@'主機名'; REVOKE UPDATE ON db3.`account` FROM 'lisi'@'%';
1. 概念:Java DataBase Connectivity Java 數據庫鏈接, Java語言操做數據庫 * JDBC本質:實際上是官方(sun公司)定義的一套操做全部關係型數據庫的規則,即接口。各個數據庫廠商去實現這套接口,提供數據庫驅動jar包。咱們可使用這套接口(JDBC)編程,真正執行的代碼是驅動jar包中的實現類。 2. 快速入門: * 步驟: 1. 導入驅動jar包 mysql-connector-java-5.1.37-bin.jar 1.複製mysql-connector-java-5.1.37-bin.jar到項目的libs目錄下 2.右鍵-->Add As Library 2. 註冊驅動 3. 獲取數據庫鏈接對象 Connection 4. 定義sql 5. 獲取執行sql語句的對象 Statement 6. 執行sql,接受返回結果 7. 處理結果 8. 釋放資源 * 代碼實現: //1. 導入驅動jar包 //2.註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //3.獲取數據庫鏈接對象 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root"); //4.定義sql語句 String sql = "update account set balance = 500 where id = 1"; //5.獲取執行sql的對象 Statement Statement stmt = conn.createStatement(); //6.執行sql int count = stmt.executeUpdate(sql); //7.處理結果 System.out.println(count); //8.釋放資源 stmt.close(); conn.close(); 3. 詳解各個對象: 1. DriverManager:驅動管理對象 * 功能: 1. 註冊驅動:告訴程序該使用哪個數據庫驅動jar static void registerDriver(Driver driver) :註冊與給定的驅動程序 DriverManager 。 寫代碼使用: Class.forName("com.mysql.jdbc.Driver"); 經過查看源碼發現:在com.mysql.jdbc.Driver類中存在靜態代碼塊 static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } 注意:mysql5以後的驅動jar包能夠省略註冊驅動的步驟。 2. 獲取數據庫鏈接: * 方法:static Connection getConnection(String url, String user, String password) * 參數: * url:指定鏈接的路徑 * 語法:jdbc:mysql://ip地址(域名):端口號/數據庫名稱 * 例子:jdbc:mysql://localhost:3306/db3 * 細節:若是鏈接的是本機mysql服務器,而且mysql服務默認端口是3306,則url能夠簡寫爲:jdbc:mysql:///數據庫名稱 * user:用戶名 * password:密碼 2. Connection:數據庫鏈接對象 1. 功能: 1. 獲取執行sql 的對象 * Statement createStatement() * PreparedStatement prepareStatement(String sql) 2. 管理事務: * 開啓事務:setAutoCommit(boolean autoCommit) :調用該方法設置參數爲false,即開啓事務 * 提交事務:commit() * 回滾事務:rollback() 3. Statement:執行sql的對象 1. 執行sql 1. boolean execute(String sql) :能夠執行任意的sql 瞭解 2. int executeUpdate(String sql) :執行DML(insert、update、delete)語句、DDL(create,alter、drop)語句 * 返回值:影響的行數,能夠經過這個影響的行數判斷DML語句是否執行成功 返回值>0的則執行成功,反之,則失敗。 3. ResultSet executeQuery(String sql) :執行DQL(select)語句 2. 練習: 1. account表 添加一條記錄 2. account表 修改記錄 3. account表 刪除一條記錄 代碼: Statement stmt = null; Connection conn = null; try { //1. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2. 定義sql String sql = "insert into account values(null,'王五',3000)"; //3.獲取Connection對象 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //4.獲取執行sql的對象 Statement stmt = conn.createStatement(); //5.執行sql int count = stmt.executeUpdate(sql);//影響的行數 //6.處理結果 System.out.println(count); if(count > 0){ System.out.println("添加成功!"); }else{ System.out.println("添加失敗!"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { //stmt.close(); //7. 釋放資源 //避免空指針異常 if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } 4. ResultSet:結果集對象,封裝查詢結果 * boolean next(): 遊標向下移動一行,判斷當前行是不是最後一行末尾(是否有數據),若是是,則返回false,若是不是則返回true * getXxx(參數):獲取數據 * Xxx:表明數據類型 如: int getInt() , String getString() * 參數: 1. int:表明列的編號,從1開始 如: getString(1) 2. String:表明列名稱。 如: getDouble("balance") * 注意: * 使用步驟: 1. 遊標向下移動一行 2. 判斷是否有數據 3. 獲取數據 //循環判斷遊標是不是最後一行末尾。 while(rs.next()){ //獲取數據 //6.2 獲取數據 int id = rs.getInt(1); String name = rs.getString("name"); double balance = rs.getDouble(3); System.out.println(id + "---" + name + "---" + balance); } * 練習: * 定義一個方法,查詢emp表的數據將其封裝爲對象,而後裝載集合,返回。 1. 定義Emp類 2. 定義方法 public List<Emp> findAll(){} 3. 實現方法 select * from emp; 5. PreparedStatement:執行sql的對象 1. SQL注入問題:在拼接sql時,有一些sql的特殊關鍵字參與字符串的拼接。會形成安全性問題 1. 輸入用戶隨便,輸入密碼:a' or 'a' = 'a 2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a' 2. 解決sql注入問題:使用PreparedStatement對象來解決 3. 預編譯的SQL:參數使用?做爲佔位符 4. 步驟: 1. 導入驅動jar包 mysql-connector-java-5.1.37-bin.jar 2. 註冊驅動 3. 獲取數據庫鏈接對象 Connection 4. 定義sql * 注意:sql的參數使用?做爲佔位符。 如:select * from user where username = ? and password = ?; 5. 獲取執行sql語句的對象 PreparedStatement Connection.prepareStatement(String sql) 6. 給?賦值: * 方法: setXxx(參數1,參數2) * 參數1:?的位置編號 從1 開始 * 參數2:?的值 7. 執行sql,接受返回結果,不須要傳遞sql語句 8. 處理結果 9. 釋放資源 5. 注意:後期都會使用PreparedStatement來完成增刪改查的全部操做 1. 能夠防止SQL注入 2. 效率更高
* 目的:簡化書寫 * 分析: 1. 註冊驅動也抽取 2. 抽取一個方法獲取鏈接對象 * 需求:不想傳遞參數(麻煩),還得保證工具類的通用性。 * 解決:配置文件 jdbc.properties url= user= password= 3. 抽取一個方法釋放資源 * 代碼實現: public class JDBCUtils { private static String url; private static String user; private static String password; private static String driver; /** * 文件的讀取,只須要讀取一次便可拿到這些值。使用靜態代碼塊 */ static{ //讀取資源文件,獲取值。 try { //1. 建立Properties集合類。 Properties pro = new Properties(); //獲取src路徑下的文件的方式--->ClassLoader 類加載器 ClassLoader classLoader = JDBCUtils.class.getClassLoader(); URL res = classLoader.getResource("jdbc.properties"); String path = res.getPath(); System.out.println(path);///D:/IdeaProjects/itcast/out/production/day04_jdbc/jdbc.properties //2. 加載文件 // pro.load(new FileReader("D:\\IdeaProjects\\itcast\\day04_jdbc\\src\\jdbc.properties")); pro.load(new FileReader(path)); //3. 獲取數據,賦值 url = pro.getProperty("url"); user = pro.getProperty("user"); password = pro.getProperty("password"); driver = pro.getProperty("driver"); //4. 註冊驅動 Class.forName(driver); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 獲取鏈接 * @return 鏈接對象 */ public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } /** * 釋放資源 * @param stmt * @param conn */ public static void close(Statement stmt,Connection conn){ if( stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if( conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 釋放資源 * @param stmt * @param conn */ public static void close(ResultSet rs,Statement stmt, Connection conn){ if( rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if( stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if( conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } * 練習: * 需求: 1. 經過鍵盤錄入用戶名和密碼 2. 判斷用戶是否登陸成功 * select * from user where username = "" and password = ""; * 若是這個sql有查詢結果,則成功,反之,則失敗 * 步驟: 1. 建立數據庫表 user CREATE TABLE USER( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32), PASSWORD VARCHAR(32) ); INSERT INTO USER VALUES(NULL,'zhangsan','123'); INSERT INTO USER VALUES(NULL,'lisi','234'); 2. 代碼實現: public class JDBCDemo9 { public static void main(String[] args) { //1.鍵盤錄入,接受用戶名和密碼 Scanner sc = new Scanner(System.in); System.out.println("請輸入用戶名:"); String username = sc.nextLine(); System.out.println("請輸入密碼:"); String password = sc.nextLine(); //2.調用方法 boolean flag = new JDBCDemo9().login(username, password); //3.判斷結果,輸出不一樣語句 if(flag){ //登陸成功 System.out.println("登陸成功!"); }else{ System.out.println("用戶名或密碼錯誤!"); } } /** * 登陸方法 */ public boolean login(String username ,String password){ if(username == null || password == null){ return false; } //鏈接數據庫判斷是否登陸成功 Connection conn = null; Statement stmt = null; ResultSet rs = null; //1.獲取鏈接 try { conn = JDBCUtils.getConnection(); //2.定義sql String sql = "select * from user where username = '"+username+"' and password = '"+password+"' "; //3.獲取執行sql的對象 stmt = conn.createStatement(); //4.執行查詢 rs = stmt.executeQuery(sql); //5.判斷 /* if(rs.next()){//若是有下一行,則返回true return true; }else{ return false; }*/ return rs.next();//若是有下一行,則返回true } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(rs,stmt,conn); } return false; } }
1. 事務:一個包含多個步驟的業務操做。若是這個業務操做被事務管理,則這多個步驟要麼同時成功,要麼同時失敗。 2. 操做: 1. 開啓事務 2. 提交事務 3. 回滾事務 3. 使用Connection對象來管理事務 * 開啓事務:setAutoCommit(boolean autoCommit) :調用該方法設置參數爲false,即開啓事務 * 在執行sql以前開啓事務 * 提交事務:commit() * 當全部sql都執行完提交事務 * 回滾事務:rollback() * 在catch中回滾事務 4. 代碼: public class JDBCDemo10 { public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt1 = null; PreparedStatement pstmt2 = null; try { //1.獲取鏈接 conn = JDBCUtils.getConnection(); //開啓事務 conn.setAutoCommit(false); //2.定義sql //2.1 張三 - 500 String sql1 = "update account set balance = balance - ? where id = ?"; //2.2 李四 + 500 String sql2 = "update account set balance = balance + ? where id = ?"; //3.獲取執行sql對象 pstmt1 = conn.prepareStatement(sql1); pstmt2 = conn.prepareStatement(sql2); //4. 設置參數 pstmt1.setDouble(1,500); pstmt1.setInt(2,1); pstmt2.setDouble(1,500); pstmt2.setInt(2,2); //5.執行sql pstmt1.executeUpdate(); // 手動製造異常 int i = 3/0; pstmt2.executeUpdate(); //提交事務 conn.commit(); } catch (Exception e) { //事務回滾 try { if(conn != null) { conn.rollback(); } } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { JDBCUtils.close(pstmt1,conn); JDBCUtils.close(pstmt2,null); } } }
1. 概念:其實就是一個容器(集合),存放數據庫鏈接的容器。 當系統初始化好後,容器被建立,容器中會申請一些鏈接對象,當用戶來訪問數據庫時,從容器中獲取鏈接對象,用戶訪問完以後,會將鏈接對象歸還給容器。 2. 好處: 1. 節約資源 2. 用戶訪問高效 3. 實現: 1. 標準接口:DataSource javax.sql包下的 1. 方法: * 獲取鏈接:getConnection() * 歸還鏈接:Connection.close()。若是鏈接對象Connection是從鏈接池中獲取的,那麼調用Connection.close()方法,則不會再關閉鏈接了。而是歸還鏈接 2. 通常咱們不去實現它,有數據庫廠商來實現 1. C3P0:數據庫鏈接池技術 2. Druid:數據庫鏈接池實現技術,由阿里巴巴提供的 4. C3P0:數據庫鏈接池技術 * 步驟: 1. 導入jar包 (兩個) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar , * 不要忘記導入數據庫驅動jar包 2. 定義配置文件: * 名稱: c3p0.properties 或者 c3p0-config.xml * 路徑:直接將文件放在src目錄下便可。 3. 建立核心對象 數據庫鏈接池對象 ComboPooledDataSource 4. 獲取鏈接: getConnection * 代碼: //1.建立數據庫鏈接池對象 DataSource ds = new ComboPooledDataSource(); //2. 獲取鏈接對象 Connection conn = ds.getConnection(); 5. Druid:數據庫鏈接池實現技術,由阿里巴巴提供的 1. 步驟: 1. 導入jar包 druid-1.0.9.jar 2. 定義配置文件: * 是properties形式的 * 能夠叫任意名稱,能夠放在任意目錄下 3. 加載配置文件。Properties 4. 獲取數據庫鏈接池對象:經過工廠來來獲取 DruidDataSourceFactory 5. 獲取鏈接:getConnection * 代碼: //3.加載配置文件 Properties pro = new Properties(); InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(is); //4.獲取鏈接池對象 DataSource ds = DruidDataSourceFactory.createDataSource(pro); //5.獲取鏈接 Connection conn = ds.getConnection(); 2. 定義工具類 1. 定義一個類 JDBCUtils 2. 提供靜態代碼塊加載配置文件,初始化鏈接池對象 3. 提供方法 1. 獲取鏈接方法:經過數據庫鏈接池獲取鏈接 2. 釋放資源 3. 獲取鏈接池的方法 * 代碼: public class JDBCUtils { //1.定義成員變量 DataSource private static DataSource ds ; static{ try { //1.加載配置文件 Properties pro = new Properties(); pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")); //2.獲取DataSource ds = DruidDataSourceFactory.createDataSource(pro); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 獲取鏈接 */ public static Connection getConnection() throws SQLException { return ds.getConnection(); } /** * 釋放資源 */ public static void close(Statement stmt,Connection conn){ /* if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close();//歸還鏈接 } catch (SQLException e) { e.printStackTrace(); } }*/ close(null,stmt,conn); } public static void close(ResultSet rs , Statement stmt, Connection conn){ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close();//歸還鏈接 } catch (SQLException e) { e.printStackTrace(); } } } /** * 獲取鏈接池方法 */ public static DataSource getDataSource(){ return ds; } }
* Spring框架對JDBC的簡單封裝。提供了一個JDBCTemplate對象簡化JDBC的開發 * 步驟: 1. 導入jar包 2. 建立JdbcTemplate對象。依賴於數據源DataSource * JdbcTemplate template = new JdbcTemplate(ds); 3. 調用JdbcTemplate的方法來完成CRUD的操做 * update():執行DML語句。增、刪、改語句 * queryForMap():查詢結果將結果集封裝爲map集合,將列名做爲key,將值做爲value 將這條記錄封裝爲一個map集合 * 注意:這個方法查詢的結果集長度只能是1 * queryForList():查詢結果將結果集封裝爲list集合 * 注意:將每一條記錄封裝爲一個Map集合,再將Map集合裝載到List集合中 * query():查詢結果,將結果封裝爲JavaBean對象 * query的參數:RowMapper * 通常咱們使用BeanPropertyRowMapper實現類。能夠完成數據到JavaBean的自動封裝 * new BeanPropertyRowMapper<類型>(類型.class) * queryForObject:查詢結果,將結果封裝爲對象 * 通常用於聚合函數的查詢 4. 練習: * 需求: 1. 修改1號數據的 salary 爲 10000 2. 添加一條記錄 3. 刪除剛纔添加的記錄 4. 查詢id爲1的記錄,將其封裝爲Map集合 5. 查詢全部記錄,將其封裝爲List 6. 查詢全部記錄,將其封裝爲Emp對象的List集合 7. 查詢總記錄數 * 代碼: import cn.itcast.domain.Emp; import cn.itcast.utils.JDBCUtils; import org.junit.Test; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import java.util.Map; public class JdbcTemplateDemo2 { //Junit單元測試,可讓方法獨立執行 //1. 獲取JDBCTemplate對象 private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); /** * 1. 修改1號數據的 salary 爲 10000 */ @Test public void test1(){ //2. 定義sql String sql = "update emp set salary = 10000 where id = 1001"; //3. 執行sql int count = template.update(sql); System.out.println(count); } /** * 2. 添加一條記錄 */ @Test public void test2(){ String sql = "insert into emp(id,ename,dept_id) values(?,?,?)"; int count = template.update(sql, 1015, "郭靖", 10); System.out.println(count); } /** * 3.刪除剛纔添加的記錄 */ @Test public void test3(){ String sql = "delete from emp where id = ?"; int count = template.update(sql, 1015); System.out.println(count); } /** * 4.查詢id爲1001的記錄,將其封裝爲Map集合 * 注意:這個方法查詢的結果集長度只能是1 */ @Test public void test4(){ String sql = "select * from emp where id = ? or id = ?"; Map<String, Object> map = template.queryForMap(sql, 1001,1002); System.out.println(map); //{id=1001, ename=孫悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20} } /** * 5. 查詢全部記錄,將其封裝爲List */ @Test public void test5(){ String sql = "select * from emp"; List<Map<String, Object>> list = template.queryForList(sql); for (Map<String, Object> stringObjectMap : list) { System.out.println(stringObjectMap); } } /** * 6. 查詢全部記錄,將其封裝爲Emp對象的List集合 */ @Test public void test6(){ String sql = "select * from emp"; List<Emp> list = template.query(sql, new RowMapper<Emp>() { @Override public Emp mapRow(ResultSet rs, int i) throws SQLException { Emp emp = new Emp(); int id = rs.getInt("id"); String ename = rs.getString("ename"); int job_id = rs.getInt("job_id"); int mgr = rs.getInt("mgr"); Date joindate = rs.getDate("joindate"); double salary = rs.getDouble("salary"); double bonus = rs.getDouble("bonus"); int dept_id = rs.getInt("dept_id"); emp.setId(id); emp.setEname(ename); emp.setJob_id(job_id); emp.setMgr(mgr); emp.setJoindate(joindate); emp.setSalary(salary); emp.setBonus(bonus); emp.setDept_id(dept_id); return emp; } }); for (Emp emp : list) { System.out.println(emp); } } /** * 6. 查詢全部記錄,將其封裝爲Emp對象的List集合 */ @Test public void test6_2(){ String sql = "select * from emp"; List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class)); for (Emp emp : list) { System.out.println(emp); } } /** * 7. 查詢總記錄數 */ @Test public void test7(){ String sql = "select count(id) from emp"; Long total = template.queryForObject(sql, Long.class); System.out.println(total); } }