【乾貨】長達4萬字的Java知識點!

最近在學習Redis的時候,突然發現以前學的集合等內容都忘了,所以乾脆花了兩天時間把大一學習JAVA的知識差不多複習了一遍,並且寫下了這篇博客,本文寫的東西基本都是學習中或者個人理解的重點,因爲寫的時間比較短,所以可能有一些地方略微粗糙或者是某些知識點一筆帶過,希望大家見諒!也希望能夠幫助到大家!

本文長度在4W字左右,以下爲目錄:


1-Java的基礎信息瞭解

三大平臺:

  • Java SE-Java Platform Standard Edition
    學習及開發Java其他平臺的應用,必須先了解Java SE以奠定基礎
    Java SE包括:JVM(虛擬機)、JRE(Java運行時環境)、JDK(Java開發工具包)和Java語言
  • Java EE-Java Platform Enterprise Edition
    以Java SE爲基礎,定義了一系列的服務、API、協議等
    適用於開發分佈式、以WEB爲基礎的應用程序
  • Java ME-Java Platform Micor Edition
    主要用於開發消費性電子產品或嵌入式系統中的應用程序

Java SE分爲四個組成部分

  1. JVM:Java Virtual Machine
    將Java編譯好的文件翻譯成對應的機器語言
  2. JRE:Java SE Runtime Environment
    包含用於Java的運行環境
  3. JDK:Java Development kits
    包含用於Java開發的工具
  4. Java語言:定義Java開發的語法規則
  • 掌握Java開發工具JDK配置

  • 掌握利用DOS代碼進行編輯、編譯、運行Java程序

  • 常用的開發工具的選擇
    ·記事本/Notepad++/editplus/ultraedit
    ·Eclipse/MyEclipse(MY比前者功能豐富)(選擇)
    ·JCreator
    ·Netbeans
    ·IntelliJ IDEA

  • 瞭解安裝目錄:
    -bin目錄:存放可執行文件
    -lib目錄:存放Java的類庫文件
    -include目錄:存放用於本地方法的文件
    -demo目錄:存放演示程序
    -jre目錄:存放Java運行環境文件

有關main中的String[] args的理解:
String[]表示定義一個字符串數組變量,變量名爲args.
println中爲Hello World,即爲傳入main中的字符串變量.
如果將println中的字符串改爲args[0],則表示輸出args字符串數組中的第一個字符串.
這時在cmd命令行中不可以直接用java HelloWorld在執行java程序.
因爲這時沒有傳入任何字符串數組,故要執行還要在其後加上字符串,則輸出結果就爲該字符串.

Java特性

  1. Java平臺無關性:Java是一種既面向對象又可跨平臺的語言
    Java源程序代碼->編譯->Java字節碼文件(可跨平臺)->運行->Java虛擬機
    Java虛擬機面向:Windows系統、Linux系統、Solaris系統
  2. 開發Java程序小結
    1、創建Java源程序:擴展名爲.java,可以用任何文本編輯器創建與編輯;
    2、編譯源程序:使用"javac"命令,讀取書寫好的Java源程序並翻譯成Java虛擬機能夠明白的指令集合,
    且以字節碼的形式保存在文件中.通常,字節碼文件以.class作爲擴展名;
    3、運行class文件:Java解釋器讀取字節碼,取出指令並且翻譯成計算機能執行的代碼,完成運行過程;

2-Java的變量知識

數據類型 類型說明符 位數
整形 int 32
短整型 short 16
長整形 long 64
字節型 byte 8
單精浮點 float 32
雙精浮點 double 64
布爾類型 boolean 8
字符類型 char 16
字符串型 String -

注意:對精確的超大型數值計算比如天文數據(一般指64位以上的數據運算),一般不會採用基本數據類型,而採用BigInteger或BigDecimal類型的數據進行精確計算

掌握變量命令規則
掌握變量的聲明和初始化
注意:當聲明一個float類型並初始化的時候,會默認該變量爲double型,故要在數據後加f
注意:常量的定義:final + 類型名稱 + 變量名 = 數據; //只有賦初值,後面無法更改

常見錯誤:
1、未聲明、未初始化的變量和未使用的變量
2、賦值時數值溢出
要參考類型的最大值和最小值,具體操作如:syso(Integer.MAX_VALUE);-syso(Integer.MIN_VALUE);
3、取整錯誤
比如:1.0-0.9=0.99999999…
4、冗餘(重複、複雜、囉嗦)的輸入對象

格式化輸出內容:

Row1 Row2 Row3
%d-10進制輸出整數 %f-10進制輸出小數 %e、%E科學計數法輸出小數
%o-8進制輸出整數 %x、%X-16進制輸出整數 %s、%S-字符串方式輸出
%c、%C-字符符號輸出 %n-按照特定操作系統輸出換行符 -------------

字符串的定義以及比較

定義字符串變量時最好給初值:String a=null; //字符串指向空 或 String b=""; //字符串爲空字符
字符串比較時,不可以直接用"=="來進行比較,最好用"常量".equals(變量);
Java中的字符串不允許if(password == "123456")這樣的判斷
標準的寫法:if(password.equals("123456"))
更加專業的寫法:if("123456".equals(password))	//這兩種否定情況都是在前面加'!'
延申另一種寫法:if("123456".equalsIgnoreCase(password))	//忽略大小寫的比較

接收用戶輸入Scanner用法:

import java.util.Scanner;	//輸入Scnner後自動出現的導入工具包
Scanner input = new Scanner(System.in);		//掃描對象,用來掃描系統的輸入'System.in'
總的來說輸入就是:
Scanner 類型名 = new Scanner(System.in);
注意:良好的習慣就是在最後加一個input.close();
----------------------------------------------------------------------------------
類型 變量名 = 類型名.對應的"next"
對應的"next":如果類型爲int,則爲nextInt;爲double,則爲nextDouble;爲String,則爲next;
難點:錄入char類型
char 變量名 = input.next().charAt(0);		//"."可以理解爲"的"
----------------------------------------------------------------------------------
關於Scanner input = new Scanner(System.in);的理解↓
其實這相當於兩句話:
第一句話是Scanner input;作用是先聲明一個變量,變量的名字爲input
第二句話是input = new Scanner(System.in);作用是將新創建的空間的地址賦值給左邊的變量
匿名的方式調用Scanner: 變量 = new Scanner(System.in).nextINt();

強制類型轉換
類型轉換:1、自動類型轉換 2、強制類型轉換

1、示例:long number = 2147483647l;		//整型數字後加l則自動轉換爲long型
示例:int num = 90; double num1 = num;	 //將num自動轉換爲double賦值給num1,*小轉大*
2、當double轉爲int時則不可以用自動轉換,要用強制類型轉換
示例:double num = 90.0;	 int num1 = (int)num;	 //強制轉換
注意:double num = 5/2;時,結果還是2.0,因爲右邊爲整形,如果要爲2.5則右邊要爲5/2d或5/2.0
滿足自動類型轉換的條件:
1、兩種類型要兼容(數值類型)
2、目標類型大於源類型	short -> int -> long -> float -> double

字符串常用方法:

 方法								說明
length()				獲取字符串中的字符個數(不包括'\0')
chatAt(index)			返回字符串中指定下標的字符
concat(str)				拼接字符串,返回一個新字符串對象
toUpperCase()			返回一個新字符串,所有字母大寫
toLowerCase()			返回一個新字符串,所有字母小寫
trim()					返回一個新字符串,去掉了兩邊空格
char[] toCharArray()	將此字符串轉換爲一個新的字符數組
conpareTo(str)			作比較:大於返回>0;等於返回0;小於返回<0

一定要掌握的方法:
indexOf(ch)				返回字符串中出現的第一個字符ch的下標,沒有匹配返回-1
indexOf(ch,2)			//這裏2相當於從第幾個下標開始計算
indexOf(s)				返回字符串中出現的第一個字符串s的下標,無匹配返回-1
substring(begin)		返回該字符串的子字符串,從begin下標到字符串的結尾
substring(begin,end)	返回該字符串的子字符串,從begin下標到end-1下標之間

3-成員變量與局部變量

public class Hero{
	整型類型1 變量1;					
	整型類型2 變量2;					成員變量
	整型類型3 變量3;
	
	public 返回值類型 方法1(){
		數據類型4 變量4;				局部變量
	}
	public 返回值類型 方法2(){}
}

注意:

  1. 成員變量的作用域在整個類都是可見的,方法1和方法2都可以使用變量1、2、3
  2. 局部變量的作用域僅限於定義他的方法,變量4只能分別在方法1中使用
  3. 成員變量有默認的初始值,數字爲0、對象爲null
  4. 局部變量默認沒有初始值,需要賦初值再使用
  5. 成員變量和局部變量重名時,局部變量優先級更高

4-Java的運算符以及判斷語句

算術運算符:(幾元就是有幾個操作數)
一元運算符:++、–
二元運算符:+、-、*、/、%
三元運算符:?、:
一元運算符:難點:區別前置還是後置
int result1 = num1++; 等價於 int result1 = num1;num1++;
int result2 = ++num2; 等價於 ++num2;int result2 = num2;
二元運算符:%的難點,取模的時候,結果的正負由第一個操作數決定
三元運算符:int num = 5>2?39:93; 意思是,如果5>2那麼把39賦值給num;否則把93賦值給num

if-else 條件選擇結構 —— 掌握

if(條件1){
	//代碼塊1
	}else if(條件2){
	//代碼塊2
	}else if(條件3){
	//代碼塊3
	}
}

switch-case 結構 —— 掌握

