classpath
.;%java_home%\lib;%java_home%\lib\tools.jar;D:\Java\;
java_home
D:\Program Files\Java\jdk1.8.0_51
path
C:\Users\BaseKing-Sunie\AppData\Local\Code\bin;%java_home%\bin;%java_home%\jre\bin;
D:\adt-bundle-windows-x86_64_20131020\sdk\tools;D:\adt-bundle-windows-x86_64_20131020\sdk\platform-tools;
TEMP
%USERPROFILE%\AppData\Local\Temp
TMP
%USERPROFILE%\AppData\Local\Temp
第一本書
【Run As】
發現程序有問題,程序無法運行,但沒有錯誤時,可以右鍵,然後移到Run As,如果顯示是Run Configurations,而不是Java Application,則你的主函數可能錯了。
【Scanner】類
掃描儀
scan 掃描
【println】
輸出信息 換行打印
System.out.println(“”); 在控制台輸出
[scan.nextDouble();]
double pay=scan.nextDouble();這句程序中,只有在你用鍵盤輸入一個double型的數字後才會開始運行這句程序之後的程序。重點是scan.nextDouble();只針對這個。
[&]
Java變量只能包含數字、字母、下劃線和$,而&不能在變量命名中使用,因此會出現編譯錯誤
int &size=20; //用&是錯誤的
System.out.println(&size);
[jvm]
uitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013/lib/visualvm/visualvm/modules
【默認】
int共有10位數,long有19位數。
除了通常的十進制數字形式,整數直接量也可以寫成16進制的形式(以0X或0x開頭)或8進制的形式(以0開頭),請看如下直接量三種表現形式:
int a = 100000; // 10進制
int b = 0x186a0; // 16進制
int c = 0303240; // 8進制
如果要表示long直接量,需要以 L 或 l 結尾。默認的是整形直接量int。示例代碼如下:
long a = 10000000000; //會有編譯錯誤,因為10000000000編譯器認為是int類型,而這個值,已經超出了int的范圍
long b = 10000000000l; //正確
默認的浮點直接量為double型,如果需要表示float類型的直接量,需要加“f”或“F”後綴。例如:
float f1 = 3.14 //編譯錯誤,應該寫成3.14f
[+]
int a = 1, b = 10;
int c1 = a++;
int c2 = ++b;
System.out.println("a=" + a + ", b=" + b + ", c1=" + c1 + ", c2=" + c2);
程序運行出來的結果
a=2, b=11, c1=1, c2=11
[計時操作]時間
JDK提供 System.currentTimeMillis() 方法,返回1970年1月1日零點到此時此刻所經歷的毫秒數,數據太大,故其數據類型為long。示例代碼如下:
long time = System.currentTimeMillis();
System.out.println(time); //輸出的結果為: 1383835712828
通過上面的代碼可以看出,輸出的結果已經超出int類型的最大值,因此,JDK設計的返回類型為long型,該方法常常被用於計時操作。
【char類型】
字符類型char事實上是一個16位無符號整數(都是正數),這個值是對應字符的編碼,Java字符類型采用Unicode字符集編碼(通用碼、統一碼、萬國碼)
,而Unicode是世界通用的定長字符集,所有的字符都是16位來表示。例如:字符a實際的值為97,字符A實際的值為65,字符0實際的值為48。
字符直接量可以采用諸如:‘中’的形式,也可以采用16進制的表示形式,例如: ‘\u4e2d’,代碼如下所示:
char c1 = ‘中’; //c1中存的是”中”的編碼
char c2 = '\u4e2d'; //‘4e2d’為‘中’所對應的16位Unicode編碼的16進制表示形式
System.out.println(c1);
System.out.println(c2);
如上代碼的輸出結果:c1的值為中,c2值也為中,但c1和c2內部存儲的其實是”中”這個字符所對應的Unicode碼,即:一個無符號的整數。
對char型變量賦值
char abc='1';
System.out.println(abc); //輸出1
System.out.println(abc+1); //輸出50
char abc=1;
System.out.println(abc); //輸出
System.out.println(abc+1); //輸出2
在對char型變量賦值時,可以采用如下三種方式:
方式一:
字符直接量:形如‘A’,變量中實際存儲的是該字符的Unicode編碼(無符號整數值),一個char型變量只能存儲一個字符。示例如下:
char c1 = 'A';
方式二:
整型直接量:范圍在0~65535之間的整數,變量中實際存儲的即該整數值,但表示的是該整數值所對應的Unicode字符。示例如下:
char c2 = 65;
Unicode形式:形如‘\u0041’,Unicode字符的16進制形式。示例如下:
char c3 = '\u0041';
使用轉義字符
char c = '\\';
System.out.println(c); //輸出的結果為:\
'\n' 表示回車符
'\r' 表示換行符
'\\' 表示反斜槓(\)
'\'' 表示單引號(')
'\"' 表示雙引號(")
' ' 表示空格符
“\t” 輸出時,空格 //System.out.println(c+“\t”);
System.out.println("請選擇功能:\n 1.查看余額 2.取款 3.繳電話費");
【boolean】
boolean類型適用於關系、邏輯運算, 表示某個條件是否成立, 只允許取值true或false,true表示條件成立, 而false表示條件不成立。
boolean型變量經常用於存儲關系運算的結果,所謂關系運算就是比較兩個變量的大小相等等關系(此知識點,後續詳細介紹)。boolean示例代碼如下所示:
int age = 18;
boolean isChild = age<16;
System.out.println(isChild); // isChild的值為false
boolean running = true;
boolean closed = false;
【變量命名】 值 //引用命名 對象 八種基本數據類型以值的形式存在於內存中,而不是對象
在java語言中,對於變量、常量、方法、類、包等等都有名字,將這些名字統一稱之為java標識符,標識符的命名規則如下列表所示:
可以由字母、數字、“_”或“$”符組成,但是不能以數字開頭。
中文可以作為變量名,但不提倡使用。
Java大小寫敏感,即:嚴格區分大小寫,在給命名變量時需要注意。
不能使用Java保留字(一些Java語言規定好的,有特殊含義的字符),如:int、if、else、for、break等。
【賦值】
public static void main(String[] args) {
int a, b = 10;
int c = a + b; // 編譯錯誤 變量a並未賦初始值就直接使用了,違反了java語法的規定,變量使用之前必須初始化
System.out.prinltn(c);
}
public static void main(String[] args) {
int sum = 0; //聲明同時初始化
int a = 5;
int b = 6;
sum = a + b;
System.out.println(sum);
}
public static void main(String[] args) {
int sum;
sum = 0; // 在使用sum變量之前對其進行初始化。
sum = sum + 100;
System.out.println(sum);
}
int b,c,d; //聲明3個變量
【溢出】
兩個整數進行運算時, 其結果可能會超過整數的范圍而發生溢出,正數過大而產生的溢出,結果為負數;負數過大而產生的溢出,結果為正數。示例代碼如下所示:
int a = 2147483647; //int類型整數的上限
int b = -2147483648; //int類型整數的下限
a = a + 1;
b = b - 1;
System.out.println("a=" + a); //輸出結果: a=-2147483648 溢出,結果錯誤。
System.out.println("b=" + b); //輸出結果: b=2147483647溢出,結果錯誤。
如果可能溢出時,把相乘的幾個數中的第一個加上L/l,如果加在最後面,可能數在前面就已經溢出了,再加就沒意義了。
初始化時超多21億多則是編譯錯誤,運算時超過21億多則是溢出。
【數據類型】八種基本數據類型
boolean byte char short int long float double
String 字符串
int[] 非基本的數據類型(引用類型)
byte b1 =20>>>1;
byte b1 = 10;byte b=b1++;
byte b1 = 10, b2 = 20;byte b=(byte)(b1+b2);
【類型轉換】
byte->short->int->long->float->double
char->int->long->float->double
強制轉化:從大類型到小類型需要強制轉換符,語法如下:
因為大類型的精度值大於小類型,取值范圍大於小類型,所以,當使用強制轉化時,有可能會造成精度的損失或者溢出,
所以,在使用強制轉化時要求顯式的告訴編譯器,正在進行強制轉換。
int a = 100;
int b = 200;
long c = a + b; //自動將int轉化為long
long l1 = 1024l;
int i = (int) l1; //需要加強制轉化符由於1024在int的范圍內,所以沒有產生溢出
long l = 1024L * 1024 * 1024 * 4;
int j = (int) l; //會產生溢出
System.out.println(j); // 結果為:0
double pi = 3.1415926535897932384;
float f = (float) pi; //會造成精度的損失,因為單精度的精確度小於double
System.out.println(f); //結果為:3.1415927
如果在一個表達式中出現了多種數據類型,則運算結果會自動的向較大的類型進行轉化,
//由於有long型的直接量參與,整個表達式的結果為long
long distance = 10000 * 365 * 24 * 60 * 60 * 299792458l;
//由於有double型的直接量599.0參與,整個表達式的結果為 double
double change = 800 - 599.0;
//結果為0.0,右邊都是int型數據運算結果也為int類型,結果為0,再賦值給double
型,將0轉化為 0.0
double persent1 = 80 / 100;
//結果為0.8,右邊表達式有double型直接量參與, 運算結果為double型
double persent2 = 80.0 / 100;
int直接量可以直接賦值給byte、char和short,只要不超過其表示范圍。示例如下:
byte b = 97;
short s = 97;
char c = 97;
byte、char、short三種類型參與運算時,先一律轉換成int類型再進行運算。示例如下:
byte b = 97;
int num = b + b; //num的值為194
byte b1=5;
byte b2=6;
//byte b3=b1+b2; //編譯錯誤
byte b3=(byte)(b1+b2);
int b3=b1+b2;
【MyEclipseGen】
先拖入MyEclipse 8.6軟件的一個包內,然後給這個類加一個包名,然後運行,填一個用戶名,回車就可以得到注冊碼
然後在工具欄的MyEclipse中的第五個Subscription Information欄進行注冊。
【運算符】
【算術運算符】
+ - * / % ++ --
%:取模運算 意為取余 例子:5%2 取余為1 ;2%8 取余為2 ;8.567%2 取余為0.567
++/-- : 單獨使用時a++,在前在後無差別;被使用時c=a++,在前在後有差別。
a++>5,是先用a和5來比,之後a再加一;++a>5,是先用a加一,之後再與5來比。
擴展賦值運算符,比較推薦,因為方便。
a += 10; //相當於a=a+10
a *= 2; //相當於a=a*2
字符串拼接運算符
+
若兩邊都是數字,則做加法運算
若有一邊是字符串,則做字符串拼接 例如:(“age=”+age+“歲了”) //age=37
則輸出 age=37歲了
String a=100+“”+300; //“100”+300 輸出100300
String a=”“+100+300; //“100”+300 輸出100300
Steing b=100+300+“”; //400+“” 輸出400
System.out.println(2+2) // 輸出4
System.out.println(‘2’+‘2’) // 輸出100
System.out.println(2+”2“) // 輸出22
【關系運算符】
Java中的關系運算符用於判斷數據之間的大小關系,包括大於(>)、小於(<)、大於等於(>=)、小於等於(<=)、等於(= =)、不等於(!=) 六個運算符。
= =:是等於號; =:是賦值。
【邏輯運算符】
與(&&) 兩個都要對 一個&指不會短路的與
或(||) 兩個只要有一個對 一個|指不會短路的或
非(!) 一個反著來
邏輯運算的結果還是boolean型。
Java邏輯運算中的&&和||有短路的特性,當第一個關系表達式就可以判斷出整個表達式的結果時,就不會再去判斷後面的第二個表達式。
對於“&&”,當第一個操作數為false時,將不會判斷第二個操作數,因為此時無論第二個操作數是什麼最後的結果一定是false;
對於“||”,當第一個操作數為true時,將不會判斷第二個操作數,因為此時無論第二個操作數為何,最後的運算結果一定是true。
示例代碼如下所示:
int i = 100, j = 200;
boolean b1 = (i > j) && (i++ > 100);
System.out.println(b1); // 結果為:false
System.out.println(i); // 結果為:100,發生短路,i++不會被執行
boolean b2 = i > 0 || j++ > 200;
System.out.println(b2); // 結果為:true
System.out.println(j); // 結果為:200,發生短路,j++不會被執行
賦值運算符
字符運算符
三目運算符
一元運算符:! ++ --
二元運算符:+ - * /
三元運算符:
條件運算符又稱“三目”運算符,其結構為:boolean表達式 ? 表達式1:表達式2。
條件運算符的規則如下: //?: ?:
先計算boolean表達式;
如果boolean表達式的值為true,整個表達式的值為表達式1的值;
如果boolean表達式的值為false,整個表達式的值為表達式2的值。
示例代碼如下:
int a = 100, b = 200;
int flag = a > b ? 1 : -1; //因為a>b為false,所以整個表達式的值為-1,將其賦給flag,即:flag的值為-1。
【if】
(1)
int a=scan.nextInt();
if (a>10){
if(a>20){
System.out.println("A");
}else{
System.out.println("B");
}
}else{
System.out.println("C");
}
(2)
if(score>=90) {
System.out.println("A");
} else if (score>=80) {
System.out.println("B");
} else if(score>=60) {
System.out.println("C");
} else {
System.out.println("D");
}
【SWITCH】
int num = 2; //可以用 byte short char int
switch(num) {
case 1:
System.out.println(“呼叫教學部”);
break; //跳出switch
case 2:
System.out.println(“呼叫人事部”);
break;
default: //所有case都沒有匹配時執行。
System.out.println(“人工服務”);
}
從JDK 7.0開始,switch-case可以支持字符串表達式,將更加方便程序的操作。
【循環結構】
(while、do…while、for)
while( boolean表達式 ) {
}
while語句的執行過程為,首先計算boolean表達式的值,而後進行判斷,若值為true則執行語句塊,語句塊執行完後再次判斷boolean
表達式的值,如果為true則繼續執行語句塊,如此循環往復,直到boolean表達式的值為false時退出while循環而執行while之後的語句。
int x = 0;
while ( x < 10 ) {
if ( 5 == x )
{
break;
}
System.out.println(x);
x ++ ;
}
分析上面的代碼得出結論,輸出結果為0 1 2 3 4,因為當x等於5時執行break語句直接退出循環結構了,即if語句塊後面的輸出x的值以及x++不再被執行。
do-while
do-while語句的執行過程為,先執行語句塊,再判斷boolean表達式,如果為true則再次執行語句塊,如此循環往復,直到boolean表達式的
值為false時止。也就是說,do-while語句,無論boolean表達式是否為true,都先執行一次語句塊。
do {
語句塊
} while( boolean表達式 ) ;
注意:while和do-while語句的不同僅僅體現在第一次就不滿足條件的循環中;如果不是這樣的情況,while與do-while可以互換。
示例1:while循環方式
int pwd = 0;
while ( 123 != pwd){
System.out.print(“密碼:”);
pwd = scanner.nextInt();
}
示例2: do-while循環方式
int pwd ;
do{
System.out.print(“密碼”);
pwd = scanner.nextInt();
} while ( 123 != pwd) ;
分析示例1與示例2得出結論,運行結果完全一樣。這是因為兩段代碼第一次的while條件都滿足,此時while與do-whlie可以互換,所以結果完全一樣。
示例3:for循環變量
for ( 表達式1;表達式2;表達式3 ) {
語句塊(循環體)
}
for(int count =0;count<10;count++){ //1 2 3
System.out.println("行動是成功的階梯"); //4
}
例子1.1:
int j = 0;
for(int i = 0;i < 100;i++){
j = j++;
}
System.out.println(j); //輸出j=0
例子1.2:
int j = 0;
for(int i = 0;i < 100;i++){
j++;
}
System.out.println(j); //輸出100
例子:1.3
int j = 0;
int c = 0;
for(int i = 0;i < 100;i++){
c=j++;
}
System.out.println(c); //輸出99
程序運行順序是1 2 4 3 2 4 3 2 4 3 2
for語句,首先計算表達式1,接著執行表達式2,若表達式2的值等於true,則執行大括號中的語句塊,接著計算表達式3,
然後再判斷表達式2的值。依次重復下去,直到表達式2的值等於false。
1可以挪到上面,3可以挪到下面,但分號不可以省。2如果省了就變成無限循環。
for ( int i =1 , j = 6 ; i <= 6 ; i +=2 , j -=2 ) {
System.out.println(“ i , j = “ + i + “,” + j );
}
上面的代碼的執行邏輯如下:
i , j = 1 , 6
i , j = 3 , 4
i , j = 5 , 2
【continue】
continue語句只能用於循環中,它的作用為跳過循環體中剩余語句而執行下一次循環,
int sum = 0;
for(int i=1; i<=100; i++){
if( i % 10 == 3 ){
continue;
}
sum += i;
}
System.out.println(sum);
上面的程序需要統計1到100的累加和,條件是跳過所有個位為3的,此案例通過在if語句中使用continue
實現了跳過for語句中剩余的循環體語句,本程序最終sum的值為: 4570。
int sum = 0;
for(int i=1; i<=100; i++){
if( i % 10 != 3 ){
sum += i;
}
}
System.out.println(sum);
【循環問題】
如果業務可以轉換為“當……“這樣的句式時,優先選擇while語句來實現。
如果業務可轉換為”直到……”這樣的句式時,優先選擇do-while語句來實現。
如果業務中可以獲取到一個確切的循環次數時可以考慮使用for循環來實現,
循環嵌套 外面循環走一次,內面循環走所有次。
【數組】數組是一種非基本的數據類型(引用類型)
數組為相同數據類型的元素組成的集合,數組元素按線性順序排列,所謂線性順序是指除第一個元素外,每一個元素都有唯一的
前驅元素;除最後一個元素外,每一個元素都有唯一的後繼元素(“一個跟一個”),可以通過元素所在位置的順序號(下標)
做標識訪問每一個元素(下標從0開始,最大到元素個數-1)
int[] arr=new int[4]; //一個整型數組 //聲明int型數組arr,包含4個元素。且每個元素都是int型,每個元素默認為0
double[] arr=new int[4]; //聲明double型數組arr,包含4個元素。且每個元素都是double型,每個元素默認為 0.0
boolean[] arr=new int[4]; //聲明boolean型數組arr,包含4個元素。且每個元素都是boolean型,每個元素默認為false
byte short char int long 為0
float double為0.0
boolean 為false
注意char的默認值是0(碼)而不是‘0’(字符)所代表的48.
int[] arr={1,3,5,7}; //4個元素,分別是1,3,5,7
int[] arr=new int[]{1,3,5,7}; //4個元素,分別是1,3,5,7
int[] arr;
arr={1,3,5,7}; //編譯錯誤,{}賦值只能聲明的同時初始化
arr=new int[]{1,3,5,7}; //正確
int[] arr=new int[4];
System.out.println(arr.length); //數組的長度是4 arr.length指數組的長度
int[] arr=new int[]{1,3,5,7};
System.out.println(arr[arr.length-1]); //輸出arr中的最後一個元素
例子:
int[] arr = new int[10];
for ( int i = 0 ; i < arr.length ; i ++ ){
arr [ i ] = 100;
}
正序輸出:
int[ ] arr = new int [ ] {10,20,30,40,50 } ; //正序輸出
for ( int i=0; i< arr.length; i++) {
System.out.println ( arr[ i ] ) ;
}
逆序輸出:
int[] arr5 = new int[] {10,20,30,40,50 } ; //逆序輸出
for ( int i = (arr5.length -1) ; i >= 0 ; i -- ) {
System.out.println ( arr5[ i ] ) ;
}
【數組的復制】
一:System.arraycopy
public static void arraycopy(Object src, int srcPos,Object dest, int destPos, int length)
如上代碼的,每一個參數的意義見下列表:
src:源數組
srcPos:源數組中的起始位置
dest:目標數組
destPos : 目標數組中的起始位置
length:要復制的數組元素的數量
通過下面的代碼,可實現數組的復制:
int[ ] a = { 10 ,20 ,30 ,40 ,50 };
int[ ] a1 = new int[ 6 ] ;
System.arraycopy( a , 1 , a1 , 0 , 4 ); //結果:20,30,40,50
如上方法的意義可以理解為:將a數組的從下標1(第二個)開始的4個元素復制到a1數組中,a1數組從下標0位置開始賦值。
程序執行完後,a1的值為20,30,40,50,0,0。其交互效果如圖 – 3所示:
二:Arrays.copyOf()方法示例代碼如下所示:
int [ ] a = { 10,20,30,40,50 } ;
int [ ] a1 = Arrays . copyOf ( a, 6 );
上段代碼執行後,a1的結果為:10 20 30 40 50 0,分析其執行過程為:聲明一個整型數組,數組變量名稱為a,賦初始值為10 20 30 40 50,
聲明整型數組a1,將a數組數據復制到a1數組,設置其為6個長度,因a數組只有5個元素,所以最後一位補0。故而輸出結果為10 20 30 40 50 0。
總結出Arrays.copyOf()方法的特點如下列表所示:
生成的新數組是原始數組的副本;
newLength小於源數組,則進行截取;(自己通過代碼演示效果);
newLength大於源數組,則用0或 null進行填充;
System.out.println("新數組中的數據"+Arrays.toString(arr)); //顯示整個數組
//新數組中的數據[71, 45, 66, 90, 58, 91, 5, 44, 43, 50, 91]
【排序算法】
常用排序算法有:插入排序、冒泡排序、快速排序等。
long a=System.currentTimeMills();
冒泡算法 //3000毫秒
long b=System.currentTimeMills();
System.out.println(b-a); //得3000毫秒
Arrays.sort(arr)比冒泡排序要塊 //升序排列 arr是函數的名稱
System.out.println("新數組中的數據"+Arrays.toString(arr));
int[] a=new int[]{1,0,1,0,1,5,5,8};
int[] b=new int[]{5,5,98,4,2,3,5,4,5,4,2,5,4};
System.arraycopy(a,0,b,0,5); //a,0,b,0,5(長度不可以長於上面的也不可以長於下面的)
System.out.println(Arrays.toString(b));
【方法】(函數,過程)
方法常常用於封裝一段特定的邏輯功能,例如:執行計算或操作
方法可以在程序中反復被調用,這樣,就可以減少代碼的重復,更便於程序的維護。
oid say() { } //無參方法
void say( string name ) { } //1個參數方法
int sum ( int num1 , int num2 ) { } //2個參數方法
【返回值】
若方法不需要返回數據,將返回值類型聲明為void。
若方法需要返回數據,將返回值類型聲明為特定數據類型。
方法的返回值 取錢 要返回值(返回錢) 存錢 可以沒有返回值,沒有憑條(因為網上數據已經改了)
int num
【參數】
double b=Math.sqrt(9);
有參數
double b=Math.random();
沒參數
public static int sum(int num1 , int num2 ){ }
修飾詞 返回值 方法名 參數 方法體
public static void s(){} //無參,void表示無返回值
sayHello2(); //System.out.println();不需要這個
//無參無返回值
public static void sayHello2(){
System.out.println("大家好,我叫張三");
}
double num=sayHello3(); //
System.out.println(num); //250.25
//無參有返回值
public static double sayHello3(){
return 250.25; //return;編譯錯誤,必須返回一個值 return “wkj”;編譯錯誤,返回值類型不匹配
}
sayHello("zhangsan"); //sayHello();編譯錯誤,沒提供參數 //sayHello(25);編譯錯誤,參數類型不匹配 //System.out.println();不需要這個
//有參無返回值
public static void sayHello(String name){
System.out.println("大家好,我叫"+name);
return; //僅僅表示方法結束
}
int b=sayHello4(2,5);
System.out.println(b);
//有參有返回值
public static int sayHello4(int num1,int num2){
int num =num1+num2;
return num;
}
salary:薪水 demo:演示 var:定義變量 score:成績 DataTypeDemo:數據類型演示 UnitPrice:單價 qty:數量
cost:花費 count:計數 correct:正確的 Error:錯誤 Date:日期 index:下標 array:數組 letter:字母
flag:插旗 cell:格子 info:信息 row:行 col:列 drop:向下 Override:重寫 Overload:重載
area:面積 square:正方形 shape:圖形 circle:圓形 circumference:周長 remove:移動 set:設定
add:增加 subtract:減去 Bill:賬單 drawMoney:取款 getBalance:查詢余額 award:獎品 checkPwd:檢查密碼
IDcard:身份證postalCode:郵編value:價值 compare:比較 matches:比較 util:有用的 regex:正則表達式
identitycard//Pattern:模式 Syntax:語法 Format:格式 Bounds:出界 Cast:造型
${cursor} 光標(用來設置快捷鍵)
Android
RelativeLayout 相對布局
LinearLayout 線性布局
TableLayout 表格布局
FrameLayout 幀布局
GridLayout 網格布局
TableRow 表格行
TextView 顯示文本的組件
Adapter 適配器
stretchColumns 伸展 設置網格的列數
android:stretchColumns="0,1,2"> <!--拉伸使平均分布 -->
android:stretchColumns="1" android:shrinkColumns="1"這兩個屬性是TableLayout所特有的,也是這兩個屬性影響了子對象的布局。 表格布局是按照行列來組...
classCastException:類型轉換異常
class Var{
int a; //實例變量 //屬於成員變量
static int b; //類變量,靜態變量 //屬於成員變量
public void display(String str1){ //參數變量
String str2; //局部變量
}
}
取反 ~3 等於-4
第二本書:面向對象
【面向過程】
面向過程的結構化程序設計
/** 打印員工信息的方法 */
public static void printEmpInfo(String name,int age, //面向過程
char gender,double salary) {
System.out.println("--------------------");
System.out.println("姓名: " + name);
System.out.println("年齡:" + age);
System.out.println("性別:" + gender);
System.out.println("薪水:" + salary);
}
/** 打印雇員信息 */
public static void main (String[ ] args ){
//雇員1
String emp1Name = "黃河大蝦";
int emp1Age = 25;
char emp1Gender = '男';
double emp1Salary = 8000.00;
//打印員工信息
printEmpInfo(emp1Name, emp1Age, emp1Gender, emp1Salary);
//修改員工工資(增長20%)並打印
emp1Salary *= 120.0 / 100.0;
printEmpInfo(emp1Name, emp1Age,emp1Gender, emp1Salary);
}
【抽象數據類型】(自己創造數據類型)
面向對象的第一步就是抽象數據類型,所謂抽象數據類型可以理解為:
將不同類型的數據的集合組成個整體用來描述一種新的事物。像如上程序中,可以將姓名String、年齡int、性別char、工資double這4個不同類型的數據組成一個整體來描述雇員這個新事物。
【面向對象】
【類】 //雇員類,一種數據類型(非基本的)
類定義了一種抽象數據類型,而類不但定義了抽象數據類型的組成(成員變量),同時還定義了對該類型可以實施的操作(方法)。看如下代碼定義了雇員類:
1.類,一種數據類型
2.現實生活中是由很多很多對象組成的
基於這些對象,抽出了類(動物是類,姚明是對象)
3.對象是一個真實的個體。類為類別。
4.類可以包含:
a.所有對象所共有的特征/屬性-------數據(變量)
b.所有對象所共有的行為---------對數據的操作(方法)
5.一個類可以創建多個對象
同一個類創建的對象,結構相同,數據不同。
6.引用類型間畫等號:指向同一個對象; Cell c1=new Cell(); Cell c2=c1; //有new
對一個數據的修改,會影響另一個
基本類型間畫等號:賦值 int a=5; int b=a;
對一個數據的修改,不會影響另一個
7.null:空,不再指向任何對象。不能做任何操作。
/**進一步修改後的雇員類*/
public class Emp{ //面向對象
String name;
int age;
char gender;
double salary;
/**打印信息的方法*/
public void printInfo() { //定義在類中,可直接對成員變量進行操作
System.out.println("--------------------");
System.out.println("姓名: " + name);
System.out.println("年齡:" + age);
System.out.println("性別:" + gender);
System.out.println("薪水:" + salary);
}
}
/**針對修改後的Emp類的使用方式*/
public class EmpManager {
public static void main(String[] args) {
Emp emp2 = new Emp(); // cell c = new cell();
// 類(變量) 引用 對象 //類引用對象 變量引用對象
emp2.name = "白發馍女";
emp2.age = 24; //對象.
emp2.gender = '女';
emp2.salary = 6000;
/**調用方法打印信息*/ //創建完Emp對象後,對其成員變量賦值,然後調
emp2.printInfo(); //用其printInfo()方法打印各個成員變量信息
emp2.salary *= 125.0 / 100.0;
emp2.printInfo();
}
}
java中一個對象引用先後指向兩個對象時,前一個對象是否是被釋放掉?
第一個new的數組對象失去引用,會被垃圾回收器回收
java內存管理機制比較特殊,並不是對象不被引用了就會馬上回收,也就是仍然在內存中,
直到垃圾回收器執行回收操作,不過這些java底層有一套機制,我們暫時不用糾結他什麼時候釋放內存
只要引用釋放掉就可以了
通過上面的代碼,很好的實現了對數據的封裝,並且實現了數據與方法的統一。這種方式即為面向對象方式,即:以對象為中心來構建軟件系統。
成員變量的默認值 //賦初值
定義好類之後,可以創建該類的對象,對象創建之後,其成員變量可以按照默認的方式初始化;對象成員變量的默認初始化值規則如下圖 - 5所示:
byte short int long float double 默認值 0
boolean 默認值 false
char 默認值 \u0000 無
引用類型 默認值 null //String 雇員類 引用數組 默認值 null //基本類型數組的初始默認值為具體值
對象是一個客觀存在的實體,是面向對象編程過程中分析與解決問題的出發點與基礎。對象的實質就是內存中的一塊數據存儲區域,其數據結構由定義它的類來決定。
類是用於構建對象的模板,對象通過類的實例化產生,一個類可以創建多個對象,每個對象擁有自己的數據和行為。
class 類名 {
成員變量類型 變量名稱;
………
返回值類型 方法名稱(參數列表) {
方法體………
}
}
cell c = new cell(); //類引用對象
類 引用 對象
【方法的簽名】
方法的簽名包含如下兩個方面:方法名和參數列表。
Java語法規定,一個類中不可以有兩個方法簽名完全相同的方法,即:一個類中不可以有兩個方法的方法名和參數列表都完全相同,但是,如果一個類的兩個方法只是方法名相同而參數列表不同,是可以的。
【方法的重載】
方法名相同,參數列表不同
class Aoo{
void say(){}
void say(String name){}
void say(String name ,int age ){}
void say(int age,String name){}
//void say(){return 1;} 編譯錯誤和void say(){}重了
// void say(String address){} 編譯錯誤和void say(String name){}重了
}
【構造方法】
通過構造方法初始化成員變量 //沒有返回值
class Cell {
int row ; //成員變量 (堆中)在方法外
int col ; //成員變量
public Cell (int row1 , int col1){ //構造方法不需要返回值 //局部變量(棧中) 在方法內
row = row1; //默認指this.row = row1; 指c1.row=row1; c1.row=15;
col = col1;
}
}
class TestCell {
public static void main(String args[ ] ){
Cell c1 = new Cell( 15 , 6 );
printCell(c1);
}
}
1.常常用於給成員變量賦初值
2.語法與類同名,沒有返回值
3.在創建對象new自動調用
4.若自己不寫構造方法,則系統會提供一個默認的無參構造;若自己寫了,就不在提供空的 Cell c1 = new Cell(); // Cell(){}
5.構造方法可以重載
【this】
1)this.成員變量--------訪問成員變量
2)this.方法名()----調用方法
3)this()------調用構造方法
this用來指代當前對象,哪個對象調用,就指那個對象
在方法中訪問成員變量的前面,默認有一個this //T(int row,int col){ this.cells[0]=new Cell(row,col);}
this在成員變量和局部變量相同時,不能省略
【擴展:(this)】
1.this 是什麼?
this 是一個引用,它的值指向對象,是一個對象的地址。
2.this 用在哪裡?
this 應用在非靜態方法內部,永遠指向調用這個方法的對象。
FAQ? 一個類可以有很多個類的對象
那this具體指向哪個對象呢?
取決於哪個對象調用此方法。
3.this的使用形式?
1)this.屬性/方法
2)this(參數列表): 應用在構造方法內部,
用於調用本類其它構造方法,並且只能寫在第一行。
注意:在內部類中訪問外部類的this時使用"外部類的名字.this";
row++ //默認為this.row++ //指c.row++ this就是指c
1)
class Cell {
int row ; //成員變量 (堆中)在方法外
int col ; //成員變量
public Cell (int row , int col){ //構造方法不需要返回值 //局部變量(棧中) 在方法內
this.row = row; //指c1.row=row; c1.row=15;
this.col = col;
}
}
class TestCell {
public static void main(String args[ ] ){
Cell c1 = new Cell( 15 , 6 );
printCell(c1);
}
}
2)Cell(){
this(0,0); //(0,0)可以寫但沒意義,不能是(0,0,0)
}
等於
Cell(int n){
this(n,n);
}
等於
Cell (int row , int col){
this.row = row;
this.col = col;
例子:
package day28;
class Good {
int a;
int b;
public Good() {
this(00); //沒有這步就是輸出0 0
}
public Good(int a){
this(15,16);
}
public Good(int a, int b) {
super();
this.a = a;
this.b = b;
}
}
class Test0{
public static void main(String[] args) {
Good t= new Good();
System.out.println(t.a+" "+t.b); //15 16
}
}
引用類型數組的聲明
Cell [ ] cells = new Cell [ 4 ] ;
new Cell[4]實際是分配了4個空間用於存放4個Cell類型的引用,並賦初始值為null,而並非是分配了4個Cell類型的對象。
package oo.day02;
public class Array {
public static void main(String[] args) {
int[][] arr=new int[3][4];
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
arr[i][j]=100;
System.out.print(arr[i][j]+" ");
}
}
}
}
【super】
super();調用父類的無參數構造方法。可省略不寫。 // super(5);調用父類的有參數構造方法
super.方法()----調用父類的方法
super.成員變量----調用父類的成員變量
【方法區】【內存】【JVM】
在JAVA中,有java程序、虛擬機、操作系統三個層次,其中java程序與虛擬機交互,而虛擬機與操作系統交互。編譯好的java字節碼文件運行在JVM中。
程序中無論代碼還是數據,都需要存儲在內存中,而java程序所需內存均由JVM進行管理分配,
開發者只需關心JVM是如何管理內存的,而無需關注某種操作系統是如何管理內存的,這就保證了java程序的平台無關性。
JVM會將申請的內存從邏輯上劃分為三個區域:堆、棧、方法區。這三個區域分別用於存儲不同的數據。
堆內存用於存儲使用new關鍵字所創建的對象;
棧內存用於存儲程序運行時在方法中聲明的所有的局部變量;
方法區用於存放類的信息,Java程序運行時,首先會通過類裝載器載入類文件的字節碼信息,經過解析後將其裝入方法區。
類的各種信息(包括方法)都在方法區存儲。
Foo foo = new Foo();
foo.f();
以上代碼的內存實現原理為:
1.Foo類首先被裝載到JVM的方法區,其中包括類的信息,包括方法和構造等。
2.在棧內存中分配引用變量foo。
3.在堆內存中按照Foo類型信息分配實例變量內存空間;然後,將棧中引用foo指向foo對象堆內存的首地址。
4.使用引用foo調用方法,根據foo引用的類型Foo調用f方法。
【堆內存】
【生命周期】
成員變量的生命周期
當聲明好對象之後,對該對象(堆中的Cell)的訪問需要依靠引用變量(棧中的c),那麼當一個對象沒有任何引用時,
該對象被視為廢棄的對象,屬於被回收的范圍,同時該對象中的所有成員變量也隨之被回收。
可以這樣認為,成員變量的生命周期為:從對象在堆中創建開始到對象從堆中被回收結束。
【null】
請看如下的代碼,演示了對象不再被引用:
Cell c = new Cell();
c = null ;
當將c賦值為null時,表示c不再指向剛剛分配的對象空間,此時成員變量失效。 //沒有地址,再不能指向任何東西
Cell c = new Cell();
Cell c1=c; //此時不會被回收,雖然棧中c不再指向堆中Cell,但棧中c1依然指向堆中Cell
c = null ;
【垃圾回收機制】 //堆
垃圾回收器(Garbage Collection,GC)是JVM自帶的一個線程(自動運行著的程序),用於回收沒有任何引用所指向的對象。
GC線程會從棧中的引用變量開始跟蹤,從而判定哪些內存是正在使用的,若GC無法跟蹤到某一塊堆內存,
那麼GC就認為這塊內存不再使用了,即為可回收的。但是,java程序員不用擔心內存管理,因為垃圾收集器會自動進行管理。
【內存洩露】
Java程序的內存洩露問題
內存洩露是指,不再被使用的內存沒有被及時的回收,嚴重的內存洩露會因過多的內存占用而導致程序的崩潰。在程序中應該盡量避免不必要的內存浪費。
GC線程判斷對象是否可以被回收的依據是該對象是否有引用來指向,因此,當確定該對象不再使用時,應該及時的將其引用設置為null,這樣,該對象即不再被引用,屬於可回收的范圍。
【非堆】----【棧】
棧用於存放方法中的局部變量
【生命周期】
局部變量的生命周期
一個運行的Java程序從開始到結束會有多次方法的調用。JVM會為每一個方法的調用在棧中分配一個對應的空間,這個空間稱為該方法的棧幀。
一個棧幀對應一個正在調用中的方法,棧幀中存儲了該方法的參數、局部變量等數據。當某一個方法調用完成後,其對應的棧幀將被清除,局部變量即失效。
main(){
Aoo o=new Aoo();
o.test(55); // 棧幀 正在調用中的方法 存儲了該方法的參數、局部變量等數據。
}
成員變量和局部變量
成員變量與局部變量的差別如下:
局部變量:
1) 定義在方法中;
2) 沒有默認值,必須自行設定初始值;
3) 方法被調用時,存在棧中,方法調用結束時局部變量從棧中清除;
成員變量:
1) 定義在類中,方法外;
2) 由系統設定默認初始值,可以不顯式初始化;
3) 所在類被實例化後,存在堆中,對象被回收時,成員變量失效;
堆內存 非堆----棧 非堆----方法區
【方法區】
方法區用於存放類的信息,Java程序運行時,首先會通過類裝載器載入類文件的字節碼信息,經過解析後將其裝入方法區。類的各種信息(包括方法)都在方法區存儲
方法只有一份
當類的信息被加載到方法區時,除了類的類型信息以外,同時類內的方法定義也被加載到方法區;
類在實例化對象時,多個對象會擁有各自在堆中的空間,但所有實例對象是共用在方法區中的一份方法定義的。意味著,方法只有一份。看如下代碼:
JFrame f1 = new JFrame();
JFrame f2 = new JFrame();
f1.setSize(200, 300);
f2.setSize(300,400);
如上的代碼中,對象有兩個,但是setSize方法只有一份,分別針對f1指向的對象和f2指向的對象調用了兩次。
【繼承】
泛化的過程
前面的案例中定義了T類和J類, 通過分析可以發現, 在這兩個類中存在著大量的重復代碼,像cells屬性、print方法、drop方法、
moveLeft方法、moveRight方法,在這兩個類中都存在,並且實現上基本也是相同的,本著代碼重用的原則,可以使用繼承的方式來實現。
首先,構建T類和J類的父類Tetromino類,將公共的(T類和J類公有的)信息存放在父類中, T類和J類繼承Tetromino父類。此時,子類即可以共享父類的數據。這個過程就是泛化的過程。
【extends】關鍵字
使用繼承可以實現代碼的重用,在java語言中,需要通過extends關鍵字實現類的繼承。繼承完成後,
子類(Sub class)可以繼承父類(Super class)的成員變量及成員方法,同時子類也可以定義自己的成員變量和成員方法。屆時,子類將具有父類的成員及本類的成員。
需要注意的是,Java語言不支持多重繼承,即:一個類只能繼承一個父類,但一個父類可以有多個子類。看下面的代碼:
【繼承】:
目的:避免代碼重復;
通過:extends;
父類:所有子類所共有的
子類:子類所獨有的
一個子類只能繼承一個父類;
繼承具有傳遞性a繼承->b; b繼承->c;
【System.gc()方法】
GC的回收對程序員來說是透明的,並不一定一發現有無引用的對象就立即回收。一般情況下,當我們需要GC線程即刻回收無用對象時,
可以調用System.gc()方法。此方法用於建議JVM馬上調度GC線程回收資源,但具體的實現策略取決於不同的JVM系統。
分析上面的代碼,在子類構造方法中沒有寫super調用父類構造方法,這時編譯器會默認添加super()來調用父類的無參構造方法,但是父類中又沒有定義無參的構造方法,因此會發生編譯錯誤。
針對上面的問題,可以有兩種解決方案,方案一為在父類中添加無參的構造方法,
方案二為在子類構造方法中顯示調用父類的有參構造方法(常常使用),這樣可以保證父類的成員變量均被初始化,參見下面的代碼:
class Goo extends Foo {
int num;
Goo(int value, int num) {
super(value);
this.num = num
}
}
【向上造型】
//動物是動物
Animal 01=new Animal();
//老虎是老虎
Tiger 02= new Tiger();
//一個新的老虎是動物
Animal 03= new tiger();
//動物是老虎 //編譯錯誤,邏輯錯誤
Tiger 04=new Animal();
【向上造型】
(1)
Same t =new SameT(5, 5); //向上造型
printwall(t); //向上造型後傳值
public static void printwall(Same same) { }
(2)
SameJ j= new SameJ(3,4);
printwall(j); //傳值的同時向上造型
public static void printwall(Same same) { }
(A)
class Moo{
int m;
void show(){}
}
class Zoo extends Moo{ //隱藏一個Zoo(){super();} 隱藏一個無參構造,默認super();調用父類的無參數構造方法
int n;
void say(){}
}
Moo a=new Zoo(); //一個子類到父類
a.m=1;
a.show();
// a.n=2; //編譯錯誤,只能點出父類的,能點出什麼看類型,左邊的。
///////
Zoo b=new Zoo(); //子類是子類 全可以點出來
b.m=1;
b.show();
b.n=2;
b.say();
Moo c=new Moo(); //父類是父類
c.m=1;
c.show();
//c.n=2; //編譯錯誤,
//c.say(); //編譯錯誤,
(B)
int row; // 行號
int col; // 列號
Cell(int row,int col){ //有參構造方法
this.row=row;
this.col=col;
}
Cell(int n){ //有參構造方法
this(n, n+1);
}
Cell(){ //無參構造方法
this(0,0);
}
【父類】
父類的構造方法不是被繼承的,而是被調用的。
【重寫】
在java語言中,子類可以重寫(覆蓋)繼承自父類的方法,即方法名和參數列表與父類的方法相同,但是方法的實現不同。
Person p1 =new Person();
p1.sayHi(); //調用父類Person的。
Student s1=new Student();
s1.sayHi(); //調用子類Student的。
當子類重寫了父類的方法後,該重寫方法被調用時(無論是通過子類的引用調用還是通過父類的引用調用),運行的都是子類重寫後的版本。看如下的示例:
class Foo {
public void f() {
System.out.println("Foo.f()");
}
}
class Goo extends Foo {
public void f() {
System.out.println("Goo.f()");
}
}
class Test{
public static void main(String[] args){
Goo obj1 = new Goo();
obj1.f();
Foo obj2 = new Goo();
obj2.f();
}
}
分析代碼得出結論:輸出結果均為“Goo.f()”,因為都是Goo的對象,所以無論是子類的引用還是父類的引用,最終運行的都是子類重寫後的版本。
1.兩同:方法名,參數列表相同
2.1)子類返回值類型小於或等於父類的:
1.1)父類void ------子類也必須是void
1.2)父類八種基本類型 ---子類也必須是八種基本類型
1.3)父類引用類型-------子類返回值類型小於或等於父類的
2)子類方法拋出的異常小於或等於父類
3.子類的訪問權限大於或等於父類
【重載重寫】
重載Overload: 是指在一個類中定義多個方法名相同但參數列表不同的方法,在編譯時,根據參數的個數和類型來決定綁定哪個方法。看類型(編譯器)
重寫Override: 是指在子類中定義和父類完全相同的方法(方法名,參數列表都相同),在程序運行時,根據對象的類型(而不是引用類型)而調用不同的方法。看對象(運行器)
向上造型能點出什麼看類型 強制類型轉換 看對象
【包的概念】package語句
定義類時需要指定類的名稱,但是如果僅僅將類名作為類的唯一標識,則不可避免的出現命名沖突問題,
這會給組件復用以及團隊間的合作造成很大的麻煩!因為原則上來說,類名是不可以重復的。
在Java語言中,命名沖突問題是用包(package)的概念來解決的,也就是說,在定義一個類時,除了定義類的名稱一般還要指定一個包的名稱,定義包名的語法如下所示:
package 包名;
需要注意的是,在定義包時,package語句必須寫在Java源文件的最開始處,即在類定義之前,如下面的語句將為Point類指定包名為“test”:
package test;
class Point{
……
}
一旦使用package指定了包名,則類的全稱應該是“包名.類名”,如上語句的Point類的全稱為test.Point。
使用package即可以解決命名沖突問題,只要保證在同一個包中的類名不重復即可,而不同的包中可以定義相同的類名,
例如:test1.Point和test2.Point是兩個截然不同的名稱,雖然類名相同,但包名不同,亦表示兩個完全不同的類。
在命名包名時,包名可以有層次結構,在一個包中可以包含另外一個包,可以按照如下的方法定義package語句:
package 包名1.包名2…包名n;
org.apache.commons.lang.StringUtil
如上類的定義可以分為4個部分,其中,StringUtil是類名,org.apache.commons.lang是多層包名,其含義如下:org.apache
表示公司或組織的信息(是這個公司或組織域名的反寫);commons表示項目的名稱信息;lang表示模塊的名稱信息。
同一個包內的類,可以直接引用
不同包內,不可以直接引用
要用 import 包名+類名 //引用兩個同類名的類時 import p1.Aoo; import p2.Aoo; //p1.Aoo a=new p1.Aoo() ; p2.Aoo a=new p2.Aoo() ;
完全限定名 包名+類名 ---不建議p1.Aoo a=new p1.Aoo() ;
【封裝】
封裝的意義就是提供可調的穩定的功能
降低代碼出錯的可能性,更便於維護。
當內部實現細節改變時,只要保證對外的功能定義不變,其他的模塊不需要更改。
在軟件系統中,封裝常常需要依靠一些訪問控制修飾符來實現。
【訪問修飾符】
public:公共的,任何地方都可以
protected:受保護的,本類,子類,同包類
默認的:什麼也不寫, 本類,同包類
private:私有的,本類
類只能用public或默認的來修飾
類中的成員或方法都可以
【static】 靜態的
1. static修飾成員變量 靜態變量
1.1)屬於類的,而不屬於對象
1.2)和類的信息一起存儲在方法區,只有一份。
1.3)常常通過;類名來訪問
1.4)何時用:所有對象都一樣時
// Students.classname="JSD1503";
class Same { // 類的共同點,被繼承的父類
Cell[] cells;
static int size; //
Same() {
this.cells = new Cell[4];
Same.size=100; //
System.out.println(Same.size);
}
}
2. static修飾方法 靜態方法
2.1)沒有this傳遞
2.2)靜態方法中不能直接訪問實例成員
可以直接訪問靜態成員 //但非static靜態方法可以訪問static成員(方法)
2.3)常常通過類名來訪問
2.4)何時用:方法的操作與對象無關與成員變量無關,而僅與參數相關 //很少用 //Math.random();
3. static塊 靜態塊
3.1)static塊為屬於類的代碼塊,在類加載期間執行的代碼塊,只執行一次,因為類只加載一次
3.2)可以用來在軟件中加載靜態資源(圖像、音頻等等)。
成員變量可分為
實例變量 不用static修飾
靜態變量 static修飾
靜態變量輸出時,可以通過類名來訪問
Ioo o1=new Ioo();
System.out.println(Ioo.b) ; //類.
System.out.println(o1.b) ; //可以但不建議
//方法中訪問成員變量前面默認有個this
實例成員必須通過對象.來訪問
靜態方法沒有隱式this
【final】
1)修飾變量:變量不可以被修改
1.1)成員變量: 聲明同時初始化 構造方法中初始化 //之後就不可以在其他方法中改變其值的大小,不然就是編譯錯誤
A)
class Loo{
final int a=100; //聲明同時初始化
final int b;
Loo(){
b=200; //構造方法中初始化
}
void show(){
final int c; //用之前初始化即可 局部變量
//a=250; //編譯錯誤,不可被修改
}
}
B)
public class Emp {
private final int no = 100; // final成員變量聲明時初始化
public static void main(String[] args) {
no = 99;
}
}
如上的語句,no=99會出現編譯期錯誤,因為final的變量不可被改變。
1.2)局部變量:在使用之前初始化即可
2)修飾方法:方法不可以被重寫 //可以重載,不可以被重寫
class Moo{
void show(){}
final void say(){}
void say(int a){}
}
class Noo extends Moo{
void show(){}
// void say(){} //無法被重寫
}
3)修飾類:類不可以被繼承
final class Moo{ //可以繼承別人
void show(){}
final void say(){}
}
/*
class Noo extends Moo{ //Moo不能被繼承
void show(){}
}
*/
【static final常量】
static final 修飾的成員變量稱為常量,必須聲明同時初始化,並且不可被改變。常量建議所有字母大寫。
實際應用中應用率較廣,因為static final常量是在編譯期被替換的,可以節約不必要的開支,如下代碼演示了static final的用法:
class Foo {
public static final int NUM = 100; //public final static int NUM = 100; static 和 final二者的前後順序不限。
}
class Goo {
public static void main(String[] args) {
System.out.println(Foo.NUM); //類.
// 代碼編譯時,會替換為:System.out.println(100);
}
}
說明:static final常量Foo.NUM會在編譯時被替換為其常量值(100),在運行Goo類時,Foo類不需要被載入。這樣減少了不必要的開支。
【順序】
新建引用了一個子類時:
父類靜態塊
子類靜態塊
父類成員變量
父類構造方法
子類成員變量
子類構造方法
//通過類調用靜態方法時,會先加載類 //Config.getIntValue("port");
//靜態方法不會被加載
//靜態塊和靜態成員變量按順序加載,哪個在前面先運行哪個
//靜態塊內有方法的話,會運行這個方法
【抽象類】【抽象方法】
抽象方法:由abstract修飾的方法為抽象方法,抽象方法即只有方法的定義,沒有方法體實現,用一個分號結尾。
即方法五要素中,抽象方法缺少了一個要素(即:方法體)。也可以將抽象方法理解為不完整的方法。
若將抽象方法包含在類中,則該類也應該為抽象的,可以理解為,該類也不完整。抽象類由abstract關鍵字聲明。
抽象類是不能實例化對象的,而一個類不能實例化是沒有意義的,所以,需要定義類來繼承抽象類,而如果一個類繼承了抽象類,
則其必須重寫其抽象方法(變不完整為完整),除非該類也聲明為抽象類。看下面的代碼,定義了抽象方法和抽象類:
沒有抽象方法,也可以生成抽象類
abstract class Shape {
private double c;
public Shape(double c) {
this.c = c;
}
public abstract double area();
}
通過上面的代碼可以看到,area()方法沒有方法體(連大括號也不存在),由abstract修飾,此為抽象方法。而Shape方法也由abstract修飾,即為抽象類。
【抽象類不可以實例化】
抽象類不可以實例化,若Shape是抽象類的話,下面的代碼是錯誤的: 不可以創建對象,但可以創建數組 Shape[] s1 = new Shape[4];
// Shape s1 = new Shape(); //代碼是錯誤的
即使一個類中沒有抽象方法,也可以將其定義為抽象類,同樣,該類不可以實例化。
需要注意一點:abstract和final關鍵字不可以同時用於修飾一個類,因為final關鍵字使得類不可繼承,而abstract修飾的類如果不可以繼承將沒有任何意義。兩者放在一起,會起沖突。
【設計原則】
1.只要是幾個類共有的方法,就搞到父類中。
2.所有子類的工作(方法)都一樣時用普通方法
所有子類都不一樣時用抽象方法。
3.符合既是也是關系時,使用接口。
----接口是對繼承單根性的擴展
【繼承抽象類】
一個類繼承抽象類後,必須實現其抽象方法,不同的子類可以有不同的實現。看下面的代碼,Square類與Circle類
都繼承自Shape類,並分別實現了重寫的area()方法,只是其具體實現的代碼不同:
class Square extends Shape {
private double c;
public Square(double c) {
super(c);
}
public double area() {
return 0.0625*c*c;
}
}
class Circle extends Shape{
private double c;
public Circle(double c) {
super(c);
}
public double area() {
return 0.0796*c*c;
}
}
【抽象類的意義】
定義抽象類的意義在於:
為其子類提供一個公共的類型(父類引用指向子類對象); 公共的入口
封裝子類中的重復內容(成員變量和方法);
定義有抽象方法,子類雖然有不同的實現,但該方法的定義是一致的。(子類需要實現此抽象方法)。
看如下的代碼:
Shape[] sArr = {new Circle(100), new Square(100),
new Circle(200), new Square(150) };
for(int i=0; i<sArr.length; i++) {
Shape shape = sArr[i];
System.out.println(shape.area());
}
通過上面的代碼可以看出,以Shape類型的引用訪問其子類,所有子類都會有area方法,只是其具體的實現各不一樣。
【接口】 接口可以申明 成員變量 和int int[] 類一樣
1)是一個標准,規范
實現了接口,就能干某件事-------API後就能體會
2)由interface定義
3)接口中只能包含常量(默認)和抽象方法(默認)
interface Inter{ //只有interface是默認public權限
public static final int NUM=5;
public abstract void show();
double Pi=3.14159; // 默認public static final
void say(); //默認public abstract
}
4)接口不能被實例化 //接口不能被實例化 抽象類不可以實例化
5)接口也需要被實現(繼承)。實現類(子類)
5.1)必須實現接口中的所有抽象方法
class Aoo implements Inter{
public void show(){} //必須要加public 不然會默認為默認權限,而比父類的默認public權限小
//子類的訪問權限大於或等於父類
}
6)繼承只能繼承一個類,但實現可以實現多個接口。用逗號分開,若又繼承又實現接口時,必須先繼承再實現
7)接口間可以繼承(接口和接口叫繼承,類和接口叫實現)
class AmericanCurl implements Runner , … {
public void run() {
System.out.println("run...");
}
}
另外需要說明的一點,接口可以作為一種類型聲明變量,一個接口類型的變量可以引用實現了該接口的類的對象;
通過該變量可以調用該接口中定義的方法(具體的實現類提供了方法的實現)。代碼如下所示:
Runner runner = new AmericanCurl();
此句代碼為,一個接口類型變量,引用了子類的對象。調用時,調用的是子類對象的具體的實現。
抽象類和接口都不能實例化對象,用於被其他類繼承和實現。
接口裡只能包含抽象方法,抽象類則可以包含普通方法和抽象方法。
接口裡不包含構造器;抽象類裡可以包含構造器,抽象類裡的構造器並不是用於創建對象,而是讓其子類調用這些構造器來完成屬於抽象類的初始化操作。
一個類只能有一個直接父類;但一個類可以直接實現多個接口,實現多繼承。
【接口和抽象類的區別】
抽象類和接口的區別:
1)一個類只能繼承一個抽象類,但可以實現多個接口。
2)抽象類中可以包含抽象方法和非抽象方法,而接口中的所有方法均為抽象的。
3)子類繼承抽象類必須實現抽象類中所有抽象方法,否則子類也必須是抽象類。而子類實現接口則必須實現接口中的所有抽象方法。
【oop】
面向對象編程(Object Oriented Programming,OOP,面向對象程序設計)是一種計算機編程架構。
【多態】 //父類運行時指向不同的子類
優點:保證可維護性,實現低耦合
首先,一個類型的引用在指向不同的對象時會有不同的實現,看如下的代碼:
達內職員 emp1 = new 達內講師();
達內職員 emp2 = new 達內項目經理();
emp1.完成工作();
emp2.完成工作();
同樣是達內職員類型,當指向不同的對象時,可以有不同的表現。
其次,同樣一個對象,造型成不同的類型時,會有不同的功能,看如下代碼所示:
達內講師 teacher = new 達內講師();
企業技術顧問 consultant = teacher; // teacher = new 達內講師(); //teacher 達內講師 類型
技術圖書作者 author = teacher; // teacher = new 達內講師(); //teacher 達內講師 類型
consultant.培訓員工();
author.編輯稿件();
通過上面的代碼,可以看出,同樣的達內講師對象,當將其造型為企業技術顧問及技術圖書作者時,可以實現不同的功能。
2.向上造型
1)能向上造型為:父類,實現的接口
2)能點出什麼看類型
【數據類型轉換】
1.自動類型轉換:小類型轉換到大類型
2.強制類型轉換:大類型轉換到小類型
引用類型:父類大,子類小
強制類型轉換成功的條件
1)引用所指向的對象就是該類型
2)引用所指向的對象實現了該接口
強制類型轉換失敗會發生ClassCastException(類型轉換異常)
所以在強轉之前使用instanceof判斷
Aoo o =new Boo();
Boo o1 =(Boo)o; //引用o所指向的對象(new Boo())就是該類型Boo //強制類型轉換 看對象
Inter1 o2=(Inter1)o; //引用o所指向的對象(new Boo())實現了該接口
//Coo o3=(Coo)o; //編譯錯誤 ClassCastException(類型轉換異常)
instanceof返回boolean型結果,若true,則成功 // System.out.println(o instanceof Boo); //true 則成功
或if(o instanceof Boo){Boo o1=(Boo)o;}
interface Inter1{
}
class Aoo{
}
class Boo extends Aoo implements Inter1{
}
class Coo extends Aoo{
}
【內部類】 //內部類應用率比較低 //成員內部類
一個類可以定義在另外一個類的內部,定義在類內部的類稱之為Inner內部類,其所在的類稱之為Outer外部類;
Inter定義在Outer的內部,通常只服務於Outer,對外不具備可見性,
Inter可以直接調用Outer的成員及方法(包括私有的)。看如下代碼:
class Outer{
private int time;
class Inner{
public void timeInc(){
time++;
}
}
}
內部類對象會在外部類中創建(構造方法或其他方法)
public class Line{
private Point p;
public class{
p=new Point(); // p=this.new Point();
}
public class Point{}
}
從上面的代碼可以看出,在Outer類之中聲明了Inner類,在Inner類中直接操作了Outer類的私有成員變量time。
內部類中也有獨立的Outer$Inner.class //Mama$Baby.class
實例內部類
靜態內部類,
局部內部類,
匿名內部類
package day28;
public class DemoClass {
class A{ //實例內部類
}
static class B{ //靜態內部類
String name ="lisi";
void f(){
System.out.println(name);
}
}
public static void doClick(){
class C{ //局部內部類
String name ="zhangsan";
}
C c=new C(); //只能在局部內新建,在其他地方無法新建
System.out.println(c.name);
}
public static void main(String[] args) {
/*DemoClass d=new DemoClass(); //實例內部類
A a=d.new A();*/
A a=new DemoClass().new A();//實例內部類
B b= new DemoClass.B(); //靜態內部類
//B b= new B(); //靜態內部類
Runnable d = new Runnable() { //匿名內部類
@Override
public void run() {
// TODO Auto-generated method stub
}
};
}
}
【局部內部類】
final Thread ta =new Thread(){ } //局部內部類想訪問方法內的變量時,要用final修飾。 //不是成員
【匿名內部類】 //應用率比較高
如果在一段程序中需要創建一個類的對象(通常這個類需要實現某個接口或者繼承某個類),而且對象創建後,
這個類的價值也就不存在了,這個類可以不必命名,稱之為匿名內部類。看下面的代碼:
SuperType obj = new SuperType (…) {
… … …
};
其中,第一個SuperType為用匿名類所實現的接口或所繼承的父類類型聲明的引用;
第二個SuperType為匿名類所要實現的接口或繼承的父類;小括號()中為構造方法參數;大括號中為匿名中定義的成員變量或方法。
請參見下面的代碼:
public interface Action { //接口
public void execute(); //抽象方法
}
public class Main {
public static void main(String[] args) {
Action action = new Action(){
public void execute() {
System.out.println("Hello, World");
}
};
action.execute();
}
}
如上的代碼中,創建了實現了Action接口的內部匿名類對象,並調用其execute方法。
匿名內部類中訪問外部成員,該成員必須加final修飾
匿名內部類中也有獨立的NstInnerDemo$1.class NstInnerDemo$2.class
面向對象
1)封裝:保護數據
1.1)類---封裝的對象的特征和行為
1.2)方法----封裝的功能的具體的實現
1.3)訪問修飾符----封裝的是成員的訪問權限
2)繼承:代碼的重用
2.1)所有子類所共有的特征和行為----父類中
特有的特征和行為----子類
2.2)繼承後,子類具有自己特有的以及父類共有的
3)多態:
3.1)意義:
3.1.1)同一類型引用指向不同對象時有不同的實現
3.1.2)同一個對象被塑造為不同的類型時,有不同的功能
3.2)變現形式:重寫,重載
3.3)向上造型
3.3.1)父類的引用指向子類的對象
3.3.2)能點出什麼看類型
3.3.2)重寫看對象
【字符串轉換】 //字符串類型轉換為其他類型
int choice=Integer.parseInt(scan.next()); //把字符串轉換成int型整數 字符串整數
double num = Double.parseDouble(scan.next()); //把字符串轉換成雙精度浮點型 字符串雙精度浮點型
String str = scan.next().trim().toUpperCase(); // if (str.equals("EXIT")) {break;}
char[] input = str.toCharArray(); //把字符串轉換成char[]字符數組 字符串字符數組
byte[] date =str.getBytes(); //將當前字符串按照系統默認字符集轉換為對應的字節數組 //搜索Stringbyte //可加("GBK")
String a=scan.nextLine();
【使用圖片的類】
import java.awt.image.BufferedImage;
圖片可以從外面直接拖進eclipse的包內
【隨機整數】
import java.util.Random;
Random rand = new Random ();
x=rand.nextInt(ShootGame.WIDTH-this.width);
x=(int)(Math.random()*(ShootGame.WIDTH-this.width));
【JFrame】:窗口----相框
【JPanel】:面板
數據放在面板上
面板放在窗口上
import javax.swing.JFrame;
import javax.swing.JPanel;
【定時器】
private Timer timer; //定時器
private int intervel =10; //時間間隔(毫秒)
//靜態,沒有隱式this,與對象無關,與參數有關
public static FlyingObject nextOne(){ //工廠方法 //隨機生成蜜蜂和敵機
Random rand =new Random();
int type=rand.nextInt(20);
if(type==0){ //蜜蜂的概率小
return new Bee();
}else{
return new Airplane();
}
}
int flyEnteredIndex=0;
public void enterAction(){ //10毫秒走一次
flyEnteredIndex++;
if(flyEnteredIndex%40==0){
FlyingObject obj=nextOne();
flyings=Arrays.copyOf(flyings, flyings.length+1); //擴容
flyings[flyings.length-1]=obj; //把新產生的敵人加到flyings數組的最後一個
}
}
public void stepAction(){
}
public void action(){
timer =new Timer();
//抽象類TimerTask的對象,不能直接new,因為是抽象的,所以用匿名內部類,
//第一個10指程序啟動到第一次觸發的間隔 //第二個10指第一次和第二次觸發的間隔
timer.schedule(new TimerTask(){
//可以自動進行的程序放在run()裡面。
public void run(){ //定時干的事(10毫秒走一次)
enterAction(); //敵人(敵機和小蜜蜂)入場
stepAction(); //飛行物走一步
}
}, intervel,intervel);
}
【paint()】方法的調用
1.frame.setVisible(true); //1.設置窗口可見 2.盡快調用paint()方法
2.repaint(); //重畫(自動調用paint()方法)
【監聽器】
private Timer timer; //定時器
private int intervel =10; //時間間隔(毫秒)
public void action(){ //運行一次
MouseAdapter l =new MouseAdapter(){ //【監聽器】
public void mouseMoved(MouseEvent e){ //鼠標移動,就會進入這個程序
if(state==RUNNING){ //1
int x=e.getX();
int y=e.getY();
hero.moveTo(x, y); //英雄機坐標和鼠標坐標結合起來
}
}
public void mouseClicked(MouseEvent e){ //鼠標點擊,就會進入這個程序
switch(state){
case START: //0
state=RUNNING; //1
break;
case GAME_OVER: //3
hero=new Hero(); //清理現場
flyings=new FlyingObject[0];
bullets=new Bullet[0];
score=0;
state=START; //0
break;
case RUNNING:
state=PAUSE;
break;
case PAUSE:
state=RUNNING;
break;
}
}
public void mouseExited(MouseEvent e){ //鼠標出去,就會進入這個程序
if(state==RUNNING ){ //1
state=PAUSE; //2
}
}
public void mouseEntered(MouseEvent e){ //鼠標進入,就會進入這個程序
if(state==PAUSE){ //2
state=RUNNING; //1
}
}
};
this.addMouseListener(l); //this 指代game //監聽器放入面板
this.addMouseMotionListener(l);
timer =new Timer();
//抽象類TimerTask的對象,不能直接new,因為是抽象的,所以用匿名內部類,
//第一個10指程序啟動到第一次觸發的間隔 //第二個10指第一次和第二次觸發的間隔
timer.schedule(new TimerTask(){ //定時器
//可以自動進行的程序放在run()裡面。
public void run(){ //定時干的事(10毫秒走一次)
if(state==RUNNING){ //1
enterAction(); //敵人(敵機和小蜜蜂)入場
shootAction(); //子彈入場
stepAction(); //飛行物走一步
bangAction(); //敵人和子彈碰撞
outOfBoundsAction();//刪除越界的敵人和子彈
checkGameOverAction(); //檢查游戲是否結束
}
repaint(); //重畫(自動調用paint()方法)
}
}, intervel,intervel);
}
事件:
1.鼠標移動事件:英雄機隨之移動
mouseMoved
2.鼠標點擊事件:啟動狀態變為運行狀態
mouseClicked
3.鼠標移開事件:運行狀態變為暫停狀態
mouseExited
4.鼠標移入事件:暫停狀態變為運行狀態
mouseEntered
對面板操作
【顏色】 零
g.setColor(new Color(0xff0000));//0xff0000純紅色 0x0000ff藍色 0x00ff00綠色
【文字】
Font font =new Font(Font.SANS_SERIF,Font.BOLD,14);//字體 加粗 大小
g.setFont(font);
第三本書
【API】
JAVA核心API(上)
JDK根據提供的功能不同,將類庫劃分為若干個包,
java.io包:比如用於操作輸入輸出的java.io包, //input output
java.lang:java程序語言設計基礎類的java.lang包, //如:字符串,多線程。使用頻率高不用導入,可以直接使用
java.math:提供各種數學運算的java.math包,
java.net:基於網絡應用的java.net包,
java.util:以及一些共用程序類所在的java.util包等等。
java.security:安全相關操作
java.sql 數據庫訪問
java.text 處理文字,日期,數字,信息的格式
【文檔注釋】
/**.......*/ 文檔注釋 加在類和方法的開頭,用於說明作者,時間,版本,要實現功能的詳細描述等信息
通過javaoc工具,可以輕松的將此注釋轉換為HTML文檔說明;學習者和程序員主要通過文檔了解API的功能
(//..... 或 /*.... */) 普通注釋
普通注釋寫在程序之中,用於程序員進行代碼維護和交流,無法通過工具生成文檔,而
文檔注釋寫在類和方法的開頭,專門用於生成供API使用者進行參考的文檔資料
Export---Java---Javadoc---生成文檔資料
【字符串類】 //lang包
【字符串】String不能被繼承 //String學習
由於字符串在實際開發中被廣泛使用,那麼在頻繁使用某個字符串時,會出現頻繁創建一個字符串對象的現象,
java為此對字符串的使用采用了一個優化措施,使得String對象為不可變對象,一旦在內存中創建,內容不能發生變化,
若要對字符串內容改變,那麼就會創建新對象。這樣做的目的是可以最大程度的重用相同內容的字符串以減小系統資源的開銷。
出於性能的考慮,JVM會將字符串直接量對象緩存在常量池中;對於重復出現的字符串直接量,JVM會首先在常量池中查找,如果存在即返回該對象。
如果是使用new關鍵字創建的字符串,則不會緩存在常量池中,使用new關鍵字將會創建新的String對象。
String str="HelloWorld"; //特權:字面量 直接量 引用類型String且不用new
int a=1;
String str1="HelloWorld";
String str2="HelloWorld";
System.out.println(str1==str2);
輸出:true //str1,str2指向同一個對象,沒有新建
str2=str2+"!"; //改變之後會新建一個字符串String
System.out.println(str1+" "+str2);
System.out.println(str1==str2);
輸出:HelloWorld
HelloWorld!
false
String s1="123abc";
String s2="123abc";
String s3="123"+"abc"; //java編譯器在編譯代碼時有個優化措施:當一個計算代表式中計算符兩邊的內容都是字面量
//編譯器會將其進行運算然後將結果寫入字節碼文件中。所以下面的表達式在字節碼文件中的樣子是:
//String s3="123abc";
System.out.println(s1==s2); //true
System.out.println(s1==s3); //true
String s4=1+'2'+3+"abc"; //如果是“2”就等 //s4=54abc; //如果是1 + 2 + "3"+ "abc",則為33abc
System.out.println(s1==s4); //false
String s5="123";
String s6=s5+"abc"; //不是兩邊都是字面量,無法在編譯時就計算
System.out.println(s1==s6); //false
if(s1.equals(s6)){ //true
System.out.println(123);
}
String s7=new String("123abc"); //直接新建一個,所以和原來的就不是同一個
System.out.println(s1==s7); //false
【length()】 //長度
String str ="我愛java";
System.out.println(str.length()); //字符長度 輸出6
//數組的.length後面沒有(),字符串的.length後面有()。
使用Java中的String類的length方法計算字符串的長度,無論中文還是英文都算1個長度。
另外,在Java中,字符在內存裡采用的是Unicode編碼,每個字符占用兩個字節,請注意區別。
【indexOf()】 //通過字母找下標索引
int indexOf(String str)
* 查看給定字符串在當前字符串中的位置
* 若當前字符串中包含給定字符串,會返回給定字符串第一個字符在當前
* 字符串中的位置,若當前字符串不含給定字符串,則返回-1
String str ="thinking in java";
int index=str.indexOf("java"); //如果是in,則輸出2
System.out.println(index);
輸出12,從零開始,空格也算一個
//從下標(0123)是3,個數第四個字符開始尋找第一次出現in的位置
String str ="thinking in java";
int index=str.indexOf("in",3);
System.out.println(index); //輸出5
【lastIndexOf()】
/**
* int lastIndexOf(str)
* 查找最後一次出現給定字符串的位置
* */
String str ="thinking in java";
int index=str.lastIndexOf("in");
System.out.println(index); //輸出9
【substring()】 //獲得 截取
/**
* String substring(int start,int end );
* 截取當前字符串中指定范圍內的子字符串
* java API中,有一個特點
* 用兩個數字表示范圍時,通常是 //含頭不含尾<=x<
* 下面的參數就是:包含11位置的字符,但不包含17位置的字符
* */
String str ="http://www.oracle.com";
String sub=str.substring(11,17); //只有11一個參數時,輸出oracle.com
System.out.println(sub); //輸出oracle
可以只填一個 //只有11一個參數時,輸出oracle.com
String sub=str.substring(11);
/**
* 獲取一個URL的域名
* 思路:截取地址中第一個“.”與第二個"."之間的字符串即可
* 步驟:
* 1.找到第一個"."的位置
* 2.找到第二個"."的位置
* 3.截取第一個點後面的第一個字符開始,到第二個點的位置的所有字符
*/
String url="http://www.tarena.com.cn";
int start =url.indexOf(".");
int end =url.indexOf(".",start+1);
String name=url.substring(start+1,end);
System.out.println(name); //輸出tarena
最後一個“/”後的所有字符
String str="someapp/manager/emplist.action";
int index=str.lastIndexOf("/");
String sub=str.substring(index+1,str.length());
System.out.println(sub); //輸出:emplist.action
【trim()】 //去掉左右兩邊“空白”,中間的不會去除
/**
* String trim();
* 該方法就是將當前字符串中左右兩邊的“空白”去掉,中間的不會去除
* trim方法一般用於去除用戶輸入信息中的前後空白以及處理文件內容時,去除文件中的空白。
* */
String str=" hel lo ";
String trim=str.trim();
System.out.println(str);
System.out.println(trim);
輸出:
hel lo
hel lo
【charAt()】 //通過下標索引找字母
/**
* char charAt(int i);
* 返回當前字符串中給定位置處對應的字符
* */
String str ="thinking in java";
char c=str.charAt(9);
System.out.println(c); //輸出i
/**
* 檢查一個字符串是否為“回文”;
* */
String str= "上海自來水來自海上";
for(int i=0;i<str.length()/2;i++){
if(str.charAt(i)!=str.charAt(str.length()-i-1)){
System.out.println("不是回文");
return; //返回,不再執行下面的部分,前提是返回值為void。也可以用開關來設定
}
}
System.out.println("是回文");
【startsWith()】【endsWith()】 //判斷以什麼開頭,以什麼結尾
/** boolean startsWith(String str)
*判斷當前字符串是否是以給定字符串開始的
*
*boolean endsWith(String str)
*判斷當前字符串是否是以給定字符結束的
*/
String str ="thinking in java";
boolean starts=str.startsWith("th");
System.out.println("starts:"+starts);
boolean ends=str.endsWith("ava");
System.out.println("ends:"+ends);
輸出:
starts:true
ends:true
【toUpperCase()】【toLowerCase()】 //大小寫
/**
* String toUpperCase()
* 將當前字符串中的英文部分轉換為全大寫
* String toLowerCase()
* 將當前字符串中的英文部分轉換為全小寫
* 常被用於檢查字符串中英文部分,完成忽略大小寫操作
* */
String str="我愛Java";
String upper =str.toUpperCase();
System.out.println(upper);
String lower =str.toLowerCase();
System.out.println(lower);
輸出:
我愛JAVA
我愛java
【valueOf()】 //其他類型轉換為字符串類型
/**
* 字符串提供了若干的重載靜態方法valueOf()
* 通常用來將其他類型轉換為字符串形態
* @author tarena
* */
* int i=100;
String s1=String.valueOf(i); //String s3=i+"";同樣可以整型轉換成字符串
System.out.println(s1);
* double d=1000.123;
String s2 =String.valueOf(d); //浮點型轉換為字符串
System.out.println(s2);
* String str3=new String(字節數組,0,n); //將字節數組中的所有字節轉換為對應的字符串
* char[] a={'a','b','v','g','d'};
String s2 =String.valueOf(a); //字符數組轉換為字符串 方法0
System.out.println(s2);
* String s3=new String(字符數組); //字符數組轉換為字符串 方法一
char[] a={'a','b','v','g','d'}; //字符數組轉換為字符串 方法二
String s="";
for (int i = 0; i < a.length; i++) {
s+=a[i];
}
System.out.println(s); //abvgd
char[] a={'a','b','v','g','d'};
StringBuilder sb=new StringBuilder();
for (int i = 0; i < a.length; i++) {
sb.append(a[i]); //字符數組轉換為字符串 方法三
}
String s=sb.toString();
System.out.println(s); //abvgd
*Arrays.toString(a1) //數組轉換成字符串
【StringBuilder】
* StringBuilder用於解決修改字符串導致的內存消耗問題
* StringBuilder內部維護一個可變的字符數組,所以修改的
* 字符串內容都是在當前對象中完成,而不會創建新對象
* StringBuilder提供了修改字符串的相關方法:增刪改插
* */
StringBuffer有如下常用構造方法: //不懂
public StringBuilder()
public StringBuilder(String str)
構造方法StringBuffer()將創建不包含任何字符序列的StringBuilder對象 //可變 //安全
而StringBuilder(String str)將創建包含參數字符串str的StringBuilder對象 //可變 //不安全,但很方便
String //String不可變
String str ="好好學習java";
StringBuilder builder=new StringBuilder(str);
/**
* 獲取StringBuilder表示的字符串
* String toString();
* */
str =builder.toString();
System.out.println(str); //輸出:好好學習java
/**
* StringBuilder append(String str)
* 該方法用於向當前字符串末尾追加給定字符串
* 返回值還是當前StringBuilder
* */
builder.append(",為了改變世界!"); //追加
str =builder.toString();
System.out.println(str); //輸出:好好學習java,為了改變世界!
/**
* StringBuilder insert(int i,String str);
* 在當前字符串的指定位置插入給定字符串,
* 原位置及後續字符串順序向後移動
* */
builder.insert(9,"就是"); //插入
str =builder.toString();
System.out.println(str); //輸出:好好學習java,就是為了改變世界!
//活著,就是為了改變世界!
/**
* StringBuilder replace(int start,int end,String s );
* 將當前字符串中指定范圍內的字符串替換為給定的字符串 //含頭不含尾
* */
builder.replace(0, 8, "活著"); //替換
str =builder.toString();
System.out.println(str); //輸出:活著,就是為了改變世界!
//活著,就是為了改變世界
/**
* StringBuilder delete(int start,int end);
* 刪除當前字符串中指定范圍的字符串
* */
builder.delete(11, 12); //刪除
str=builder.toString();
System.out.println(str); //輸出:活著,就是為了改變世界
/**
* reverse();
* 將當前字符串內容反轉
* */
builder.reverse(); //反轉
str=builder.toString();
System.out.println(str); //輸出:界世變改了為是就,著活
例子:
String str= "上海自來水來自海上";
StringBuilder builder=new StringBuilder(str);
builder.reverse();
String str1 =builder.toString();
if(str.equals(str1)){
System.out.println("是回文");
}else{
System.out.println("不是回文");
}
System.out.println(str==str1);
輸出:
是回文
false
【基本正則表達式】 //
驗證一個字符串滿不滿足格式要求(只關注格式,不關注有沒有校)
轉意字符: +(加號) \(斜槓) .(小數點) 需要加\(斜槓) 輸入兩次輸出一次
1、“.”和"\"
"."點兒,在正則表達式中表示任意一個字符。
"\"在正則表達式中是轉意字符,當我們需要描述一個已經被正則表達式使用的特殊字符時,我們就可以通過使用"\"將其轉變為原本的意思。
"\"在正則表達式中也有一些預定義的特殊內容:
\d:表示任意一個數字
\w:表示任意一個單詞字符(只能是 數字,字母,下劃線)
\s:表示任意一個空白字符(\t \r \n \f \x0B)
\D:表示任意一個非數字字符
\W:表示任意一個非單詞字符
\S:表示任意一個非空白字符
2、"字符集合 []"
"[]"用來描述單一字符,方括號內部可以定義這個字符的內容,也可以描述一個范圍。例如:
[abc]:表示該字符只能是a或者b或者c
[123]:表示該字符只能是1或者2或者3
當我們需要描述所有小寫字母時,我們可以使用范圍 [a-z],表示該字符可以是任意一個小寫字母。
同樣還可以使用 [0-9] 來表示該字符可以是任意一個數字。
也可以在多個范圍內選擇。比如,[a-zA-Z0-9_] 表示該字符可以是任意字母,數字以及"下劃線"。
[a-z&&[^bc]]a到z中除去bc的字母 除了^
3、"*"、"+"、"?"
通常我們需要描述的字符串會有很多重復出現的元素,但又不需要嚴格限制出現的次數時,我們就可以使用"*","+"這些量詞。
例如:郵箱地址,那麼在"@"字符前允許出現若干字符作為用戶名。這時候我們就可以使用"\w+"來描述這裡至少出現一個單詞字符了。
"+":表示內容可以連續出現至少1次以上
"*":表示內容出現0-若干次
"?":表示內容出現0-1次
4、{n}、{n,}{n,m}
除了前面講到的量詞外,有時我們也需要要求內容出現的次數有具體要求。比如手機號碼。這時我們要求出現的數字就不能是一個模糊的概念了,
而必須要求11位。又比如我們要求用戶輸入密碼時,要求密碼是6-15位。遇到這類問題是,我們可以使用:
{n}:表示內容必須出現n次
{n,m}:表示內容出現n-m次
{n,}:表示內容出現至少n次
例如,\d{11} 就表示數字只能出現11位,這樣就解決了上述的問題。
【0-9】{0,6}//0到6次 不能是負數
【0-9】{6,} //6到無數次
[abc]{3} //aaa //abc //acb
(abc){3} //abcabcabc
^[abc]{3}$ //只能是abc,不能加其他的東西 ^表示開始 $表示結尾
5、分組
通過上面的內容,我們還無法解決類似下面的問題:
在描述電話號碼時,前面有區號,區號的形式可以是0086或者+86
那麼我們如何在這兩個字符串之間選擇?
這時我們可以使用分組"()"。() 可以將內容看做一個整體,()中可以使用"|"來表示或關系。例如,(+86|0086) 表示這裡可以是+86或者0086。
6、 "^ "和"$"
通過在正則表達式的開始添加"^"以及末尾添加"$"來表示一個整體。若不使用它們,那麼正則表達式只匹配某個字符串的部分內容是否符合格式規則,
但使用它們,則要求字符串必須從頭到尾都滿足該格式規則。例如,^\w{ 8,10 }$ 表示整體字符串只能出現單詞字符8-10個。
檢索郵政編碼 規則為6位數字
【0-9】【0-9】【0-9】【0-9】【0-9】【0-9】 //方法一
\d\d\d\d\d\d //方法二
\d{6} //方法三 "^[1-9][0-9]{5}$";
驗證身份證號碼的正則表達式 //[0-9]{15}([0-9]{2}[0-9]xX)
private static final String IDENTITY_CARD = "^\\d{15}|\\d{18}$";
匹配手機號碼前面的區號 例子: +86 13838389438
(\+89|0086)?\s*\d{11} //String sssString="(\\+89|0086)?\\s*\\d{11}";
\+:轉意字符,匹配+號
?:前面的組可有可無
\s:空白字符
*:前面的字符數量>=0
\d:數字字符
{11}:前面的字符數量為11位
匹配用戶名規則,從頭到尾連續8-10個單詞字符 \w 表示[a-zA-Z0-9_]
\w{8,10} //abcd1234_abcd可以通過
^\w{8,10}$ //abcd1234_abcd不可以通過
【matches】 //整體比較 //正則表達式放在括號內
matches()方法的參數要求我們傳入一個用字符串描述的正則表達式,然後使用該正則表達式描述的字符串格式規則來匹配當前字符串,
若滿足那麼該方法返回true。否則返回false。
例子:
String regex="[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\\.[a-zA-Z0-9]+)+"; //要比較. 要輸出\. 則要輸入\\. // \.編譯錯誤
System.out.println(regex);
String str ="[email protected]";
boolean matches=str.matches(regex);
System.out.println(matches?"是郵箱":"不是郵箱");
輸出:
[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\.[a-zA-Z0-9]+)+
是郵箱
例子:
String sssString="(\\+89|0086)?\\s*\\d{11}"; //"([+][8][9]|0086)?\\s*\\d{11}";//"^(13)[0-9]{9}|15[89][0-9]{8}$";
System.out.println(sssString);
String str ="+89 13456987120";
boolean matches=str.matches(sssString);
System.out.println(matches?"是電話號碼":"不是電話號碼");
輸出:
(\+89|0086)?\s*\d{11}
是電話號碼
【split】方法 //拆分
String[] split(String regex):參數要求傳入一個用字符串描述的正則表達式,然後使用該正則表達式描述的字符串規則來匹配當前字符串,並按照滿足的部分將字符串拆分。
/**
* 切掉所有數字部分,只保留所有英文部分
* */
String str ="asdfa4544sfg556fh5sfh5sg5sh";
StringBuilder s=new StringBuilder();
String[] arr =str.split("[0-9]+");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]); //asdfasfgfhsfhsgsh //把數字給拆沒了
s.append(arr[i]);
}
System.out.println();
str=s.toString();
System.out.println(str); //改為了字符串asdfasfgfhsfhsgsh
String str1 ="1\\2\\3\\4\\5\\6\\7\\8\\9\\0"; //為一條斜槓
String[] arr1=str1.split("\\\\"); //為兩條斜槓
for (int i = 0; i < arr1.length; i++) {
System.out.print(arr1[i]);
}
System.out.println();
輸出:1234567890
String str2="1,2,3,4,5,6,7,8,9";
/**
* 如果,在字符串前面,中間,連續出現了若干次要拆分的字符,那麼每一項中間都會拆除一個空字符
* 例如:,,,,,1,2,3,4,,,,,5,6,7
* 在1之前,會拆出5個空字符串,中間也是
* 如果在後面的話,不會拆出空字符串 //1,2,3,,,,,,
* */
String[] arr2=str2.split(",");
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i]);
}
System.out.println();
String imgName="2015/04/03.jpg";
String[] arr3=imgName.split("\\."); //如果填. 則代表所有字符,會把所有字符都刪掉
long c=System.currentTimeMillis();
imgName=c+"."+arr3[1];
System.out.println(imgName);
【replaceAll】方法 //替換
String replaceAll(String regex,String replacement):參數要求傳入一個用字符串描述的正則表達式和
一個需要替換的字符串,然後使用該正則表達式描述的字符串規則來匹配當前字符串,並將滿足的部分替換為需要替換的這個字符串。
String str="sdg545sf65s4dg5s5f4gs54gs5dg";
/**
* 將字符串中的數字部分替換為字符串“#NUMBER”
* */
System.out.println(str);
str =str.replaceAll("[0-9]+", "#NUMBER");
System.out.println(str);
String regex = "(wqnmlgb|cnm|sb|fuck|nmd)";
String message="wqnmlgb,你怎麼搞得,sb.";
message =message.replaceAll(regex, "****");
System.out.println(message);
【Pattern】 //封裝正則表達式 //重點是Matcher //有一個例子
【Matcher】 //封裝正則表達式和要匹配的字符串
一次次向後查看下一段匹配的子串
Pattern p0= Pattern.compile("[0-9]+"); //創建對象 //不能直接new
Matcher m0 =p0.matcher("good good study"); //創建對象 //還是不能new
//find();方法 //向後查找下一對匹配的子串 ,返回boolean值,表示是否找到字串
//group();方法 //返回剛剛找到的子串
//start();方法 //返回剛剛找到的起始位置 含頭不含尾
//end();方法 //返回剛剛找到的結束位置 含頭不含尾
System.out.println("輸入"); //輸入sgshsf2654646gbigjk56454531
String s =new Scanner(System.in).nextLine();
Pattern p =Pattern.compile("\\d{3,}"); //創建對象
Matcher m =p.matcher(s);
while(m.find()){ //一次次向後查看下一段
String tel =m.group(); //取出找到的字串 //可放在end下面
int start =m.start(); //起始位置
int end =m.end(); //結束位置
System.out.println(start+","+end+":"+tel); //6,13:2654646 //19,27:56454531
【Object】任何一個類在最終都會繼承Object類
【toString()】 //返回一個字符串
package day02;
public class StringDemo06 {
public static void main(String[] args) {
/**
* String toString()
* 該方法要求返回一個字符串
* Java希望我們定義的類若需要使用toString該方法時,就重寫該方法
* Object中的實現返回的字符串格式位:類型@地址
* */
point p =new point();
p.x=1;
p.y=2;
String string =p.toString();
System.out.println(string); //重寫toString之前day02.point@868c6d //重寫toString之後(1,2)
/**
* System.out.println(Object o)
* 該方法會將給定的對象的toString方法返回字符串輸出到控制台
* */
System.out.println(p); //(1,2)
}
}
class point {
public int x;
public int y;
public String toString(){
return "("+x+","+y+")"; //輸出(1,2)
}
public boolean equals(Object o){
if(o==null){ //空
return false;
}
if(o==this){ //他自己
return true;
}
if(o instanceof Point){ //if (obj instanceof Emp) {
Point p=(Point)o; //Emp emp = (Emp) obj;
/**
* 比較兩個對象的屬性內容是否一致
* 這裡參與的屬性要結合實際需求
* 當前例子:x,y都一樣
* */
return this.x==p.x&&this.y==p.y; //都是整形 //return this.name.equals(emp.name); //字符串
}
return false;
}
}
【equals】 //等於
Point p1=new Point();
p1.x=1;
p1.y=2;
boolean t=p.equals(p1);
System.out.println(t); //true
【包裝類】 //
我們知道java是面向對象的語言,其精髓之一是可以使用多態性,提高程序的靈活度。
但是java中有8個基本類型:byte,short,int,long,float,double,char,boolean。它
們是以值的形式存在於內存中,而不是對象。它們不是Object的子類,不能參與面向對象的開發。
在java1.5版本以前以下的代碼是不能通過的
public class Test{
public static void main(String[] args){
String str = "hello";
doSome(str);//可以,因為String是Object的子類
int i = 1;
//程序編譯不通過,原因在於int不是Object的子類,不能使用多態性。
doSome(i);
}
public static void doSome(Object o){
....
}
}
問題出現的原因就是基本類型int沒有繼承關系,它不是Object的子類。所以,若想讓基本類型以對象的形式存在,
我們就需要定義一個類Integer,然後用其實例來描述一個基本類型int。這樣的好處在於,我們使用對象來描述基本類型數據,
而類又是繼承自Object的。從而可以讓基本類型參與面向對象的開發。好在,像Integer這樣的類不需要我們定義,因為java已經提供了8中基本類型對應的包裝類。
注:java1.5版本後出現了自動拆裝箱特性,上述代碼可以正常編譯通過。自動拆裝箱我們後面會詳細描述。
對於8個基本類型,java提供了他們相應的包裝類:
基本類型 包裝類
byte java.lang.Byte //父類java.lang.Number //Byte
short java.lang.Short //父類java.lang.Number //Short
int java.lang.Integer //父類java.lang.Number //Integer
long java.lang.Long //父類java.lang.Number //Long
float java.lang.Float //父類java.lang.Number //Float
double java.lang.Double //父類java.lang.Number //Double
char java.lang.Character //父類java.lang.Object //Character
boolean java.lang.Boolean //父類java.lang.Object //Boolean
其中除了Character與Boolean的父類是Object之外,其余的都是繼承自:java.lang.Number
【intValue()】 //將當前對象表示的數字以基本類型的int值返回
/**
*int intValue()
*將當前對象表示的數字以基本類型的int值返回
*
* double doubleValue()
* 將當前獨享表示的數字以基本類型的double值返回
* */
1.Integer a=new Integer(10);
2.Integer a=Integer.valueOf(10);
Double doub =new Double(1.2); //定義double類型的包裝類
double d=doub.doubleValue();
System.out.println(d); //1.2
//還可以轉換為其他基本數據類型,不過可能會丟失精度
int i=doub.intValue();
System.out.println(i); //1
byteValue
shortValue
intValue
longValue
floatValue
doubleValue
【MAX_VALUE】【MIN_VALUE】 //最大值 最小值
/**
* 數字包裝有兩個常量
* max min
* */
int max=Integer.MAX_VALUE;
int min=Integer.MIN_VALUE;
System.out.println(max); //2147483647
System.out.println(min); //-2147483648
【Integer常用功能】【parseInt】【parseDouble】 //將字符串轉換為對應的基本類型
/**
* 包裝類最常用的一個方法
* 數字包裝類有一個靜態方法:parseXXX()
* 可以將字符串轉換為對應的基本類型
* */
Integer.parseInt("255"); //255
Integer.parseInt("ff",16); //16進制 //255
Integer.parseInt("377",8); //8進制 //255
Integer.parseInt("11111111",2); //2進制 //255
String str ="123";
int i=Integer.parseInt(str); //str必須是整數,不能是小數,或有字母漢字
System.out.println(i); //123
double d =Double.parseDouble(str);
System.out.println(d); //123.0
【Double】//對特殊值進行檢查的方法
Double.isInfinite(double d);
Double.isNaN(double d);
【BigDecimal】 //大數值//做精確的浮點數運算 //加減乘數+-*/ //高精度
【BigInteger】 //做超出長整形范圍的整數運算 //超過long //超出long
BigDecimal bd =BigDecimal.valueOf(3.14);
add(BigDecimal bd) //+
subtract(BigDecimal bd) //-
multiply(BigDecimal bd) //*
divide(BigDecimal bd) // /
divide(BigDecimal bd,小數位數,捨入方式) // /方法的重寫 //
捨入方式 BigDecimal.ROUND_HALF_UP ; BigDecimal.ROUND_UP ; BigDecimal.ROUND_DOWN
設置捨入方式 setScale(小數位數,捨入方式)
例子:+-*/
System.out.println("輸入");
double a=new Scanner(System.in).nextDouble(); //輸入15.5
double b=new Scanner(System.in).nextDouble(); //10
BigDecimal bd =BigDecimal.valueOf(a);
BigDecimal bed =BigDecimal.valueOf(b);
System.out.println("a+b:"+bed.add(bd)); //a+b:25.5
System.out.println("a-b:"+bed.subtract(bd)); //a-b:-5.5
System.out.println("a*b:"+bed.multiply(bd)); //a*b:155.00
System.out.println("a/b:"+bed.divide(bd,10,BigDecimal.ROUND_HALF_UP)); //a/b:0.6451612903
對一個浮點數,四捨五入保留小數點後2位 : //設置捨入方式 setScale(小數位數,捨入方式)
double a=2.45665;
BigDecimal bd =BigDecimal.valueOf(a);
BigDecimal aa=bd.setScale(2,BigDecimal.ROUND_HALF_DOWN);
//double cc=aa.doubleValue(); System.out.println(cc); //轉換為double浮點型
System.out.println(aa);
【DecimalFormat】 //格式字符串
DecimalFormat f =new DecimalFormat(格式字符串); //格式字符串
//方法:format(數字) //數字格式化成字符串
//方法:parse(字符串) //字符串轉換成數字
//方法:setPattern(格式) //修改格式
System.out.println("輸入數字");
double a =new Scanner(System.in).nextDouble(); //輸入152
DecimalFormat f =new DecimalFormat("\u00A4###,###.000");
String s =f.format(a);
System.out.println(s);//¥152.000
Number n=f.parse(s);
a=n.doubleValue();
System.out.println(a); //152.0
$###,###.000 //將數據格式化為每三位一個逗號,保留三位小數
【自動裝箱和拆箱操作】【valueOf】
Integer inte =Integer.valueOf(1); //將基本類型轉換為包裝類
Integer inte =1; //JVM依然不認可,但5.0之後編譯器默認加上Integer.valueOf(1); 自動裝箱特性
int i1=inte; //JVM依然不認可,但5.0之後編譯器默認加上inte.intValue(); 自動拆箱特性
Integer a = 100 => Integer a = Integer.valueOf(100);
Integer b = 200 => Integer b = Integer.valueOf(200);
Integer c = a+b => Integer c = Integer.valueOf (a.intValue( ) + b.intValue( ));
double d = c => double d = c . doubleValue( );
/**
* 基本類型轉換為包裝類時建議使用
* 靜態方法 valueOf() ////equals比較封裝的值 //==比較地址
* */
Integer i1=Integer.valueOf(129); //推薦使用這種方法 //如果封裝的數值是-128到127,會從Integer對象緩存區獲得已經存在的對象
Integer i2=Integer.valueOf(129); //否則,會新建一個對象
System.out.println(i1==i2); //false 小於等於127的話是true
System.out.println(i1.equals(i2)); //true
Integer i3=new Integer(2);
Integer i4=new Integer(2);
System.out.println(i3==i4); //false 只要new了就一定會新建,不會相等
System.out.println(i3.equals(i4)); //true
Integer d= Integer.valueOf(255); //255的2進制為 11111111
System.out.println(d.byteValue()); //-1 //byte一字節八位,就變成-1
System.out.println(d.shortValue()); //255
System.out.println(d.intValue()); //255
System.out.println(d.longValue()); //255
System.out.println(d.floatValue()); //255.0
System.out.println(d.doubleValue()); //255.0
【時間類】
【JAVA 中的時間】
Java中的時間使用標准類庫的Date類表示,是用距離一個固定時間點的毫秒數(可正可負,long類型)表達一個特定的時間點。
固定的時間點叫紀元(epoch),是UTC時間1970年 1月 1日 00:00:00。
UTC(Universal Time Coordinated世界調整時間)與GMT(Greenwich Mean Time格林威治時間)一樣,是一種具有實際目的的科學標准時間。
【Date類】簡介 // x之後點擊推薦的第二個類 //不能導入sql,要導入util包
java.util.Date 類封裝日期及時間信息。
Date類的大多數用於進行時間分量計算的方法已經被Calendar取代。查看如下代碼:
Date date = new Date();
// 系統當前的日期及時間信息
System.out.println(date);
// Sun Jan 06 11:52:55 CST 2013
long time = date.getTime();
//1970年1月1日至今的毫秒數
因為Date的設計具有"千年蟲"以及"時區"的問題,所以Date中的大部分方法已經不建議使用了,它們都被java.util.Calendar類所取代,該類我們稍後會講解。
【顯示時間】【Date】選推薦的第二個類
import java.util.Date;
/**
* java.util.Date
* 該類內部維護一個long值,表示從1970年元旦到要描述的時間之間所經過的毫秒值
* 由於Date的設計缺陷,現在僅用它表示時間,而不做時間相關的其他操作
* */
Date date =new Date(); //x之後推薦的第二個類 //新建一個
System.out.println(date); //輸出Tue Apr 07 10:34:31 CST 2015
/**
* long getTime()
* 獲取當前Date內部維護的long值
* 即:1970年元旦到描述的時間點之間的毫秒值
* */
獲取毫秒數
long time =date.getTime();
System.out.println(time); //毫秒值 //1428374852902
time +=1000*60*60*24; //在編譯器內已經算完了,在class內就是結果//加一天的毫秒數
/**
* void setTime(long time)
* 將給定的毫秒值設定到當前的Date對象中,使其表示該時間
* */
毫秒轉到時間 第一種
date.setTime(time);
System.out.println(date); //輸出:Wed Apr 08 10:47:32 CST 2015
毫秒轉到時間 第二種
long last =111111111111111L; //file.lastModified();
Date date=new Date(last);
System.out.println(date);//5490-12-21
【SimpleDateFormat】【sdf.format()】【sdf.parse()】 //2015-04-07 11:05:03
/**
* 該類的主要作用:
* 將Date轉換為字符串
* 將字符串轉換為Date
* 在兩者之間進行轉換是需要指定格式的
* 而格式也需要一個字符串描述
* */
Date now = new Date(); //當前系統時間
//Date的toString
System.out.println(now); //Tue Apr 07 11:05:03 CST 2015
/**
* 希望輸出的字符串樣式:
* 2015-04-07 11:00:58
* yyyy-MM-dd HH:mm:ss
* */
英文習慣的時間改成中文習慣的字符串時間
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String str1=sdf.format(now); //sdf.format()
System.out.println(str1); //輸出:2015-04-07 11:05:03 星期
把字符串改為英文習慣的時間
String str="2008/08/08 20:08:08";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
/**
* Date parse(String str)
* 將給定的字符床按照SimpleDateFormat指定的日期
* 格式解析為時間並用Date表示
* */
把字符串改為英文習慣的時間
Date date=sdf.parse(str); //點第二個 //sdf.parse()
System.out.println(date); //輸出:Fri Aug 08 20:08:08 CST 2008
String ss="00:00:11";
SimpleDateFormat sdf =new SimpleDateFormat("HH:mm:ss");
long dateStart=sdf.parse(ss).getTime()+28800000; //時區帶來的8小時
System.out.println(dateStart );
【日歷類】
/**
* Calender 日歷類
* 用於操作時間的類
* 本身是抽象類不能實例化,常用的是封裝了格裡高利歷法的實例類
* 就是所謂的陽歷
* 其提供了一個靜態方法,用於獲取一個適當的實現類
* java.util.Calendar;
* 默認創建出來的也是表示當前系統時間
* */
創建一個
Calendar calendar=Calendar.getInstance(); //不推薦 Calendar calendar=new GregorianCalender();使用的是羅馬歷,公歷
System.out.println(calendar); //Calendar重寫了toString,不可讀
/**
* Date getTime()
* 該方法用於獲取一個Date對象,該對象表示時間
* 就是當前Calender所表示的時間
* */
獲得時間
Date date2=calendar.getTime();
System.out.println(date2);
System.out.println(calendar.getTimeInMillis());//1422813722812 獲得毫秒數
calendar.setTimeInMillis(time); //通過毫秒數設定時間,還是calendar類型
/**
* void setTime(Date date)
* 使當前Calendar表示給定的Date所表示的時間
* */
設定時間 //設置時間
calendar.setTime(date2); //setTimeInMillis() //設定毫秒數
/**
* String,Date,Calender之間的相互轉換
* String->Date
* 借助於SimpleDateFormat的parse()方法
*
* Date->String
* 借助於SimpleDateFormat的format()方法
*
* Date->Calender
* 使用Calender的setTime()方法
*
* Claender->Date
* 使用Calender的getTime()方法
* */
/**
* Calender設置時間
* 可以對當前Calender的不同時間單位進行分別的設置
* 使得其可以表示給定的時間
* */
/**
* void set(int field,int value)
* 對給定時間分量(單位)設置給定的值
* */
Calendar calendar2=Calendar.getInstance();
/**
* 當我們對某個時間分量設置新值後,通常年月日時分秒能不變的就不變,
*但有些情況也是要受到牽連而跟著變化,比如星期幾
* */
設置年份
calendar2.set(Calendar.YEAR, 2008); //設置年,星期可能會跟著改變
System.out.println(calendar2.getTime());
/**
* 設置為10月
* 月份的值有常量對應
* 若學數字需要注意:0表示1月,以此類推11表示12月
* */
設置月份 //輸入10,輸出11月 //星期設定3,才是周2
calendar2.set(Calendar.MONTH, 10);
System.out.println(calendar2.getTime());
SimpleDateFormat sdf0 =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String str0=sdf0.format(calendar2.getTime()); //sdf.format()
System.out.println(str0); //輸出:2008-11-07 15:05:36 星期五
/**
* 設置日
* 8號
* DATE:月中的天 幾號
* DAY_OF_MONTH:與DATE等價
*
* DAY_OF_WEEK: 星期中的天 星期幾
* DAY_OF_YEAR:年中的天
* */
//設置日
calendar2.set(Calendar.DAY_OF_MONTH, 8);
System.out.println(calendar2.getTime());
/**
* 設置時
* HOUR:12小時制
* HOUR_OF_DAY:24小時制
* */
//設置時
calendar2.set(Calendar.HOUR_OF_DAY, 20);
calendar2.set(Calendar.MINUTE, 8);
calendar2.set(Calendar.SECOND, 8);
System.out.println(calendar2.getTime()); //Sat Nov 08 20:08:08 CST 2008
String str00=sdf0.format(calendar2.getTime()); //sdf.format()
System.out.println(str00); //2008-11-08 20:08:08 星期六 星期自動變不用設置
今天是某年某月某日星期幾 一年的第多少天
/**
* 獲取當前Calendar表示的時間中某個時間分量對應的值
* int get(int field)
* */
Calendar calendar =Calendar.getInstance();
//獲取年
int year =calendar.get(Calendar.YEAR);
System.out.println(year); //2015年
//獲取月
int month =calendar.get(Calendar.MONTH);
System.out.println(month+1); //4月
//獲取日
int day =calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day); //7日
//今年的第幾天
int day1 =calendar.get(Calendar.DAY_OF_YEAR);
System.out.println(day1); //今年的第97天
//今天星期幾
int dow =calendar.get(Calendar.DAY_OF_WEEK);
System.out.println(dow==1?7:dow-1); // 星期2
一年共365天
/**
* 截取某個時間分量所允許的最大值
* */
/**總是以當前Calender所表示的時間作為基准,看給定的時間分量
* 所允許的最大值
* */
Calendar calender=Calendar.getInstance();
int days=calender.getActualMaximum(Calendar.DAY_OF_YEAR);
System.out.println(days); //共365天
時間的計算方法
/**
* 時間的計算方法
* void add(int field,int value)
* 對給定的時間分量累加給定的值,若值為負數,就減
* */
Calendar calendar =Calendar.getInstance();
/**
*2年3個月零15天以後的那周的周二是幾號
* */
calendar.add(Calendar.YEAR, 2);
calendar.add(Calendar.MONTH, 3);
calendar.add(Calendar.DAY_OF_YEAR, 15); //加天的時候用DAY_OF_YEAR,因為可能會跨年
System.out.println(calendar.getTime());//Sat Jul 22 15:58:40 CST 2017
calendar.set(Calendar.DAY_OF_WEEK, 3); //設定3,才是周2
System.out.println(calendar.getTime());//Tue Jul 18 15:58:40 CST 2017
【集合接口】
Collection
java提供了一種可以存數一組數據的數據結構,其提供了豐富的方法,在實際開發中往往比數組使用的廣泛。這種數據結構成為集合:Collection。
Collection是一個接口,其定義了集合的相關功能方法。
【List】 實現類ArrayList LinkedList
【Set】 實現類HashSet TreeSet
Collection派生出了兩個子接口,一個是List另一個則是Set。
List:稱為可重復集,顧名思義,該集合中是允許存放重復元素的,那麼何為重復元素?重復元素指的並非是同一個元素,而是指equals方法比較為true的元素。//有序
Set:稱為不可重復集,所以,該集合中是不能將相同的元素存入集合兩次,同List,這裡相同指的也是兩個元素的equals比較結果為true。 //大部分無序
集合持有對象的引用
集合中存儲的都是引用類型的元素,那麼引用類型變量實際上存儲的是對象的“地址”,所以實際上集合只存儲了元素對象在堆中的地址。而並不是將對象本身存入了集合中。
如果只在兩端操作數據,選擇LinkedList
只要會操作中間的數據,就用ArrayList
List:訪問兩端效率高
/**
* java.util.Collection
* 集合用於存放一組元素
* 其定義了用於操作集合元素的相關方法
* 通常我們存放一組元素使用集合而不是數組
* */
//創建List集合
Collection c = new ArrayList();
/**
* boolean add(E e)
* 向集合中添加給定的元素
* 添加成功返回true,否則返回false
* 集合雖然什麼類型的實例都可以放,但實際使用時還是大部分情況還是只存放一種類型的元素
* */
//加集合元素
c.add("one");
c.add("two");
c.add("three");
//輸出集合
System.out.println(c); //[one, two, three] 集合沒有長度 //自己寫的方法要重寫toSring方法
/**
* int size()
* 獲取當前集合的元素個數 不是長度,集合沒有長度
* */
//顯示個數,不是長度,集合沒有長度 //c.size()
System.out.println(c.size()); //3
/**
* boolean isEmpty()
* 判斷當前集合是否為一個空集
* */
//判斷當前集合是否為一個空集 //boolean
boolean isEmpty = c.isEmpty();
System.out.println(isEmpty); //false 不是空集 空集不是空
/**
* void clear()
* 清空集合,刪除集合中所有的元素
* */
//清空集合 //c.clear();
c.clear();
System.out.println(c.size()); //個數是0
isEmpty =c.isEmpty();
System.out.println(isEmpty); //true 是空集
list.getFirdt() //LinkedList()也能用
list.getLast()
list.removeFirst() //移除,返回被移除的數據 首位
list.removeLast() //移除,返回被移除的數據 末尾
【contains方法】判斷
該方法會用於判斷給定的元素是否被包含在集合中。若包含則返回true,否則返回false。
這裡需要注意的是,集合在判斷元素是否被包含在集合中是使用元素的equals的比較結果。
比較規則如下:
(o==null ? e==null : o.equals(e))
Collection<Cell> cells = new ArrayList<Cell>();
cells.add(new Cell(1, 2));
cells.add(new Cell(1, 3));
cells.add(new Cell(2, 2));
cells.add(new Cell(2, 3));
Cell cell = new Cell(1, 3);
// List集合contains方法和對象的equals方法相關
boolean flag = cells.contains(cell);
// 如果Cell不重寫equals方法將為false
System.out.println(flag); // true
集合的批量操作方法
/**
* 集合的批量操作方法
* addAll(Collection c)
* 將給定集合中的所有元素添加到當前集合
* 執行完畢後,若當前集合元素發生了變化就返回true
* containsAll(Collection c)
* 判斷當前集合是否包含給定集合中的所有元素
* */
Collection c1 =new ArrayList();
c1.add("java");
c1.add("c");
c1.add("c++");
System.out.println(c1); //[java, c, c++]
//放進去的順序改變,只要集合元素不變,輸出的順序不會改變
Collection c2 =new HashSet(); //Set集合用的不多,就是HashSet()可能會用
c2.add("php");
c2.add("object");
c2.add("c#"); //c撒
c2.add("java");
System.out.println(c2); //[php, java, c#, object]
把c2中的所有元素加到c1中
c1.addAll(c2); //如果沒有All,則輸出[java, c, c++, [php, java, c#, object]]
System.out.println(c1);//[java, c, c++, php, java, c#, object]
Collection c3 =new LinkedList();
c3.add("java");
c3.add("php");
c3.add("c++");
判斷c1集合是否包含c3集合中的所有元素
boolean contains =c1.containsAll(c3); //必須寫All,不然就是false
System.out.println(contains); //true
【Iterator】迭代器遍歷集合
Iterator用於遍歷集合元素。獲取Iterator可以使用Collection定義的iterator方法。
Iterator的next方法用於返回迭代的下一個元素,hasNext方法用於判斷集合是否還有元素可以遍歷。
在使用Iterator遍歷集合時,不能通過集合的remove方法刪除集合元素,否則會拋出異常。我們可以通過迭代器自身提供的remove()方法來刪除通過next()迭代出的元素。
增強for循環並非新的語法,而是在編譯過程中,編譯器會將新循環轉換為迭代器模式,所以增強for循環本質上是迭代器。
迭代器與for循環相比,不用每次都從頭開始遍歷,只用挨著循環一次
ArrayList<Integer> list =new ArrayList<Integer>();
list.add(666);
list.add(555);
list.add(null);
list.add(999);
Iterator<Integer> it =list.iterator();
while(it.hasNext()){
Integer s=it.next();
System.out.println(s); //666 555 null 999
}
獲取元素 刪除元素 //迭代器 die迭
Collection c=new ArrayList();
c.add("one");
c.add("#");
c.add("two");
c.add("#");
c.add("three");
c.add("#");
//import java.util.Iterator;
Iterator it =c.iterator(); //迭代器遍歷集合
/**
* boolean hasNext()
* 該方法是判斷集合中是否還有元素可以被取出
* */
while(it.hasNext()){
/**
* E next()
* 獲取集合中當前元素
* 需要注意,要確定hasNext為true才能調用這個方法
* */
Object obj=it.next();
String str =(String)obj; //可以沒有這一步,直接用System.out.print(obj+" ");
System.out.print(str+" "); //one # two # three #
//刪除所有的“#”
if("#".equals(str)){ //只能在迭代器內用
/**
* 使用迭代器遍歷集合的過程中,不能通過集合定義
* 的方法對元素數量進行修改,否則可能拋出異常
* */
//c.remove(str); //List.remove("four");//List.remove(2);
/**
* 迭代器的remove方法會將next()遍歷出來的元素從集合中刪除
* */
it.remove();
}
}
System.out.println(c);//[one, two, three]
新for循環獲取數組
/**
* 新循環,增強循環,增強for循環,for each
* java5.1推出的新特性
* 用於遍歷集合獲取數組的
* */
String[] array = {"a","b","c","d","e"};
for (int i = 0; i < array.length; i++) {
String str =array[i];
System.out.println(str); //abcde
}
for(String str : array ){
System.out.println(str); //abcde
}
例子:
Collection c =new ArrayList();
c.add("one");
c.add("two");
c.add("three");
//方法一:比較復雜 //迭代器
Iterator it =c.iterator();
while (it.hasNext()){
Object o =it.next();
System.out.println(o); //one two three
}
//方法二:比較方便 //新for循環
/**
* 新循環是編譯器認可的而非JVM
* 編譯器會在編譯程序的時候將新循環改為迭代器
* 模式,所以不能在循環過程中刪除元素
* */
for(Object o:c){ //新for循環不能在循環過程中刪除元素
System.out.println(o); //one two three
}
for(Iterator<Integer> it =c.iterator();it.hasNext();){
Integer inte=it.next();
}
【泛型】 //兩邊的泛型要一樣
/**
* 泛型
* 對於Position類而言
* 創建實例時,x,y的實際類型為Object
* */
【泛型的繼承】
List<? super Integer> lis1 =new LinkedList<Object>();
List<? extends Object> lis2 =new LinkedList<Integer>();
/**
* 由於我們使用了泛型約束了方法參數的類型,那麼編譯器會自動檢查我們
* 實際傳入的參數是否滿足類型,不滿組則編譯不通過
泛型,對集合中存放的數據類型進行限制,不支持基本類型int,可用基本類型的包裝類型Integer
* */
Position<Integer,Double> p= //泛型< >內要用引用類型,不能是基本數據類型
new Position<Integer, Double>(1,9.0);
int x1 =p.getX();
double y1=p.getY();
System.out.println(x1+","+y1);
/**
* 當泛型約束方法返回值後,那麼實際返回是會自動強制類型轉換
* */
//int x2 =p.getX();//(返回的是Integer,再自動拆箱成int)不推薦如果上面是null,會出現空指針異常
Integer x2=p.getX(); //推薦這種方式
/**
* 若沒有指定泛型的具體類型,默認就是Object
* */
Position p2 =p; //沒有< >默認就是Object
p2.setX("張三"); //從Object變成String
String xx =(String)p2.getX();
System.out.println("xx:"+xx); //xx:張三
/**
* 由於x是以p2的角度時已經改成了String類型的實例
* 在這裡隱式轉換為Integer的時候會出現類造型異常
* */
x2=p.getX();//String不可以強轉為Integer
System.out.println(x2); //類造型異常
package day04;
import javax.security.auth.x500.X500Principal;
public class Position<X,Y> {
private X x;
private Y y;
public Position(X x, Y y) {
super();
this.x = x;
this.y = y;
}
public X getX() {
return x;
}
public void setX(X x) {
this.x = x;
}
public Y getY() {
return y;
}
public void setY(Y y) {
this.y = y;
}
}
泛型用來約束集合中的元素類型
/**
* 泛型在集合中的應用
* 泛型用來約束集合中的元素類型
* */
Collection<String> c =new ArrayList<String>();
c.add("one");
c.add("two");
c.add("three");
for(String str :c){
System.out.println(str);
}
/**
* 迭代器也支持泛型,泛型的類型應當與遍歷的集合
* 所定義的泛型類型一致即可
* */
Iterator<String> it =c.iterator();
while(it.hasNext()){ //這樣遍歷出來後,就不用強轉了
String str=it.next();
System.out.println(str);
}
方法泛型
Private static <E> Hoider<E> f(E e){ // <T> T f(T t)
Holder<E> h=new Holder<E>();
h.setV(e);
return;
}
【List集合】 //選推薦的第二個類
/**
* List集合 //選推薦的第二個類
* 可重復集
* 特點:有序集,可以通過下標操作元素
* 常用實現類ArrayList,LinkedList
* ArrayList內部由數組實現,利於查詢,不利於增刪
* LinkedList內部由鏈表實現,利於增刪,不利於查詢
* */
//List集合ArrayList,LinkedList
List<String> list=new ArrayList<String>();//List導入import java.util.List;
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list); //[one, two, three, four, five]
/**
* E get(int index)
* List集合的get方法用於獲取指定下標對應的元素
* */
//通過下標獲取元素
String els= list.get(2); //是下標
System.out.println(els); //three
/**
* 對於list,也可以使用類似遍歷數組的方式
* 通過下標遍歷每一個元素
* */
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));//one two three four five
}
/**
* E set(int index,E e)
* 將給定的元素設置到給定的位置上,返回值為原位置上的元素,實質上就是替換操作
* */
//替換操作
String old= list.set(1, "2"); //下標不能超過集合元素個數
System.out.println(list);//[one, 2, three, four, five]
System.out.println("old:"+old); //old:two
//替換操作 //互相轉換
//Collections.swap(i,j); //替換操作 //互相轉換
/**
* List提供了一套方法
* void add(int index,E e)
* E remove(int index)
* */
List<String> list=new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);//[one, two, three, four, five]
/**
* void add(int index,E e)
* 將給定的元素插入到給定的位置上,原位置以及後續元素順序向後移動
* */
//插入元素
list.add(2,"3"); //搜索.add(0
System.out.println(list);//[one, two, 3, three, four, five]
/**
* E remove(int index)
* 將給定位置的元素刪除並返回
* */
//刪除元素並返回
String old= list.remove(3); //list.remove(Integer.valueOf(3)); //如果集合內元素是int型,3就只能表示下標,不能表示元素,要刪掉元素3,則必須要用包裝Integer.valueOf(3)
System.out.println(list);//[one, two, 3, four, five]
System.out.println(old); //three
/**
* List提供了一個可以獲取子集的方法
* */
//獲取子集
List<Integer> list =new ArrayList<Integer>();
for(int i=0;i<10;i++){
list.add(i);
}
System.out.println(list);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
/**
* List subList(int start,int end)
* 獲取當前集合中指定范圍的子集
* */
List<Integer> subList =list.subList(3, 8);
System.out.println(subList); //[3, 4, 5, 6, 7]
/**
* 將子集中每個元素擴大10倍
* */
//將子集中每個元素擴大10倍
for(int i=0;i<subList.size();i++){
subList.set(i, subList.get(i)*10);
}
System.out.println(subList);//[30, 40, 50, 60, 70]
//修改子集會影響原集合
System.out.println(list);//[0, 1, 2, 30, 40, 50, 60, 70, 8, 9]
subList.clear();
System.out.println(subList);//[]
System.out.println(list);//[0, 1, 2, 8, 9]
/**
* 集合轉換為數組
* Collection提供了一個方法toString()可以將
* 當前集合轉換為數組
* */
//集合轉換為數組
Collection<String> c=new ArrayList<String>();
c.add("one");
c.add("two");
c.add("three");
c.add("four");
/**
* Object toArray()
* */
//Object[] array =c.toArray(); //不太常用
/**
* T[] toArray(T[] t)
* 我們傳入的數組可以存放集合的所有元素的話,就使用我們給定的數組,存不下
* 就創建一個同類型的數組
* */
String[] array =c.toArray(new String[c.size()]);
//如果是10,則輸出onetwothreefournullnullnullnullnullnull
//如果是2,則輸出onetwothreefour
for(String str:array){
System.out.print(str);//one two three four
}
/**
* 數組轉換為集合
* 需要注意的是,只能轉換為List集,不能轉換為Set集
* Arrays.asList()
* */
//數組轉換為集合
String[] array ={"one","two","three","four"};
List<String> list =Arrays.asList(array);
System.out.println(list);//[one, two, three, four]
//如果集合是從數組轉換過來的,則不能添加元素
//不能添加元素
//list.add("five");//異常java.lang.UnsupportedOperationException
//可以替換
list.set(0, "1"); //返回的是被替換出來的元素
System.out.println(list);//[1, two, three, four]
//替換了集合,數組也會跟著改變
System.out.println(Arrays.toString(array));//[1, two, three, four]
/**
* 若想添加新元素,做這樣的操作,需要創建一個新集合
* */
//若想添加新元素,需要創建一個新集合
List<String> newList =new ArrayList<String>(list);//(list)只要是集合就可放進去
System.out.println(newList);//[1, two, three, four]
newList.add("five");
System.out.println(newList);//[1, two, three, four, five]
刪除元素,移除集合元素
newList.remove("four");
System.out.println(newList); //[1, two, three, five]
/**
* 集合的排序,排序只針對List集
* */
Random random =new Random();
List<Integer> list =new ArrayList<Integer>();
for(int i=0;i<10;i++){
list.add(random.nextInt(100));
}
System.out.println(list);//[13, 60, 85, 13, 24, 41, 32, 73, 84, 51]
/**
* 對集合進行自然排序
* 從小到大
* 使用集合的工具類Collections的靜態方法sort
* Collection和Collections的區別
* Collection是集合的接口,定義了集合應有的行為
* Collections是集合的工具類,提供了方便操作集合的方法
* */
//排序
Collections.sort(list);
System.out.println(list); //[13, 13, 24, 32, 41, 51, 60, 73, 84, 85]
//替換操作 //互相轉換
//Collections.swap(i,j); //替換操作 //互相轉換
【Comparable】排序
第一種方法:實現接口Comparable //不太常用 //用於ArrayList<Point>
package day05;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class SortCollectionDemo1 {
public static void main(String[] args) {
List<Point> list =new ArrayList<Point>(); //Point<>要重寫toString方法
list.add(new Point(1, 2));
list.add(new Point(6,7));
list.add(new Point(3 , 4));
list.add(new Point(5, 5));
System.out.println(list); //[(1,2), (6,7), (3,4), (5,5)]
/**
* 要排序的集合必須保證其元素是可以比較大小的
* */
//要排序的集合必須保證其元素是可以比較大小的
Collections.sort(list); //實現接口,重載方法後可以排序
System.out.println(list);//[(1,2), (3,4), (5,5), (6,7)]
}
}
package day05;
//若當前類的實例間可以比較大小,當前類要實現接口Comparable,
//並重寫比較方法。
public class Point implements Comparable<Point>{ //實現接口Comparable
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String toString(){
return "("+x+","+y+")";
}
/**
* 當我們實現了Comparable接口後,要求重寫該方法
* 該方法的作用是定義Point兩個對象間比較大小的邏輯
* 該方法的放回值為一個int型。放回值不關注具體取值是多少,只關注取值范圍
* 若返回值>0:當前對象比參數對象大
* 若返回值=0:當前對象比參數對象相等
* 若返回值<0:當前對象比參數對象小
* */
//重寫Comparable接口的compareTo(Point o)方法
public int compareTo(Point o) {
/**
* 判斷標准,坐標點到原點的距離長的就大
* */
//判斷標准,坐標點到原點的距離長的就大
int len=this.x*this.x+this.y*this.y;
int olen=o.x*o.x+o.y*o.y;
return len-olen;
}
}
第二種方法:比較器Comparator //更常用
package day05;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortCollectionDemo2 {
public static void main(String[] args) {
List<String> list =new ArrayList<String>();
list.add("boss");
list.add("good");
list.add("No");
list.add("Fine");
System.out.println(list);//[boss, good, No, Fine]
Collections.sort(list);
System.out.println(list);//[Fine, No, boss, good]
list.add("我們");
list.add("你就是");
list.add("他很調");
list.add("明天見");
/**
* sort方法按照元素自身定義的比較規則,但是某些情況下,元素自身提供的比較規則
* 不能滿足我們對於排序需求時,就應當使用重載的sort方法
* */
System.out.println(list);//[Fine, No, boss, good, 我們, 你就是, 他很調, 明天見]
/**
* static void sort(List list,Comparator com) 比Comparable接口更常用
* 重載的sort方法要求我們傳入一個比較器,這是一個臨時的比較規則
* sort可以按照比較器的比較規則對list集合中的元素進行比較大小,然後進行自然排序
* 因為使用自定義的比較器,所以該方法不要求list集合中的元素必須實現Comparable接口。
* */
//比較漢字,用長度
Comparator<String> com=new Comparator<String>(){ //匿名內部類
public int compare(String o1,String o2){
return o1.length()-o2.length();
}
};
Collections.sort(list,com);
System.out.println(list);//[No, 我們, 你就是, 他很調, 明天見, Fine, boss, good]
}
}
str0.compareToIgnoreCase(str1) //無視大小寫比較字母
Collections.sort(list, new Comparator<Contacts>() { //漢字的比較,按字母 //漢字排序
@Override
public int compare(Contacts lhs, Contacts rhs) {
Comparator<Object> cmp0=Collator.getInstance(java.util.Locale.CHINA);
String str0=lhs.getName();
String str1=rhs.getName();
String[] strs={str0,str1};
Arrays.sort(strs,cmp0);
if(strs[0].equals(str1)) {
return 1;
}
return -1;
}
});
【隊列】【Queue】 先進先出 【集合】【LinkedList】
JDK中提供了Queue接口來實現隊列這個數據結構,同時使得LinkedList實現了該接口;
同時,JDK中還提供了Deque接口來實現棧這個數據結構,而 LinkedList也實現了該接口。
如果只在兩端操作數據,選擇LinkedList
只要會操作中間的數據,就用ArrayList
/**
* 隊列
* 該數據結構與集合相似之處在於也是用於存放一組元素只能從隊首獲取
* 所以不能插入元素,也不能任意獲取其中某個元素
* */
//隊列queue //集合LinkedList
Queue<String> queue =new LinkedList<String>();
/**
* boolean offer(E e) //addLast
* 向隊尾追加元素
* */
//向隊尾追加元素
queue.offer("one");
queue.offer("two");
queue.offer("three");
queue.offer("four");
System.out.println(queue);//[one, two, three, four]
/**
* E poll()
* 從隊首獲取元素,出隊操作
* 需要注意,調用後,隊首元素就從隊列中被移除了
* */
//引用隊首元素,並刪除poll();
String str =queue.poll();
System.out.println(str);//one
System.out.println(queue);//[two, three, four]
//引用隊首元素,但不刪除peek();
str =queue.peek();
System.out.println(str);//two
System.out.println(queue);//[two, three, four]
/**
* 遍歷隊列
* int size()
* 隊列也有size方法,用於獲取隊列元素個數
* */
遍歷隊列
方法一:
for(int i=queue.size();i>0;i--){
System.out.println(queue.poll()); //two three four
}
方法二:
while(queue.size()>0){
System.out.println(queue.poll()); //two three four
}
【棧】【Deque】 先進後出 【集合】【LinkedList】
/**
* 棧
* 同樣可以存儲一組元素,棧必須遵循“先進後出”原則
* 棧用於解決一些列的操作可追溯。例如:後退功能
* 站內沒東西了,還pop();會出異常。
* */
//棧Deque 先進後出
Deque<String> stack =new LinkedList<String>();
/**
* 雙端隊列,若只調用一端的進出隊方法,就形成了棧的效果
* */
/**
* void push()
* 入棧操作
* */
//入棧操作
stack.push("one");
stack.push("two");
stack.push("three");
stack.push("four");
stack.push("five");
System.out.println(stack);//[five, four, three, two, one]
/**
* E pop() //removeFist
* 出棧之後,獲取棧頂元素,並且該元素會從棧中被刪除
* */
//出棧之後,該元素會從棧中被刪除
String str =stack.pop();
System.out.println(str); //five
System.out.println(stack); //[four, three, two, one]
//同樣的peek方法也可以引用棧首元素,而不做出戰操作
String str0 =stack.peek();
System.out.println(str0); //four
System.out.println(stack); //[four, three, two, one]
//遍歷棧也是一次性的
while(stack.size()>0){
System.out.print(stack.pop());//four three two one
}
System.out.println(stack); //[]
【HashSet】
此類實現 Set 接口,由哈希表(實際上是一個 HashMap 實例)支持。它不保證 set 的迭代順序;
特別是它不保證該順序恆久不變。此類允許使用 null 元素。
add(數據)
remove(數據)
size()
iterator()
contains(數據)
clear()
不支持下標index訪問
【Map接口】-又稱查找表 //HashMap //TreeSet //沒繼承Collection
Map集合的用處
Map接口定義的集合又稱查找表,用於存儲所謂“Key-Value”映射對。Key可以看成是Value的索引,作為Key的對象在集合中不可以重復。
/**
* map 以key-value對的形式存放數據
* 其中key在Map中是不允許重復的
* 常用的實現類: HashMap
* java.util.*
* Map的key與value的類型是分開指定的
* */
Map<String, Integer>map =new HashMap<String, Integer>();
/**
* V put(K key,V v)
* 將給定的key與value存放入Map中
* 由於Map中不允許存放重復的key,所以,若給定的key已經在Map中存在,
* 則是替換value操作,那麼put方法的返回值就是被替換的元素,否則
* 返回null
* */
//將給定的key與value存放入Map中
map.put("語文", 98); //Integer a=map.put("語文", 98);用Integer 不用int,容易出現異常
map.put("數學", 98);
map.put("英語", 98);
map.put("物理", 98);
map.put("化學", 98);
System.out.println(map);//也重寫了toString{物理=98, 語文=98, 英語=98, 數學=98, 化學=98}
//替換
//重復輸入的元素,被替換出來的是之前的元素的值
Integer re =map.put("化學", 100);
System.out.println(map); //{物理=98, 語文=98, 英語=98, 數學=98, 化學=100}
System.out.println(re); //被替換出來的,之前的值98
//新輸入的元素,被替換出來的是null
Integer ac =map.put("生物", 80);
System.out.println(map);//{物理=98, 語文=98, 英語=98, 數學=98, 化學=100, 生物=80}
System.out.println(ac); //null
/**
* V get(K k)
* 根據給定的key獲取對應的value
* 若給定的key在當前Map中不存在,則返回null
* */
//通過key獲取value值
Integer number =map.get("語文");
System.out.println("語文:"+number);//語文:98
/**
* boolean containsKey(K k)
* 判斷給定的key是否在Map中存在
* 判斷依據也是根據給定的key與Map中所有的key是否具有
* equals比較為true
* */
//判斷是否存在某個元素
boolean contains =map.containsKey("化學");
System.out.println("包含化學:"+contains);//包含化學:true
輸出無序
HashMap<Integer,String> map=new HashMap<Integer, String>();
map.put(111, "111");
map.put(222, "222");
map.put(555, "555");
map.put(777, "777");
map.put(333, "333");
map.put(444, null);
map.put(null, "111"); //key能為null //改正過 //但只能有一個key為null,有兩個也只能顯示一個
map.put(666, "666");
map.put(111, "112");
System.out.println(map); //{null=111, 222=222, 444=null, 666=666, 111=112, 333=333, 555=555, 777=777}
System.out.println(map.size()); //8
System.out.println(map.get(333)); //333
System.out.println(map.remove(444)); //返回值為null
System.out.println(map.containsKey(555)); //true
System.out.println(map.containsValue("999")); //false
System.out.println(map);//{null=111, 222=222, 666=666, 111=112, 333=333, 555=555, 777=777}
【hashcode】 //無序 //但只要輸入的數據一樣,其順序不變 //哈希值 //散列碼
/**
* 重寫一個類的equals方法時,應當連同重寫hashcode方法
* 因為,若當前類的實例在Map中作為key使用時,這兩個方法對於HashMap
* 的性能產生著直接的影響
* 要求:
* 1.若兩個對象equals比較為true,那麼hashcode方法返回的數字必須相同
* 反之沒有要求,但是應當盡量保證兩個對象hashcode不同equals方法也應為
* false。否則對HashMap性能產生直接影響
* 2.hashcode方法返回的數字應該是一個穩定的值,意思是若當前對象的屬性
* 沒有發生改變,hashcode方法返回的數字不應該變化
* */
hashCode方法的意義
以java.lang.Object來理解,JVM每實例化一個Object,它都會將這個Object放入到一個Hash哈希表中去,這樣的話,
下次做Object的比較或者取這個對象的時候,它會根據對象的hashCode再從Hash表中取這個對象。這樣做的目的是提高取對象的效率。具體過程如下:
1) new Object(),JVM根據這個對象的hashCode值,放入到對應的Hash表對應的Key上,如果不同的對象產生了相同的hash值,
也就是發生了Hash key相同導致沖突的情況,那麼就在這個Hash key的地方產生一個鏈表,將所有產生相同hashCode的對象放到這個單鏈表上去,串在一起,就是Hash桶。
2) 比較兩個對象的時候,首先根據他們的hashCode去hash表中找它的對象,當兩個對象的hashCode相同,也就是說這兩個對象
放在Hash表中的同一個key上,則他們一定在這個key上的鏈表上。那麼此時就只能根據Object的equals方法來比較這個對象是否相等。當兩個對象的hashCode不同時,則這兩個對象一定不能相等。
1.通過key.hashCode()得出哈希值
2.用哈希值計算出下標index
3.新建Entry對象 //包括key和value
4.將Entry對象放入index位置
4.1. index是空位置,會直接放入
4.2. index位置有entry對象
4.2.1 依次比較equals()比較鍵是否相等
4.2.1.1 找到相等的,覆蓋掉之前的
4.2.1.2 沒有找到相等的,掛在一起,形成鏈表
只有對象作為哈希表的鍵時,才有用
將對象的內存地址值,處理成int,
如果對象作為鍵,放入哈希表,必須重寫hashCode()方法
可以使用對象屬性,來計算產生hashCode、
容量桶使用超過75%,就加大容量桶個數,使空容量桶變多。
通過加大容量桶的個數,減少哈希值相等的情況,使得每一個容量桶內元素的個數減少 ,
class Cell{
private int row;
private int col;
public Cell(int row, int col) {
super();
this.row = row;
this.col = col;
}
@Override
public int hashCode() { //可一鍵生成
final int prime = 31;
int result = 1;
result = prime * result + col;
result = prime * result + row;
return result;
}
@Override
public boolean equals(Object obj) { //可一鍵生成
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Cell other = (Cell) obj;
if (col != other.col)
return false;
if (row != other.row)
return false;
return true;
}
}
【裝載因子及HashMap優化】
在散列表中有一下名詞需要了解:
Capacity:容量, hash表裡bucket(桶)容量桶的數量, 也就是散列數組大小.
Initial capacity:初始容量, 創建hash表的時 初始bucket的數量, 默認構建容量是16. 也可以使用特定容量.
Size : 大小, 當前散列表中存儲數據的數量.
Load factor:加載因子, 默認值0.75(就是75%), 向散列表增加數據時如果 size/capacity 的值大於Load factor則發生擴容並且重新散列(rehash).
那麼當加載因子較小時候散列查找性能會提高, 同時也浪費了散列桶空間容量. 0.75是性能和空間相對平衡結果. 在創建散列表時候指定合理容量, 從而可以減少rehash提高性能。
【遍歷Map有三種方式】
/**
* 遍歷Map有三種方式
* 遍歷所有的key
* 遍歷所有的key-value對
* 遍歷所有的value(不常用)
* */
Map<String ,Integer> map=new HashMap<String, Integer>();
//new LinkedHashMap {語文=98, 數學=99, 英語=98, 物理=98, 化學=98} 有序的
map.put("語文",98);
map.put("數學",99);
map.put("英語",98);
map.put("物理",98);
map.put("化學",98);
System.out.println(map);//{物理=98, 語文=98, 英語=98, 數學=99, 化學=98} 無序的
/**
* 遍歷所有的key
* Set<K> keySet()
* 該方法會將當前Map中的所有key存入一個Set集合
* 後將其返回,所以遍歷該集合就相當於遍歷了所有的key
* */
//遍歷所有的key //遍歷key //新for循環
Set<String> keyset =map.keySet();
for(String key:keyset){
System.out.print("key:"+key); //key:物理key:語文key:英語key:數學key:化學
}
//另一個例子中key為Integer,value為String。
//for(Iterator<Integer> it=keyset.iterator();it.hasNext();){
// Integer k=it.next(); String v=map.get(k);System.out.println(k+"="+v);
//}
/**
* 遍歷每一組鍵值對
* Set<Entry> entrySet()
* Map有一個內部類Entry,其定義了兩個屬性,分別是
* Key與Value,那麼每一個Entry實例就可以表示Map
* 中的一組鍵值對
* 所以entrySet方法就是將Map中的每一組鍵值對(每一個Entry)
* 存入Set集合然後返回
* Entry的泛型應當與Map的泛型一致
* */
//遍歷每一組鍵值對entry
Set<Entry<String,Integer>> entrySet =map.entrySet();
for(Entry<String , Integer> entry: entrySet){
String key =entry.getKey();
Integer value=entry.getValue();
System.out.print(key+":"+value);//key:物理key:語文key:英語key:數學key:化學物理:98語文:98英語:98數學:99化學:98
}
//另一個例子中key為Integer,value為String。
//for(Iterator<Entry<Integer,String>> it=entrySet.iterator();it.hasNext();){
// Entry<String , Integer> e=it.next(); Integer k=e.getKey();String v=e.getValue():System.out.println(k+"="+v);
//}
/**
* 遍歷所有的value
* Collection<V> values()
* 將Map中所有的value存入一個集合然後返回
* 這個集合不是Set,因為Map可以存放重復的value
* */
//遍歷所有的value //不常用 //不能用Set,因為Set內不可重復,而Map的Value值可重復,只有key不可重復
Collection<Integer> values=map.values();
for(Integer value:values){
System.out.println(value); //98 98 98 99 98
}
//另一個例子中key為Integer,value為String。
//for(Iterator<String> it=value.iterator();it.hasNext();){
// String v=it.next(); System.out.println(v);
//}
【TreeMap】
樹形,左小,中間中等,右邊大,先從從簡開始,一層一層往下跑,只用跑幾層。
Key鍵值:
1.不重復
2.有序的
3.不容許null值(空值)
創建對象
1. TreeMap map =new TreeMap();
2. //輸出從小到大
HashMap<Integer,String> map=new HashMap<Integer, String>();
map.put(111, "111");
map.put(222, "222");
map.put(555, "555");
map.put(777, "777");
map.put(333, "333");
map.put(444, "null");
//map.put(null, "111"); //key不能為null
map.put(666, "666");
map.put(111, "112");
System.out.println(map); //{111=112, 222=222, 333=333, 444=null, 555=555, 666=666, 777=777}
System.out.println(map.size()); //7
System.out.println(map.get(333)); //333
System.out.println(map.remove(444)); //返回值為null
System.out.println(map.containsKey(555)); //true
System.out.println(map.containsValue("999")); //false
System.out.println(map);//{111=112, 222=222, 333=333, 555=555, 666=666, 777=777}
//如兩種方法都有,則使用比較器的代碼
第一種方法: //用於TreeMap //使用實現implements Comparable接口
package day04;
import java.util.TreeMap;
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
Point p1 =new Point(1,3);
Point p2 =new Point(2,5);
TreeMap<Point, String> map =new TreeMap<Point, String>();
map.put(p1, "2.9億");
map.put(p2, "3億");
System.out.println(map); //{(x=1, y=3)=2.9億, (x=2, y=5)=3億}
}
}
package day04;
public class Point implements Comparable<Point>{
private int x;
private int y;
public Point() {
super();
}
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "(x=" + x + ", y=" + y + ")";
}
@Override
public int compareTo(Point o) {
return x-o.x;
}
}
第二種方法: //用於TreeMap //使用自制比較器Comparator,沒用實現
package day04;
import java.util.Comparator;
import java.util.TreeMap;
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
Point p1 =new Point(1,3);
Point p2 =new Point(2,5);
Comparator<Point> comp =new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
return o1.getY()-o2.getY();
}
};
TreeMap<Point, String> map =new TreeMap<Point, String>(comp);
map.put(p1, "2.9億");
map.put(p2, "3億");
System.out.println(map); //{(x=1, y=3)=2.9億, (x=2, y=5)=3億}
}
}
package day04;
public class Point{
private int x;
private int y;
public Point() {
super();
}
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "(x=" + x + ", y=" + y + ")";
}
}
【枚舉】【enum】
一組固定選項
可以代替數字代碼常量
枚舉本質就是類
enum關鍵字,代替class關鍵字
固定的枚舉選項,本質是枚舉類的實例
public enum Type{
COLD,HEAT,NUCLEAR
}
public class Type{
public static final Type COLD=new Type();
public static final Type HEAT =new Type();
public static final Type NUCLEAR=new Type();
}
void f(Type t){
}
f(Type.COLD);
f(Type.HEAT);
Type t =weapon.getType();
switch(t){ //變形金剛
case COLD: //不用Type.COLD //枚舉的特性
case HEAT:
}
【異常】
封裝錯誤信息的對象
對象類型名稱
錯誤提示
出錯行號
異常繼承結構
Throwable
|-Error 系統級錯誤 //比如超出內存memory
|-Exception 可以編寫代碼修復的錯誤
|-其他 //需要手動設置異常拋出管道 //如果不設置,就要捕獲這種異常
|-RuntimeException //和其子類型存在默認的異常拋出管道
|-NullPointException
|-ArrayIndexOutOfBoundsException
|-NumberFormatException //數字格式異常
|-ArithmeticException //計算異常
異常捕獲
package day05;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
while(true){ //異常捕獲
try{
test2();
break;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("請輸入兩個數字,不是一個");
}catch(NumberFormatException e){
System.out.println("請輸入整數");
}catch(Exception e){ //父類錯誤要放在後面,不然子類錯誤就沒用了
System.out.println("不懂你輸入的是什麼東西!");
}finally{
System.out.println("絕對會執行的");
}
}
}
private static void test2(){
System.out.println("輸入逗號隔開的兩個整數");
String s=new Scanner(System.in).nextLine();
String[] arr =s.split(",");
int a =Integer.parseInt(arr[0]);
int b=Integer.parseInt(arr[1]);
int c =a/b;
System.out.println(a+"+"+b+"="+c);
System.out.println(180.0/0); //Infinity無窮大
}
}
設置異常拋出管道
package day05;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
try{
test1();
}catch(ParseException e){
System.out.println("親,你輸入的不是日期!");
}
}
private static void test1() throws ParseException{ //throws**設置異常拋出管道
System.out.println("輸入日期(yyyy-MM-dd),"+"顯示該日期距離"+"1970-1-1 0點多少毫秒");
String s =new Scanner(System.in).nextLine();
SimpleDateFormat f=new SimpleDateFormat("yyyy-MM-dd");
Date d=f.parse(s);
System.out.println(d.getTime());
}
}
記錄異常
try{
test1();
}catch(Exception e){
e.printStackTrace(); //java.text.ParseException: Unparseable date: "15415hy"
System.out.println(e.getMessage());//Unparseable date: "15415hy"
}
【finally】 //最後會執行
try{
test2();
break;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("請輸入兩個數字,不是一個");
}catch(NumberFormatException e){
System.out.println("請輸入整數");
}catch(Exception e){ //父類錯誤要放在後面,不然子類錯誤就沒用了
System.out.println("不懂你輸入的是什麼東西!");
}finally{ //最後會執行
System.out.println("絕對會執行的");
}
【File】表示一個文件或目錄
//為了避免在不同系統上運行時的異常,所以目錄用相對目錄,不用絕對目錄
/**
* java.io.File
* 該類用於表示一個文件或目錄
* 使用該類可以獲取表示的文件或目錄的屬性信息
* 但是不能訪問文件的內容
* 使用該類還可以操作文件或目錄(新建,刪除等)
("d:\\a.txt"); (目錄,文件名)
File f1 =new File("d:\\good.txt"); //存在的文件
File f2= new File("D:\\workspace_1503","study.txt"); //存在的文件
File f4= new File("D:\\workspace_1503"); //存在的目錄
File f3 =new File("d:\\goodday.txt"); //不存在的文件
System.out.println("可讀:"+f1.canRead()); //可讀:true
System.out.println("可寫:"+f1.canWrite()); //可寫:true
System.out.println("可執行:"+f1.canExecute()); //可執行:true
System.out.println("隱藏:"+f1.isHidden()); //隱藏:false
System.out.println("存在:"+f1.exists()); //存在:true
System.out.println("完整路徑:"+f1.getAbsolutePath()); //完整路徑:d:\good.txt
System.out.println("文件名:"+f1.getName()); //文件名:good.txt
System.out.println("父目錄:"+f1.getParent()); //父目錄:d:\
System.out.println("最後修改時間(毫秒):"+f1.lastModified()); //最後修改時間(毫秒):1429258060390
System.out.println("字節量:"+f1.length()); //字節量:61
System.out.println("是目錄:"+f1.isDirectory()); //是目錄:false
System.out.println("字文件:"+f1.isFile()); //字文件:true
System.out.println("總空間:"+f1.getTotalSpace()); //總空間:143670931456
System.out.println("可用空間:"+f1.getFreeSpace()); //可用空間:133532409856
createNewFile(); //創建文件
dir.mkdirs(); //創建多重目錄
dir.mkdir(); //創建目錄
* */
/**
* 創建一個File用來表示項目根目錄下的test.txt文件
* ("./test.txt");表示當前項目的目錄 //只表示當前目錄時./可以省略
* File.separator表示/或者\
* */
File file =new File("."+File.separator+"test.txt"); //不會創建新的
/**
* 判斷表示的文件是否真實存在於硬盤上
* boolean exists()
* */
//判斷表示的文件是否真實存在於硬盤上
if(file.exists()){
System.out.println("文件存在");//文件存在
}else{
System.out.println("文件不存在");
}
/**
* long length()
* 查看當前文件占用的字節量
* */
//查看當前文件占用的字節量
long length =file.length();
System.out.println("占用"+length+"字節"); //占用18字節
/**
* boolean isFile()
* 判斷當前File對象表示的是不是一個文件
* 是則返回true
* */
//判斷當前File對象表示的是不是一個文件
if(file.isFile()){
System.out.println("是文件");//是文件
}else{
System.out.println("不是文件");
}
/**
* boolean isDirectory()
* 判斷當前File對象表示的是否為一個目錄
* */
//判斷當前File對象表示的是否為一個目錄
if(file.isDirectory()){
System.out.println("是目錄");
}else{
System.out.println("不是目錄");//不是目錄
}
/**
* 以下三個方法返回boolean值
* 分別表示:
* 可運行,可讀,可寫
* */
//可運行,可讀,可寫
// file.canExecute()
// file.canRead()
// file.canWrite()
/**
* 文件的最後寫該時間
* long表示1970年元旦到這一刻的毫秒值
* */
//文件的最後寫該時間
long last =file.lastModified();
Date date=new Date(last);
System.out.println(date);//2015-04-09
SimpleDateFormat sdf =new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str =sdf.format(date);
System.out.println(str); //2015年04月09日 16:37:18
/**
* String getName()
* 獲取當前File對象表示的文件或目錄名
* */
//獲取當前File對象表示的文件或目錄名
String name=file.getName();
System.out.println(name);//test.txt
/**
* 在當前項目根目錄下創建文件demo.txt
* */
//在當前項目根目錄下創建文件
File file =new File("demo.txt");
//若不存在才創建
if(!file.exists()){
file.createNewFile(); //創建文件
System.out.println("創建完畢");//創建完畢
}
/**
* 刪除一個文件
* 刪除項目根目錄下的demo.txt文件
* */
//刪除項目根目錄下的demo.txt文件
File file =new File("demo.txt");
if(file.exists()){
file.delete();
System.out.println("刪除完畢");//刪除完畢
}
/**
* 在當前項目根目錄下創建子目錄demo
* */
//創建目錄 //創建文件夾
File dir =new File("demo");
if(!dir.exists()){
dir.mkdir();
System.out.println("創建完畢");
}
//刪除目錄,刪除文件
//這個文件夾必須是空的,內面不能有文件或文件夾
File dir =new File("demo");
if(dir.exists()){
dir.delete();
System.out.println("刪除完畢"); //刪除完畢
}
/**
* 在當前項目根目錄下創建目錄:a/b/c/d/e/f
* */
//創建目錄:a/b/c/d/e/f //創建文件夾
File dir =new File(
"."+File.separator+"a"+
File.separator+"b"+
File.separator+"c"+
File.separator+"d"+
File.separator+"e");
if(!dir.exists()){
dir.mkdirs(); //創建目錄
System.out.println("創建完畢"); //創建完畢
}
/**
* 查看一個目錄下的所有子項
* */
//查看一個目錄下的所有子項
File dir =new File(".");
/**
* File[] listFiles() //dir.list();
* 將當前目錄下的每一個子項用一個File對象去描述然後將他們存入一個數組返回
* */
File[] subs= dir.listFiles();
for(File sub:subs){
if(sub.isFile()){
System.out.println("是文件:"); //是文件: //是文件:
}
if(sub.isDirectory()){
System.out.println("目錄:"); //目錄: //目錄: //目錄:
}
System.out.println(sub.getName()); //bin //src //.settings //.project //.classpath
}
//目錄:
//bin
//目錄:
//src
//目錄:
//.settings
//是文件:
//.project
//是文件:
//.classpath
遍歷一個目錄內的所有文件 //遍歷文件名
package day18;
import java.io.File;
public class Test1 {
public static void main(String[] args) {
File dir =new File("D:\\1503下載\\java_code\\day01\\day0101_HelloWorld");
String[] names =dir.list(); //String[]
File[] files =dir.listFiles(); //File[]
for(String s:names){
System.out.print(s+" "); //.classpath .project .settings bin src //目錄文件
}
System.out.println();
for(File f:files){
String n =f.getName();
long len =f.length();
System.out.print(n+" ");
if(f.isFile()){
System.out.println("------"+len);
}else{
System.out.println("------"+len);
}
}
}
}
//.classpath ------301
//.project ------394
//.settings ------0
//bin ------0
//src ------0
改文件的名字
File a =new File("d:\\f1");
File b =new File("d:\\f11");
if(a.exists()){
boolean bol =a.renameTo(b);
System.out.println("改名成功:"+bol);
}else{
boolean bol=b.renameTo(a);
System.out.println("改名成功:"+bol);
}
創建臨時文件 //不確定
File.creatTempFile("d:\\","a.txt")
/**
* 使用文件過濾器FileFilter來獲取一個目錄下
* 滿足條件的部分子項
* */
//過濾器FileFilter
//使用文件過濾器FileFilter來獲取一個目錄下滿足條件的部分子項
FileFilter filter =new FileFilter() {
/**
* 實現FileFilter接口後必須重寫accept方法
* 該方法用於定義過濾條件,若參數file滿足過濾條件返回值久違true即可
* */
@Override
public boolean accept(File file) {
System.out.println("正在過濾:"+file.getName());//正在過濾:bin 正在過濾:src 正在過濾:.settings 正在過濾:.project 正在過濾:.classpath
return file.isFile();
}
};
File dir =new File(".");
//獲取當前目錄下滿足過濾器要求的所有子項
File[] subs =dir.listFiles(filter);
for(File sub:subs){
System.out.println(sub.getName()); //.project //.classpath
}
//刪掉當前目錄下文件後綴為".jar"的文件,但不能刪掉子文件中的文件
FileFilter filter =new FileFilter() { //過濾器FileFilter
public boolean accept(File file) {
if(file.isFile()){
if(file.getName().endsWith(".jar")){
return true;
}
}
return false;
}
};
File dir =new File(".");
File[] subs =dir.listFiles(filter);
for(File sub:subs){
System.out.println(sub.getName());
}
【遞歸刪除】 //不能用循環就用遞歸
package day06;
import java.io.File;
public class FileDemo3 {
public static void main(String[] args) {
/**
* 刪除給定的File對象
* 該對象可能表示文件也可能表示目錄,總之要刪除
* */
/**
* 將給定的File對象表示的文件或目錄刪除
* */
//遞歸刪除 一個目錄(文件夾)內所有目錄文件或文件
File dirs =new File("a");
delete(dirs);
}
public static void delete(File file){ //遞歸刪除,在方法內部調方法
if(file.isDirectory()){ //如果是空目錄也會走這一步
//先將所有子項刪除
File[] subs =file.listFiles();
for(File sub:subs){ //如果是空文件夾,就不會走下面這步進入循環,
delete(sub);
}
}
file.delete();
}
}
package day06; //1+2+3+.......+100
public class HomeWork1 {
int b = 0;
int i=1;
public static void main(String[] args) {
HomeWork1 a=new HomeWork1();
a.add();
System.out.println(a.b); //5050
}
public void add(){ //還可以用 if(n==1){return 1;} return n+add(n-1);
if(i<=100){
b =b+i;
if(i==100){
System.out.print(i+"=");
}else{
System.out.print(i+"+");
}
if(i%10==0){
System.out.print('\n');
}
i++;
add();
}
}
}
【讀寫文件數據】 //下載時,開幾個線程分別從不同的字節開始下載 //斷點續傳
/**
* java.io.RandomAccessFile
* 該類用於讀寫文件數據
* */
/**
RandomAccessFile的兩種創建模式
讀寫模式與只讀模式
讀寫模式:可以讀取文件數據,也可以向文件中寫入數據
只讀模式:只能讀取文件數據
* RandomAccessFile的讀寫操作是基於指針的,總是在
* 指針當前指向的位置進行讀寫操作的
* */
/**
* 創建一個用於讀寫項目根目錄下的test.dat文件的RandomAccessFile
* 兩個常用的構造方法
* RandomAccessFile(String path,String mode)
* RandomAccessFile(File file,String mode)
* */
RandomAccessFile類的read方法和write方法使用int類型存儲byte數據的方式和原因:
1)RandomAccessFile提供了一個可以從文件中讀取字節的方法:
int read()
該方法會從文件中讀取一個byte(8位) 填充到int的低八位, 高24位為0, 返回值范圍正數: 0~255,
如果返回-1表示讀取到了文件末尾! 每次讀取後自動移動文件指針, 准備下次讀取。
2)RandomAccessFile提供了一個可以向文件中寫出字節的方法:
void write(int d)
該方法會根據當前指針所在位置處寫入一個字節,是將參數int的”低8位”寫出。
3)使用int類型存儲byte數據,這是因為,RandomAccessFile類的read方法,能讀到的數據有257個數值,
其中,0到255表示數據,-1表示讀取到了文件末尾。而write方法與read方法是一對方法,因此write方法也采用了int類型。
新建
//方法一
// File file =new File("test.dat");
// RandomAccessFile raf1 =new RandomAccessFile(file, "rw");
//方法二
RandomAccessFile raf=new RandomAccessFile("test.dat","rw"); //創建文件
/**
* void write(int d)
* int四個字節 最大值為01111111 11111111 11111111 11111111
* 首位是符號位
* 向文件中寫入一個字節,寫出的是給定的int值2進制中的“低8位”
* 00000000 00000000 00000000 00000001 //是1
* 11111111 11111111 11111111 11111111 //負1,加1進位為0
* 永遠是最後8個0
* */
//寫入一個值 //最大255
raf.write(255); //最大255。 //256時,00000001 00000000只能讀取到0
//raf.write(50);
raf.close();
//讀取文件
RandomAccessFile raf2=new RandomAccessFile("test.dat","r");
/**
* int read()
* 從文件中讀取一個字節,並以int形式返回,需要注意
* 該int值只有“低八位”有值
* 若讀取到了文件末尾,負的最大值是-1,則返回-1
* EOF(end of file)
* */
int n =raf2.read();
//int c=raf2.read();
System.out.println(n); //255
//System.out.println(c) //50
raf2.close();
/**
* 1.創建RandomAccessFile讀取源文件
* 2.創建RandomAccessFile用於寫道目標文件
* 3.循環從源文件讀取讀取一個字節寫入到目標文件,直到源文件所有內容都讀取完畢
* 4.關閉RandomAccessFile
* */
//復制文件 //循環讀取一個字節
RandomAccessFile src =new RandomAccessFile("test.txt", "r");
RandomAccessFile des =new RandomAccessFile("test_copy.txt", "rw");
long start =System.currentTimeMillis();
int d =-1;
while((d=src.read())!=-1){ //注意括號
des.write(d);
}
long end =System.currentTimeMillis();
System.out.println("文件復制完畢!");
System.out.println("耗時:"+(end-start)+"ms");
src.close();
des.close();
//批量寫入 //寫入字符串
RandomAccessFile raf =new RandomAccessFile("test.txt", "rw");
/**
* void write(byte[] d)
* 將給定的字節數組中的所有字節一次性寫出
* */
String str ="摩擦摩擦在這光滑的地面上摩擦"; //復制在最上面
*將當前字符串按照系統默認字符集轉換為對應的字節
byte[] date =str.getBytes(); //搜索Stringbyte //("GBK");
raf.write(date); //寫入:摩擦摩擦在這光滑的地面上摩擦 //des.write(buf,0,len);下面有用
raf.close();
另一個例子:(
String s=“ABC中國”;
byte[] gbk =s.getBytes("GBK");//將字符串s中的字符按照“GBK”編碼規則進行處理,
System.out.println(gbk.length); //7
)
//讀取給定的字節量 //讀文件和寫文件要新建new兩個對象,不能一個對象又讀又寫,除非用raf.seek(0);把指針返回到0位置才能用一個對象寫之後再讀
RandomAccessFile raf2 =new RandomAccessFile("test.txt", "r");
/**
* int read(byte[] d)
* 一次性嘗試讀取給定的字節數組的length個字節,並存入到給定的字節數組中
* 返回值為實際讀取到的字節量。若返回值為-1,說明讀取到文件末尾的。
* */
byte[] date2 =new byte[200];
int n =raf2.read(date2); //raf.read(buf,3,4); //讀取buf內從下標3開始的4個字節, 不是區間的含頭不含尾
System.out.println("實際讀取到的字節量:"+n);//實際讀取到的字節量:81
//System.out.println("實際讀取到的字節量:"+n+Arrays.toString(date2));
//輸出:實際讀取到的字節量:28[-60, -90, -78, -63, -60, -90, -78, -63, -44, -38, -43, -30, -71, -30, -69, -84, -75, -60, -75, -40, -61, -26, -55, -49, -60, -90, -78, -63, 0, 0, 0, 0, 0,
/**
* 將字節轉換為對應的字符串
* 可以使用String的構造方法
* String(byte[] d)
* 該構造方法會將給定的字節數組中的所有字節按照
* 當前系統默認的字符集轉換為對應的字符串
* String(byte[] d,int offset,int len)
* 將當前字節數組從offset處開始的連續len個字節轉換為對應的字符串
* */
*將字節數組中的所有字節轉換為對應的字符串
* String str3=new String(date2,0,n); //只傳一次 //(gbk,"GBK")
System.out.println(str3); //摩擦摩擦在這光滑的地面上摩擦
raf2.close();
循環讀取多個字節:
byte[] date2 =new byte[4];
int n;
String cc = "";
while((n =raf2.read(date2))!=-1){
String str3=new String(date2,0,n);
cc+=str3;
}
System.out.println(cc);
編碼
String s="ABC中國";
byte[] gbk =s.getBytes("GBK");//將字符串s中的字符按照“GBK”編碼規則進行處理,
byte[] utf8 =s.getBytes("UTF-8"); //編碼
System.out.println(gbk.length); //7
System.out.println(utf8.length); //9
String ss=new String(gbk,"GBK"); //解碼
System.out.println(ss); //ABC中國
String s2= new String(utf8,"UTF-8"); //解碼
System.out.println(s2); //ABC中國
String s3=new String(utf8,"GBK"); //解碼成亂碼
System.out.println(s3); //ABC涓浗
復制
若想要提高讀寫效率,需要提高讀寫的數據量,從而降低讀寫次數
RandomAccessFile src =new RandomAccessFile("test.txt", "r");
RandomAccessFile des= new RandomAccessFile("test_copy.txt", "rw");
byte[] buf =new byte[1024*10]; //10k 緩存 //常用8192 8k
//記錄每次實際讀取到的字節量
int len=-1;
long start =System.currentTimeMillis();
* while((len=src.read(buf))!=-1){ //傳到傳完為止
/**
* void write(byte[] d,int offset,int len)
*
* */
des.write(buf,0,len);
}
long end =System.currentTimeMillis();
System.out.println("復制完畢!");//復制完畢!
System.out.println("耗時:"+(end-start)+"ms"); //耗時:0ms
src.close();
des.close();
RandomAccessFile raf =new RandomAccessFile("demo.dat", "rw");
/**
* long getFilePointer()
* 該方法用於獲取RAF當前指針位置
* */
【獲取RAF當前指針位置】
System.out.println("point:"+raf.getFilePointer());//point:0
int max =Integer.MAX_VALUE;
//01111111 11111111 11111111 11111111
//raf.write(max>>>24); //向右移24位
raf.writeInt(max); //系統自己移四次,把最大值寫出去
//寫入四個字節
【writeInt】 //writeDouble(double d) // writeUTF(String s) abc 輸出00 03 61 62 63 兩個字節表示長度,剩下的的表示字符串//十六進制61是97
System.out.println("point:"+raf.getFilePointer()); //point:4
raf.writeLong(123L);
System.out.println("point:"+raf.getFilePointer()); //point:12
raf.writeDouble(123.123);
System.out.println("point:"+raf.getFilePointer()); //point:20
/**
* void seek(long pos)
* 將指針移動到指定位置
* */
//將指針移動到指定位置
raf.seek(0);
/**
* int readInt() //int有四個字節
* 連續讀取4個字節,將對應的int值返回
* 若讀取到文件末尾,-1,該方法會拋出異常
* 一開是就在末尾,就是-1,就會報錯,所以要將將指針移動到指定位置0
* */
【readInt】 //readDouble //readUTF() 先讀取2個字節來確定字符串的字節長度,再讀取這些字節,轉換成字符串
//連續讀取4個字節 //因為會讀取整數,可能是-1,所以不能用-1表示結束,用EOFException異常表示結束
int a=raf.readInt();
System.out.println(a);//2147483647
long l=raf.readLong();
System.out.println("long:"+l);//long:123
double d=raf.readDouble();
System.out.println("double:"+d); //double:123.123
raf.close();
RandomAccessFile raf =new RandomAccessFile("d:\\f4", "rw");
raf.write(97);
raf.write(98);
raf.writeInt(97);
raf.writeInt(98);
raf.writeUTF("abc中文");
raf.writeDouble(3.14);
raf.seek(0);
System.out.println(raf.read()); //97
System.out.println(raf.read()); //98
System.out.println(raf.readInt()); //97
System.out.println(raf.readInt()); //98
System.out.println(raf.readUTF()); //"abc中文"
System.out.println(raf.readDouble()); //3.14
raf.close();
【移位運算符】
計算機中數據管理單位是8位byte,文件IO都是8位單元組成
<< //左移 //數據的鏈接 //將數據byte合並為我們需要的數據,稱為“反序列化”
11010011 10100110//向左移,右邊加個0
>> //算術右移 //負數右移依然是負數
11010011 11101001//向右移,
>>> //邏輯右移 //負數右移變成正數 //將int long等數據進行拆分 //將數據拆分為byte數據才能寫出到文件,稱為“序列化”
11010011 01101001 //向右移,左邊加個0
序列化和反序列化可以由API完成
將String拆分為byte數據才能寫出到文件,稱為“編碼”
編碼方式有:GBK GB2312 UTF-8 UTF-16BE
編碼和解碼的規則必須一致,否則亂碼
int c=8;
Log.i("info","c<<3"+(c<<33));
33%32 為1,所以等於c<<1,所以c=16
int a=8;
a=a>>1;
Log.i("info","a="+a);
a=4
int b=-8;
Log.i("info","b>>2="+(b>>2));
b等於-2
Log.i("info","b>>>2="+(b>>>2));
b等於1073741822,相當於將原數據看成無符號數4294967288(fffffff8),再除4
int a=-100;
a=a>>2;
System.out.println(a);//-25
//255/2<<16=01111111 00000000 00000000
//255/2<<8= 01111111 00000000
//255/2 = 01111111
//color =(r<<16)+(g<<8)+b;
//int =(b1<<24)+(b2<<16)+(b3<<8)+b4; //數據的鏈接 //左移
【文字編碼規則】
GBK 編碼規則
A 變長編碼 1~2字節
英文 1字節
中文 2字節
如:“ABC中國”->{byte*7}
B 支持的文字數量:中文+英文 20000+
C 中國本地最優編碼
UTF-8編碼規則
A 變長編碼1~4字節
英文1字節
中文3字節
如:“ABC中國”->{byte*9}
B 支持文字數量:100000+
英文 中 日 韓 希伯來 阿拉伯。。。。等地球上有的
C 國際化最優編碼
String s="ABC中國";
byte[] gbk =s.getBytes("GBK");//將字符串s中的字符按照“GBK”編碼規則進行處理,
byte[] utf8 =s.getBytes("UTF-8"); //編碼
System.out.println(gbk.length); //7
System.out.println(utf8.length); //9
String ss=new String(gbk,"GBK"); //解碼
System.out.println(ss); //ABC中國
String s2= new String(utf8,"UTF-8"); //解碼
System.out.println(s2); //ABC中國
String s3=new String(utf8,"GBK"); //解碼成亂碼
System.out.println(s3); //ABC涓浗
【二進制】
十進制轉換為二進制
System.out.println(Integer.toBinaryString(210)); //11010010
當輸入10進制時,java將輸入的10進制字符串轉換為2進制數據,保存到內部
當需要將內存數據顯示給用戶時,再利用算法將2進制轉換為10進制的字符串顯示
十進制到二進制 到16進制
int n =Integer.parseInt("250"); //字符串到整形 //自動調用 //字符串整形
System.out.println(Integer.toBinaryString(n)); //11111010//十進制到二進制
System.out.println(Integer.toHexString(156));//9c //10進制到16進制
//十進制轉換為任意進制
String a=Integer.toString(111, 16); //整形到字符串 左邊是數,右邊是進制 //自動調用
System.out.println(a); //6f
//二進制轉換為十進制 //任意進制轉換為十進制
String x="111";
int y=Integer.parseInt(x, 2); //右邊參數是進制 //轉成10進制
System.out.println(y); //十進制7
System.out.println(Integer.toBinaryString(y)); //二進制111
int aa=-1;
aa=aa+(1024*1024*1024*2);
System.out.println(aa); //2147483647 //加半圈,等於相對的,絕對值相加等於同一個數
int cc=0;
cc=cc+(1024*1024*1024*2);
System.out.println(cc); //-2147483648 //加半圈
int bb=8;
bb=bb+(1024*1024*1024*2*2);
System.out.println(bb); //8 加一圈等於自己
int ii=-1;
System.out.println(Integer.toBinaryString(ii));//11111111111111111111111111111111
System.out.println(Integer.toBinaryString(2147483647)); //最大值01111111111111111111111111111111
System.out.println(Integer.toBinaryString(-2147483648));//最小值10000000000000000000000000000000
便捷書寫二進制的-1
int i=0xffffffff; //-1
前面加0是8進制
007 //7
008 //錯,8進制沒有008,已經進位成010
0150 //104
【顏色】
JFrame f =new JFrame();
JPanel p =new JPanel();
int color=(int)(Math.random()*0xffffff);//16777215 //隨機顏色
p.setBackground(new Color(0xff<<8)); //new Color(0xff<<8) 綠色
f.setSize(450,550);
f.add(p);
f.setVisible(true);
【InputStream與OutputStream】
【字節流】 //可以處理圖片,音樂,文件等,使用的頻率比字符流高 //都是Stream結尾
【InputStream與OutputStream】 //抽象類 //輸入和讀取要新建兩個對象,output和input
【輸入流】【輸出流】 //不可能又讀又寫
什麼是輸入:輸入是一個從外界進入到程序的方向,通常我們需要“讀取”外界的數據時,使用輸入。所以輸入是用來讀取數據的。
什麼是輸出:輸出是一個從程序發送到外界的方向,通常我們需要”寫出”數據到外界時,使用輸出。所以輸出是用來寫出數據的。
//引用為null,不能調用任何方法,比如.close();
【節點流】和【處理流】 //流不為null 才能.close();
按照流是否直接與特定的地方 (如磁盤、內存、設備等) 相連,分為節點流和處理流兩類。
節點流:可以從或向一個特定的地方(節點)讀寫數據。 //低級流 :真正幫我們來進行讀寫操作的流,來源(輸入流)和去向(輸出流)是明確的
處理流:是對一個已存在的流的連接和封裝,通過所封裝的流的功能調用實現數據讀寫。 //高級流 也分為輸入流和輸出流
處理流的構造方法總是要帶一個其他的流對象做參數。一個流對象經過其他流的多次包裝,稱為流的鏈接。
//高級流不能獨立存在,必須基於另一個流進行工作,通常是對被處理流中的數據進行加工,以簡化我們對讀寫的操作復雜度。
//高級流類似於連在水龍頭上的淨水器或熱水器 //麥克風 喇叭
InputStream是所有字節輸入流的父類,其定義了基礎的讀取方法,常用的方法如下:
int read()
讀取一個字節,以int形式返回,該int值的”低八位”有效,若返回值為-1則表示EOF。
int read(byte[] d)
嘗試最多讀取給定數組的length個字節並存入該數組,返回值為實際讀取到的字節量。
available()
獲得剩余的可讀取字節量
OutputStream是所有字節輸出流的父類,其定義了基礎的寫出方法,常用的方法如下:
void write(int d)
寫出一個字節,寫的是給定的int的”低八位”
void write(byte[] d)
將給定的字節數組中的所有字節全部寫出
write(byte[] d ,int from ,int n);
讀取字節數組d從from開始的n個字節 //不是含頭不含尾
【文件流】
創建FOS對象(重寫模式) //低級流 //寫入內容
FileOutputStream是文件的字節輸出流,我們使用該流可以以字節為單位將數據寫入文件。
構造方法 1:
FileOutputStream(File file)
創建一個向指定 File 對象表示的文件中寫入數據的文件輸出流。
例如:
File file = new File("demo.dat");
FileOutputStream fos = new FileOutputStream(file);
構造方法 2:
FileOutputStream(String filename):
創建一個向具有指定名稱的文件中寫入數據的輸出文 件流。
例如:
FileOutputStream fos = new FileOutputStream("demo.dat"); //創建文件,寫入內容
這裡需要注意,若指定的文件已經包含內容,那麼當使用FOS對其寫入數據時,會將該文件中原有數據全部清除。
創建FOS對象(追加模式)
通過上一節的構造方法創建的FOS對文件進行寫操作時會覆蓋文件中原有數據。若想在文件的原有數據之後追加新數據則需要以下構造方法創建FOS
構造方法:
FileOutputStream(File file,boolean append)
創建一個向指定 File 對象表示的文件中寫入數據的文件輸出流。
例如:
File file = new File("demo.dat");
FileOutputStream fos = new FileOutputStream(file,true);
構造方法:
FileOutputStream(String filename,boolean append):
創建一個向具有指定名稱的文件中寫入數據的輸出文 件流。
例如:
FileOutputStream fos = new FileOutputStream("demo.dat",true); //創建文件,寫入內容
以上兩個構造方法中,第二個參數若為true,那麼通過該FOS寫出的數據都是在文件末尾追加的。
FileOutputStream out =new FileOutputStream("d:\\f4");
out.write(97);
out.write(98);
out.write(93);
out.write(200);
byte[] buf ={100,101,102,103,104,105,106};
out.write(buf);
out.write(buf,2,5); //從下標2開始寫5個
out.close();
創建FIS對象 //讀取內容
FileInputStream是文件的字節輸入流,我們使用該流可以以字節為單位讀取文件內容。
FileInputStream有兩個常用的構造方法:
FileInputStream(File file):
創建用於讀取給定的File對象所表示的文件FIS
例如:
File file = new File("demo.dat");
FileInputStream fis
= new FileInputStream(file);//創建一個用於讀取demo.dat文件的輸入流
另一個構造方法:
FileInputStream(String name):
創建用於讀取給定的文件系統中的路徑名name所指定的文件的FIS
例如
FileInputStream fis
//創建一個用於讀取demo.dat文件的輸入流
= new FileInputStream("demo"); //不會創建文件
流的使用范例:
FileOutputStream fos =new FileOutputStream("fos.txt",true); //加true後,不會覆蓋源文件的內容 //輸出流
String str ="一馬奔騰神雕摩擦摩擦是";
byte[] dat =str.getBytes("UTF-8"); //編碼怎麼放
//寫入 fos.write(dat); //寫入
fos.close(); //流使用完畢後要關閉,以釋放底層C的資源
FileInputStream fis //創建一個用於讀取demo.dat文件的 //輸入流
= new FileInputStream("fos.txt");
byte[] buf =new byte[100]; //嘗試讀取100個字節,返回值為實際讀取到的字節量
//讀取 int len =fis.read(buf); //讀取
String str1 =new String(buf,0,len,"UTF-8"); //編碼怎麼放
System.out.println(str);
fis.close();
FileInputStream in;
in=new FileInputStream("d:\\f4");
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
in.close();
in=new FileInputStream("d:\\f4");
byte[] buf =new byte[20];
int a=in.read(buf);
String string=new String(buf,0,a);
System.out.println(string);
System.out.println(in.read(buf)+"我"+Arrays.toString(buf));
in.close();
用低級流來復制文件
一個字節一個字節的復制
FileInputStream fis
= new FileInputStream("fos.txt"); //輸入流
FileOutputStream fos =new FileOutputStream("fos_copy.txt"); //輸出流
int d=-1;
while((d=fis.read())!=-1){
fos.write(d);
}
System.out.println("文件復制完畢!");
fis.close();
fos.close();
10KB個字節的復制
FileInputStream fis
= new FileInputStream("fos.txt"); //輸入流
FileOutputStream fos =new FileOutputStream("fos_copy.txt"); //輸出流
byte[] buf =new byte[1024*10]; //10K
int d=-1;
while((d=fis.read(buf))!=-1){
fos.write(buf,0,d);
}
System.out.println("文件復制完畢!");
fis.close();
fos.close();
/**
*BOS與BIS
*緩沖字節輸入與輸出可以提高讀寫效率
*內部維護一個緩沖區,原理還是提高了讀寫的數據量減少
*讀寫次數來實現提高讀寫效率的
* */
【高級流】
用高級流(操作流)來復制文件,提高讀取速度
*與其它流相接,
*)從其他流讀取數據,處理後再返回數據
*)對輸出的數據,處理之後,再向其他流輸出
java.io.BufferedInputStream/BufferedOutputStream
*提高內存緩存區
*提高單字節讀寫效率
*Buffer流一個一個字節讀取,會從相接的流,讀取一批字節,放在內存的數組中
創建對象 //
FileInputStream fis =new FileInputStream("桌面.tar.gz");
BufferedInputStream bis =new BufferedInputStream(fis); //高級流 //可以有參,新建為new BufferedInputStream(相接的流,30*1024); //也可以無參(fis)(緩存為8k)
FileOutputStream fos =new FileOutputStream("桌面.tar_copy.gz");
BufferedOutputStream bos =new BufferedOutputStream(fos); //高級流
int d=-1;
long start=System.currentTimeMillis();
while((d=bis.read())!=-1){
bos.write(d);
}
long end =System.currentTimeMillis();
System.out.println("復制完畢!耗時"+(end-start)+"ms");//原先耗時644ms//用高級流後耗時48ms
bis.close(); //關高級流
bos.close(); //關高級流
【flush】方法
手動刷新一下緩存,close時會自動調用一次
out.flush();
【DataInputStream】【讀寫固定字節格式】
java.io.DataInputStream/java.io.DataOutputStream
*讀寫固定字節格式
創建對象
DataOutputStream out =new DataOutputStream(相接的流);
writeInt(int i);
writeDouble(double d)
writeUTF(String s);
DataInputStream
readInt(); //
readDouble(); //
readUTF();
例如:DataOutputStream out =new DataOutputStream(new FileOutputStream("/sdcard/stu",true));
System.out.println(out) //沒有重寫toString
【PrintStream】
例子:PrintStream out =new PrintStream(new FileOutputStream("d:\\f5"));
print(數據)
println(數據) 十六進制 十六進制 十進制0 = 十進制字符48 == 十六進制字符30
out.write(97); //00 00 00 61---->61
out.writeInt(97); //00 00 00 61---->00 00 00 61
十六進制字符
out.print(97); //00 00 00 61---->39 37 //改成了字符 //十六進制字符39= 十進制字符57= 十進制9
out.println(97); //00 00 00 61---->39 37 0D(換行符) //0A回車符現在已經沒人用了
【System.out輸出到控制台】
【字符編碼】 encoding
【字符集】 charset
ASCll //美國
0-127
ISO-8859-1 //Latin-1 //西歐
159-255
GB2312 //中國
7k多個中文 不包含喆,镕
GBK //中國
20902個中文
英文單字節
中文雙字節
UNICODE //統一碼 萬國碼
70萬以上
常用字符,雙字節表示 //中英文都是雙字節//通常用
生僻字符,三字節表示 //基本不用
java的char類型,采用的是unicode編碼
中文window用gbk編碼
手機上默認是utf-8
Unicode的傳輸碼就是UTF-8 ,UTF-16Be ,UTF-16Le ,UTF-32
UTF-8:
英文:單字節
某些字符:雙字節
中文:三字節
編碼轉換運算
Unicode-->其他編碼
String s="abc中文";
byte[] a=s.getBytes(); //轉成系統默認
byte[] a=s.getBytes("UTF-8"); //轉成指定編碼
其他編碼-->Unicode
String s=new String(a,"UTF-8");
例子:
String s ="abc中文喆镕";
byte[] a;
a=s.getBytes();
System.out.println("默認:"+Arrays.toString(a));
a=s.getBytes("GBK");
System.out.println("GBK:"+Arrays.toString(a));
a=s.getBytes("UTF-8");
System.out.println("UTF-8:"+Arrays.toString(a));
輸出:
默認:[97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70]
GBK:[97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70]
UTF-8:[97, 98, 99, -28, -72, -83, -26, -106, -121, -27, -106, -122, -23, -107, -107]
String s;
byte[] a;
a=new byte[]{97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70};
s=new String(a);
System.out.println(s);
a=new byte[]{97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70};
s=new String(a,"GBK");
System.out.println(s);
a=new byte[]{97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70};
s=new String(a,"UTF-8");
System.out.println(s);
a=new byte[]{97, 98, 99, -28, -72, -83, -26, -106, -121, -27, -106, -122, -23, -107, -107};
s=new String(a,"UTF-8");
System.out.println(s);
輸出:
abc中文喆镕
abc中文喆镕
abc??????
abc中文喆镕
【字符流】 //主要用於文件,比如.txt文件 //只能處理文字,用的比字節流少 //都是Writer,Reader結尾
【Writer】【Reader】 //字符流抽象父類
java.io.Reader/Writer
讀寫字符數據
*字符流的抽象父類
方法
Writer
write(int c)
截取int末尾兩個字節,作為字符輸出
write(char[] buf)
write(char[] buf,int from ,int n) //從from開始,讀取n個字符 //不是含頭不含尾
write(String s)
Reader
read()
讀取一個字符,補兩個0字節轉成int
read(char[] buf)
java.io.InputStreamReader/OutputStreamWriter
【InputStreamReader】 其他編碼-->Unicode //轉換流
【OutputStreamWriter】 Unicode-->其他編碼
*編碼轉換流
創建對象
1. OutputStreamWriter out=new OutputStreamWriter(相接的字節流);
OutputStreamWriter out=new OutputStreamWriter(相接的字節流,編碼);
例子:
InputStreamReader in;
in= new InputStreamReader(new FileInputStream("d:\\GHOSTERR.TXT"));
char[] buf =new char[8192];
int n;
while((n=in.read(buf))!=-1){
String s =new String(buf,0,n);
System.out.println(s); //把文件在控制台打印出來
}
in.close();
例子:復制
InputStreamReader in=new InputStreamReader(new FileInputStream(from),編碼格式); //編碼怎麼放
OutputStreamWriter out=new OutputStreamWriter(new FileOutputStream(to),編碼格式); //編碼怎麼放
char[] buf =new char[8192];
int n;
while((n=in.read(buf))!=-1){
out.write(buf,0,n);
}
in.close();
out.close();
【BufferedReader】 /bufferedWriter //字符緩沖
*字符緩沖
*提高單字符讀寫效率
創建對象
BufferedReader in =new BufferedReader(new InputStreamReader(new FileInputStream(from),編碼)); //編碼怎麼放
方法:read() //讀取單個字符。
方法 readLine() 讀取一行字符串,不包含末尾的換行符 所以打印用的不是out.write,而是out.println。
讀取結束,再讀取,返回null
【PrintWriter】 //字符流 //與PrintStream相似
java.io.PrintWriter
*PrintStream、 只能與字節流相接
*PrintWriter 能接字符流,也能接字節流
創建對象:
PrintWriter out=new PrintWriter(new OutputStreamWriter(new FileOutputStream(to),編碼)); //編碼怎麼放
out=new PrintWriter(new OutputStreamWriter(new FileOutputStream("d:\\dd.txt",true),"UTF-8"),true); //輸出流
方法: 不覆蓋 刷新
out.write(97);
out.writeInt(97);
out.print(97);
out.println(97);
【FileReader】 //字符流 //內部是"轉換流"接"文件字節流"
java.io.FileReader/Writer
*內部是"轉換流"接"文件字節流"
*不能指定編碼
創建對象
FileReader out = new FileReader(文件)
【字節流】 //都是Stream結尾
【ObjectInputStream】【ObjectOutputStream】 //對象序列化,對象反序列化
java.io.ObjectInputStream
ObjectOutputStream out =new ObjectOutputStream(相接的流);
方法:
ObjectOutputStream
writeObject(Object obj) //序列化輸出一個對象
ObjectInputStream
readObject()
學生類要序列化則要實現一個接口implements Serializable
標識接口
標識學生類,可以進行序列化
是個空接口,沒有任何抽象方法
不序列化的成員
static 靜態
transient 臨時,暫時 //private transient int age; //很少用
序列化頭部字節值
新建ObjectOutputStream時,會寫入兩個字節 AC ED //一個神奇字節,一個版本號
新建ObjectInputStream時,會讀取頭部字節值
序列化版本號
舊版本的序列化數據 //升級後就沒用了。
不會恢復成新版本的類型
*定義版本
private static final long serialVersionUID=3L;
例子:
public static void test1()throws FileNotFoundException, IOException{
Student s=new Student(74,"張三","男",22);
ObjectOutputStream out =new ObjectOutputStream(
new FileOutputStream("d:\\f8"));
out.writeObject(s);
out.close();
}
public static void test2() throws FileNotFoundException, IOException, ClassNotFoundException{
ObjectInputStream in =new ObjectInputStream(
new FileInputStream("d:\\f8") );
Student s=(Student)in.readObject();
System.out.println(s);
in.close();
}
【ByteArrayOutputStream】 //讀寫字節數組中的數據 //方法:toByteArray()
創建對象、
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(baos);
DataOutputStream dos=new DataOutputStream(new FileOutputStream("d:\\f9"));
DataOutputStream //固定字節格式
例子:寫入
Student s =new Student(80,"張三","男",19);
//Student ss =new Student(50,"李斯","女",25); //無意義,沒用
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(baos);
oos.writeObject(s);
//oos.writeObject(ss);
oos.close();
byte[] a=baos.toByteArray();
DataOutputStream dos=new DataOutputStream(new FileOutputStream("d:\\f9"));
dos.writeInt(a.length);
dos.write(a);
dos.close();
例子:讀取
DataInputStream dis =new DataInputStream(
new FileInputStream("d:\\f9"));
int len =dis.readInt();
byte[] a=new byte[len];
dis.read(a);
dis.close();
ObjectInputStream ois=new ObjectInputStream(
new ByteArrayInputStream(a));
Student s=(Student) ois.readObject();
System.out.println("讀取"+len+"個字節值,恢復成學生對象");
System.out.println(s);
輸出:
讀取139個字節值,恢復成學生對象
id:80
姓名:張三
性別:男
年齡19
【XML】
*可擴展的標記語言
*結構化的數據
*自描述的文件
*作用:
*)存儲數據
*)傳輸數據
不能給普通用戶看,由機器來處理
例子: //openwith --> XML Editor
<?xml version="1.0" encoding="UTF-8"?> //開頭,版本,格式
//<!DOCTYPE email SYSTEM "email.dtd"> //引用DTD:
<!DOCTYPE email [ //DTD //email和 [] 要隔開
<!ELEMENT email (from,to subject,body)>
<!ELEMENT from (#PCDATA)> //#PCDATA純文本
<!ELEMENT to (to-email+)>
<!ELEMENT subject (#PCDATA)>
<!ELEMENT body (#PCDATA)>
<!ATTLIST email
date CDATA #REQUIRED //必須有
time CDATA #IMPLIED //可選的
>
]>
<email date="2015-4-22" time="11:13:08"> //根元素,頂層元素,可自己設定,但只能有一個,
<from>[email protected]</from> //又開始,就要有結束
<to>
<to-email>[email protected]</to-email> //元素必須正確嵌套
<to-email>[email protected]</to-email> //<a k1="v1" k2='v2'> 屬性必須有屬性值,屬性值必須有引號,單引號雙引號都可以
<to-email>[email protected]</to-email> //單引號內可以有雙引號,雙引號內可以有單引號
</to>
<subject>Hello XML</subject>
<body>
Hello XML!
XML 你好!
</body>
</email>
【屬性】---Attribute
【文本】---text
子元素(和子元素內的文本)可以放在父元素的屬性中,也可以作為子元素 //屬性<email date="2015-4-22"> //文本<email> <子元素> 文本 </子元素> //安卓常用屬性
復雜結構的文本,長文本,應該使用“文本”
【轉義實體】
< <
> >
" "
' '
& &
【】 <![CDATA[ ]]>
機器從CDATA標簽提取內容時,不做任何運算處理
所有內容作為普通字符提取出來
【注釋】 <!-- -->
【標簽】 Tag <a></a>
【元素】Element //從開始到結束
<to>
<to-email>[email protected]</to-email>
<to-email>[email protected]</to-email>
<to-email>[email protected]</to-email>
</to>
【DTD】
在特定的領域內定義的xml編寫規范
由行業組織、領袖企業、技術領袖來制定DTD規范
引用DTD:
<!DOCTYPE email SYSTEM "email.dtd">
【Java處理XML】
SAX ---- Simple API for XML
DOM4J ---- Doctument Model Object for Java
XML PULL -- Android中集成的的開源API
【XPath】
========================================
* 用路徑的形式,表示 xml 中的數據
/email/from
/email/to/to-email
/email/@date
/books/book/name
/books/book/authors/name
/books/book//name
//name
//@isbn
【【SAX】】
SaxParserFactory //工廠對象
*解析器工廠,輔助
創建對象
SaxParserFactory f=SaxParserFactory.newlnstance()
方法----
newSAXParser()
SaxParser
*sax解析器,讀取並解析xml文檔
創建對象
SaxParser p=工廠對象.newSAXParser()
方法
parse(文件,處理器對象)
parse(文件字節流,處理器對象)
parse(文件字符流,處理器對象)
DefaultHandler
*編寫DefaultHandler的子類來處理sax解析器提取出來的數據 //新建子類繼承它
方法
startElement() //處理開始標簽數據
endElement() //處理結束標簽數據
characters() //處理文本
例子:調用xml文件中開始標簽,文本,結束標簽
{
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParser p=SAXParserFactory.newInstance().newSAXParser();
EmailHandler h=new EmailHandler();
p.parse("E:\\workspace_1503\\day0100\\src\\day21\\email.xml", h);
}
static class EmailHandler extends DefaultHandler{ //匿名內部類
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("開始標簽:"+qName);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("結束標簽:"+qName);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String s=new String(ch,start,length);
System.out.println("文本");
System.out.println(s);
}
}
}
輸出:
開始標簽:email
開始標簽:from
文本
[email protected]
結束標簽:from
開始標簽:to
開始標簽:to-email
文本
[email protected]
結束標簽:to-email
.
.
.
【絕對路徑】
* 有一個工具,可以用相對路徑的方式,
* 獲得文件的磁盤絕對路徑”/”表示程序運行的目錄
String path=Demo000.class.getResource("\\email.xml").getPath();
p.parse(path, h);
等於:
p.parse("E:\\workspace_1503\\day0100\\src\\day21\\email.xml", h);
【【DOM4J】】
*符合java編程習慣的DOM API
*第三方的開源API //不是java類庫中有的 //需要導入dom4j-1.6.1.jar類庫 和 jaxen-1.1-beta-6.jar
*將xml數據讀入到內存,生成一個樹狀結構
SAXReader
String path =Test1.class.getResource("\\email.xml").getPath();
* SAXReader reader = new SAXReader();
/**
* 讀取文件中的xml數據,生成dom樹,Document對象,是樹根。
* */
* Document doc = reader.read(path);
//獲得根源樹<email>
Element email =doc.getRootElement();
【SAX和DOM4J的區別】
*DOM4J占用更多內存資源
*解析大文件選擇SAX //幾百M
【【XML PULL】】 //Android推薦要重點掌握,以後使用最多 //pull解析
=================================
* 第三方開源 API
* android 開發庫中,集成了 XML PULL
XmlPullParserFactory 工廠,用來創建解析器和序列化器
XmlPullParser 用來解析 xml
XmlSerializer 用來生成 xml
Xml 工廠輔助類,代替工廠來創建解析器和序列化器
【XmlPullParserFactory】
===================================================
* 工廠,用來創建解析器和序列化器
創建對象
------------------------------------
XmlPullParserFactory f =
XmlPullParserFactory.newInstance();
方法
------------------------------------
* newPullParser() 創建解析器 XmlPullParser
* newSerializer() 創建序列化器 XmlSerializer
【Xml】
==========================================
* 工廠輔助類,代替工廠來創建解析器和序列化器
方法
------------------------------------
Xml.newPullParser()
Xml.newSerializer()
【XmlPullParser】
==========================================
* xml pull 解析器
* 讀取並解析提取 xml 文檔中的數據
* 從頭到尾,
一段一段的提取 xml 數據
創建對象
--------------------------------------
XmlPullParser p=Xml.newPullParser();
或
XmlPullParser p=XmlPullParserFactory.newInstance().newPullParser()
方法
--------------------------------------
setInput(Reader in)
setInput(InputStream in, String charset)
設置輸入流,必須首先調用,以及設置編碼格式比如"UTF-8"
next()
一次一次地,跳到下一段;
返回一個數字代碼,表示當前位置的數據類型
如果文檔結束,再向後跳,
返回 XmlPullParser.END_DOCUMENT (即數字1)
getEventType()
返回當前位置的數字代碼
getText()
數字代碼是 XmlPullParser.TEXT 時,
才能調用 getText() 方法,取出文本
nextText()
數字代碼是 XmlPullParser.START_TAG 時,
才能調用 nextText(),跳到下一段取文本
相當於:
p.next();
p.getText();
getName()
數字代碼是
XmlPullParser.START_TAG
XmlPullParser.END_TAG
時,才能調用 getName() 獲得標簽名
getAttributeCount()
獲得這個標簽內的屬性數量
獲得屬性數量
getAttributeName(int index)
獲得指定位置的屬性名
getAttributeValue(int index)
獲得指定位置的屬性值
getAttributeValue(String namespace, String name)
用屬性名,獲得對應的屬性值
*) 屬性方法,必須在數字代碼是
XmlPullParser.START_TAG 時,才能調用
【XmlSerializer】
=========================================
* 用來將數據序列化成 xml 格式的字符序列輸出
創建對象
-------------------------------------
用 XmlPullParserFactory 或 Xml 類創建
XmlSerializer s =Xml.newSerializer(); //序列化器
方法
-------------------------------------
setOutput(Writer out)
setOutput(OutputStream out,String charset)
設置用來輸出數據的流,
必須首先調用
startDocument(String encoding,boolean standalone)
用來輸出頭標簽xml頭標簽
<?xml version="1.0" encoding="指定的編碼" standalone="布爾值" ?>
standalone 參數:
true: 獨立文檔
false: 引用其他文檔
startTag(String namespace,String name)
用來輸出開始標簽
namespace:命名空間
<t:student xmlns:t="http://www.tarena.com/sudents"> //網絡路徑可存在也可不存在
</t:student>
<n:student xmlns:n="http://www.newdongfang.com/sudents">
</n:student>
attribute(String namespace ,String name,String )
在開始標簽中,輸出屬性,
必須在調用 startTag() 之後,調用 attribute()
text(String text)
在開始標簽後面輸出文本,
必須在調用 startTag() 之後,調用 text
endTag(String namespace,String name)
輸出結束標簽
必須在調用startTag()之後,調用endTag
cdsect(String text)
輸出<![CDATA[]]之後,調用cdsect() // //.cdsect會結束,不會返回s,所以要用”;”來結束,再重新開始 //注意轉義字符
comment(String text)
輸出<!--注釋 -->
flush()
【需要加權限】 //將數據序列化成xml格式的字符序列輸出
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
【第二個老師】 //內容回顧
Day01-1 自我介紹
----------------------------------------------
齊雷
[email protected]
QQ:67182745
----------------------------------------------
Day01-2 內容回顧 (編程基礎)
1.基礎語法
1)標識符(用戶定義一些元素的名字)
2)變量(局部變量,參數變量,實例變量,類變量)
class Var{
int a;實例變量(每個對象都有一份)
static int b; 類變量(所有對象共享一份)
public void display(String str1){//參數變量
String str2;//局部變量
}
}按作用域劃分為四種類型
3)語句
3.1)兩大分支(if,switch)
3.2)三大循環(for,while,do{}while())
4)函數
4.1)實例方法(通過類的對象調用)
4.2)靜態方法(通過類名)
無論實例方法還是靜態方法都可以重載。
5)數組
5.1)一維數組: int[]a ,int []b;
5.2)多維數組
int a[][]={{1,2}};
int b[][][]={{{}},{{}}}
int c[][][][];
2.面向對象
1)兩大對象(類對象Point.class,類的對象new Point())
2)三大特性 (封裝,繼承,多態)
3)兩大對象關鍵字(this,super)
4)兩大修飾符(static,final)
5)兩大抽象(抽象類,接口)
6)四大內部類(實例內部類,靜態內部類,局部內部類,匿名內部類)
3.API
3.1 基礎API
1) 數學系列:(Number,Math,BigDecimal,Integer,.....)
2) 字符系列: (String,StringBuilder,StringBuffer,CharSequence)
3) 日期系列: (Date,Calendar)
3.2 集合API
1)Collection (List,Set,Queue,...)
2)Map (HashMap,TreeMap,....)
3)Iterator
4)Collections
3.3 IO流
1)輸入(in): 讀 (內存,外存(文件,數據庫,網絡))
|-->InputStream
|-->Reader
2)輸出(out):寫(內存,外存(....),)
|-->OutputStream
|-->Writer
3.4 XML
1)編寫
2)解析(pull,sax,dom4j,.....)
擴展:
1)ctrl+shift+t
2)ctrl+o
3)ctrl+t
-----------------------------------------------
Scanner scan = new Scanner(System.in);
s = scan.nextLine(); //阻塞式方法
scan.close();
【局部內部類】
final Thread ta =new Thread(){ } //局部內部類想訪問方法內的變量時,要用final修飾。 //不是成員
實例內部類
靜態內部類,
局部內部類,
匿名內部類
【要求】
1.習慣於使用快捷鍵(提高寫代碼的速度)
2.習慣於獨立的查詢API。
3.習慣於課前預習,課後總結。
4.習慣於獨立思考,創新。
【線程基礎】
1.回顧Android底層架構?
Android 是一個平台,主要由四層構成:
Application(應用層):浏覽器,支付寶,...
---------------------
Application Framwork (應用框架層): activity,service,...
---------------------
Libraries , Dalvik (虛擬機) :SQLite,....
---------------------
Linux kernal(內核):包含了大量的驅動
其中Linux 是使用C語言編寫的操作系統,負責管理,調度所有硬件資源,並為應用軟件提供一個可運行的平台。
Linux 系統是一個多任務操作系統,可以同時運行多個任務。
2.【進程】(Process)
進程通常可以理解為正在運行的程序,有自己獨立的內存空間,由操作系統負責為其分配資源,
例如CPU的調度。多個進程可以並發執行。對於單個CPU,並發從宏觀上理解是在同時執行,但在微觀上是順序執行。
3.【線程】(Thread)
線程是進程中的一個順序的執行流(一個線程執行多個任務時,這多個任務是順序執行的)
,一個進程可以啟動多個線程,多個線程可以共享進程資源,並發執行。
4.【線程對象的創建?】
在Java中所有的線程對象的類型為Thread類型。我們創建線程對象的方式通常有兩種:
1)創建Thread類的子類對象,重寫Thread類的run方法,在此run方法中執行任務。
package day27;
public class ThreadDemo1 {
static void doMethod1(){
while(true){
String name=Thread.currentThread().getName();
System.out.println(name+"-->doMethod1");
}
}
/**想辦法讓此方法運行在自己創建的線程中*/
static void doMethod2(){
while(true){
String name=
Thread.currentThread().getName();
System.out.println(name+"-->doMethod2");
}
}
//此函數運行於JVM啟動的一個main線程中
public static void main(String[] args) {
SubThread t=new SubThread();
t.start();//啟動線程
doMethod1();
//doMethod2();
}
static class SubThread extends Thread{ //繼承一個
@Override
public void run() { //重寫run方法
doMethod2();
}
}
}
2)創建Thread類的對象,
調用Thread(Runnable r)構造方法。此時需要將要執行的任務寫在r對象的run方法中。
package day27;
public class Test2 {
//static String s;
static class Task implements Runnable{
@Override
public void run() {
while (true) {
System.out.println("run()");
}
//s="hello";
}
}
public static void main(String[] args) {
//構建線程對象
Thread t=new Thread(new Task()); //新建一個
//啟動線程對象,線程啟動以後會自動執行task對象的run方法
t.start(); //先啟動,不一定先執行,什麼時候執行操作系統說了算
while(true){
System.out.println("main()");
}
//System.out.println(s.toUpperCase());
}
}
說明:線程對象創建以後不會自動執行,需要
調用Thread類的實例方法start()方法啟動線程,
線程啟動以後,如果獲得了cpu會自動執行run
方法。
例子:匿名內部類
package day27;
import java.util.Scanner;
public class Test3 {
static String s;
public static void main(String[] args) {
/**
* 案例
* 1.在主線程構建兩個工作線程
* 1.1.第一個線程:Thread類的子類(線程名位WorkA)
* 1.2.第二個線程:Thread類的對象,接收Runnable類型的任務(new Thread(任務)),
* 線程名位WorkB
* 2.線程A從負責從鍵盤輸入一個字符串
* 3.線程B將線程A輸入的字符串轉換為大寫輸出
* 4.用匿名內部類寫。
* */
ta.start();
tb.start();
}
static Thread ta =new Thread(){
@Override
public void run() {
System.out.println("請輸入一組字符串");
Scanner scan =new Scanner(System.in);
s=scan.nextLine();
scan.close(); //關閉線程
}
};
static Thread tb=new Thread(new Runnable(){
@Override
public void run() {
while(s==null){}
System.out.println(s.toUpperCase());
}
});
}
FAQ? 【多線程的優勢與劣勢】
優勢:提高效率,改善用戶體驗。
劣勢:調試,維護會相對困難。
5.【線程對象的狀態及相關方法的應用】
5.1 【線程狀態】
1)新建狀態(new Thread())
2)就緒狀態(可運行狀態)
3)運行狀態(正在執行run方法)
4)阻塞狀態(線程不可獲得CPU)
5)死亡狀態(線程已經運行結束)
5.2 【線程方法】
1)構造方法(重要)
2)setName(String name)
3)currentThread()
4)getName()
5)start() 啟動線程,線程處於就緒狀態
6)run() 在此方法執行業務邏輯,此時線程線程處於運行狀態。
7)sleep(); 線程讓出cpu處於阻塞狀態
【休眠】
Thread.sleep(5000); //在不是繼承了Thread的類中 //比如只是實現了Runnable
sleep(5000); //繼承了Thread類的子類中,可以省略Thread.
8)interrupt();喚醒正在休眠的線程,被喚醒的線程處於就緒狀態。
9)join()方法:調用此方法的線程優先執行。
10)setDaemon(boolean flag)
【守護線程】
當flag的值為true時,表示設置此線程為守護線程(精靈線程),可以將守護線程理解為服務
性線程。當沒有其它線程在執行時(包括main線程也停止時),守護線程會自動銷毀。
11)yeild()方法:讓出cpu,但此線程處於就緒態。
12) isAlive() 判斷線程是否還活著。
13) getState() 返回線程狀態
14) setPriority() 設置線程優先級
----------------------------------------------
【線程的同步】
------------------------------
1.【何為線程同步?】
所謂線程同步通常可以理解為,多個線程在共享數據集上的互斥和協作。
FAQ?
1)多個線程並發執行
2)多個線程存在共享數據集
2.【線程同步的作用?】
1)保證線程安全(數據的安全)。
2)保證數據的合理性。
3.【線程的互斥?】
所謂線程互斥:
多個線程在共享數據集上排隊執行。
【對象鎖】
【如何實現?】
在共享數據集所在的代碼塊上添加一把鎖,這個鎖通常稱之為對象鎖。
獲得鎖的線程對象優先執行,其他線程等待。當獲得了對象鎖的線程執行完代碼塊會釋放鎖,其他線程
競爭鎖,然後執行代碼塊。
代碼中的實現:
1)【同步代碼塊】
synchronized (對象鎖) { //主類.class //用這個省事
被鎖的共享數據集
}
2)【同步方法】(默認同步鎖是誰?)
public synchronized void sale(){
被鎖的共享數據集
對象鎖默認為this;
}
public static synchronized void sale(){
被鎖的共享數據集
對象鎖默認為類對象(例如TicketTask.class)
}
說明:我們使用加鎖的方式實現了線程的互斥,保證了數據的安全,但同時也會降低系統的執行效率,
所以在一些線程安全的環境下盡量不要使用同步代碼塊或同步方法。
對synchronized(this)的一些理解
一、當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。
二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
四、當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。
FAQ? //最近問到的問題
【】【】
1)StringBuffer與StringBuilder的
區別時什麼?
StringBuffer是一個線程安全的StringBuilder,在很多方法上都
添加了synchronized關鍵字。
2)ArrayList與Vector的區別?
Vector是一個線程安全的ArrayList.
3)HashMap與HashTable的區別?
HashTable是一個線程安全的HashMap
4)Collections中的synchronizedXXX()系列
方法是將線程非安全的集合轉換為線程安全的集合。
5)在線程非安全的環境或者高並發的環境
建議使用ConcurrentHashMap.
-----------------------------------
回顧:
對象構建過程?
Point p=new Point();
1)加載類(將類讀到內存),存儲到代碼區(Code Area)在加載的過程中假如有靜態
變量,靜態代碼塊,它從上到下依次初始化。
2)為對象分配堆內存(隨機分配)
3)在堆內存初始化實例變量(從上到下)
4)調用構造方法。
【類加載】
1.如果靜態變量在靜態塊之上
則類加載時,先運行靜態變量,再運行靜態塊
2.靜態塊只能訪問靜態成員
3.類加載時,不會加載靜態內部類,在運行靜態內部類時,才會加載它
【線程同步】【(線程協作)】
當多個線程在共享數據集上要實現交互操作,通常要借助object類中的
wait,notify,notifyall方法實現。
【wait】方法:調用此方法的線程會處於等待狀態同時會釋放對象鎖。
【notify】方法:調用此方法用於通知具備相同鎖對象的線程開始執行。同時調用此方法的線程會釋放鎖。 //等待之後被通知喚醒後不會再進行判斷
【notifyall】方法用於通知多個具備相同鎖的對象。
Object.class.wait();
Object.class.notify();
注意:
1) 這些方法要應用在同步代碼塊或同步方法內部
2) 這些方法由對象鎖調用。
1)【何為池?】(程序中)
內存中的一塊區域,假如這塊區域中存儲的是字符串,那可以將此池理解
為字符串池,假如是整數,那可以稱之為整數池。
2)【線程池?】
在內存中有一塊區域,這塊區域中可以存儲很多個線程,這些線程可以得到"重用"。
3)【使用線程池的目的?】
減少線程對象的創建次數,讓我們的線程對象在程序可以得到重用,以提高系統的執行效率。
備注:線程池中線程的數量的多少取決於具體業務。
4)【Java中線程池的創建?】
1)Executors (借助此類的靜態方法創建線程)
2)ExecutorService(線程池的管理者)
a)負責從池中取線程執行任務
b)負責將線程放回池中
c)關閉線程池。
例子:【es.execute(new Runnable() 】 //無返回值
//1.創建線程池
//1.1創建只有一個線程的線程池
ExecutorService es = Executors.newSingleThreadExecutor();
//1.2創建線程固定的線程池
ExecutorService es = Executors.newFixedThreadPool(10); //用得最多
//1.3創建一個上限數量沒有限定的線程池
ExecutorService es =Executors.newCachedThreadPool();
//執行任務
es.execute(new Runnable() {
@Override
public void run() {
while(true){
String name=Thread.currentThread().getName();
System.out.println(name+"企鵝");
}
}
});
------------------------------------------------------------------------------
例子:【es.submit(new Callable】 //有返回值
System.out.println("輸入一個數");
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
ExecutorService es = Executors.newSingleThreadExecutor();
Future<Integer> f=es.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum=1;
for(int i=1;i<=n;i++){
sum=sum*i;
}
return sum;
}
});
//阻塞主線程
int n=f.get(3,TimeUnit.SECONDS); //只等待3秒 //時間長了會崩潰
System.out.println("n="+n);
es.shutdown();
----------------------------------------
【線程任務調度】 //與時間有關
-------------------------------------------
1.何為任務調度?
所謂任務調度,就是操作系統為線程分配CPU執行任務。
分配CPU的方式通常有兩種方式:
1)按時間片
2)按優先級
假設我們現在有一個需求,讓CPU在某個時間去執行某個任務,那如何實現?
2. 【Timer類】在任務調度中應用?
對於任務數量比較少,比較簡單的一些調用可以借助Timer類的對象實現。
如何實現?(實現步驟)
1)構建Timer對象?(看類型,看構造方法)
2)借助Timer對象的schedule方法執行任務,任務類型為TimerTask類型,將要執行的任務寫到TimerTask對象的方法中。
3)任務結束以後,調用timer對象的cancel退出調度。
例子:
final Timer t=new Timer();
t.schedule(new TimerTask(){
@Override
public void run() {
String name=
Thread.currentThread().getName();
System.out.println(name+"-->helloworld");
t.cancel();
}
},2000);//2000為延遲時間(默認相對於當前時間)
2. 【ScheduledExecutorService類】在任務調度中應用?
ScheduledExecutorService接口繼承ExecutorService,並此基礎之上擴展了一些相關方法。
此接口類型的對象,用於管理一個線程池,可以通過線程池中的線程,執行任務。
假設要通過ScheduledExecutorService接口執行任務調度,首先要借助Executors的方法
構建ScheduledExecutorService的實現類的對象,然後借助此對象的相關方法再去執行任務。
例子:
ScheduledExecutorService es=Executors.newScheduledThreadPool(3);
class Task implements Runnable{
private String name;
public Task(String name){
this.name=name;
}
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
@Override
public void run() {
try{Thread.sleep(1000);}catch(Exception e){}
System.out.println( name+"-->"+sdf.format(new Date()));
}
}
es.scheduleAtFixedRate( //兩次任務的調度時間間隔為period
new Task("A"),
1,//initialDelay //初始延遲
1,//period
TimeUnit.SECONDS);//下一次調度,可能上一次任務還沒有結束
es.scheduleWithFixedDelay( //兩次任務的調度時間為delay+任務執行時間
new Task("B"),
1,//initialDelay //初始延遲
1, //delay
TimeUnit.SECONDS);//下一次的任務調度,需要等待上一次的任務執行結束
}
---------------------------------------------
【重復新建】
List<Weather> list=null; //定義集合 //聲明
list=new ArrayList<Weather>(); //新建集合 //初始化
Weather wea=null; //定義對象 //聲明
wea=new Weather(); //新建對象 //初始化
list.add(wea); //把對象加入到集合中
wea=null; //把對象清零
【DeBug】
F5:進入方法
F6:下一步
F7:返回上一次調用
F8:跳入下一個斷點
一張圖片的String狀態
<image>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
/EeP/wdsPh55c2BhFQAAAABJRU5ErkJggg==
【Touch事件處理】
Android中提供了ViewGroup、View、Activity三個等級的Touch事件處理。也就是說,這三個地方都有事件回調方法。Android事件傳遞機制【按鍵事件】
測試DEMO視圖結構:
<com .orgcent.eventtest.EventLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#032d3d"
android:orientation="vertical" >
<com .orgcent.eventtest.EventTextView
android:id="@+id/tvEvent"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:gravity="center"
android:textColor="@android:color/black"
android:background="@android:color/white"
android:text="Activity - ViewGroup - View Event http://orgcent.com dispatch Test"/>
</com>
至於三者之間的執行順序,將在下面詳細闡述:
整體上看,事件傳遞順序為ViewGroup::onInterceptTouchEvent() –> ViewGroup或View的onTouchEvent() –> Activity::onTouchEvent()
由於上面每個事件回調方法的返回值不同,導致事件本身及順序發生微妙變化。下面以返回值為主線來詳細闡述:
需要注意以下兩點:
1、onInterceptTouchEvent()返回true,那麼這個方法只會攔截動作ACTION_DOWN。
2、onInterceptTouchEvent()負責事件分發(事件傳遞方向),onTouchEvent()負責事件處理(消費)。
1、ViewGroup的onInterceptTouchEvent()
返回false:
默認實現方式。事件(按下、移動、抬起等)將直接傳遞給目標view(用戶觸摸的view)。
在ViewGroup觸發,調用ViewGroup::onTouchEvent(),在View觸發,調用View::onTouchEvent()。
androi-touch-event-1
PS:這裡發現ViewGroup::onTouchEvent()也被調用了,原因是View::onTouchEvent()沒有處理該事件(返回false),事件將交給父容器處理。
返回true:
表示ViewGroup將攔截子View的Touch事件。事件會直接傳遞到ViewGroup::onTouchEvent()處理。
也就是說,事件後面的移動、抬起動作不會經過onInterceptTouchEvent(),而是直接傳到onTouchEvent()。
androi-touch-event-2
2、ViewGroup/View的onTouchEvent()
返回true:
表示事件按下動作被處理,意味著事件的移動、抬起等後續動作將會傳到此方法。
如果是View處理,那麼ViewGroup的onTouchEvent()將不會獲得該事件。
androi-touch-event-3
PS:只要onInterceptTouchEvent()返回false,而且目標控件View::onTouchEvent()返回true,那麼事件的每一個動作(按下、移動、抬起等)會都會首先傳遞到onInterceptTouchEvent()中。
如果是ViewGroup處理,那麼Activity不會獲得事件。
androi-touch-event-4
返回false:
表示View或ViewGroup不處理事件,系統將把事件傳遞給其父級處理。
如果View返回false,那麼將由其父容器ViewGroup處理。如果ViewGroup不處理,最終將交給Activity來處理。
androi-touch-event-5
如果ViewGroup返回false,將交給最後一級Activity來處理。
androi-touch-event-6
3、Activity的onTouchEvent()
這個方法是事件最後被處理的地方。如果不處理,系統將拋棄這個事件。暫時沒有發現這個方法的返回值對程序有什麼意義。也許返回true能告訴系統事件被處理了。