單例模式猩谊,類加載祭刚,反射墙牌,枚舉

單例模式

讓一個類在java內存中只創(chuàng)建一個對象

//懶漢式 飽漢式

public class MyTool {

private static MyTool myTool = null;

//私有話構造方法, 讓使用者無法new對象

//這樣使用者就沒有辦法創(chuàng)建多個對象了

private MyTool(){}

//提供一個靜態(tài)方法, 使用者調用這個方法可以獲取對象

//這樣,我們就可以控制創(chuàng)建的對象了

public static MyTool getInstance(){

//第一次訪問時,發(fā)現(xiàn)變量中沒有記錄對象, 就新建對象

//如果已經創(chuàng)建過對象,就直接返回

if(myTool==null){

myTool = new MyTool();

}

return myTool;

}

}

}

2.餓漢式

public class MyTool2 {

private static MyTool2 myTool = new MyTool2();

//私有話構造方法, 讓使用者無法new對象

//這樣使用者就沒有辦法創(chuàng)建多個對象了

private MyTool2(){}

//提供一個靜態(tài)方法, 使用者調用這個方法可以獲取對象

//這樣,我們就可以控制創(chuàng)建的對象了

public static MyTool2 getInstance(){

return myTool;

}

public String encoding(String str){

return "";

}

}

3.實現(xiàn)步驟

1.私有化構造方法

2.自己創(chuàng)建對象并記錄

3保證這個變量的安全

4.總結

優(yōu)點:節(jié)省靜態(tài)方法區(qū)的內存喜滨,使用時效高

缺點:相對于靜態(tài)來說虽风,效率還是要低一些

枚舉

枚舉是一個概念寄月,列舉的意思,將所有的情況都列舉出來那么取值的時候只能是這幾種情況内舟,不能是別的初橘。

在Java中枚舉可以理解為有限制的多例,在當前類中定義多個實例供別人使用耕蝉。

方法的枚舉

public class Week {

public static final Week MON = new Week("星期一");

public static final Week TUE = new Week("星期二");

public static final Week WED = new Week("星期三");

public static final Week THU = new Week("星期四");

public static final Week FRI = new Week("星期五");

public static final Week SAT = new Week("星期六");

public static final Week SUN = new Week("星期日");

public String name;

//私有化構造

private Week(String name){

this.name = name;

}

//提供getter方法,便于別人使用

public String getName() {

return name;

}

//提供特殊方法

public? void show(){

System.out.println("今天是"+name);

}

}

注意事項

枚舉多用于將一組信息裝載到一個對象中

二. enum關鍵字的枚舉(jdk1.5)


1.定義

jdk1.5推出了enum關鍵字來幫助我們簡化格式

省略了static final 關鍵字和創(chuàng)建對象

enum關鍵字還能對格式進行檢查

2.演示

public enum Week2 {

//定義變量,指向對象

MON("星期一") ,TUE("星期二") ,WED("星期三") ,THU("星期四") ,FRI("星期五") ,SAT("星期六") ,SUN("星期日") ;

String name ;

//私有化構造

private Week2(String name){

this.name = name;

}

public String getName() {

return name;

}

}

3.注意事項

定義枚舉需要用關鍵字enum

所有枚舉都是enum的子類

枚舉類的第一行上必須是枚舉項垒在,最后一個枚舉項后的分號是可以省略的场躯,但是如果枚舉類

有其他的東西旅挤,這個分號就不能省略。建議不要省略

枚舉可以有構造器签舞,但必須是private的柒瓣,它默認的也是private

枚舉類也可以有抽象方法,但是枚舉類必須重寫該方法

switch語句可以使用枚舉搂鲫。

案例


public static void main(String[] args) {

Week2 week2 = Week2.MON;

switch (week2) {

case FRI:

System.out.println("好高興哦");

break;

case MON:

System.out.println("過了星期三,越過越心寬");

break;

default:

System.out.println("沒有了");

break;

}

}

常用方法

int ordinal() 獲取枚舉項的序號