switch(表達式){
	case 常量1:
		語句1;
		break;
	case 常量2:
		語句2;
		break;
	...
	default:
		語句;
}

注意:
1、switch後的表達式可以是整形、字符型、String型
2、case後常量表達式的值不能相同
3、case後允許多條語句,不需要大括號
4、如果不添加break語句,需要特別注意執行順序
5、case和default子句的先後順序可以自動變動
6、default可以省略


5-循環語句

1、理解循環結構的基本原理
2、使用while循環結構
3、使用do-while循環
4、會使用工具調試程序

循環三要素:
1、循環變量的初值 2、循環變量的判斷 3、循環變量的更新 特點:先判斷,後執行

while循環:

while(循環條件){
	//循環操作語句
	....
}

do-while循環:

do{
	循環操作
}while(循環條件);

do-while特點:先執行一邊循環操作,若符合條件,循環繼續執行;否則循環退出
while循環和do-while循環的區別:
1.執行順序不同
2.初識情況不滿足循環條件時:1、while循環一次都不會執行 2、do-while循環無條件執行一次

for與for-each循環:

for(循環變量的初值;循環變量的判斷;循環變量的更新){
	語句;
}

綜合案例(用到了窮舉法):
/*甲乙丙丁一共加工零件370個,如果把甲的個數加10,乙的個數-20,丙的個數乘2
丁的個數除以2,那麼四個人做的零件數量相等。問:四個人分別做了幾個?*/
for(int i=1;i<367;i++){//甲的數量
	for(int j=1;j<367;j++){//乙的數量
		for(int k=1;k<367;k++){//丙的數量
			//丁的數量
			int d = 370 - i - j - k;
			if(i+j+k+d==370&&i+10==j-20&&j-20==k*2&&k*2==d/2)
			System.out.printf("四人的數量分別爲:%-4d%-4d%-4d%-4d\n",i,j,k,d);
		}
	}
}

小議break語句
break語句的作用:跳出循環,執行循環之後的語句(跳出for,while,do-while,switch語句)


6-數組的使用

語法:datatype[] arrayName = new datatype[size];
例子:String[] names = new String[15];
錯誤例子:int[] nums = null; nums[0] = 9;
錯誤原因:這裏因爲把nums數組設爲了空,所以找不到空間賦值
錯誤例子:int years[6] = {1,2,3,5,6,8};
錯誤原因:聲明並初始化數組時不需要指定數組的大小

關於數組大小和默認值:
1、創建數組後就不能再修改數組的大小
2、基本數據類型數組的默認值爲0
3、char型數組元素的默認值爲\u0000
4、布爾類型數組的默認值爲false

除了數組的靜態賦值(聲明並賦值),我們還要掌握數組的動態賦值:

int[] nums = new int[10];
for (int i = 0; i < nums.length; i++) {
	nums[i] = (((int)(Math.random()*10)%10+1))*100;
}
System.out.println("數組元素:");
for (int i = 0; i < nums.length; i++) {
	System.out.print(nums[i]+" ");
}

//實際上與 for(int i=0;i<nums.length;i++)一樣,都是遍歷作用,這裏的i相當於nums[i]
for(int i:nums){
	System.out.print(i+" ");
}

這裏有個利用隨機數來賦值的操作,可能有夥伴看不懂,這裏順便說一下Math.random的使用
Java中生成隨機數字的三種方式(原理都一樣):

int start = 5; int end = 15;
//方案1:使用Math類提供的隨機方法生成start到end之間的數
int attack1 = ((int)(Math.random()*1000))%(end - start +1)+start;
//方案2:使用隨機類,生成start到end之間的數
Random rand = new Random();
int attack2 = rand.nextInt(end-start+1)+start;
//方案3:使用系統時間(1970-1-1到當前的毫秒數)生成start到end之間的數
int attack3 = (int)(System.currentTimeMillis()%(end-start+1)+start);
long 變量名 = System.currentTimeMillis();//1970-1-1到現在的毫秒數

數組元素的刪除和插入:
1、找到要刪除元素的下標(插入元素則相反)
2、從要刪除下標開始,後面元素賦值給前面元素(覆蓋)
3、數組總長度-1 (障眼法:實際上數組總大小沒變,只是輸出的時候長度減一)
主要代碼:

for(int i=index;i<array.length-1;i++){
	array[i] = array[i+1];
}
for (int i = 0; i < array.length -1; i++) {
	System.out.print(array[i]+" ");
}

7-重點:冒泡排序、選擇排序、快速排序

冒泡排序:

//1.一共會比較數組元素個數-1輪
//2.每一輪,比較的次數比上一輪少1
//3.如果前面一個數組大於/小於後面一個數字,那麼交換
final int N = 100;	//常量
int[] nums = new int[N];
for (int i = 0; i < nums.length; i++) {
	nums[i] = (int)(Math.random()*10000);
}
int temp;	//臨時變量
for (int i = 0; i < nums.length -1; i++) {
	for (int j = 0; j < nums.length - i -1; j++) {
		if(nums[j]<nums[j+1]){
			temp = nums[j];
			nums[j] = nums[j+1];
			nums[j+1] = temp;
		}
	}
}
System.out.println("排序後:");
for (int i = 0; i < nums.length; i++) {
	System.out.print(nums[i]+"\t");
	if((i+1)%10==0)System.out.println();
}System.out.println();

選擇排序:
選擇排序效率高於冒泡,因爲並沒有像冒泡一樣每一次都交換,而是一次性的比較後再交換

final int N = 100;	//常量
int[] nums = new int[N];
for (int i = 0; i < nums.length; i++) {
	nums[i] = (int)(Math.random()*10000);
}
int temp,maxindex,max;	//臨時變量
for (int i = 0; i < nums.length; i++) {
	max = nums[i];
	maxindex = i;
	for (int j = i+1; j < nums.length; j++) {
		if(max<nums[j]){
			max = nums[j];
			maxindex = j;
		}
	}
	temp = nums[i];
	nums[i] = nums[maxindex];
	nums[maxindex] = temp;
}
System.out.println("排序後:");
for (int i = 0; i < nums.length; i++) {
	System.out.print(nums[i]+"\t");
	if((i+1)%10==0)System.out.println();
}System.out.println();

快速排序:

利用Arrays.sort(數組名);直接進行快速排序,默認爲升序排序
如果要將快速排序後的數組逆序,則利用for循環來排序
for(i=0;i<nums.length/2;i++){		//nums.length/2是爲了避免後面再逆序一次
	int temp = nums[i];
	nums[i] = nums[nums.length - i - 1];
	nums[nums.length - i - 1] = temp;
}

二分查找法:
使用前提:數組已經按升序排序
基本原理:首先將要查找的元素(key)與數組的中間元素比較
1、如果key小於中間元素,只需要在數組的前一半中繼續查找(high的下標移到中間值的前一個)
2、如果key和中間元素相等,匹配成功,查找結束
3、如果key大於中間元素,只需要在數組的後一半元素中繼續查找key(low的下標移到中間值的後一個)
mid = (low+high)/2
代碼示例:

Scanner input = new Scanner(System.in);
int[] array={2,5,8,10,15,35,45,55,65,75,89};
System.out.print("請輸入要查找的數字:");
int searchNum = input.nextInt();
boolean isFind = false;					//是否找到
int low = 0,high = array.length - 1;	//下標
int index = 0;
//不知道要查找幾次
while(high>=low){
	if(searchNum>array[(low+high)/2]){
		low = (low+high)/2+1;
	}
	else if(searchNum<array[(low+high)/2]){
		high = (low+high)/2-1;
	}else{
		isFind = true;
		index = (low+high)/2;
		break;
	}
}
System.out.println(index);

8-方法、類、對象

方法有內置方法與自定義方法
內置方法主要由JDK類庫提供,需要導入相應的包
自定義方法可以通過自己的需要來寫
上面我們所說的Math.random函數就是內置方法的一種,這裏列出常用的數學函數

Math類提供了很多使用的方法,用來計算常用的數學函數
-----------------------------------------------------------------------------------------------
類別:三角函數方法
Math.PI/Math.E									圓周率的近似值/算術常量e的值(近似於2.71828)
Math.sin(radians"弧度")							返回角度的三角正弦函數值(以弧度爲單位)
Math.cos(radians)								返回角度的三角餘弦函數值
Math.tan(radians)								返回角度的三角正切函數值
Math.toRadians(degree)							將以度爲單位的值轉換爲弧度
Math.toDegrees(radians)							將以弧度爲單位的值轉換爲度
Math.asin(a)									返回角度的反三角正弦函數值
Math.acos(a)									返回角度的反三角餘弦函數值
Math.atan(a)									返回角度的反三角正切函數值
-----------------------------------------------------------------------------------------------
類別:指數函數方法
Math.exp(x)										返回算術常量E的x次方
Math.log(x)										返回x的自然底數--Math.log(Math.E)的值爲1.0
Math.log10(x)									返回x的以10爲底的對數
Math.pow(a,b)									返回a的b次方
Math.sqrt(x)									對於0以上的數字,返回x的平方根
-----------------------------------------------------------------------------------------------
類別:取整方法
Math.ceil(x)/Math.floor(x)						向上/下取整x最接近的整數
Math.rint(x)									取整爲x最接近的整數,距離相等則返回偶數整數
Math.round(x)									四捨五入取整--返回(int/long)Math.floor(x+0.5)
Math.min/max/Math.abs							返回兩個數的最小/大值|返回絕對值

