基礎教學:lecture, video, lecturer: Matt Stokerhtml
Java教學:http://www.runoob.com/java/java-intro.html【菜鳥教程,很是適合複習】java
Ref: JAVA 學到什麼水平就能夠轉戰 Android 了mysql
Ref:設計模式菜鳥教程android
Ref:Java教程git
Ref: Java code 實例程序員
複習感覺:Java已經再也不是過去熟悉的Java!github
第一課:web
觀後感,應該總結一套控件代碼:控件代碼收集。面試
看上去不錯de樣子。後記,貌似沒有用了,有了Material Design。正則表達式
Ref: chenyangcun/MaterialDesignExample
Ref: 加載圖片助手:https://www.fresco-cn.org/
第二課:
現代Android開發:一些建議。
從一開始起就嚴格按照material design寫,
Material Design
不要自定義一堆padding margin,但你須要邊框,邊距的時候,請看看
?android:attr/裏面有木有你需求的(因爲android studio強大的補全功能,你通常只需打幾個關鍵詞就有提示了),好比你須要給一個ImageButton加點擊效果,
不要傻不拉幾的去寫一個selector了,你只須要輸入 item select這些關鍵詞,自動補全就會給你提示了。
不要定義一大堆亂七八糟的
字體大小了,materail design上的幾種基本字體大小能夠知足你!
再也
不要使用ListView了,改爲RecycleView吧!
再也
不要尋找第三方下拉刷新控件了,SwipeRefreshLayout確定符合你的要求(不信你看,知乎Android客戶端都是用的這個(●ˇ∀ˇ●))。
再也
不要使用第三方側滑欄了,DrawerLayout能知足你!
再也
不要使用ViewPagerTabStripe這一類的第三方Tab控件了,請使用TabLayout!
再也
不用找圓形頭像控件,圓角控件了,其餘的Univeral Image Loader /Picasso也不用看了,直接上Fresco | Fresco 中文說明吧,它都有!不如用省下的時間看看Fresco的源碼。
關於Material Design,控件章節作介紹。
相關視頻講解:谷歌Material Design設計語言詳解
這裏先複習下Java語言基礎知識,耗時五小時。
參考:Java 教程
初步複習內容
Java分爲三個體系:
- JavaSE (J2SE) (Java2 Platform Standard Edition,java平臺標準版)
- JavaEE (J2EE) (Java 2 Platform,Enterprise Edition,java平臺企業版)
- JavaME (J2ME) (Java 2 Platform Micro Edition,java平臺微型版)。
基本語法
- 主方法入口:全部的Java 程序由public static void main(String []args)方法開始執行。
Java標識符
- 全部的標識符都應該以字母(A-Z或者a-z),美圓符($)、或者下劃線(_)開始
- 首字符以後能夠是字母(A-Z或者a-z),美圓符($)、下劃線(_)或數字的任何字符組合
Java修飾符
像其餘語言同樣,Java可使用修飾符來修飾類中方法和屬性。主要有兩類修飾符:
- 訪問控制修飾符 : default, public , protected, private
- 非訪問控制修飾符 : final, abstract, strictfp
Java變量
Java中主要有以下幾種類型的變量
- 局部變量
- 類變量(靜態變量)
- 成員變量(非靜態變量)
Java數組
Java枚舉
Java關鍵字
下面列出了Java保留字。這些保留字不能用於常量、變量、和任何標識符的名稱。
類別 |
關鍵字 |
說明 |
訪問控制 |
private |
私有的 |
protected |
受保護的 |
public |
公共的 |
類、方法和變量修飾符 |
abstract |
聲明抽象 |
class |
類 |
extends |
擴允,繼承 |
final |
最終值,不可改變的 |
implements |
實現(接口) |
interface |
接口 |
native |
本地,原生方法(非Java實現) |
new |
新,建立 |
static |
靜態 |
strictfp |
嚴格,精準 |
synchronized |
線程,同步 |
transient |
短暫 |
volatile |
易失 |
程序控制語句 |
break |
跳出循環 |
case |
定義一個值以供switch選擇 |
continue |
繼續 |
default |
默認 |
do |
運行 |
else |
不然 |
for |
循環 |
if |
若是 |
instanceof |
實例 |
return |
返回 |
switch |
根據值選擇執行 |
while |
循環 |
錯誤處理 |
assert |
斷言表達式是否爲真 |
catch |
捕捉異常 |
finally |
有沒有異常都執行 |
throw |
拋出一個異常對象 |
throws |
聲明一個異常可能被拋出 |
try |
捕獲異常 |
包相關 |
import |
引入 |
package |
包 |
基本類型 |
boolean |
布爾型 |
byte |
字節型 |
char |
字符型 |
double |
雙精度浮點 |
float |
單精度浮點 |
int |
整型 |
long |
長整型 |
short |
短整型 |
null |
空 |
變量引用 |
super |
父類,超類 |
this |
本類 |
void |
無返回值 |
保留關鍵字 |
goto |
是關鍵字,但不能使用 |
const |
是關鍵字,但不能使用 |
Java註釋
Java 空行
繼承
被繼承的類稱爲超類(super class),派生類稱爲子類(subclass)。
接口
詳細的複習內容
Java 對象和類
public class Puppy{
int puppyAge;
static int cls_var = 10
public Puppy(String name){
System.out.println("小狗的名字是 : " + name );
}
public void setAge( int age ){
puppyAge = age;
}
public int getAge( ){
System.out.println("小狗的年齡爲 : " + puppyAge );
return puppyAge;
}
public static void main(String []args){
Puppy myPuppy = new Puppy( "tommy" );
myPuppy.setAge( 2 );
myPuppy.getAge( );
System.out.println("變量值 : " + myPuppy.puppyAge );
}
}
源文件聲明規則
-
- 一個源文件中只能有一個public類
- 一個源文件能夠有多個非public類
- 順序:package語句、import語句、類定義。
- import語句和package語句對源文件中定義的全部類都有效。在同一源文件中,不能給不一樣的類不一樣的包聲明。
Ref: Java安裝相關路徑查找
Java 基本數據類型
byte,節省空間。
System.out.println("基本類型:byte 二進制位數:" + Byte.SIZE);
System.out.println("包裝類:java. .Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
對象、數組都是引用數據類型。
全部引用類型的默認值都是null。
final double PI = 3.1415927;
低 ------------------------------------> 高
byte,short,char—> int —> long—> float —> double
Ref: 例子不錯的連接。
Java 變量類型
Java 修飾符
咱們能夠經過如下表來講明訪問權限:
修飾符 |
當前類 |
同一包內 |
子孫類 |
其餘包 |
public |
Y |
Y |
Y |
Y |
protected |
Y |
Y |
Y |
N |
default |
Y |
Y |
N |
N |
private |
Y |
N |
N |
N |
static變量
static方法
final變量,宏
final方法,不能被子類修改
final類,不能被繼承其任何特性
abstract方法
abstract類,包含若干個抽象方法則必爲抽象類,或抽象類能夠不包含抽象方法
synchronized 修飾符
public synchronized void showDetails(){
.......
}
transient 修飾符
對應的變量加上transient關鍵字,那麼,這個字段的生命週期僅存於調用者的內存中而不會寫到磁盤裏持久化。
參考:http://www.javashuo.com/article/p-odbasryu-n.html
volatile 修飾符
Java語言規範中指出:爲了得到最佳速度,容許線程保存共享成員變量的私有拷貝,並且只當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比。
這樣當多個線程同時與某個對象交互時,就必需要注意到要讓線程及時的獲得共享成員變量的變化。
使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當要訪問的變量已在synchronized代碼塊中,或者爲常量時,沒必要使用。
因爲使用volatile屏蔽掉了VM中必要的代碼優化,因此在效率上比較低,所以必定在必要時才使用此關鍵字。
Java 運算符
instanceof 運算符
String name = "James";
boolean result = name instanceof String; // 因爲 name 是 String 類型,因此返回真
Java 循環結構 - for, while 及 do...while
Java 加強 for 循環,爲方便數組訪問。
public class Test {
public static void main(String args[]){
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ){
System.out.print( x );
System.out.print(",");
}
}
}
Java 分支結構 - if...else/switch
Java Number & Math 類
全部的包裝類(Integer、Long、Byte、Double、Float、Short)都是抽象類 Number 的子類。
當 x 被賦爲整型值時,
-
- 因爲x是一個對象,因此編譯器要對x進行裝箱。
- 而後,爲了使x能進行加運算,因此要對x進行拆箱。
Integer x = 5;
x = x + 10;
public class Test {
public static void main (String []args)
{
System.out.println("90 度的正弦值:" + Math.sin(Math.PI/2));
System.out.println("0度的餘弦值:" + Math.cos(0));
System.out.println("60度的正切值:" + Math.tan(Math.PI/3));
System.out.println("1的反正切值: " + Math.atan(1));
System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI/2));
System.out.println(Math.PI);
}
}
Java Character 類
提供了一些好用的方法:
Java String 類
1 char charAt(int index)
返回指定索引處的 char 值。
2 int compareTo(Object o)
把這個字符串和另外一個對象比較。
3 int compareTo(String anotherString)
按字典順序比較兩個字符串。
4 int compareToIgnoreCase(String str)
按字典順序比較兩個字符串,不考慮大小寫。
5 String concat(String str)
將指定字符串鏈接到此字符串的結尾。
6 boolean contentEquals(StringBuffer sb)
當且僅當字符串與指定的StringButter有相同順序的字符時候返回真。
7 static String copyValueOf(char[] data)
返回指定數組中表示該字符序列的 String。
8 static String copyValueOf(char[] data, int offset, int count)
返回指定數組中表示該字符序列的 String。
9 boolean endsWith(String suffix)
測試此字符串是否以指定的後綴結束。
10 boolean equals(Object anObject)
將此字符串與指定的對象比較。
11 boolean equalsIgnoreCase(String anotherString)
將此 String 與另外一個 String 比較,不考慮大小寫。
12 byte[] getBytes()
使用平臺的默認字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。
13 byte[] getBytes(String charsetName)
使用指定的字符集將此 String 編碼爲 byte 序列,並將結果存儲到一個新的 byte 數組中。
14 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
將字符今後字符串複製到目標字符數組。
15 int hashCode()
返回此字符串的哈希碼。
16 int indexOf(int ch)
返回指定字符在此字符串中第一次出現處的索引。
17 int indexOf(int ch, int fromIndex)
返回在此字符串中第一次出現指定字符處的索引,從指定的索引開始搜索。
18 int indexOf(String str)
返回指定子字符串在此字符串中第一次出現處的索引。
19 int indexOf(String str, int fromIndex)
返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始。
20 String intern()
返回字符串對象的規範化表示形式。
21 int lastIndexOf(int ch)
返回指定字符在此字符串中最後一次出現處的索引。
22 int lastIndexOf(int ch, int fromIndex)
返回指定字符在此字符串中最後一次出現處的索引,從指定的索引處開始進行反向搜索。
23 int lastIndexOf(String str)
返回指定子字符串在此字符串中最右邊出現處的索引。
24 int lastIndexOf(String str, int fromIndex)
返回指定子字符串在此字符串中最後一次出現處的索引,從指定的索引開始反向搜索。
25 int length()
返回此字符串的長度。
26 boolean matches(String regex)
告知此字符串是否匹配給定的正則表達式。
27 boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
測試兩個字符串區域是否相等。
28 boolean regionMatches(int toffset, String other, int ooffset, int len)
測試兩個字符串區域是否相等。
29 String replace(char oldChar, char newChar)
返回一個新的字符串,它是經過用 newChar 替換此字符串中出現的全部 oldChar 獲得的。
30 String replaceAll(String regex, String replacement
使用給定的 replacement 替換此字符串全部匹配給定的正則表達式的子字符串。
31 String replaceFirst(String regex, String replacement)
使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串。
32 String[] split(String regex)
根據給定正則表達式的匹配拆分此字符串。
33 String[] split(String regex, int limit)
根據匹配給定的正則表達式來拆分此字符串。
34 boolean startsWith(String prefix)
測試此字符串是否以指定的前綴開始。
35 boolean startsWith(String prefix, int toffset)
測試此字符串從指定索引開始的子字符串是否以指定前綴開始。
36 CharSequence subSequence(int beginIndex, int endIndex)
返回一個新的字符序列,它是此序列的一個子序列。
37 String substring(int beginIndex)
返回一個新的字符串,它是此字符串的一個子字符串。
38 String substring(int beginIndex, int endIndex)
返回一個新字符串,它是此字符串的一個子字符串。
39 char[] toCharArray()
將此字符串轉換爲一個新的字符數組。
40 String toLowerCase()
使用默認語言環境的規則將此 String 中的全部字符都轉換爲小寫。
41 String toLowerCase(Locale locale)
使用給定 Locale 的規則將此 String 中的全部字符都轉換爲小寫。
42 String toString()
返回此對象自己(它已是一個字符串!)。
43 String toUpperCase()
使用默認語言環境的規則將此 String 中的全部字符都轉換爲大寫。
44 String toUpperCase(Locale locale)
使用給定 Locale 的規則將此 String 中的全部字符都轉換爲大寫。
45 String trim()
返回字符串的副本,忽略前導空白和尾部空白。
46 static String valueOf(primitive data type x)
返回給定data type類型x參數的字符串表示形式。
View Code
Java StringBuffer 和 StringBuilder 類
當對字符串進行修改:
-
- StringBuilder:更快!
- StringBuffer:線程安全!
本身特有的方案,其餘與String類似。
序號 |
方法描述 |
1 |
public StringBuffer append(String s) 將指定的字符串追加到此字符序列。 |
2 |
public StringBuffer reverse() 將此字符序列用其反轉形式取代。 |
3 |
public delete(int start, int end) 移除此序列的子字符串中的字符。 |
4 |
public insert(int offset, int i) 將 int 參數的字符串表示形式插入此序列中。 |
5 |
replace(int start, int end, String str) 使用給定 String 中的字符替換此序列的子字符串中的字符。 |
Java 數組
值傳遞:爲何 Java 只有值傳遞,但 C# 既有值傳遞,又有引用傳遞,這種語言設計有哪些好處?
dataType[] arrayRefVar = new dataType[arraySize];
dataType[] arrayRefVar = {value0, value1, ..., valuek};
String str[][] = new String[3][4];
Arrays 類
序號 |
方法和說明 |
1 |
public static int binarySearch(Object[] a, Object key) 用二分查找算法在給定數組中搜索給定值的對象(Byte,Int,double等)。數組在調用前必須排序好的。若是查找值包含在數組中,則返回搜索鍵的索引;不然返回 (-(插入點) - 1)。 |
2 |
public static boolean equals(long[] a, long[] a2) 若是兩個指定的 long 型數組彼此相等,則返回 true。若是兩個數組包含相同數量的元素,而且兩個數組中的全部相應元素對都是相等的,則認爲這兩個數組是相等的。換句話說,若是兩個數組以相同順序包含相同的元素,則兩個數組是相等的。一樣的方法適用於全部的其餘基本數據類型(Byte,short,Int等)。 |
3 |
public static void fill(int[] a, int val) 將指定的 int 值分配給指定 int 型數組指定範圍中的每一個元素。一樣的方法適用於全部的其餘基本數據類型(Byte,short,Int等)。 |
4 |
public static void sort(Object[] a) 對指定對象數組根據其元素的天然順序進行升序排列。一樣的方法適用於全部的其餘基本數據類型(Byte,short,Int等)。 |
Java 日期時間
Java 正則表達式
參見:[PyProj] Think in Python : Regex
java.util.regex 包主要包括如下三個類:
-
- Pattern 類:
pattern 對象是一個正則表達式的編譯表示。Pattern 類沒有公共構造方法。要建立一個 Pattern 對象,你必須首先調用其公共靜態編譯方法,它返回一個 Pattern 對象。該方法接受一個正則表達式做爲它的第一個參數。
- Matcher 類:
Matcher 對象是對輸入字符串進行解釋和匹配操做的引擎。與Pattern 類同樣,Matcher 也沒有公共構造方法。你須要調用 Pattern 對象的 matcher 方法來得到一個 Matcher 對象。
- PatternSyntaxException:
PatternSyntaxException 是一個非強制異常類,它表示一個正則表達式模式中的語法錯誤。
import java.util.regex.*;
class RegexExample1{
public static void main(String args[]){
String content = "I am noob " + "from runoob.com.";
String pattern = ".*runoob.*";
boolean isMatch = Pattern.matches(pattern, content); // <----
System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch);
}
}
More詳見原文。
Java 方法
public class VarargsDemo {
public static void main(String args[]) {
// 調用可變參數的方法
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});
}
public static void printMax( double... numbers) { //numbers已經變成了一個數組 if (numbers.length == 0) {
System.out.println("No argument passed");
return;
}
double result = numbers[0];
for (int i = 1; i < numbers.length; i++){
if (numbers[i] > result) {
result = numbers[i];
}
}
System.out.println("The max value is " + result);
}
}
public class FinalizationDemo {
public static void main(String[] args) {
Cake c1 = new Cake(1);
Cake c2 = new Cake(2);
Cake c3 = new Cake(3);
c2 = c3 = null;
System.gc(); //調用Java垃圾收集器,當垃圾回收器(garbage colector)決定回收某對象時,就會運行該對象的finalize()方法。
}
}
class Cake extends Object { //finalize()是在java.lang.Object裏定義的 private int id;
public Cake(int id) {
this.id = id;
System.out.println("Cake Object " + id + "is created");
}
protected void finalize() throws java.lang.Throwable {
super.finalize();
System.out.println("Cake Object " + id + "is disposed");
}
}
Java 容許定義這樣的方法,它在對象被垃圾收集器析構(回收)以前調用,這個方法叫作 finalize( ),它用來清除回收對象。
注意:但有一種JNI(Java Native Interface)調用non-Java程序(C或C++),finalize()的工做就是回收這部分的內存。【在自動回收內存垃圾以外的使用狀況】
Java 流(Stream)、文件(File)和IO
FileInputStream
InputStream input = new FileInputStream("C:/java/hello");
File f = new File("C:/java/hello");
InputStream input = new FileInputStream(f);
序號 |
方法及描述 |
1 |
public void close() throws IOException{} 關閉此文件輸入流並釋放與此流有關的全部系統資源。拋出IOException異常。 |
2 |
protected void finalize() throws IOException {} 這個方法清除與該文件的鏈接。確保在再也不引用文件輸入流時調用其 close 方法。拋出IOException異常。 |
3 |
public int read(int r) throws IOException{} 這個方法從 InputStream 對象讀取指定字節的數據。返回爲整數值。返回下一字節數據,若是已經到結尾則返回-1。 |
4 |
public int read(byte[] r) throws IOException{} 這個方法從輸入流讀取r.length長度的字節。返回讀取的字節數。若是是文件結尾則返回-1。 |
5 |
public int available() throws IOException{} 返回下一次對此輸入流調用的方法能夠不受阻塞地今後輸入流讀取的字節數。返回一個整數值。 |
其餘的輸入流
FileOutputStream
OutputStream output = new FileOutputStream("C:/java/hello")
File f = new File("C:/java/hello");
OutputStream output = new FileOutputStream(f);
序號 |
方法及描述 |
1 |
public void close() throws IOException{} 關閉此文件輸入流並釋放與此流有關的全部系統資源。拋出IOException異常。 |
2 |
protected void finalize() throws IOException {} 這個方法清除與該文件的鏈接。確保在再也不引用文件輸入流時調用其 close 方法。拋出IOException異常。 |
3 |
public void write(int w) throws IOException{} 這個方法把指定的字節寫到輸出流中。 |
4 |
public void write(byte[] w) 把指定數組中w.length長度的字節寫到OutputStream中。 |
其餘的輸出流
以上是字節流; --> 例子,解決亂碼問題
下面是字符流;--> 關於文件和I/O的類
import java.io.*;
public class FileRead{
public static void main(String args[])throws IOException{
File file = new File("Hello1.txt");
// 建立文件
file.createNewFile();
// creates a FileWriter Object
FileWriter writer = new FileWriter(file);
// 向文件寫入內容
writer.write("This\n is\n an\n example\n");
writer.flush();
writer.close();
// 建立 FileReader 對象
FileReader fr = new FileReader(file);
char [] a = new char[50];
fr.read(a); // 讀取數組中的內容
for(char c : a)
System.out.print(c); // 一個一個打印字符
fr.close();
}
}
Java Scanner 類
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 從鍵盤接收數據
// next方式接收字符串
System.out.println("next方式接收:");
// 判斷是否還有輸入
if (scan.hasNext()) {
String str1 = scan.next();
System.out.println("輸入的數據爲:" + str1);
}
scan.close();
}
}
next():
-
- 一、必定要讀取到有效字符後才能夠結束輸入。
- 二、對輸入有效字符以前遇到的空白,next() 方法會自動將其去掉。
- 三、只有輸入有效字符後纔將其後面輸入的空白做爲分隔符或者結束符。
- next() 不能獲得帶有空格的字符串。
nextLine():
-
- 一、以Enter爲結束符,也就是說 nextLine()方法返回的是輸入回車以前的全部字符。
- 二、能夠得到空白。
Java 異常處理
產品級代碼的必會重點,連接這裏。
例子:
-
- 用戶輸入了非法數據。
- 要打開的文件不存在。
- 網絡通訊時鏈接中斷,或者JVM內存溢出。
三類:
-
- 檢查性異常:最具表明的檢查性異常是用戶錯誤或問題引發的異常,這是程序員沒法預見的。例如要打開一個不存在文件時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略。
- 運行時異常: 運行時異常是可能被程序員避免的異常。與檢查性異常相反,運行時異常能夠在編譯時被忽略。
- 錯誤: 錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中一般被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的。
Java 內置異常類
異常 |
描述 |
ArithmeticException |
當出現異常的運算條件時,拋出此異常。例如,一個整數"除以零"時,拋出此類的一個實例。 |
ArrayIndexOutOfBoundsException |
用非法索引訪問數組時拋出的異常。若是索引爲負或大於等於數組大小,則該索引爲非法索引。 |
ArrayStoreException |
試圖將錯誤類型的對象存儲到一個對象數組時拋出的異常。 |
ClassCastException |
當試圖將對象強制轉換爲不是實例的子類時,拋出該異常。 |
IllegalArgumentException |
拋出的異常代表向方法傳遞了一個不合法或不正確的參數。 |
IllegalMonitorStateException |
拋出的異常代表某一線程已經試圖等待對象的監視器,或者試圖通知其餘正在等待對象的監視器而自己沒有指定監視器的線程。 |
IllegalStateException |
在非法或不適當的時間調用方法時產生的信號。換句話說,即 Java 環境或 Java 應用程序沒有處於請求操做所要求的適當狀態下。 |
IllegalThreadStateException |
線程沒有處於請求操做所要求的適當狀態時拋出的異常。 |
IndexOutOfBoundsException |
指示某排序索引(例如對數組、字符串或向量的排序)超出範圍時拋出。 |
NegativeArraySizeException |
若是應用程序試圖建立大小爲負的數組,則拋出該異常。 |
NullPointerException |
當應用程序試圖在須要對象的地方使用 null 時,拋出該異常 |
NumberFormatException |
當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換爲適當格式時,拋出該異常。 |
SecurityException |
由安全管理器拋出的異常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException |
此異常由 String 方法拋出,指示索引或者爲負,或者超出字符串的大小。 |
UnsupportedOperationException |
當不支持請求的操做時,拋出該異常。 |
異常 |
描述 |
ClassNotFoundException |
應用程序試圖加載類時,找不到相應的類,拋出該異常。 |
CloneNotSupportedException |
當調用 Object 類中的 clone 方法克隆對象,但該對象的類沒法實現 Cloneable 接口時,拋出該異常。 |
IllegalAccessException |
拒絕訪問一個類的時候,拋出該異常。 |
InstantiationException |
當試圖使用 Class 類中的 newInstance 方法建立一個類的實例,而指定的類對象由於是一個接口或是一個抽象類而沒法實例化時,拋出該異常。 |
InterruptedException |
一個線程被另外一個線程中斷,拋出該異常。 |
NoSuchFieldException |
請求的變量不存在 |
NoSuchMethodException |
請求的方法不存在 |
異常方法
下面的列表是 Throwable 類的主要方法:
序號 |
方法及說明 |
1 |
public String getMessage() 返回關於發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了。 |
2 |
public Throwable getCause() 返回一個Throwable 對象表明異常緣由。 |
3 |
public String toString() 使用getMessage()的結果返回類的串級名字。 |
4 |
public void printStackTrace() 打印toString()結果和棧層次到System.err,即錯誤輸出流。 |
5 |
public StackTraceElement [] getStackTrace() 返回一個包含堆棧層次的數組。下標爲0的元素表明棧頂,最後一個元素表明方法調用堆棧的棧底。 |
6 |
public Throwable fillInStackTrace() 用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。 |
try...catch 捕獲異常
// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){ // 處理數組越界
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
擴展 之 多重捕獲。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch(IOException i){
i.printStackTrace();
return -1;
} catch(FileNotFoundException f){
f.printStackTrace();
return -1;
}
好處:
爲避免與正常的代碼混在一塊兒,很差區分開。
所以,Java、C#等設計了try catch這一種特殊的方式。
try{
....
CreateFile( "C:\abc.txt" );
}catch(AccessException e){
....//代碼進入這裏說明發生【沒有權限錯誤】
}catch(FileExistedException e){
....//代碼進入這裏說明發生【文件已經存在錯誤】
}catch(TimeoutException e){
....//代碼進入這裏說明發生【超時錯誤】
}
更高的認識:
說處處理異常,咱們固然會想到 try catch finally
在java中咱們會對異常的處理有更高的認識 咱們會學習 throw throws等更好的處理異常。
手動拋出異常可是有時候有些錯誤在jvm看來不是錯誤,好比說
int age = 0;
age = -100;
System.out.println(age);
因此,咱們須要本身手動引起異常,這就是throw的做用。
int age = 0;
age = -100;
if(age<0)
{
Exception e = new Exception(); // ----> 建立異常對象
throw e; // ----> 拋出異常
}
System.out.println(age);
異常被拋到這個方法的調用者那裏,這個有點像下屬處理不了的問題就交到上司手裏同樣,稱爲迴避異常。
可是這使得調用這個方法就有了危險,由於誰也不知道這個方法何時會丟一個什麼樣的異常給調用者。
因此,在定義方法時,就須要在方法頭部分使用throws來聲明這個方法可能迴避的異常。
/**
* fun()可能會拋出兩種異常
*/
void fun()throws IOException,SQLException
{
...
}
try{
fun();
/**
* 調用fun()的時候,就知道該如何作準備來處理異常了
*/
}catch(IOException e){
...
}catch(SQLException e){
...
}
throws/throw 關鍵字:
import java.io.*;
public class className
{
public void deposit(double amount) throws RemoteException, InsufficientFundsException // 拋出了多個異常,throwable的子類
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
實例:try-catch 和 throw, throws 的區別
public class ZeroTest {
public static void main(String[] args) {
try{
int i = 100/ 0; // 這裏遇到算數異常
System.out.print(i);
}catch(Exception e){
System.out.print(1);
throw new RuntimeException(); // 緩存異常後,執行finally
}finally{
System.out.print(2); // 執行完後,再執行以上緩存中的異常
}
System.out.print(3);
}
}
class A{
public void func() throws Exception{ // 代表這個方法有可能會拋出一個異常 throw new Exception();
}
public void g() throws Exception{
}
}
聲明自定義異常
在 Java 中你能夠自定義異常。編寫本身的異常類時須要記住下面的幾點。
-
- 全部異常都必須是 Throwable 的子類。
- 若是但願寫一個檢查性異常類,則須要繼承 Exception 類。
- 若是你想寫一個運行時異常類,那麼須要繼承 RuntimeException 類。
簡單實例,幫助理解:
(a). 自定義異常類
// 文件名InsufficientFundsException.java
import java.io.*;
//自定義異常類,繼承Exception類
public class InsufficientFundsException extends Exception
{
//此處的amount用來儲存當出現異常(取出錢多於餘額時)所缺少的錢
private double amount;
public InsufficientFundsException(double amount)
{
this.amount = amount;
}
public double getAmount()
{
return amount;
}
}
(b). 工具類
// 文件名稱 CheckingAccount.java
import java.io.*;
//此類模擬銀行帳戶
public class CheckingAccount
{
//balance爲餘額,number爲卡號
private double balance;
private int number;
public CheckingAccount(int number)
{
this.number = number;
}
//方法:存錢
public void deposit(double amount)
{
balance += amount;
}
//方法:取錢
public void withdraw(double amount) throws InsufficientFundsException
{
if(amount <= balance)
{
balance -= amount;
}
else
{
double needs = amount - balance;
throw new InsufficientFundsException(needs); // --> 02.拋出了自定義異常
}
}
//方法:返回餘額
public double getBalance()
{
return balance;
}
//方法:返回卡號
public int getNumber()
{
return number;
}
}
(c). 使用main函數。
//文件名稱 BankDemo.java
public class BankDemo
{
public static void main(String [] args)
{
CheckingAccount c = new CheckingAccount(101);
System.out.println("Depositing $500...");
c.deposit(500.00);
try
{
System.out.println("\nWithdrawing $100...");
c.withdraw(100.00);
System.out.println("\nWithdrawing $600...");
c.withdraw(600.00); // --> 01.透支,須要拋出異常
/**
* 上述函數可能會拋出異常,那麼下面就作好處理的準備。
* catch是瞭解withdraw會拋出怎樣異常的!
*/
}catch(InsufficientFundsException e) { // --> 03. 這裏捕獲自定義異常
System.out.println("Sorry, but you are short $" + e.getAmount());
e.printStackTrace();
}
}
}
Java 面向對象
Java 繼承
- 全部的類都是繼承於 java.lang.Object。
單繼承:
class 子類 extends 父類 {
...
}
經過接口多繼承:
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
...
}
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 調用本身的方法
super.eat(); // super 調用父類方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
定義爲不能繼承的,即最終類;
Or 用於修飾方法,該方法不能被子類重寫。
構造方法順序:
class SuperClass {
private int n;
SuperClass(){
System.out.println("SuperClass()");
}
SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
class SubClass extends SuperClass{
private int n;
SubClass(){
super(300); // 給本身的父類傳參
System.out.println("SubClass");
}
public SubClass(int n){
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
SubClass sc = new SubClass();
SubClass sc2 = new SubClass(200);
}
}
Java 重寫(Override)與重載(Overload)
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 對象
Animal b = new Dog(); // Dog 對象
a.move(); // 執行 Animal 類的方法
b.move(); //執行 Dog 類的方法
b.bark();
}
}
區別點 |
重載方法 |
重寫方法 |
參數列表 |
必須修改 |
必定不能修改 |
返回類型 |
能夠修改 |
必定不能修改 |
異常 |
能夠修改 |
能夠減小或刪除,必定不能拋出新的或者更廣的異常 |
訪問 |
能夠修改 |
必定不能作更嚴格的限制(能夠下降限制) |
Java 多態
多態的實現方式
方式一:重寫:
方式二:接口
方式三:抽象類和抽象方法
Java 抽象類
From:Java中抽象類和接口的用法和區別
(一)語法層次
(二)設計層次
一、 抽象層次不一樣
抽象類:對類抽象;對整個類總體進行抽象,包括屬性、行爲。
接口 :對行爲的抽象;對類局部(行爲)進行抽象。
二、 跨域不一樣
抽象類:所跨域的是具備類似特色的類,
接口 :能夠跨域不一樣的類。
三、 設計層次不一樣
抽象類:它是自下而上來設計的,咱們要先知道子類才能抽象出父類。
-
- 好比咱們只有一個貓類在這裏,若是你抽象成一個動物類,是否是設計有點兒過分?咱們起碼要有兩個動物類,貓、狗在這裏,咱們在抽象他們的共同點造成動物抽象類吧!因此說抽象類每每都是經過重構而來的!
接口 :不一樣,它根本就不須要知道子類的存在,只須要定義一個規則便可,至於什麼子類、何時怎麼實現它一律不知。
-
- 可是接口就不一樣,好比說飛,咱們根本就不知道會有什麼東西來實現這個飛接口,怎麼實現也不得而知,咱們要作的就是事前定義好飛的行爲接口。因此說抽象類是自底向上抽象而來的,接口是自頂向下設計出來的。
Java 封裝
相似於c#的set, get屬性。
/* 文件名: EncapTest.java */
public class EncapTest{
private String name;
private String idNum;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public String getIdNum(){
return idNum;
}
public void setAge( int newAge){
age = newAge;
}
public void setName(String newName){
name = newName;
}
public void setIdNum( String newId){
idNum = newId;
}
}
/* F文件名 : RunEncap.java */
public class RunEncap{
public static void main(String args[]){
EncapTest encap = new EncapTest();
encap.setName("James");
encap.setAge(20);
encap.setIdNum("12343ms");
System.out.print("Name : " + encap.getName() + Age : " + encap.getAge());
}
}
Java 接口
接口的繼承
一個接口能繼承另外一個接口,和類之間的繼承方式比較類似。接口的繼承使用extends關鍵字,子接口繼承父接口的方法。
下面的Sports接口被Hockey和Football接口繼承:
// 文件名: Sports.java
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports // Hockey接口本身聲明瞭四個方法,從Sports接口繼承了兩個方法
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
標記接口
Ref: 第37條:用標記接口定義類型
Ref: 爲何這些java接口沒有抽象方法?淺談Java標記接口
好處一:這樣針對於不一樣的List採起不一樣的遍歷形式,可讓遍歷的速度更快。
例如:RandomAccess
import java.util.List;
import java.util.RandomAccess;
public class SourceLearning
{
public void iteratorElements(List<String> list) // 這裏的list可能只是override
{
if (list instanceof RandomAccess)
{
for (int i = 0, size = list.size(); i < size; i++)
{
String element = list.get(i);
}
}
else
{
for (String element : list)
{
// ... ...
}
}
}
}
判斷是否實現RandomAccess接口,就能夠決定採起哪一種遍歷的方式。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//...
}
// 而LinkedList就沒有實現該標記接口 public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//...
}
好處二:優雅地表示對象是否具有這個能力
例如:Cloneable
標記該對象的是否擁有克隆的能力。
public interface Cloneable {
... ...
}
例如:java.io.Serializable
/**
* Write the specified object to the ObjectOutputStream. The class of the
* object, the signature of the class, and the values of the non-transient
* and non-static fields of the class and all of its supertypes are
* written. Default serialization for a class can be overridden using the
* writeObject and the readObject methods. Objects referenced by this
* object are written transitively so that a complete equivalent graph of
* objects can be reconstructed by an ObjectInputStream.
*
* <p>Exceptions are thrown for problems with the OutputStream and for
* classes that should not be serialized. All exceptions are fatal to the
* OutputStream, which is left in an indeterminate state, and it is up to
* the caller to ignore or recover the stream state.
*
* @throws InvalidClassException Something is wrong with a class used by
* serialization.
* @throws NotSerializableException Some object to be serialized does not
* implement the java.io.Serializable interface.
* @throws IOException Any exception thrown by the underlying
* OutputStream.
*/
public final void writeObject(Object obj) throws IOException {
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}
View Code
Java 包(package)
在一個.java文件中能夠一個public類和多個非public類,若是要將這些類組織在一個包當中,則在.java文件中除註釋之外的第一行使用關鍵字package便可實現。
1 爲了儘可能使包名保持惟一性,包名一般採用小寫、按倒寫互聯網址的形式進行定義。如:com.hank.www表示包文件放置的文件路徑爲com/hank/www。
2 在進行命名包時,應該避免使用與系統發生衝突的名字,如java.lang、java.swing等。
建立了一個叫作animals的包:
/* 文件名: Animal.java */
package animals; interface Animal { // 在包中加入接口 public void eat();
public void travel();
}
MammalInt.java 文件代碼:在同一個包中加入該接口的實現。
package animals; /* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
放在文件夾animals裏,而後命令運行:
$ java animals/MammalInt
Mammal eats
Mammal travel
Boss.java 文件代碼:
package payroll;
public class Boss
{
public void payEmployee(Employee e) //payroll 包已經包含了 Employee 類,不用實用功能全名:payroll.Employee
{
e.mailCheck();
}
}
他們兩個是互逆過程
將你這個類放在了/freedom/bean/這個文件夾下面,要使用的話
import freedom.bean.*;導入這個類
一般,一個公司使用它互聯網域名的顛倒形式來做爲它的包名。
例如:互聯網域名是 runoob.com,全部的包名都以 com.runoob 開頭。包名中的每個部分對應一個子目錄。
(1). 該目錄下常見文件Runoob.java
....\com\runoob\test\Runoob.java
// 文件名: Runoob.java
package com.runoob.test;
public class Runoob {
}
class Google {
}
(2). 編譯
獲得.class文件
.\com\runoob\test\Runoob.class
.\com\runoob\test\Google.class
放置其它位置,但包名要保持一致!
<path-one>\sources\com\runoob\test\Runoob.java
<path-two>\classes\com\runoob\test\Google.class
|-- class path ---|--- package ---|
這樣,你能夠將你的類目錄分享給其餘的編程人員,而不用透露本身的源碼。
(3). 設置 CLASSPATH 系統變量
一個 class path 可能會包含好幾個路徑,多路徑應該用分隔符分開。
默認狀況下,編譯器和 JVM 查找當前目錄。
JAR 文件按包含 Java 平臺相關的類,因此他們的目錄默認放在了 class path 中。
用下面的命令顯示當前的CLASSPATH變量:
Windows 平臺(DOS 命令行下):C:\> set CLASSPATH
UNIX 平臺(Bourne shell 下):# echo $CLASSPATH
刪除當前CLASSPATH變量內容:
Windows 平臺(DOS 命令行下):C:\> set CLASSPATH=
UNIX 平臺(Bourne shell 下):# unset CLASSPATH; export CLASSPATH
設置CLASSPATH變量:
Windows 平臺(DOS 命令行下): C:\> set CLASSPATH=C:\users\jack\java\classes
UNIX 平臺(Bourne shell 下):# CLASSPATH=/home/jack/java/classes; export CLASSPATH
View Code
Java 高級教程
Java 數據結構
import java.util.Vector;
import java.util.Enumeration;
public class EnumerationTester {
public static void main(String args[]) {
Enumeration<String> days;
Vector<String> dayNames = new Vector<String>();
dayNames.add("Sunday");
dayNames.add("Monday");
dayNames.add("Tuesday");
dayNames.add("Wednesday");
dayNames.add("Thursday");
dayNames.add("Friday");
dayNames.add("Saturday");
days = dayNames.elements();
while (days.hasMoreElements()){
System.out.println(days.nextElement());
}
}
}
理解:bits2.and(bits1); bits2與bits1作運算,bits2發生變化。
import java.util.BitSet;
public class BitSetDemo {
public static void main(String args[]) {
BitSet bits1 = new BitSet(16);
BitSet bits2 = new BitSet(16);
// set some bits
for(int i=0; i<16; i++) {
if((i%2) == 0) bits1.set(i);
if((i%5) != 0) bits2.set(i);
}
System.out.println("Initial pattern in bits1: ");
System.out.println(bits1);
System.out.println("\nInitial pattern in bits2: ");
System.out.println(bits2);
// AND bits
bits2.and(bits1);
System.out.println("\nbits2 AND bits1: ");
System.out.println(bits2);
// OR bits
bits2.or(bits1);
System.out.println("\nbits2 OR bits1: ");
System.out.println(bits2);
// XOR bits
bits2.xor(bits1);
System.out.println("\nbits2 XOR bits1: ");
System.out.println(bits2);
}
}
能根據須要動態的變化,和ArrayList和類似,區別是什麼?
Ref: Arraylist與Vector的區別
- 白色的部分是須要去了解的,
- 黃色部分是咱們要去重點了解的,不但要知道怎麼去用,至少還須要讀一次源碼。
- 綠色部份內容已經不多用了,但在面試題中有可能會問到
Vector vs ArrayList
標準答案:
一、Vector是線程安全的,ArrayList不是線程安全的。
二、ArrayList在底層數組不夠用時在原來的基礎上擴展0.5倍,Vector是擴展1倍。
因此:
無一例外,只要是關鍵性的操做,方法前面都加了synchronized關鍵字,來保證線程的安全性。
- 單線程的環境中,Vector效率要差不少。
- 多線程環境不容許用ArrayList,須要作處理。
ArrayList vs LinkedList
- ArrayList能夠直接經過數組下標獲得元素;
- LinkedList則須要根據所給的下標從頭部或尾部開始往下標的位置依次得到下一個元素或上一個元素。
import java.util.*;
public class StackDemo {
static void showpush(Stack<Integer> st, int a) {
st.push(new Integer(a));
System.out.println("push(" + a + ")");
System.out.println("stack: " + st);
}
static void showpop(Stack<Integer> st) {
System.out.print("pop -> ");
Integer a = (Integer) st.pop();
System.out.println(a);
System.out.println("stack: " + st);
}
public static void main(String args[]) {
Stack<Integer> st = new Stack<Integer>();
System.out.println("stack: " + st);
showpush(st, 42); // push
showpush(st, 66);
showpush(st, 99);
showpop(st); // pop
showpop(st);
showpop(st);
try {
showpop(st);
} catch (EmptyStackException e) {
System.out.println("empty stack");
}
}
}
Dictionary類已通過時了。在實際開發中,你能夠實現Map接口來獲取鍵/值的存儲功能。
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
Map m1 = new HashMap();
m1.put("Zara", "8");
m1.put("Mahnaz", "31");
m1.put("Ayan", "12");
m1.put("Daisy", "14");
System.out.println();
System.out.println(" Map Elements");
System.out.print("\t" + m1);
}
}
hashmap |
線程不安全 |
容許有null的鍵和值 |
效率高一點、 |
方法不是Synchronize的要提供外同步 |
有containsvalue和containsKey方法 |
HashMap 是Java1.2 引進的Map interface 的一個實現 |
HashMap是Hashtable的輕量級實現 |
hashtable |
線程安全 |
不容許有null的鍵和值 |
效率稍低、 |
方法是是Synchronize的 |
有contains方法方法 |
Hashtable 繼承於Dictionary 類 |
Hashtable 比HashMap 要舊 |
Ref: Java中Properties類的操做
在Java中,其配置文件常爲.properties文件,格式爲文本文件,文件的內容的格式是「鍵=值」的格式,文本註釋信息能夠用"#"來註釋。
它提供了幾個主要的方法:
1. getProperty ( String key),用指定的鍵在此屬性列表中搜索屬性。也就是經過參數 key ,獲得 key 所對應的 value。
2. load ( InputStream inStream),從輸入流中讀取屬性列表(鍵和元素對)。經過對指定的文件(好比說上面的 test.properties 文件)進行裝載來獲取該文件中的全部鍵 - 值對。以供 getProperty ( String key) 來搜索。
3. setProperty ( String key, String value) ,調用 Hashtable 的方法 put 。他經過調用基類的put方法來設置 鍵 - 值對。
4. store ( OutputStream out, String comments),以適合使用 load 方法加載到 Properties 表中的格式,將此 Properties 表中的屬性列表(鍵和元素對)寫入輸出流。與 load 方法相反,該方法將鍵 - 值對寫入到指定的文件中去。
5. clear (),清除全部裝載的 鍵 - 值對。該方法在基類中提供。
Java 集合框架
Java 集合框架提供了一套性能優良,使用方便的接口和類,java集合框架位於java.util包中, 因此當使用集合框架的時候須要進行導包。
Ref:Java中的集合框架
更詳細的圖,參考:java集合框架綜述
Java 泛型
泛型的本質是參數化類型,也就是說所操做的數據類型被指定爲一個參數。
假定咱們有這樣一個需求:寫一個排序方法,可以對整型數組、字符串數組甚至其餘任何類型的數組進行排序,該如何實現?
答案:可使用 Java 泛型。
public class GenericMethodTest
{
// 泛型方法 printArray
public static <E> void printArray( E[] inputArray )
{
// 輸出數組元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] )
{
// 建立不一樣類型數組: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型數組元素爲:" );
printArray( intArray ); // 傳遞一個整型數組
System.out.println( "\n雙精度型數組元素爲:" );
printArray( doubleArray ); // 傳遞一個雙精度型數組
System.out.println( "\n字符型數組元素爲:" );
printArray( charArray ); // 傳遞一個字符型數組
}
}
作一點限制,必須得是可比較的對象:
public class MaximumTest
{
// 比較三個值並返回最大值
public static <T extends Comparable<T>> T maximum(T x, T y, T z)
{
T max = x;
if ( y.compareTo( max ) > 0 ){
max = y;
}
if ( z.compareTo( max ) > 0 ){
max = z;
}
return max;
}
public static void main( String args[] )
{
System.out.printf( "%d, %d 和 %d 中最大的數爲 %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) );
System.out.printf( "%.1f, %.1f 和 %.1f 中最大的數爲 %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
System.out.printf( "%s, %s 和 %s 中最大的數爲 %s\n","pear", "apple", "orange", maximum( "pear", "apple", "orange" ) );
}
}
public class Box<T> { private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("菜鳥教程"));
System.out.printf("整型值爲 :%d\n\n", integerBox.get());
System.out.printf("字符串爲 :%s\n", stringBox.get());
}
}
Ref: Java 泛型總結(三):通配符的使用
一個數組override的例子:
-
- 對於編譯器來講,這是能夠經過編譯的,
- 在運行時期,JVM 可以知道數組的實際類型是
Apple[]
,因此當其它對象加入數組的時候就會拋出異常。
class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}
public class CovariantArrays {
public static void main(String[] args) {
Fruit[] fruit = new Apple[10]; // 數組的協變,這是一種缺陷?
// ArrayList<Fruit> flist = new ArrayList<Apple>();
fruit[0] = new Apple(); // OK
fruit[1] = new Jonathan(); // OK
... ...
}
}
當涉及到泛型時, 儘管 Apple
是 Fruit
的子類型,可是 ArrayList<Apple>
不是 ArrayList<Fruit>
的子類型,泛型不支持協變。
若是咱們確實須要創建這種 「向上轉型」 的關係怎麼辦呢?這就須要通配符來發揮做用了。
上邊界限定通配符
List<? extends Fruit> flist = new ArrayList<Apple>();
如今,咱們並不關心這個實際的類型究竟是什麼,反正是 Fruit
的子類型,Fruit
是它的上邊界。
在上面的代碼中,向 flist
中添加任何對象,不管是 Apple
仍是 Orange
甚至是 Fruit
對象,編譯器都不容許,惟一能夠添加的是 null
。
因此,若是作了泛型的向上轉型,那麼咱們也就失去了向這個 List 添加任何對象的能力,即便是 Object
也不行。
然而,
add()
接受一個泛型類型做爲參數;
可是,contains
和 indexOf
接受一個Object
類型的參數。
public boolean add (E e)
public boolean contains(Object o)
public int indexOf (Object o)
因此,本身編寫類時【替代如上的List】,方法所有定義爲泛型,就能夠支持上邊界限定通配符了。
下邊界限定通配符
public class SuperTypeWildcards {
static void writeTo(List<? super Apple> apples) {
apples.add(new Apple());
apples.add(new Jonathan());
// apples.add(new Fruit()); // Error,Fruit是Apple的父類!
}
}
以下,只要是T的父類,均可以copy()。
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src)
{
for (int i=0; i<src.size(); i++) {
dest.set(i, src.get(i));
}
}
}
無邊界通配符
List<?>
,也就是沒有任何限定。不作任何限制,跟不用類型參數的 List
有什麼區別呢?
List<?> list
表示 list
是持有某種特定類型的 List,可是不知道具體是哪一種類型。那麼咱們能夠向其中添加對象嗎?固然不能夠!
由於並不知道實際是哪一種類型,因此不能添加任何類型,這是不安全的。
單獨的 List list
,也就是沒有傳入泛型參數,表示這個 list 持有的元素的類型是 Object
,所以能夠添加任何類型的對象,只不過編譯器會有警告信息。
【如此說來,貌似沒什麼大用】
Java 序列化
優缺點比較:
|
優勢 |
缺點 |
Serializable |
使用方便,可序列化全部類 |
速度慢,佔空間 |
Protostuff |
速度快,基於protobuf |
需靜態編譯 |
一個類的對象要想序列化成功,必須知足兩個條件:
-
- 該類必須實現 java.io.Serializable 對象。
- 該類的全部屬性必須是可序列化的。若是有一個屬性不是可序列化的,則該屬性必須註明是短暫的。
SerializeDemo.java
import java.io.*;
public class SerializeDemo
{
public static void main(String [] args)
{
Employee e = new Employee();
e.name = "Reyan Ali";
e.address = "Phokka Kuan, Ambehta Peer";
e.SSN = 11122333;
e.number = 101;
try
{
FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
DeserializeDemo.java
import java.io.*;
public class DeserializeDemo
{
public static void main(String [] args)
{
Employee e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Employee...");
System.out.println("Name: " + e.name);
System.out.println("Address: " + e.address);
System.out.println("SSN: " + e.SSN);
System.out.println("Number: " + e.number);
}
}
Java 網絡編程
客戶端:經過 socket 鏈接到服務器併發送一個請求,而後等待一個響應。
// 文件名 GreetingClient.java
import java.net.*;
import java.io.*;
public class GreetingClient
{
public static void main(String [] args)
{
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try
{
System.out.println("鏈接到主機:" + serverName + " ,端口號:" + port);
Socket client = new Socket(serverName, port); // Create socket
System.out.println("遠程主機地址:" + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream(); // Create stream channel at local
DataOutputStream out = new DataOutputStream(outToServer); // Create data channel at local
out.writeUTF("Hello from " + client.getLocalSocketAddress()); // <---- 發數據
InputStream inFromServer = client.getInputStream(); // <---- Create stream channel at local 等迴應
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("服務器響應: " + in.readUTF());
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
服務端:使用 Socket 來監聽一個指定的端口。
// 文件名 GreetingServer.java
import java.net.*;
import java.io.*;
public class GreetingServer extends Thread
{
private ServerSocket serverSocket;
public GreetingServer(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run()
{
while(true)
{
try
{
System.out.println("等待遠程鏈接,端口號爲:" + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("遠程主機地址:" + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream()); // ----> 先stream 後data
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream()); // ----> 準備應答,先stream 後data
out.writeUTF("謝謝鏈接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = Integer.parseInt(args[0]);
try
{
Thread t = new GreetingServer(port); // Create thread to listen
t.run();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
Java 發送郵件
略,詳見連接。
Java 多線程編程
Java 提供了三種建立線程的方法:
-
- 經過實現 Runnable 接口;
- 經過繼承 Thread 類自己;
- 經過 Callable 和 Future 建立線程。
(1).
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() { // 運行狀態
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 讓線程睡眠一會
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start() { // 就緒狀態
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
} public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start(); // ----> 進入就緒狀態
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
(2).
與上述在寫法上沒什麼大區別。
Thread原本就是實現了Runnable,包含Runnable的功能是很正常的啊!!至於二者的真正區別最主要的就是一個是繼承,一個是實現;
還有一些面向對象的思想,
-
- Runnable就至關於一個做業,
- Thread纔是真正的處理線程,
咱們須要的只是定義這個做業,而後將做業交給線程去處理,這樣就達到了鬆耦合,也符合面向對象裏面組合的使用,
另外也節省了函數開銷,繼承Thread的同時,不只擁有了做業的方法run(),還繼承了其餘全部的方法。
綜合來看,用Runnable比Thread好的多。
class ThreadDemo extends Thread { private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() { // ----> 重寫該類的run()方法,線程的執行體
... ...
}
public void start() {
... ...
} public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
(3).
Java5策略 - 裸線程的進步callable
Ref:Java線程(七):Callable和Future
Callable和Future,一個產生結果,一個拿到結果。
Callable接口相似於Runnable,
-
- 可是Runnable不會返回結果,而且沒法拋出返回結果的異常,
- 而Callable功能更強大一些,被線程執行後,能夠返回值,這個返回值能夠被Future拿到,也就是說,Future能夠拿到異步執行任務的返回值。
Callable接口提供了一個call()方法做爲線程執行體,call()方法比run()方法功能要強大,能夠有返回值!
Java5提供了Future接口來表明Callable接口裏call()方法的返回值。
FutureTask實現了兩個接口,Runnable和Future,因此
-
- 它既能夠做爲Runnable被線程執行
- 又能夠做爲Future獲得Callable的返回值
public class CallableAndFuture {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() { public Integer call() throws Exception { // ----> call做爲線程執行體,且能夠有返回值
return new Random().nextInt(100);
}
};
/*
* 1. callable是個類的實例,裏面定義了線程執行體函數call()。
* 2. future這個類來表明callable所表明線程的返回值。
*/
FutureTask<Integer> future = new FutureTask<Integer>(callable); // ----> Future接口表明 Callable接口裏call()方法的返回值
/* 3. 準備就緒,線程start */
new Thread(future).start();
try {
Thread.sleep(5000);// 可能作一些事情
System.out.println(future.get()); // <---- 獲得返回值
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
Java5以後的策略 - Executor框架
簡化併發編程,Executor使咱們無需顯式地去管理線程的生命週期,是JDK 5以後啓動任務的首選方式。
Ref:Java併發的四種風味:Thread、Executor、ForkJoin和Actor
Ref:java併發編程--Executor框架
Executor接口的定義很是簡單:
public interface Executor {
void execute(Runnable command);
}
- Executor:一個接口,其定義了一個接收Runnable對象的方法executor,其方法簽名爲executor(Runnable command),
- ExecutorService:是一個比Executor使用更普遍的子類接口,其提供了生命週期管理的方法,以及可跟蹤一個或多個異步任務執行情況返回Future的方法
- AbstractExecutorService:ExecutorService執行方法的默認實現
- ScheduledExecutorService:一個可定時調度任務的接口
- ScheduledThreadPoolExecutor:ScheduledExecutorService的實現,一個可定時調度任務的線程池
- ThreadPoolExecutor:線程池,能夠經過調用Executors如下靜態工廠方法來建立線程池並返回一個ExecutorService對象:
線程池例子:任務執行完成後並返回執行結果
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor(); // ExecutorService繼承自Executor,管理Thread對象
Future<Integer> future = threadPool.submit(new Callable<Integer>() { // 線程池的線程提供了獲取返回值future的服務。 public Integer call() throws Exception { // 線程的執行體
return new Random().nextInt(100);
}
});
try {
Thread.sleep(5000);// 可能作一些事情
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
例1:使用newScheduledThreadPool來模擬心跳機制
public class HeartBeat {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); // <---- 有五個線程的線程池
Runnable task = new Runnable() {
public void run() {
System.out.println("HeartBeat.........................");
}
};
executor.scheduleAtFixedRate(task,5,3, TimeUnit.SECONDS); //5秒後第一次執行,以後每隔3秒執行一次
}
}
例2:線程能夠重用,節省資源
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService threadPool = Executors.newCachedThreadPool();//線程池裏面的線程數會動態變化,並可在線程線被移除前重用
for (int i = 1; i <= 3; i ++) { final int task = i;//TimeUnit.SECONDS.sleep(1); // 第六行!
threadPool.execute(new Runnable() { //接受一個Runnable實例
public void run() {
System.out.println("線程名字: " + Thread.currentThread().getName() + " 任務名爲: "+task);
}
});
}
}
}
輸出結果:
// 輸出:(爲每一個任務新建一條線程,共建立了3條線程)
線程名字: pool-1-thread-1 任務名爲: 1
線程名字: pool-1-thread-2 任務名爲: 2
線程名字: pool-1-thread-3 任務名爲: 3
// 去掉第6行的註釋其輸出以下:(始終重複利用一條線程,由於newCachedThreadPool能重用可用線程)
線程名字: pool-1-thread-1 任務名爲: 1
線程名字: pool-1-thread-1 任務名爲: 2
線程名字: pool-1-thread-1 任務名爲: 3
例3:啓動10條線程,誰先執行完成就返回誰
CompletionService:將執行完成的任務放到阻塞隊列中,經過take或poll方法來得到執行結果。
public class CompletionServiceTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(10); //建立含10條線程的線程池
CompletionService completionService = new ExecutorCompletionService(executor);
for (int i =1; i <=10; i ++) {
final int result = i;
completionService.submit(new Callable() { public Object call() throws Exception {
Thread.sleep(new Random().nextInt(5000)); //讓當前線程隨機休眠一段時間
return result;
}
});
}
System.out.println(completionService.take().get()); //獲取執行結果
}
}
輸出結果可能每次都不一樣(在1到10之間)。
經過Executor來設計應用程序能夠簡化開發過程,提升開發效率,並有助於實現併發,在開發中若是須要建立線程可優先考慮使用Executor
Java Applet 基礎
略,已被js取代。
Java 文檔註釋
javadoc 工具將你 Java 程序的源代碼做爲輸入,輸出一些包含你程序註釋的HTML文件。
詳見連接。
Java 實例
功能代碼demo參考,詳見連接。
Java 8 新特性
編程風格的不一樣:
import java.util.Collections;
// 使用 java 7 排序
private void sortUsingJava7(List<String> names){
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
}
// 上面的compare名字其實不重要
// 也就側面說明了匿名函數的必要性
// 使用 java 8 排序
private void sortUsingJava8(List<String> names){
Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
}
其餘詳見:http://www.runoob.com/java/java8-new-features.html
Java MySQL 鏈接
使用 JDBC 鏈接 MySQL 數據庫。
Java 鏈接 MySQL 須要驅動包,最新版下載地址爲:http://dev.mysql.com/downloads/connector/j/,解壓後獲得jar庫文件,而後在對應的項目中導入該庫文件。
package com.runoob.test;
import java.sql.*;
public class MySQLDemo {
// JDBC 驅動名及數據庫 URL
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
// 數據庫的用戶名與密碼,須要根據本身的設置
static final String USER = "root";
static final String PASS = "123456";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
// 1. 註冊 JDBC 驅動
Class.forName("com.mysql.jdbc.Driver");
// 2. 打開連接
System.out.println("鏈接數據庫...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
// 3. 執行查詢
System.out.println(" 實例化Statement對象...");
stmt = conn.createStatement();
String sql;
sql = "SELECT id, name, url FROM websites";
ResultSet rs = stmt.executeQuery(sql);
// 展開結果集數據庫
while(rs.next()){
// 經過字段檢索
int id = rs.getInt("id");
String name = rs.getString("name");
String url = rs.getString("url");
// 輸出數據
System.out.print("ID: " + id);
System.out.print(", 站點名稱: " + name);
System.out.print(", 站點 URL: " + url);
System.out.print("\n");
}
// 完成後關閉
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
// 處理 JDBC 錯誤
se.printStackTrace();
}catch(Exception e){
// 處理 Class.forName 錯誤
e.printStackTrace();
}finally{
// 關閉資源
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}// 什麼都不作
try{
if(conn!=null) conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
}
補充
Ref:java面試57道題,轉自知乎某位知友