int compareTo(E o)? 比較兩個枚舉項

String name() 獲取枚舉枚舉項的名稱

String toString() 獲取枚舉項的字符串表現(xiàn)形式

<T> T valueOf(Class<T> type,String name) 使用字節(jié)碼和名稱獲取枚舉項

values()

此方法雖然在JDK文檔中查找不到默穴,但每個枚舉類都具有該方法褪秀,它遍歷枚舉類的所有枚舉值非常方便

三. 類加載


定義

當程序要使用某個類是,如果該類還未被加載到內存中仑氛,則系統(tǒng)會通過加載闸英,連接,初始化三步

來實現(xiàn)對這個類就行初始化出吹。

加載

就是指將.class文件讀入內存辙喂,并為之創(chuàng)建一個class對象巍耗。任何類被使用時

系統(tǒng)都會創(chuàng)建一個class對象

連接

驗證是否正確的內部結構,并和其他類協(xié)調一致

準備 負責未類的靜態(tài)成員分配內存灸蟆,并設置默認初始化值

解析 將類的二進制數(shù)據(jù)中的符號引用替換為直接引用

初始化 就是我們以前講過的初始化步驟

加載的時機(在類真正被使用時)

創(chuàng)建類的實例

訪問類的靜態(tài)變量亲族,或者為靜態(tài)變量賦值

調用類的靜態(tài)方法

使用反射方法來強制創(chuàng)建某個類活借口對應的java.lang.class

加載某個類的子類

直接使用java.exe命令來運行某個主類

四. 類加載器的概述和分類

定義

負責將.class文件加載到內存中霎迫,并為之生成對應的Class對象。雖然我們不需要關心類加載機制杏慰,但是了解這個機制我們就能更好的理解程序的運行

類加載器的分類

Bootstrap ClassLoader 根類加載器

Extension ClassLoader 擴展類加載器

Sysetm ClassLoader 系統(tǒng)類加載器

AppClassLoader 應用類加載器

類加載器的作用

BootstrapClassLoader 根類加載器

也被稱為引導類加載器炼鞠,負責Java核心類的加載

比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中

ExtensionClassLoader 擴展類加載器

負責JRE的擴展目錄中jar包的加載朝扼。

在JDK中JRE的lib目錄下ext目錄

SysetmClassLoader 系統(tǒng)類加載器

負責在JVM啟動時加載來自java命令的class文件霎肯,以及classpath環(huán)境變量所指定的jar包和類路徑

AppClassLoader 加載其他類

負載一些非核心類和程序猿自己寫的類

演示

publicstaticvoidmain(String[]args) {

? ? //獲取TestDemo類的類加載器

? ? System.out.println(TestDemo.class.getClassLoader());


}

五. 自定義類加載器

雙親委派模型

當前類加載器從自己已經加載的類中查詢是否此類已經加載,如果已經加載則直接返回原來已經加載的類驮俗。

如果沒有找到允跑,就去委托父類加載器去加載(如代碼c = parent.loadClass(name, false)所示)。父類加載器也會采用同樣的策略索烹,查看自己已經加載過的類中是否包含這個類弱睦,有就返回,沒有就委托父類的父類去加載垒拢,一直到根類加載器焦读。因為如果父加載器為空了矗晃,就代表使用根類類加載器作為父加載器去加載

如果根類類加載器加載失敗(例如在$JAVA_HOME/jre/lib里未查找到該class)仓技,會使用拓展類加載器來嘗試加載俗他,繼續(xù)失敗則會使用AppClassLoader來加載,繼續(xù)失敗則會拋出一個異常ClassNotFoundException地沮,然后再調用當前加載器的findClass()方法進行加載

好處

主要是為了安全性羡亩,避免用戶自己編寫的類動態(tài)替換 Java的一些核心類畏铆,比如 String。

同時也避免了類的重復加載辞居,因為 JVM中區(qū)分不同類,不僅僅是根據(jù)類名鸠删,相同的 class文件被不同的 ClassLoader加載就是不同的兩個類

案例演示