是抽象的概念,僅僅是模板,比如說:“演員”、“總統”。
對象是一個你能夠看得到、摸得着得具體實體。
通過自定義類來創建一個對象,如我們現在要創建一個演員對象,那麼首先我們要自定義一個演員類:

public class Role {					//以後使用Role的時候就相當於使用一個類型名,類型爲Role
	// 名稱:勞拉
	// 等級:25
	// 職業:考古學家
	// 技能:雙槍
	/** 遊戲角色的名稱屬性 */
	public String name;
	/** 等級 */
	public int level;
	/** 職業 */
	public String job;
	public void show(){
		System.out.println(name+"\t"+level+"\t"+job);
	}
	//構造方法
	public Role(){}
	public Role(String name1,int level1,String job1){
		name = name1;
		level = level1;
		job = job1;
	}
	/* 釋放技能 */
	public void doSkill(){
		if(name.equals("勞拉")){
			System.out.println("看我雙槍!");
		}else if(name.equals("孫悟空")){
			System.out.println("吃俺老孫一棒!");
		}else{
			System.out.println(name+":發出了一記必殺技!");
		}
	}
}

//再創建一個main函數,代碼如下:
public class Roletest {
	public static void main(String[] args) {
		//實例化
		Role role1 = new Role();
		role1.name = "勞拉";
		role1.level = 25;
		role1.job = "摸金校尉";
		role1.doSkill();
		role1.show();
		
		Role role2 = new Role();
		role2.name = "至尊寶";
		role2.doSkill();
	}
}

關於構造方法
1、沒有返回值類型
2、名稱與類名一致
3、可以指定參數及實現重載
4、第二個構造方法Role()實際上就是重載,也就是說我們可以利用帶參的構造方法在創建對象的時候直接把屬性賦值了,如:Actor actor = new Actor("三上悠亞",99,檢察官);

自定義類的時候,我們可以使用封裝來保護對象的屬性,即在類中將要保護的屬性前把public改爲private,這樣當你在main函數中創建了對象之後,就不能夠直接調用對象.屬性來訪問這個對象,而只能通過Get或Set函數來訪問,這兩個函數可自行定義,這只是一種思想。

最熟悉的陌生人 —— String
String對象是不可變的,字符串一旦創建,內容不能再變
Java爲了效率:以""包括的字符串,只要內容、順序、大小寫相同,無論再程序代碼中出現幾次JVM都只會建立一個實例,並放在字符串池(String pool)中維護

案例1public static void main(String[] args){
	String song = "Yesterday Onece More";
	song = "Batter Man";
}
/*song是一個String變量,它其實存放的是String內容(對象)空間的地址,當第二次賦值的時候,
	它就指向了另一個內容(對象)空間,所以反過來想就是原來的字符串還在原來的空間位置,
		即它是固定存在的,所以它的內容不再改變。*/
案例2:
String name1 = "123";
String name2 = "123";
System.out.println(name1 == name2);

//這裏的結果是true,因爲"123"這個內容的空間地址是不變的,即兩個變量指向同一個對象。
案例3:
String value = "Hello";
value += "World";
String value2 = "HelloWorld";
syso(value == value2);

//這裏結果爲false,因爲value+="World";相當於調用了value.concat(),會返回一個新字符串對象空間

加強版字符串

  1. 使用字符串相加的時候,除了直接相加,使用StringBuffer和StringBuilder都可以大幅度提升效率
  2. StringBuffer效率爲普通相加的1000倍左右,而Builder又是Buffer的幾倍,但是Buffer更安全
  3. Buffer代碼如下(使用Builder的時候直接將Buffer替換即可):
    StringBuffer str = new StringBuffer("*");
    for(int i = 0;i<100;i++){
    	str.append("*");			//append相當於+=
    }
    
  4. StringBuffer/StringBuilder(可以看成類型)
    與String類不同的是,StringBuffer和StringBuilder類的對象能夠被多次的修改,並且不會產生新的未使用對象
    StringBuilder類在Java5中被提出,它和StringBuffer之間的最大不同在於StringBuilder的方法不是線程安全的(不能同步訪問,相當於一個字符串可以同時被多次修改,那麼可能修改會重疊)
  5. 構造方法																		說明
    StringBuffer()												構建一個默認緩存爲16的StringBuffer對象
    StringBuffer(int capacity)									構建一個指定緩存容量的StringBuffer對象
    StringBuffer(String str)									構建一個指定字符串值的StringBuffer對象
    修改StringBuffer中的字符串
    StringBuffer append(String str)									將指定的字符串追加到此字符序列
    StringBuffer reverse()											反轉字符序列
    StringBuffer void delete(int start,int end)						移除此字符序列中的字符
    StringBuffer void insert(int offset,String str)					將字符串str插入到字符序列中
    StringBuffer void replace(int start,int end,String)				使用給定的字符串str替換序列中的字符
    void setCharAt(int index,int char)								在指定索引位置設定字符
    int capacity()													返回StringBuffer當前的緩存容量
    void setLength(int newLength)									設置StringBuffer的新長度
    void trimToSize()												如果緩衝區大於其當前字符序列,那麼它可能會
    																調整大小,以便更加節省空間
    

9-繼承和多態

與現實世界類似,編程中也有繼承這個說法,利用extends關鍵字實現繼承,如:public class Warrior extends Hero{}

繼承的優點:

  1. 父類定義公共內容,方便統一修改
  2. 整體減少了代碼量
  3. 子類作爲擴展類很方便

注意:

  • 使用super關鍵字調用父類構造方法
  • 默認會調用父類構造,再調用子類構造,即先調用了父類構造的super();
  • 構造方法不可繼承
  • Java中只能繼承一個父類
  • 父類私有屬性在子類中不能直接訪問(父親的內褲不能穿)
  • 繼承關係 - 是一種"is-a"的關係:父類和子類之間必須存在is-a關係,空調is a電器
  • 子類比父類更加強大,是父類的加強版
提問:java中的子類和父類是不是一定要在同一個包中?
回答:肯定不用在一個包裏的,引用下就行了,一般放一個包裏是爲了容易理解.
	 以前老師說過,JAVA裏所有的類都是繼承自Object這個類的,也就是說它是所有類的父類,也就是說你
	 不繼承某個類的話就是默認繼承了Object類,所以不用在一個包裏!

重寫 - 繼承後很重要的技術
1、在子類中提供一個對方法的新的實現 - 重寫父親的賺錢方法,但是賺得更多
2、方法重寫具有同樣的方法簽名和返回值類型,只不過方法中的代碼可以不同
3、如果怕重寫的時候名稱出錯,可以alt+/,再打出父類中的方法即可
4、@override稱爲重寫標註,用來保證重寫的方法與原方法的簽名和返回值一致

多態 - 同一個實體,多種形式
當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;如果有,再去調用子類的同名方法。
多態的好處:可以使程序有良好的擴展,並可以對所有類的對象進行通用處理。

public class Test {
	public static void main(String[] args) {   
		Animal a = new Cat();  // 向上轉型  
		a.eat();               // 調用的是 Cat 的 eat
		Cat c = (Cat)a;        // 向下轉型  
		c.work();        // 調用的是 Cat 的 work
	}
}  
abstract class Animal {  
    abstract void eat();  
}  
  
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃魚");  
    }  
    public void work() {  
        System.out.println("抓老鼠");  
    }  
}  
輸出結果爲:
吃魚
抓老鼠
解釋:實際上是父類對象調用了父類方法,只不過父類方法被子類重寫了,
	所以不同子類對象在調用父類方法的時候實際上就是調用了對應子類中的方法

10-抽象類

final關鍵字:
 修飾成員變量:常量,不可更改
 修飾方法:不可被重寫
 修飾類:不可被繼承
作用:
 防止擴展和重寫

抽象類(abstract) - 概念類
主要用來描述該類或對象應該具備的基本特徵與功能,讓子類來實現
注意點:

  • 包含一個抽象方法的類必須是抽象類
  • 抽象類和抽象方法都是用abstract關鍵字聲明
  • 抽象方法只需要聲明而不需要實現
  • 抽象類必須被子類繼承
    子類不是抽象類時必須重寫父類中的所有抽象方法
    子類是抽象類時依然可以繼續聲明成抽象方法
  • 抽象類不可使用new實例化
  • 抽象方法必須是非靜態(Static)的
  • 抽象類除了不能用new進行實例化,其他都和普通的一樣
實例:
public abstract class ClassA(){
	void test();
}

這裏介紹一下日曆對象的使用:
Calendar和GregorianCalendar(java.util包)
GregorianCalendar是抽象類Calendar的一個具體實例
Calendar是一個抽象的基類,可以提取出詳細的日曆信息(年、月、日、時秒分等)
Calendar類的子類可以實現特定的日曆系統,如公曆(Gregorian歷)、農曆和猶太曆

常量			  說明				 		常量					說明
YEAR			日曆的年份				DAY_OF_WEEK			一週的天數(周幾),1是星期日
MONTH			日曆的月份,0表示1月		DAY_OF_MONTH		同DATE(幾號)
DATE			日曆的天(幾號)			DAY_OF_YEAR			當前年的天數,1是一年第一天
HOUR			小時(12小時制)			WEEK_OF_MONTH		當前月內的星期數,從1開始
HOUR_OF_DAY		小時(24小時制)			WEEK_OF_YEAR		當前年內的星期數,從1開始
MINUTTE			分鐘					AM_PM				0表示上午,1表示下午
SECOND			秒

日曆類用法示例:

