JAVA基礎
基本類型
-
enum 枚舉
Size { SMALL , MEDIUM , LARGE , EXTRA }
Size s = Size . MEDIUM
每個枚舉類型都有一個靜態的 values 方法 , 它將返回一個包含全部枚舉值的數組。
ordinal 方法返冋 enum 聲明中枚舉常量的位置 , 位置從 0 開始計數。
-
String
- String是對象 不是基本類型,可將變量重新賦值為新的字符串,但不能改變原始String內容
- 判斷String是否相等用equals,==比較的將是倆個對象
-
常量
- 使用final聲明常量為對象常量,每個對象都有。final CTIME = System.currentTimeMillis();
- 使用final static聲明的類靜態變量(類常量) static final CTIME = System.currentTimeMillis();
-
基本類型包裝類
基本數據類型 包裝類 byte java.lang.Byte boolean java.lang.Boolean short java.lang.Short char java.lang.Character int java.lang.Integer long java.lang.Long float java.lang.Float double java.lang.Double 轉換方法
Integer i = Integer.valueOf(1) ; i.intValue(); Integer i = 123; //由于有自動裝包拆包機制可直接聲明
關于自動裝箱還有幾點需要說明 。 首先 , 由于包裝器類引用可以為 null , 所以自動裝箱有可能會拋出一個 NullPointerException 異常。
另外,如果在一個條件表達式中混合使用 Integer 和 Double 類型 , Integer 值就會拆箱 ,提升為 double , 再裝箱為 Double。
對象與類
-
重載
類中允許同名函數不同參數的方法存在,根據調用時傳遞的參數類型自動執行對應的方法。
-
成員變量初始化
可直接賦值為常量值,也可為某個對象,也可為方法的返回值。
可通過初始化塊統一初始化,初始化塊將早于構造函數前運行
-
static
- 屬于類,而不屬于任何獨立的對象。
- static變量直接賦值 public static int i = 1;
- 放到static塊中同一初始化
- 可通過對象句柄調用靜態方法,但是不建議。
static{ i = 0x123; j = "never"; }
-
構造函數
- 所有成員變量無論生命在類中任意位置,都將在構造函數執行前得到默認初始化。
- 構造函數名稱與類名稱一致。
- 很多類會重載一個無參數的構造函數用來初始化適當的默認值。
- 如果類中沒有編寫構造函數,系統會提供一個無參數的構造函數,如果有一個有參數的構造函數,但創建對象時未傳遞參數將發生錯誤。
- 可通過this(param)調用其他重載的構造函數。
-
初始化順序
- 所有數據域被初始化為默認值 ( 0 、 false 或 null ) 。
- 按照在類聲明中出現的次序 , 依次執行所有域初始化語句和初始化塊 。
- 如果構造器第一行調用了第二個構造器,則執行第二個構造器主體
- 執行這個構造器的主體
-
final
- 當一個成員變量被聲明為final時,系統將不會給與默認初始化,需要手動初始化,初始化后不能修改。對于其保存的是一個對象時,不可修改代表不能將變量替換為其他對象的句柄,但可以該對象的屬性進行操作。
- 當一個類被聲明final時,將不允許繼承,其類的所有方法自動變為final,但不包含成員變量。
- 當一個方法被聲明final時,將不允許重寫。
-
方法參數
-
java總是按值傳遞,對于基本類型的參數發生變化后對原始變量毫無影響,對于對象參數傳遞的是對象的句柄(概念上不等于引用傳遞,因為對象變量的值就是句柄地址!),對對象進行的操作將影響外部變量。
此時變量a和b不會發生任何變化,因為a和b在方法內部被初始化為局部變量,對局部變量的修改不會影響到外部變量,但是對象的句柄地址與外部變量的地址一致,修改對象屬性會生效。
總結:
一個方法不能修改一個基本數據類型的參數(即數值型或布爾型)。
一個方法可以改變一個對象參數的狀態 。
一個方法不能讓對象參數引用一個新的對象。
public class a{ public void swap(object a,object b){ object temp = a; a = b; b = temp; } }
?
-
-
finalize
- 可以為任何一個類添加 finalize 方法。
- finalize 方法將在垃圾回收器清除對象之前調用 。
- 在實際應用中,不要依賴于使用finalize 方法回收任何短缺的資源 , 這是因為很難知道這個方法什么時候才能夠調用。
-
包
- 一個類可以使用所屬包中的所有類,其他包中的所有public類
- 可以使用完整的包名+類名訪問,也可通過import先導入包
- 當import的倆個包擁有同一個類名時需要通過完成包名+類名方式訪問。
- 靜態導入 import static java.lang.System . * ,import static java.lang.System.out ;執行system下的靜態方法時無需加前綴。
- 使用package com.xxx.a 聲明當前類所屬包,否則將處于默認包中(default package),將類放到與包名相同的路徑下,com/xxx/a。
- 編譯器在編譯源文件的時候不檢查目錄結構 。 例如 , 假定有一個源文件開頭有下列語句 :package con . myconpany ;即使這個源文件沒有在子目錄 com / mycompany 下 , 也可以進行編譯 。 如果它不依賴于其他包 , 就不會出現編譯錯誤 。 但是 , 最終的程序將無法運行 , 除非先將所有類文件移到正確的位置上 。 如果包與目錄不匹配 , 虛擬機就找不到類。
- 前面已經接觸過訪問修飾符 public 和 private。 標記為 public的部分可以被任意的類使用 ; 標記為 private 的部分只能被定義它們的類使用。 如果沒有指定 public或 private , 這 個 部分 ( 類 、 方法或變量 ) 可以被同一個包中的所有方法訪問。
-
類路徑
- 將JAR文件放在一個目錄中,例如 : /home/user/archives。
- 設置類路徑(classpath)。 類路徑是所有包含類文件的路徑的集合 。/home/user/classdir : . : / home /user/archives/*,其中" : . :"中的“.”為當前路徑。
- javac編譯器總是在當前的目錄中查找文件,但Java虛擬機僅在類路徑中有目錄的時候才查看當前目錄如果沒有設置類路徑,那也并不會產生什么問題,默認的類路徑包含目錄.然而如果 設置了類路徑卻忘記了包含目錄,則程序仍然可以通過編譯,但不能運行。
- java - classpath /home/user/classdir : . : / home/user/archives/* app 在運行時設置class path
繼承
-
基本概念
extends, super.xxx調用父類方法,super(param)調用父類構造函數。
如果子類的構造器沒有顯式地調用超類的構造器,則將自動地調用超類默認( 沒有參數 )的構造器。如果超類沒有不帶參數的構造器 ,并且在子類的構造器中又沒有顯式地調用超類的其他構造器,則Java編譯器將報告錯誤。
判斷是否應該設計為繼承關系,is-a規則,表明子類的每個對象也是父類的對象,如經理也屬于員工。is-a另一種規則是置換法則,表示出現超類的任意地方都可以用子類對象替換。可以將子類的對象賦給超類的變量。
在 Java 中子類數組的引用可以轉換成超類數組的引用 ,而不需要采用強制類型。但不建議這么做,所有數組都要牢記創建它們的元素類型 , 并負責監督僅將類型兼容的引用存儲到數組中。
java中方法的名字和參數列表作為方法的簽名,但返回值不是,如果子類擁有父類同樣簽名的方法將會覆蓋父類的方法,在覆蓋方法時一定要保證返回值的兼容性。允許子類返回值為父類返回值的子類型。
private,static,final方法編譯器可以明確知道調用的是哪個方法,這種調用稱為靜態綁定。否則為動態綁定。
程序運行動態綁定時虛擬機需要從子類到父類逐一查找適用的方法,開銷很大,所以虛擬機會提前為每個類建立一個方法表,虛擬機查詢方法表簽名找到調用方法,但用super.xxx()調用父類方法時會查詢父類的方法表。
如果方法很簡短 、 被頻繁調用且沒有真正地被覆蓋 , 那么即時編譯器就會將這個方法進行內聯處理。 內聯調用 e.getName()將被替換為訪問 e.name 域 。
在Java 中,每個對象變量都屬于一個類型 。類型描述了這個變量所引用的以及能夠引用的對象類型。所以可以得到可引用的所有類。子類可以轉為父類的引用,父類不能轉為子類的引用。使用instanceof操作符可以檢測是否可以被引用轉換。
-
多態
- 存在繼承關系
- 子類要重寫(非重載)父類的方法
- 父類數據類型的引用指向子類對象。
- 那么我們可以根據以上情況總結出多態成員訪問的特點:
成員變量
編譯看左邊(父類),運行看左邊(父類)
成員方法
編譯看左邊(父類),運行看右邊(子類)。動態綁定
靜態方法
編譯看左邊(父類),運行看左邊(父類)。
(靜態和類相關,算不上重寫,所以,訪問還是左邊的)
只有非靜態的成員方法,編譯看左邊,運行看右邊 - 多態后不能使用子類特有的屬性和方法 。
-
抽象類
- 包含抽象方法的類也必須要聲明為抽象。
- 抽象類可以包含成員變量和已經實現的方法。
- 抽象類不能實例化,但可以創建的抽象類的變量,但是只能引用已經實現全部方法的子類。
-
object
- Object.equals(obj1,obj2) 比較兩個對象是否引用同一地址。
- 如果重新定義 equals 方法, 就必須重新定義hashCode 方法, 以便用戶可以將對象插人到散列表中,Equals 與 hashCode 的定義必須一致 : 如果 x.equals (y ) 返回 true , 那么x.hashCode()就必須與 y.hashCode()具有相同的值。
- 整型數組類型 int[]可以被轉換成Object, 但不能轉換成對象數組。
-
arrayList
- arrayList管理著對象引用的一個內部數組。 最終 ,數組的全部空間有可能被用盡 。 這就顯現出數組列表操作魅力 : 如果調用 add 且內部數組已經滿了, 數組列表就將自動地創建一個更大的數組, 并將所有的對象從較小的數組中拷貝到較大的數組中 。如果已經清楚或能夠估計出數組可能存儲的元素數量 , 就可以在填充數組之前調用ensureCapacity 方法 :staff.ensureCapacity(100) ;這個方法調用將分配一個包含 100 個對象的內部數組。 然后調用100 次 add , 而不用重新分配空間。
- 容量為100的arrayList初始化完成后可能不包含任何元素,而size為100的arrayList則包含100個元素。
- staff.size()將返回 staff 數組列表的當前元素數量 , 它等價于數組 a 的 a.length 。
- 當確定arrayList大小后應調用trimToSize方法,多余的空間將會被垃圾回收。·
int actualSize = ...;//動態確定數組大小,但無法解決動態更改數組 Employee[] staff = new Employee[actualSize]; ArrayList<Integer> ids = new ArrayList<>(); //創建arrayList
?
-
可變參數
public void test(int... args){}
允許將一個數組傳遞給可變參數方法的最后一個參數:
System.out.printf ( "%d %s” new Object[] {new Integer(123) ,"widgets"} ) ;
等同于
System.out.printf("%d %s",123,"widgets");
-
反射
- 在運行時分析類的能力 。
- 在運行時查看對象 ,例如 , 編寫一個 toString 方法供所有類使用。
- 實現通用的數組操作代碼 。
- 利用Method 對象 , 這個對象很像中的函數指針。
- 在 java . lang . reflect 包中有三個類 Field 、 Method 和 Constructor 分別用于描述類的域 、 方法和構造器 。 這三個類都有一個叫做 getName 的方法 , 用來返回項目的名稱。 Field 類有一個 getType 方法, 用來返回描述域所屬類型的 Class 對象。 Method和 Constructor 類有能夠報告參數類型的方法, Method 類還有一個可以報告返回類型的方法 。 這三個類還有一個叫做 getModifiers 的方法 , 它將返回一個整型數值, 用不同的位開關描述 public和 static 這樣的修飾符使用狀況。 另外 , 還可以利用 java.lang.refleCt 包中的Modifiei類的靜態方法分析getModifiers返回的整型數值。例如,可以使用 Modifier 類中的 isPublic 、 isPrivate 或 isFinal判斷方法或構造器是否是 public 、 private 或 final 。 我們需要做的全部工作就是調用 Modifier類的相應方法, 并對返回的整型數值進行分析 , 另外 ,還可以利用 Modifier . toString 方法將修飾符打印出來。
-
class類
在Java中,每個class都有一個相應的Class對象。也就是說,當我們編寫一個類,編譯完成后,在生成的.class文件中,就會產生一個Class對象,用于表示這個類的類型信息。
在運行期間,如果我們要產生某個類的對象,JVM會檢查該類型的Class對象是否已被加載。如果沒有被加載,JVM會根據類的名稱找到.class文件并加載它。一旦某個類型的Class對象已被加載到內存,就可以用它來產生該類型的所有對象
obj.getClass()方法將會返回一個 Class 類型的實例 。
運用.class的方式來獲取Class實例對于基本數據類型的封裝類還可以采用.TYPE來獲取相對應的基本數據類型的Class實例.
還可以調用靜態方法 forName 獲得類名對應的 Class 對象。
虛擬機為每個類型管理一個 Class 對象 。 因此 , 可以利用 = =運算符實現兩個類對象比較的操作 。
newInstance方法可以創建一個相同類類型的實例,調用默認沒有參數的構造函數,返回新創建的對象。
Math.class.getMethod ("sqrt", double.class); 獲取sqrt方法
String className = "java.util.Random"; Class cl = Class.forName(className);//獲得class對象 if (e.getClass() == Employee.class) //比較class對象 String s = "java.util.Random" ; Object m = Class.forName(s).newlnstance(); //創建相同類型實例
?
-
設計技巧
- 將公共操作和域放在超類
- 不要使用受保護的域,由于可能被更多的子類繼承從而訪問,破壞封裝性。
- 使用繼承實現 “ is - a ” 關系。
- 除非所有繼承的方法都有意義,否則不要使用繼承。
- 在覆蓋方法時, 不要改變預期的行為。
- 使用多態 , 而非類型信息。
- 不要過多地使用反射
接口
- 基本概念
- 接口中的所有方法自動地屬于 public。因此,在接口中聲明方法時,不必提供關鍵字public.但實現接口的方法必須標為public。
- 在接口中還可以定義常量。double I = 1; 等于 public static final I = 1;
- 提供實例域和方法實現的任務應該由實現接口的那個類來完成。 因此 , 可以將接口看成是沒有實例域的抽象類。
- 接口不能實例化,但是可以聲明接口變量,其值必須為實現了接口的對象引用。
- 可以用instanceof檢查對象是否實現了某個接口。
- 接口也可以被繼承。
內部類
-
基本內部類
- 內部類方法可以訪問該類定義所在的作用域中的數據,包括私有的數據。
- 內部類可以對同一個包中的其他類隱藏起來。
- 當僅僅想定義一個回調函數時不想創建一個文件類時,使用匿名內部類比較便捷。
- 內部類的對象總有一個隱式引用,指向了外部類對象。這個引用在內部類的定義中不可見。
- 內部類的隱式引用對象在內部類中構造函數中創建。
- 只有內部類可以聲明為私有的,常規類只可以具有包可見性,或公有可見性。
- 在外部類作用域之外,可以這樣訪問內部類.OuterClass.InnerClass.
- 內部類中的靜態成員變量必須為final,對于每個外部對象會分別有有一個內部類實例,如果這個成員變量不是final,它肯能就不是唯一的。
- 內部類不能有static 方法。內部類是一種編譯器現象,與虛擬機無關,編譯器會把內部類翻譯成$分隔外部類名與內部類名的常規類文件,而虛擬機對此一無所知. 如: outerClass$InnerClass
- 內部類可以訪問外部類的私有成員變量,是通過在外部類添加靜態方法,靜態方法將外部類對象作為參數,返回私有成員的值。
-
局部內部類
- 局部類不能用public或private訪問說明符聲明,它的作用域被限定在這個局部塊中(一個方法中).
- 局部可以對外部世界完全隱藏起來,其他外部類的其他方法也不能訪問。除了在聲明的局部方法中,沒有任何方法知道局部類的存在。
- 局部類相比其他內部類,不僅能夠訪問外部類,還可以訪問定義局部類方法內的局部變量,不過那些局部變量必須事實上為final,這說明,它們一旦賦值就絕不會改變。局部內部類將方法中的局部變量在局部類中創建成員變量進行備份(這也說明了為什么必須事實上為final),防止包含局部類的方法執行完畢后將局部變量銷毀。
-
匿名局部類
- 假如只創建這個類的一個對象,就不必命名了,這種類被稱為匿名內部類。
- 語法格式:new SuperType(params){ 匿名局部類成員變量和方法 },其中SuperType可以是接口,于是內部類就要實現這個接口,也可以是一個類,于是內部類就要拓展它。
- 由于構造函數的名字必須與類名相同,匿名類沒有類名,所以匿名類不能有構造函數。
-
靜態內部類
- 當使用內部類只是為了把一個類隱藏在另外一個類的內部,并不需要引用外圍類對象,此時可以將內部類聲明為static,以便取消產生的引用。
- 靜態內部類可以有靜態成員變量和方法。
- 只有內部類可以聲明為static,靜態內部類的對象除了沒有對生成它的外圍類對象的引用特權外,與其他的所有內部類完全一樣。如果在內部類中聲明了靜態方法確沒有將類聲明為static,編譯器將會給出警告,沒有可用的隱式外圍類型對象初始化內部類對象。