publicclassMyClassLoaderextendsClassLoader{

? ? privateStringpath;

? ? publicMyClassLoader(Stringpath) {

? ? ? ? super();

? ? ? ? this.path=path;

? ? }

? ? @Override

? ? protectedClass<?>findClass(Stringname)throwsClassNotFoundException{

? ? ? ? //讀取本地文件

? ? ? ? byte[]bs=getBytes(path);

? ? ? ? //將字節(jié)數(shù)組裝載成Class對象

? ? ? ? Class<?>clazz=this.defineClass(name,bs,0,bs.length);

? ? ? ? returnclazz;

? ? }


? ? privatebyte[]getBytes(Stringpath){

? ? ? ? try(

? ? ? ? ? ? FileInputStreamfis=newFileInputStream(path);

? ? ? ? ? ? ByteArrayOutputStreambos=newByteArrayOutputStream();

? ? ? ? ) {

? ? ? ? ? ? byte[]bs=newbyte[1024];

? ? ? ? ? ? intlen;

? ? ? ? ? ? while((len=fis.read(bs))!=-1){

? ? ? ? ? ? ? ? bos.write(bs,0,len);

? ? ? ? ? ? }

? ? ? ? ? ? returnbos.toByteArray();

? ? ? ? }catch(Exceptione) {


? ? ? ? }

? ? ? ? returnnull;

? ? }

}

publicstaticvoidmain(String[]args)throwsException{

? ? MyClassLoaderclassLoader=newMyClassLoader("D:\\Student.class");

? ? Class<?>clazz=classLoader.findClass("com.qianfeng.Student");

? ? //Class<?> class1 = Class.forName("com.qianfeng.Student", true, classLoader);


? ? Objectobj=clazz.newInstance();

? ? System.out.println(obj.getClass().getClassLoader());

}

六. 反射

定義

java反射機制是在運行狀態(tài)中乾蛤,對于任意一個類捅僵,都能知道這個類的所有屬性和方法

對于任意一個對象眨层,都能夠調用它的任意一個方法和屬性

這種動態(tài)獲取的信息以及東臺調用對象的方法的功能稱為語言的反射機制

要想解剖一個類趴樱,必須先要獲取該類的字節(jié)碼文件對象

而解剖使用的就是Class類中的方法,所以先要獲取每一個字節(jié)碼文件對應的

Class類型的對象

說白了就是獲得一個類的骨架

獲取字節(jié)碼的三種方式

對象.getClass

類名.class

Class類中靜態(tài)方法for Name(“類名”)

七. 反射獲取構造函數(shù)

定義

Class類的newInstance()方法是使用該類無參的構造函數(shù)創(chuàng)建對象

如果一個類沒有無參的構造函數(shù), 就不能這樣創(chuàng)建了,可以調用Class類的getConstructor(String.class,int.class)方法獲取一個指定的構造函數(shù)然后再調用Constructor類的newInstance("張三",20)方法創(chuàng)建對象

演示

publicstaticvoidmain(String[]args)throwsException{

? ? Class<?>clazz=Class.forName("com.qianfeng.Student");

? ? Studentobject=(Student)clazz.newInstance();

? ? object.method();


}

榨汁機案例

分別有水果(Fruit)蘋果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)

根據(jù)客戶的需求, 隨時更換果汁

interfaceFruit{

? ? publicvoidsqueeze();

}

?

classAppleimplementsFruit{

? ? publicvoidsqueeze() {

? ? ? ? System.out.println("榨出一杯蘋果汁兒");

? ? }

}

?

classOrangeimplementsFruit{

? ? publicvoidsqueeze() {

? ? ? ? System.out.println("榨出一杯桔子汁兒");

? ? }

}

?

classJuicer{

? ? publicvoidrun(Fruitf) {

? ? ? ? f.squeeze();

? ? }

?

}