Calendar cal1 = Calendar.getInstance();
//使用日曆打印當前的時間
int year = cal1.get(Calendar.YEAR);
int month = cal1.get(Calendar.MONTH)+1;
int day = cal1.get(Calendar.DATE);
System.out.println("當前時間:");
String strTime = String.format("%d-%d-%d", year,month,day);
System.out.println(strTime);

//實現兩個日期相減
GregorianCalendar cal2 = new GregorianCalendar(2017,8-1,19);
long diff = Math.abs(cal1.getTimeInMillis() - cal2.getTimeInMillis());
int diffdays = (int)(diff / 1000 / 60 / 60 / 24);
System.out.println("相差"+diffdays+"天");

//實現日期的增加
cal1.add(year, 3);

日曆類的用法還能夠更高級更方便,我總結出了所有的日曆類用法:

注意:
	獲得當前日期的方法有:
		1、先實例化一個Calendar對象,再聲明對應的時間單位賦值,如:
			int year = cal1.get(Calendar.YEAR);
		   再將每個變量組合成String型並打印
			String time = String.format("%d-%02d-%d", year,month+1,day);
		說明:因爲cal1.get();只能獲取每個單位的時間,如YEAR,所以不用Date變量保存,用int來保存
		2、聲明一個Date變量直接儲存日期,如:
			Calendar cal2 = Calendar.getInstance();
			Date date1 = cal2.getTime();
			System.out.println(date_Of_date1);
		說明:對於Calendar類型的getTime()可以直接獲取日期,所以直接用Date
		
	設置日期的方法有:
		1、先實例化一個Calendar對象,再用set函數設置時間,如:
			Calendar cal4 = GregorianCalendar.getInstance();
			cal4.set(2012, 5, 3);
			再用Date賦值並打印
			Date date = cal.getTime();
			System.out.println(date.toLocaleString());
		說明:該方法中的set函數可以有多個選項,可以單個設置比如單純設置YEAR也可以YEAR+MONTH等
		2、先聲明一個Date變量,最後將字符串轉換爲Date類型,如:
			Date newDate = format1.parse("2017-12-30 23:50:11:555");
			System.out.println(newDate.toLocaleString());
		說明:該方法就直接將右邊的字符串類型以對應格式賦值
		
	定義一個時間表示的格式的方法:
		1、先聲明一個表格變量(SimpleDateFormat),在將對印格式賦值,如:
			SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
			String strDate = format1.format(date);
			System.out.println(strDate);
		說明:這裏的格式化中的格式內容中,所有的字母必須爲對應時間單詞的字母開頭,第二三兩行則
			 進行了格式的操作
			 
	關於聲明Calendar變量和GregorianCalendar變量的難點:
		1、聲明Calendar變量時直接用Calendar cal = Calendar.getInstance();
		2、聲明GregorianCalendar變量時:
			·如果用GregorianCalendar cal = GregorianCalendar.getInstance();	 則會報錯
			·正確的聲明:
				*Calendar cal = GregorianCalendar.getInstance();
				*Calendar cal = new GregorianCalendar();
				*GregorianCalendar cal = new GregorianCalendar();
				
	關於打印date是的格式問題:
		1、打印date時如果不用date1.toString(),則會是用外國默認的英文格式
		2、打印date時如果用date1.toLocaleString(),則會以當地對應的格式打印
	
	補充:獲得一個月中的天數
	Calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

11-接口

使用接口(和繼承類似,加implements)
 接口是一種與類相似的結構,只包含常量和抽象方法 - 是一種更抽象的抽象類
 目的是指明相關或者不相關類的多個對象的共同行爲(功能)
使用接口的案例:
 可以指明對象是可比較的、可食用的、可被攻擊的、可飛翔的甚至是可克隆的。。。

定義接口:									注意:
//定義接口(可攻擊的)							1、在Java中,接口可被看作是一種特殊的類,與抽象
public interface Assaliable(){					類相似,不能使用new操作符直接創建接口的實例	
	//常量及抽象方法聲明						2、接口必須由其它類實現,實現類不能實現的方法
}												可以繼續標識爲abstract
											3、接口中所有的數據域都是public static final,
												所有方法都是public abstract,默認情況可以省略
												這些關鍵字

接口與抽象類的比較:

  • 類中可以定義成員變量,接口中不允許存在成員變量(因爲默認爲public static final)
  • 接口中所有方法都需要實現類去實現(Java8前)
  • 接口可以被多繼承
  • 使設計和實現完全分離
  • 能夠更自然的使用多態
  • 可以更容易搭建程序框架
  • 可以更容易更換實現

注意:
在jdk1.7及以前都是抽象類中可以有抽象方法,接口是特殊的抽象類,因爲接口中的所有方法都必須是抽象的,不能有方法實現。而到了Java8,我們發現在接口中也可以有方法的實現,在接口中寫方法要加default

JavaOO到此結束


12-異常以及異常處理機制

異常就是一種對象(Exception),表示阻止程序正常執行的錯誤或情況

  • 在程序運行的過程中,如果JVM檢測出一個不可能執行的操作,就會出現運行時異常
  • 在Java中,運行時異常(RuntimeException/Error)會作爲異常(對象)拋出
  • 如果異常沒有被處理,程序將會非正常終止

異常處理 - 使程序可以繼續運行或者優雅地終止方法拋出異常,一般我們用try-catch-finally塊來處理

  • 調用者可以捕獲以及處理該異常
  • 恢復正常的程序執行
  • 進行日誌處理
  • 以某些方式提醒用戶(錯誤提示、對話框等)

注意:如果沒有異常處理的話,那麼如果一個地方出現異常,下面的所有代碼都不會運行成功

Java中的異常處理機制
可以使程序處理非預期的情景,並繼續正常的執行
異常處理機制的主要組成

try:監控有可能產生異常的語句塊
catch:以合理的方式捕獲並處理異常
finally:不管有無異常,一定會執行的語句塊(一般用來釋放資源等)
throw:手動引發異常
throws:指定由方法引發的異常
用法:
	try{
		//所監控的有可能產生異常的語句塊
	}catch(Exception e){//捕獲異常,e就是所捕獲的異常對象
		//異常處理:打印異常信息、日記記錄等
	}finally{
		//不管有無異常,一定會執行的語句塊(一般用來釋放資源等)
	}

異常可分爲Exception(異常,如一個人好吃懶做還能接受)和Error(系統級錯誤,一個人犯罪了無法接受)
RunTimeException爲運行時異常,爲特殊異常,也就是免檢異常;其他異常爲必檢異常

Exception Error
AWTException(圖形界面) AwtError(界面錯誤)
SQLException(鏈接數據庫) LinkageError(依賴錯誤)
IOException(文件讀寫) VirtualMachineError(虛擬機錯誤)

多重catch塊解決問題
try塊中的代碼可能會引發多種類型的異常
當引發異常時,會按catch的順序進行匹配異常類型,並執行第一個匹配的catch語句

public static void division(String strNum1,String strNum2){
	int result = Integer.MIN_VALUE;
	try{
		int num1 = Integer.parseInt(strNum1);
		.................
	}catch(InputMismatchException e){
		e.printStackTrace();
	}catch(ArithmeticException e){
		e.printStackTrace();
	}
}

JDK7後的簡化寫法(multi-catch feature)catch(Exception1 | Exception2 | Exception 3|...ex){}
當然也可以直接用父類Exception,如catch(Exception);來處理異常,只不過效率沒那麼高。

try-catch-finally的注意點
無論是否發生異常,finally中的代碼總能被執行
比如catch中的異常捕捉錯誤,但是仍能夠執行finally中的代碼

  1. 遇到System.exit(0)語句是不執行finally塊的唯一情況(即使前面還有return)
  2. 使用finally塊的場合:如果程序開啓了相關資源(文件、數據庫等),爲了避免因出現錯誤沒有關閉,就可以使用finally塊在執行完畢後強制要求關閉所有打開的資源
  3. 使用finally時,可以省略catch塊(慎重)

注意:使用try-catch-finally的時候,常常會忘記close();或flush();,爲了避免這種情況,可以直接在try後面加一個括號,如:try(BufferedWriter bWriter = new BufferedWriter(new FileWriter(filepath))),這是使用了jdk7之後新增的自動關閉資源的寫法,使用的前提是資源類必須實現Closeable接口

直接拋出異常
throws直接拋出異常,如public static void division throws Exception(){}
throws後面的異常可以是父類也可以是子類,子類如果名字記不住可看源代碼,,一般來講是誰調用,誰處理

throw手動拋出異常(在調用的時候還是誰調用誰處理,throw和throws一般連用(:

public void setexp(long exp)throws Exception{
	if(exp>=0)this.exp = exp;
	else{
		throw new Exception("經驗值不能爲負數!");
	}
}
總結:
try-catch-finally組合
	try-catch、try-catch-finally、try-finally
異常繼承架構
	Throwable、Exception、RuntimeException
throw、throws的使用
	throws:聲明方法會出現異常
	throw:在方法中手動拋出異常

13-Java I/O系統

1、File(文件和文件夾),可以用來處理文件目錄的問題
基本代碼示例:

public class FileDemo {
	/** 當前操作的文件的路徑 */
	private static final String FilePath = "src/(default)/FileDemo.java";
	public static void main(String[] args) {
		//當前工程所在根目錄
		File file = new File(FilePath);
		System.out.println("是否存在:"+file.exists());
		System.out.println("是不是一個文件:"+file.isFile());
		System.out.println("是否是文件夾:"+file.isDirectory());
		System.out.println("文件名/目錄名爲:"+file.getName());
		System.out.println("文件/目錄路徑:"+file.getPath());		//相對路徑
		System.out.println("文件/目錄絕對路徑:"+file.getAbsolutePath());
		System.out.println("最後修改時間:"+new Date(file.lastModified()).toLocaleString());
		System.out.println("是否隱藏:"+file.isHidden());
		System.out.println("是否可讀:"+file.canRead());
		System.out.println("是否可寫"+file.canWrite());
		System.out.println("文件空間:"+file.length()/1024+"KB");
	}
}

使用File類創建文件/文件夾:

if(!file.exists()){
	if(file.isFile()){
		file.createNewFile();
		if(file.isFile())System.out.println("文件創建成功!");
	}else{
		file.mkdir();
		if(file.mkdir())System.out.println("文件夾創建成功!");
	}
}

使用File類刪除文件/文件夾:

if(file.exists()&&file.isDirectory()){
	file.delete();			//立即刪除
	file.deleteOnExit();	//運行完刪除
}

文件過濾器案例:

static class DirFilter implements FilenameFilter{
@Override
	public boolean accept(File dir, String name) {
		//假設要求只顯示git爲後綴的文件
		if(name.endsWith("git") || name.endsWith("project")){
			return true;
		}
		return false;
	}
}
//列出當前目錄下的所有文件/文件夾
String[] fileNames = file.list(new DirFilter());
for (int i = 0; i < fileNames.length; i++) {
	System.out.println(fileNames[i]);
}

注意:

  • 在Java.io包中操作文件內容主要由兩大類:字節流和字符流,兩類都有輸入和輸出操作
  • 流中保存的實際上全部是字節文件,字符流中多了對編碼的處理
  • 在字節流中輸入數據使用的是InputStream,輸出數據主要使用OutputStream
    InputStream和OutputStream是爲字節流設計的,主要用來處理字節或二進制對象
  • 在字符流中輸入數據主要使用Reader完成,輸出數據主要使用Writer完成
    Reader和Writer是爲字符流(一個字符佔兩個字節)設計的,主要用來處理字符或字符串
    對多國語言支持比較好,如果是音頻、視頻、圖片等建議使用字節流
  • 磁盤上保存的文件是二進制字節數據,字符流中多了對編碼的處理

2、JavaIO中的裝飾流與裝飾器

FileInputStream							用於從文件中讀取信息
ByteArrayInputStream					允許將內存的緩衝區作爲輸入流使用
FilterInputStream						抽象類,作爲"裝飾器"接口
ObjectInputStream						從輸入流中讀取對象
BufferedInputStream						使用緩衝區的輸入流
DataInputStream							可以從流讀取基本數據類型(int,char,long)

組件:Component,相當於JavaIO中的InputStream/OutputStream/Read/Write
組件的實現類:TrueComponent,真正幹活的組件類,繼承了Component的方法
裝飾器類:Decorator,也是繼承了Component方法,但是是由TrueComponent來實現的,裝飾器只是把方法升級

使用裝飾器的場合:
1、當我們需要在不影響其他對象的情況下,以動態、透明的方法爲對象添加功能(擴展方法的實現)
2、當不適合使用繼承但是又想進行方法的擴展時(如:班長不能被副班長繼承但可以讓副班長修飾)

使用步驟:Component是父類,TrueComponent和Decorator爲子類
1、先創建一個抽象類(Component),用於讓子類繼承,該類中有核心方法read
2、創建一個TrueComponent,用於繼承父類並且重寫方法,作爲實現類
3、因爲如果要升級read方法則每次都要修改TrueComponent,而且會影響TrueComponent中的方法內容,
	所以使用修飾器進行修飾,即添加升級後的read方法但不影響原read方法的使用
4、創建Decorator對象,由於裝飾器是要讓TrueComponent對象來實現擴展方法,所以應該定義一個私人的TrueComponent對象,又由於調用擴展方法時
	肯定要先創建Component(或TrueComponent對象),然後再把這個對象傳給裝飾器的實現類才能使用擴展方法,所以再裝飾器類中要構造方法,
		參數爲對應的對象,再將傳入的對象賦值給裝飾器中的私人對象
5、重寫read方法,方法體中只有Component.read();將請求轉發給Component對象,之後纔可以執行擴展操作
6、書寫Decorator的子類對象,其中也需要有參數爲組件的構造方法(原理同4,將傳入的對象super給裝飾器),然後再重寫擴展操作,具體就是重寫read的方法

讀取網絡文件案例:

package URLTest;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
/**
 * 從給定的URL上讀取文件內容-暫時只支持HTTP協議
 */
public class ReadURLTest {
	private static final String filepath = "src/獲取網頁.html";
	public static void main(String[] args) throws MalformedURLException {
		URL url = new URL("https://www.163.com/");
		StringBuffer content = new StringBuffer();
		try(BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
			BufferedWriter bWriter = new BufferedWriter(new FileWriter(filepath));
			){
			String line = null;
			while((line = reader.readLine())!=null){
				content.append(line);
				content.append(System.getProperty("line.separator"));
			}
			bWriter.write(content.toString());
			System.out.println("獲取網頁成功!");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

3、序列化和反序列化

對象的輸入和輸出

  • ObjectInputStream&ObjectOutputStream可以讀寫可序列化的對象
  • 序列化的作用就是把對象以二進制寫入到文件(Save)
  • 反序列化的作用是把二進制文件轉化爲對象(Load)

什麼情況下需要序列化?

  • 當把內存中的對象保存到文件中或者從文件中讀取出來(遊戲存檔/讀檔功能)
  • 當想用套接字在網絡上傳送對象的時候
  • 當想通過RMI(遠程方法調用)傳輸對象時

4、隨機訪問與綜合實戰
RandomAccessFile - 使用順序流打開的文件稱爲順序訪問文件,順序訪問文件的內容不能更新
RandomAccessFile允許在文件的任意位置上進行讀寫(隨機訪問文件)

注意:在RandomAccessFile中

  • seek函數可以移動文件的指針,即把當前指向的位置移動多少字節
  • setLength函數可以設置文件的長度大小,當設置爲0時,即把內容刪除

綜合實戰篇:利用IO下載網絡資源

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class DownLoadDemo {
	//下載原理
	//1、當前案例主要實現從http協議下載(文件流),將文件流以緩衝的方式讀取到內存中
	// 		InputStream -> BufferedInputStream
	//2、將緩存中的數據分塊寫入到硬盤上(使用RandomAccessFile類實現)
	//		這裏我下載一個CSGO的遊戲平臺
	static final String StrUrl = "https://oss.5ewin.com/app/setup/5EClient-2.1.54.zip";
	/** 設置下載時的默認緩存大小 - 1M大小,下載1M存一次 */
	private static final int MAX_BUFFER_SIZE = 10240;
	public static void main(String[] args) {
		//1、打開http鏈接,獲得下載內容給長度(補充內容,格式固定)
		//2、創建RandomAccessFile對象
		//3、將下載的內容緩存到字節數組中
		//4、將緩存字節數組通過RandomAccessFile對象寫入到文件中(涉及到一個文件指針的操作)
		HttpURLConnection connection = null;
		BufferedInputStream bInput = null;
		try {
			URL url = new URL(StrUrl);
			//讀取二進制流或者文件大的時候不用openStream
			connection = (HttpURLConnection)url.openConnection();
			//設置鏈接屬性-Range指從服務器請求下載文件的字節數範圍,0-,表示0-最大值
			connection.setRequestProperty("Range", "bytes=0-");
			connection.connect();//連接到服務器
			//判斷連接是否成功 - 一般連接成功後返回的代碼應該在200的範圍內
			/*
			 * 1xx:指示信息,表示請求已被接受,繼續操作
			 * 2xx:成功,表示請求已被成功接受,理解,操作
			 * 3xx:重定向,要求完成請求必須進行進一步的操作
			 * 4xx:客戶端錯誤,請求有語法錯誤或請求無法實現
			 * 5xx:服務器錯誤,服務器未能實現合法請求
			 */
			if(connection.getResponseCode()/100!=2){
				System.err.println("連接的響應狀態不在200範圍內,請重試!");
				return;
			}
			int fileSize = connection.getContentLength();	//獲得要下載文件的大小(字節數)
			bInput = new BufferedInputStream(connection.getInputStream(),MAX_BUFFER_SIZE);
			int downloaded = 0;//已下載的字節數 - 用來計算當前下載的百分比
			String fileName = url.getFile();//獲得下載的文件名
			//截取字符串,從最後一個斜線+1的位置開始截取
			fileName = fileName.substring(fileName.lastIndexOf("/")+1);
			RandomAccessFile file = new RandomAccessFile(fileName,"rw");
			file.seek(0);	//將文件指針置零
			file.setLength(0);	//文件清空
			while(downloaded<fileSize){//當已下載的字節數小於文件總大小時,繼續下載
				byte[] buffer = null;	//下載緩存字節數組
				//判斷爲下載的大小是否超過最大緩存
				if(fileSize - downloaded>MAX_BUFFER_SIZE){
					buffer = new byte[MAX_BUFFER_SIZE];
				}else{
					buffer = new byte[Math.abs(fileSize - downloaded)];
				}
				//將緩存中的內容讀取
				int read = bInput.read(buffer);
				if(read == -1)break;	//下載結束
				//將當前下載的緩存寫入到文件中
				file.seek(downloaded);	//設置文件指針
				file.write(buffer,0,read);
				downloaded += read;
				System.out.printf("已下載:%.2f%%",downloaded*1.0/fileSize*100);
				System.out.println();
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			connection.disconnect();
			try {
				bInput.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

集合篇

14-List集合

問:爲什麼要使用集合框架?
答:在不確定數組存儲大小的情況下,就可以用集合框架

JavaSE提供了:

  • Collection接口:存儲另一個(某一個)元素的集合,相當於一個一個對象存儲
  • Map接口:存儲(鍵/值)對,即key-value集合
  • Collections:操作集合的工具類(包括了對集合的操作,如:排序、取值等)

Collection中的三種主要類型的集合:

  1. Set(規則表):存儲一組不重複的元素(可能無序)
  2. List(線性表):存儲一個有序集合
  3. Queue(隊列):存儲用先進先出的方式處理的對象

注意:

  • 集合框架中的所有接口和類都在Java.util包中
  • 集合框架中所有的具體類都實現了Cloneable和Serializable接口,即他們的實例都是可複製且可序
    列化的對象
  • 在定義不同類型的對象時,可以聲明Object數組,在數組中賦予不同的類型,但是這樣提取困難,特別
    是對於一些不知道數組中到底是什麼類型的開發者開說,所以應該使用泛型
  • 使用泛型的實例代碼如下:
    public class ElementDemo<E> {
    	public static void main(String[] args){
    		//<>裏填什麼類型,在add中就傳入什麼類型
    		ElementDemo<Integer> demo = new ElementDemo<Integer>;
    		demo.add(123);
    	}
    	public void add(E e){
    		//代碼省略...
    	}
    }
    

Collection接口方法和描述

---------------------------------------------------------------------------------------------
				方法											描述
boolean add(E e); / int size();					向集合中添加元素e / 返回集合中的元素個數
boolean addAll(Collection<? extends E> c);		將集合c中的所有元素添加到當前這個集合
boolean contains(Object o);						如果該集合中包含對象o,返回true
boolean containsAll(Collection<?> c);			如果該集合中包含集合c中的所有元素,返回true
boolean isEmpty();	/ void clear();				如果集合不包含任何元素,返回ture / 刪除集合中
												的所有元素
Ierator<E> iterator();							返回該集合中元素所用的迭代器(遍歷所有元素)
boolean remove(Object o);						從集合中刪除元素o
boolean removeAll(Collection<?> c);				從集合中刪除集合c中的所有元素
boolean retainAll(Collection<?> c);				保留c和該集合都有的元素(交集)
Object[] toArray();								返回該集合構成的Object數組
---------------------------------------------------------------------------------------------
注意:
	Collection雖然是集合的最高父接口,但是直接使用Collection接口會造成操作意義不明確,所以在實
	際開發中不提倡直接使用Collection接口

List接口方法和描述

---------------------------------------------------------------------------------------------
				方法											描述
public void add(int index,E element)						在指定位置增加元素
public boolean addAll(int index,Collection<? extends E> c)	在指定位置增加一組元素
E get(int index) / E set(int index,E element);				返回/替換指定位置的元素
public int indexOf(Objetct o)								查找指定元素的位置
public int lastIndexOf(Object o)							從後往前查找指定元素的位置
public ListIterator<E> listIterator()	//升級版			獲得List迭代器對象
public E remove(int index)									刪除指定位置的元素
public List<E> subList(int fromIndex,int toIndex)			取出集合中的子集合(左閉右開)
public E set(int index,E element)							替代指定位置的元素
---------------------------------------------------------------------------------------------
注意:
	List接口擴展了Collection接口的方法,這些方法使用起來比父接口更加方便,要使用List接口,需要對
	List接口的實現類實例化

List的實例化以及使用示例

//多態:使用List接口的一個子類ArrayList進行實現
List<String> list1 = new ArrayList<>();
//遍歷的方法 1、for循環中用list 2、foreach 3、迭代器 4、ListIterator迭代器
Iterator<String> it = list1.iterator();
//使用迭代器的方法相對比較固定
while(it.hasNext()){
	System.out.print(it.next() + ", ");
}
System.out.println();
ListIterator<String> listIt = list1.listIterator();
while(listIt.hasNext()){
	System.out.print(listIt.next()+", ");
}
System.out.println();
//使用ListIterator與傳統迭代器的區別
//1、ListIterator不止可以向後訪問,也可以向前訪問
//2、ListIterator可以修改集合中的元素
System.out.println("使用ListIterator從後向前遍歷");
ListIterator<String> listIt2 = list1.listIterator(list1.size()); //將指針調整到list1大小
while(listIt2.hasPrevious()){//當迭代器中的元素存在上一個時
	System.out.print(listIt2.previous()+", ");
}
System.out.println();
ListIterator<String> listIt3 = list1.listIterator(2);	//相當於將指針調整到2
if(listIt3.hasPrevious()){			//如果2前有東西,則把指針移到2前,再修改
	listIt3.previous();
	listIt3.set("蛤蛤蛤");
}
System.out.println(list1);

ArrayList與LinkedList的特性

ArrayList(數組線性表):
	1、是一個大小可變的數組,在內存中分配連續的空間
	2、遍歷元素和隨機訪問元素的效率比較高
LinkedList(鏈表):
	1、採用鏈表存儲方式
	2、提供從線性表兩端提取、插入和刪除元素的方法
	3、插入、刪除元素效率比較高
	4、鏈表相當於座位,讀取效率不高(要從第一個往後讀),但是插入和刪除很方便,比如刪除元素時,數組要將後面的所有元素向前移動一格,但是鏈表只用將後面一個元素向前移動一格即可

ArrayList與LinkedList添加元素的效率對比

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ArrayListAndLinkedListDemo {
	public static void main(String[] args) {
		System.out.println("ArrayList耗時:"+CostTime(new ArrayList<>()));
		System.out.println("LinkedList耗時:"+CostTime(new LinkedList<>()));
	}
	public static long CostTime(List<Object> list){
		Object obj = new Object();
		long startTime = System.currentTimeMillis();
		final int N = 500000;
		for (int i = 0; i < N; i++) {
			//如果是List.add(obj); 往最後一個位置添加,則Array不一定慢
			list.add(0, obj);
		}
		long endTime = System.currentTimeMillis();
		return endTime - startTime;
	}
}
結果:
ArrayList耗時:25148 ms
LinkedList耗時:335 ms
總結:
在兩種情況交叉使用的前提下,直接使用父類List即可,比如使用完LinkedList,在轉換爲ArrayList也可以

15-Set、Queue集合

Set集合類似於一個罐子,“丟進"Set集合裏的多個對象之間沒有明顯的順序。Set繼承自Collection接口,不能包含有重複元素(記住,這是整個Set類層次的共有屬性)。
Set判斷兩個對象相同不是使用”=="運算符,而是根據equals方法。

  • HashSet:用來存儲互不相同的任何元素(無序)
  • LinkedHashSet:使用鏈表擴展實現HashSet類,支持對元素的操作
    注意:如果不需要維護元素被插入的順序,就應該使用HashSet,更加高效
  • TreeSet:可以確保所有元素是有序的,可排序

Queue用於模擬"隊列"這種數據結構(先進先出 FIFO)。隊列的頭部保存着隊列中存放時間最長的元素,隊列的尾部保存着隊列中存放時間最短的元素。新元素插入(offer)到隊列的尾部,
訪問元素(poll)操作會返回隊列頭部的元素,隊列不允許隨機訪問隊列中的元素。結合生活中常見的排隊就會很好理解這個概念

  • PriorityQueue:PriorityQueue保存隊列元素的順序並不是按照加入隊列的順序,而是按照隊列元素的大小進行重新排序
  • Deque:Deque代表一個"雙端隊列",雙端隊列可以同時從兩端來添加、刪除元素,因此Deque的實現類既可以當成隊列使用、也可以當成棧使用
    1 - ArrayDeque:是一個基於數組的雙端隊列,和ArrayList類似,它們的底層都採用一個動態的、可重分配的Object[]數組來存儲集合元素,當集合元素超出該數組的容量時,系統會在底層重新分配一個Object[]數組來存儲集合元素
    2 - 此外,LinkedList也可以是西安Deque接口,將LinkedList當作雙端隊列使用。

16-Map集合

  • HashMap:HashMap不能保證key-value對的順序。判斷相等的方法是兩個key通過equals()方法比較返回true,同時兩個key的hashCode值也必須相等
    1 - LinkedHashMap:
    LinkedHashMap也使用雙向鏈表來維護key-value對的次序,該鏈表負責維護Map的迭代順序,與key-value對的插入順序一致(注意和TreeMap對所有的key-value進行排序進行區
    分)
  • Hashtable:一個古老的Map實現類
    1 - Properties
    Properties對象可以把Map對象和屬性文件關聯起來,從而可以把Map對象中的key-value對寫入到屬性文件中,也可以把屬性文件中的"屬性名-屬性值"加載到Map對象中
  • SortedMap
    正如Set接口派生出SortedSet子接口,SortedSet接口有一個TreeSet實現類一樣,Map接口也派生出一個SortedMap子接口,SortedMap接口也有一個TreeMap實現類
    1 - TreeMap
    TreeMap就是一個紅黑樹數據結構,每個key-value對即作爲紅黑樹的一個節點。TreeMap存儲key-value對(節點)時,需要根據key對節點進行排序。TreeMap可以保證所有的key-value對處於有序狀態。同樣,TreeMap也有兩種排序方式: 自然排序、定製排序

17-線程

相關概念

  1. 程序(Program):指令集 靜態概念
  2. 進程(Process):操作系統調度程序 動態概念
    進程是程序的一次動態執行過程,佔用特定的地址空間
    每個進程都是獨立的,由3部分組成(cpu、data、code)
    缺點:內存的浪費,cpu的負擔
  3. 線程(Thread):在進程內多條執行路徑(main方法也是線程)
    是進程中的"單一的連續控制流程",又被稱爲輕量級進程
    Threads run at the same time,independently of one another
    一個進程可擁有多個並行的(concurrent)線程
    一個進程中的線程共享相同的內存地址空間->可以訪問相同的變量和對象,而且它們從同一堆中分配對象->通信、數據交換、同步操作
    由於線程間的通信時在同一地址空間上進行的,所以不需要額外的通信機制,這就使得通信更簡便而且信息傳遞的速度也更快

如何使用線程?

步驟:
一、繼承Thread + 重寫run();
啓動:創建子類對象+對象.start();
注意:內部由cpu管控,線程的啓動,如果直接調用run方法,那就不是線程運行了,還是一個一個運行

二、實現Runnable + 重寫run();
啓動:使用靜態代理
	1、創建真實對象
	2、創建代理對象 Thread+引用 Thread 名 = new Thread(Runnable對象);
	3、代理角色.start();

三、實現Callable接口
優點:有返回值,可以處理異常
Callable 和 Future接口的區別:
  (1)Callable規定的方法是call(),而Runnable規定的方法是run(). 
  (2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值的。  
  (3)call()方法可拋出異常,而run()方法是不能拋出異常的。 
  (4)運行Callable任務可拿到一個Future對象,Future表示異步計算的結果。 
  (5)它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。 
  (6)通過Future對象可瞭解任務執行情況,可取消任務的執行,還可獲取任務執行的結果。 
  (7)Callable是類似於Runnable的接口,實現Callable接口的類和實現Runnable的類都是可被其它線程
	   執行的任務。 

推薦使用接口來實現多繼承:
優點:
	1、可以同時實現繼承。實現Runnable接口方式要通用一些
	2、避免單繼承
	3、方便共享資源 同一份資源 多個代理訪問
-----------------------------------------------------------------------------------------
線程的終止情況:
1、自然終止:線程體正常執行完畢
2、外部干涉
		1)、線程類中定義線程體使用的表示
		2)、線程體使用該標識
		3)、提供對外的方法改變該標識
		4)、外部根據條件調用該方法即可
-----------------------------------------------------------------------------------------
線程阻塞:
join和yield:
	1、join:合併線程
	2、yield:暫停線程
	3、sleep:休眠,不釋放鎖(每個線程對應一把鎖)
		sleep使用場景:1、與時間相關的(如倒計時的打印)	2、模擬網絡延時(可能有併發的問題)
	
	join是先把自己的線程運行完畢,再運行其他的線程,相當於把其他線程阻塞.
	yield相反,yield則是把自己先暫停,等待其他運行結束再運行自己的線程
使用方法:
	join是直接把Thread對象使用,如t.join();
	yield是在哪個線程體中使用,哪個線程體就暫停(main也是一個線程體)
-----------------------------------------------------------------------------------------
線程的其他方法以及優先級:
 * Thread.currentThread();		當前線程
 * setName(); 					設置名稱
 * getName();					獲取名稱
 * isAlive();					判斷狀態
 * 優先級:概率,不是絕對的優先級,沒有先後順序
 * 設置優先級:Thread對象.setPriority();
 * 獲得優先級:Thread對象.gerPriority();
 * MAX_PRIORITY 10
 * NORM_PRIORITY 5(默認)
 * MIN_PRIORITY 1

線程的同步與鎖定:

synchronized鎖大家又通俗的稱爲:方法鎖、對象鎖和類鎖 三種
同步:併發-多個線程訪問同一份資源,要確保資源安全-線程安全
synchronnized(lock),即把lock對象當成被鎖對象,當a訪問時就把lock給鎖住,其他對象不能訪問
使用同步的方法:
一、直接在類名行中加入synchronized修飾符,即整個類
二、同步塊(在某一位置中使用該修飾符,則有特定範圍)
	synchronized(引用類型|this|類.class){//其中類.class相當於第一種
		注意:
		1、synchronized(this)
			因爲this是當前對象本身,所以鎖定只對你自己new了並調用的那個對象有用,所以另外一個人如果
			要new並調用,則和這個不是同一個鎖,因爲this變了。
		2、synchronized(類的名.class)
			每個類在jvm裏面只有一個唯一的字節碼,所以.class是唯一的,無論多少對象,共用此同一把鎖。
	}

死鎖:過多的同步容易造成死鎖
死鎖產生原理:
	其中線程A運行時會先獲取lock1鎖對象,然後在不釋放lock1的情況下去爭奪lock2
	而線程B運行時會先獲取lock2鎖對象,然後在不釋放lock2的情況下去爭奪lock1
	這時就有可能會出現這麼一種情況:線程A獲取到了lock1,準備去搶lock2,線程B獲取到了lock2,準備去
	搶lock1。但是此時他們所需要的資源已經被對方所佔有而且擁有不會主動釋放,程序就會一直等待下去,
	死鎖就產生了
-----------------------------------------------------------------------------------------
單例設計模式:確保一個類只有一個對象
一、懶漢式(對象先爲null)
	1、構造器私有化,避免外部直接創建對象
	2、聲明一個私有的靜態變量
	3、創建一個對外的公共的靜態方法,訪問改變量,如果變量沒有對象,則創建新對象
二、餓漢式
	1、構造器私有化,避免外部直接創建對象
	2、聲明一個私有的靜態變量,同時創建該對象
	3、創建一個對外的公共的靜態方法
懶漢式注意點:
	如果單純的使用懶漢式的話效率會低下,因爲只有一個判斷對象是否存在的方法,那麼不管有沒有對象,
	存在其他的線程都要等待,則效率低下
	如果使用下面的DoubleChecking模式,則會提高效率,如果多個線程指向該方法,當已經有存在的對象時
	,則直接退出,所以效率提高
	public static Demo03 getInstance (){
		if(instance == null){ //提供效率
			synchronized(Demo03.class){
				if(null==instance){ //安全
					instance =new Demo03();
				}		
			}		
		}		
		return instance;	
	}
餓漢式注意點:
	單純的餓漢式是在創建MyJvm2對象的時候就實例化對象的屬性,等到要調用的時候又要調用,效率低下
	使用內部類的餓漢式,則會提高效率,在該用的時候調用內部類的實例化,否則不調用,提高效率
	class MyJvm2 {
		private static MyJvm2 instance = new MyJvm2();	
		private MyJvm2(){}
		public static MyJvm2 getInstance(){
			return instance;
		}
	}
	/** 
	 * 類在使用的時候加載 ,延緩加載時間 
	 */
	class MyJvm3 {
		private static class JVMholder{//內部類,這裏就會提高效率	
			private static MyJvm3 instance = new MyJvm3();	
		}	
		private MyJvm3(){}	
		public static MyJvm3 getInstance (){
			return JVMholder.instance;	
		} 
	}
-----------------------------------------------------------------------------------------
生產者消費者模式_信號燈法(ThreadDemo中)
notify();	喚醒在此對象監視器上等待的單個線程
notifyAll();	喚醒在此對象監視器上等待的所有線程
wait();		在其他線程調用此對象的notify()方法或notifyAll()方法前,導致當前線程等待
wait和sleep的區別,wait釋放鎖,sleep不釋放鎖
//信號燈(使用前提是必須要有synchronized)
//flag = T 生產者生成,消費者等待 生產完成後通知消費
//flag = F 消費者消費,生產者等待 消費完成後通知生產

Timer定時器類
TimerTask人物類
timer.schedule(task, time);					//執行一次
timer.schedule(task, firstTime, period);	//執行多次,period爲過多少毫秒運行一次
問題:JAVA相關抽象類和接口不是不能直接實例化嗎,在匿名內部類中爲什麼就可以直接用new來實例化?
回答:匿名類其實就是相當於實現接口或者實現抽象類的一個具體類,以及不是抽象類或者接口,所以可以實例化,在匿名內部類中必須實現抽象方法,或者接口的方法,否則就會報錯的,就是讓匿名類變成可以實例化的類,所以匿名內部類不是例外

18-網絡編程

  1. 網絡:將不同區域的計算機連接在一起 局域網 城域網 互聯網
  2. 地址:IP地址 確定網絡上的一個絕對的地址 | 位置 -->相當於房子的地址
  3. 端口號:區分計算機軟件的 -->房子的房門 2個字節 0-65535 共65536個
    1、在同一個協議下 端口號不能重複 不同的協議可以重複
    2、1024以下的端口不要使用,給一些之名的廠商使用如: 80–>http 21–>ftp
  4. 資源定位:URL:統一資源定位符 URI:統一資源
  5. 數據的傳輸
    1、協議:TCP協議和UDP協議
      1)、TCP:電話 類似於三次握手 面向連接 安全可靠 效率低下
      2)、UDP:短信 非面向連接 安全較低 效率高
    2、傳輸:
      1)、先封裝
      2)、後拆封

一些基礎方法

InetAddress:封裝Ip及DNS
getLocalHost();返回本機的Ip地址
getHostAddress();返回IP地址
getHostName();獲得域名|本機的計算機名
getByName("ip地址|域名");
如果創建InetAddress對象的時候用的是Ip,如果解析成功,則getHostName()返回的是域名,否則返回的還是Ip地址

URL_爬蟲原理
URL由四部分組成:協議 存放資源的主機域名 端口 資源文件名(/之後的,相對路徑)

一、創建
	URL(String spec):絕對路徑構建
	URL(URL context,String spec):相對路徑構建
二、方法
	//絕對路徑的構建
	URL url = new URL("http://www.baidu.com:80/index.html#aa?uname=bjsxt");
	System.out.println("協議:"+url.getProtocol());
	System.out.println("域名:"+url.getHost());
	System.out.println("端口:"+url.getPort());
	System.out.println("資源:"+url.getFile());
	System.out.println("相對路徑的資源:"+url.getPath());
	System.out.println("錨點:"+url.getRef());//錨點
	//?後的參數,如果存在錨點,就當成錨點的一部分了,爲null
	System.out.println("參數:"+url.getQuery());
	//相對路徑的構建
	url = new URL("http://www.baidu.com:80/a/");
	url = new URL(url,"b.txt");
	System.out.println(url.toString());
三、流
	openStream();

UDP編程原理
UDP:以數據爲中心 非面向連接 不安全 數據可能丟失 效率高

一、類 DategramSocket DategramPacket
1、客服端:
	1)、創建客戶端 DategramSocket 類 + 指定端口
	2)、準備數據 字節數組
	3)、打包 打成DategramPacket + 發送的服務器的地址及端口
	4)、發送
	5)、釋放資源