publicstaticvoidmain(String[]args)throwsException{


? ? //從本地讀取配置文件

? ? BufferedReaderbr=newBufferedReader(newFileReader("config.txt"));

//創(chuàng)建輸入流對象,關聯(lián)配置文件?

? ? Class<?>clazz=Class.forName(br.readLine());? //讀取配置文件一行內容,獲取該類的字節(jié)碼對象

? ? Fruitf=(Fruit)clazz.newInstance();? ? ? //通過字節(jié)碼對象創(chuàng)建實例對象

? ? Juicerj=newJuicer();

? ? j.run(f);

}

八. 反射獲取成員變量

定義

Class.getField(String)方法可以獲取類中的指定字段(可見的)

如果是私有的可以用getDeclaedField("name")方法獲取

通過get(obj) 和set(obj, "李四")方法可以獲取和設置指定對象上該字段的值, obj指的是這個類的對象

如果是私有的需要先調用setAccessible(true)設置訪問權限放開

演示

publicstaticvoidmain(String[]args)throwsException{

? ? Studentstudent=newStudent();

? ? Class<?>clazz=Class.forName("com.qianfeng.Student");

? //獲取共有的屬性

? ? Fieldfield=clazz.getField("name");

? //獲取所有的屬性

? ? Fieldfield2=clazz.getDeclaredField("name");

? ? //取消語言檢查

? ? field2.setAccessible(true);

? ? //給一個對象的屬性設置值

? ? field2.set(student,"333");

? ? //獲取這個對象的屬性的值

? ? Stringstr=(String)field2.get(student);

? ? System.out.println(str);


}

測試題

需求: 寫一個方法, 通過此方法可以給任意對象的任意屬性設置值

九. 反射獲取成員方法

定義

Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以獲取類中的指定方法

調用invoke(Object, Object...)可以調用對象的這個方法

演示

publicstaticvoidmain(String[]args)throwsException{

? ? Studentstudent=newStudent();

? ? Class<?>clazz=Class.forName("com.qianfeng.Student");

? ? Methodmethod=clazz.getMethod("method");

? ? method.invoke(student);

? ? //獲取私有方法

? ? Methodmethod2=clazz.getDeclaredMethod("method2");

? ? //取消語言檢查

? ? method2.setAccessible(true);

? ? //調用對象的方法

? ? method2.invoke(student);


}

測試題

需求: 往一個ArrayList<Integer> 的對象中添加String類型的值

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末疏虫,一起剝皮案震驚了整個濱河市啤呼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌翅敌,老刑警劉巖惕蹄,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卖陵,死亡現(xiàn)場離奇詭異,居然都是意外死亡液肌,警方通過查閱死者的電腦和手機鸥滨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來老速,“玉大人,你說我怎么就攤上這事额湘∨越ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵毯焕,是天一觀的道長纳猫。 經常有香客問我竹捉,道長,這世上最難降的妖魔是什么侵续? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任询兴,我火速辦了婚禮起趾,結果婚禮上,老公的妹妹穿的比我還像新娘眶根。我一直安慰自己边琉,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布族扰。 她就那樣靜靜地躺著渔呵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扩氢。 梳的紋絲不亂的頭發(fā)上录豺,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音媒抠,去河邊找鬼兢哭。 笑死夫嗓,一個胖子當著我的面吹牛舍咖,可吹牛的內容都是我干的。 我是一名探鬼主播排霉,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼攻柠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了冒滩?” 一聲冷哼從身側響起浪谴,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤苟耻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胁艰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡醋虏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年颈嚼,在試婚紗的時候發(fā)現(xiàn)自己被綠了饭寺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖员凝,靈堂內的尸體忽然破棺而出健霹,到底是詐尸還是另有隱情,我是刑警寧澤糖埋,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布瞳别,位于F島的核電站,受9級特大地震影響祟敛,放射性物質發(fā)生泄漏馆铁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一畔裕、第九天 我趴在偏房一處隱蔽的房頂上張望乖订。 院中可真熱鬧,春花似錦甜无、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寨蹋。三九已至松蒜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間已旧,已是汗流浹背秸苗。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留运褪,地道東北人惊楼。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像秸讹,于是被迫代替她去往敵國和親檀咙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353