2、服務器端:
	1)、創建 服務端 DatagramSocket 類 + 指定端口
	2)、準備接收容器 字節數組 封裝 DategramPacket
	3)、包 接受數據
	4)、分析
	5)、釋放資源

TCP_Socket通信原理

一、面向連接:請求-相應 Request -- Response
二、Socket編程
	1、服務器:ServerSocket
	2、客戶端:Socket
	3、連接客戶端和服務端的用來傳輸的管道叫Socket
注意:
	1、如果服務端已經啓動過再啓動則會出錯
	2、如果服務端沒有啓動而啓動客戶端則會出錯(而UDP不出錯)

TCP、UDP實現聊天室步驟

TCP實現步驟(服務端和客戶端基本差不多):
1、
	聲明2個輸入流 1個輸出流 1個ServerSocket 1個Socket
	其中,ServerSocket用於接受Client傳來的消息並存放在Socket內
	Socket就相當於一個存放消息的臨時容器
	2個輸入流中1個輸入流用於讀取Socket中的信息,1個用來寫入要發送的信息
	1個輸出流就是將寫入的信息傳給Socket,再利用Socket傳送到Client端口
2、
	在Try-catch-finally結構中寫入主要代碼
	Try中寫入比如具體輸入、輸出、Socket、ServerSocket的實例化,並實現功能
	catch捕捉異常,並輸出捕捉的異常
	finally用於關閉資源,避免出現不必要的浪費
3(編寫線程服務器)、
	將服務器的發送消息和傳出消息的功能封裝到線程中去
	只用在main函數中調用該線程即可,這樣main中只有一個用於讀取的輸入流
	並且這樣可以實現更靈活的雙向通信,一個專門接受,一個專門發送

UDP協議實現聊天室的主要步驟:
1、將要發送的信息存放在DategramPacket中,再利用DatagramSocket發送
2、UDP傳送數據基本都是用Byte傳輸,故不特意使用其他輸入流
3、如果要傳入其他基本數據類型,將Byte流和Date流一起使用,可以將類型轉換並傳輸
4、如果要傳入對象類型,將Obj流和Byte流一起使用
5、基本步驟和TCP類似,但簡單一些

19-註解及動態代理

另一篇博客寫的很清楚了:5分鐘幫你搞懂自定義註解及動態代理

20-正則表達式和文本操作

操作文本的非常常用的技術,它是一個簡單的小語言,有了正則,處理代碼的效率會大大提高
學習正則表達式很大程度上是學習正則表達式的語法規則

【標準字符集合_自定義字符集合】
·普通字符和簡單轉義字符
·標準字符集合:
	能夠與'多種字符'匹配的表達式
	*注意區分大小寫,大寫是相反的意思,比如大寫的D就是非數字
		\d	任意一個數字,0~9種的任意一個,注意是一個一個匹配
		\w	任意一個字母或數字或下劃線,也就是A~Z,a~z,0~9,_中任意一個
		\s	包括空格、製表符、換行符等空白字符的其中任意一個
		'.' 小數點能匹配任意一個字符(除了\n),如果要匹配包括'\n'在內的所有字符,一般用[\s\S]
		[]  自定義字符集合,表示範圍可用'-',如[2-8].表示取反可用'^',如[^abc]
【自定義字符集合特殊用法_量詞】
{n}		表示重複幾次,如:\d{6}相當於\d\d\d\d\d\d
{m,n}	表示至少重複m次,最多重複n次
{m,}	表示至少重複m次
?		匹配表達式0或1次,相當於{0,1}
+		表達式至少出現1次,相當於{1,}
*		表達式不出現或出現任意次,相當於{0,}
【字符串匹配_捕獲】
\b,匹配一個位置,如果一個字符串爲gaoqi,則gaoqi\b則可以匹配,因爲i左邊爲q,右邊爲' '
字符邊界:^ $ \b匹配的不是字符是位置,匹配到的是零寬度的,而字符佔寬度

反向引用:([a-z]{2})\1可以用來捕獲gogo toto dodo這類字符串,即要捕獲兩組才滿足要求
捕獲到的內容會存在內存中,爲了節省內存,對不需要的內容前加?:即可

Eclipse和Notepad++使用正則表達式的方式
在Notepad++使用正則表達式,ctrl+f,選擇正則表達式
在Elipse使用正則表達式,search,選擇正則表達式

Java中使用正則表達式

1、創建Pattern對象,填寫正則表達式,注意一槓變兩槓
2、創建Matcher對象,填寫待匹配對象,與表達式關聯
	調用matches()返回真值,嘗試將整個字符串序列與該模式匹配
	調用find()返回真值,如果在序列中找到了,則指針指向滿足條件的子序列末尾,下一次接着找
	調用group()返回字符串,返回滿足條件的字符串,group(0)|()都是查找整個字符串
	調用group(1)...(n)是查找捕獲的對象
	調用replaceAll("?")返回字符串,將查找到的字符串替換爲?
	調用字符串的split("?")返回字符串數字,用'?'來切割字符串,並存放到字符數組中

21-JDBC在Java中的使用

老版:加載Mysql驅動的代碼:Class.forName("com.mysql.jdbc.Driver");
*新版:加載Mysql驅動的代碼:Class.forName("com.mysql.cj.jdbc.Driver");

老版:獲得連接對象的代碼:Connection con = DriverManager.getConnection("jdbc:mysql://host:port/數據庫","user","password");
*新版:獲得連接對象的代碼:con = DriverManager.getConnection("jdbc:mysql://localhost:3306/數據庫?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC","user","password");

·建立連接對象實際上就是利用socket與遠程的數據庫進行連接,看似在一個軟件上運行,實際上不是
·連接對象內部其實包含了Socket對象,屬於遠程的連接,比較耗時!這是Connection對象管理的一個要點
·真正的開發中,爲了提高效率,都會使用連接池來管理連接對象

JDBC使用應注意的點:

一般開發中比較少直接使用Statement語句,因爲有注入危險,比如:
	String id = "5 or 1=1";
	String sql = "delete from t_user where id="+id;
	stmt.execute(sql);
如果要刪除的id是客戶端傳入的id,則像上面修改的一樣,如果1=1那麼就將所有的列都刪除了,所以我們使用PreparedStatment來執行SQL語句
批處理要避免使用PreparedStatment,因爲PreparedStament本身會佔用內存

使用PreparedStatment接口主要的注意點:
1、佔位符的問題:
	//?是佔位符,避免拼sql注入,傳入的時候有個預處理的過程,只能填單類型,多餘的進不來
	String sql = "insert into t_user (username,pwd,regTime) values (?,?,?)";
	//這樣就避免了sql注入危險
2、插入元素方式:
	//第一種插入方式,要設置對應的類型插入
	ps.setString(1, "HPF");	//參數索引是從1開始計算,而不是0!
	ps.setString(2, "HX");
	ps.setDate(3, new java.sql.Date(System.currentTimeMillis()));
	//第二種插入方式,直接使用OBJ對象插入,就不用管是什麼類型了
	ps.setObject(1, "L0UE");
	ps.setObject(2, "123456");
	ps.setObject(3, new java.sql.Date(System.currentTimeMillis()));
	ps.execute();

選取數據庫中元素的方式有:
	1、String sql = "select id,username,pwd from t_user where id>?";
	   select後面加上要選取的元素名稱
	2、String sql = "select * from t_user where id>?";
	   select後面加上*即選取整列所有元素
常用的Statment方法:
	execute():運行語句,返回是否有結果集,之後用的少
		也可以用來執行sql語句,con.execute(sql);
	executeQuery():運行select語句,返回ResultSet結果集
		ResultSet rs = ps.executeQuery();
		while(rs.next()){//next從0開始,第一次使用指向1,並返回1後有無數據
			//sql語句:String sql = "select id,username,pwd from t_user where id>?";
			System.out.println(rs.getInt(1)+"---"+rs.getString(2)+"---"+rs.getString(3));
		}
	executeUpdate():運行insert/update/delete操作,返回更新的行數,即返回修改了幾次
		int count = ps.executeUpdate();
		System.out.println(count);
使用完sql驅動後一定要關閉(finally):
	關閉的順序遵循:後開的先關,resultset --> statment --> connection
	關閉的時候一定要分開關,將三個try-catch分開寫,否則出現異常將不會執行下面語句

22-JAVASE完結

這篇文章整合了我的所有JavaSE筆記以及一些經驗理解,分享給大家看看,也方便我自己回顧知識!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章