Java基礎(chǔ)知識總結(jié)(二)

synchronized關(guān)鍵字(一)

一、當(dāng)兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內(nèi)只能有一個線程得到執(zhí)行。另一個線程必須等待當(dāng)前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。

二、然而,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

三、尤其關(guān)鍵的是,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

四、第三個例子同樣適用其它同步代碼塊。也就是說,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結(jié)果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

五、以上規(guī)則對其它對象鎖同樣適用.

package ths;

public class Thread1 implements Runnable {

public void run() {

synchronized(this) {

for (int i = 0; i < 5; i++) {

System.out.println(Thread.currentThread().getName()+"synchronized loop " + i);

}

}

}

}

synchronized關(guān)鍵字(二)

synchronized 關(guān)鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。

1. synchronized 方法:通過在方法聲明中加入 synchronized關(guān)鍵字來聲明 synchronized 方法。如:

public synchronized void accessVal(int newVal);

synchronized 方法控制對類成員變量的訪問:每個類實(shí)例對應(yīng)一把鎖,每個 synchronized 方法都必須獲得調(diào)用該方法的類實(shí)例的鎖方能執(zhí)行,否則所屬線程阻塞,方法一旦執(zhí)行,就獨(dú)占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進(jìn)入可執(zhí)行狀態(tài)。這種機(jī)制確保了同一時刻對于每一個類實(shí)例,其所有聲明為 synchronized 的成員函數(shù)中至多只有一個處于可執(zhí)行狀態(tài)(因?yàn)橹炼嘀挥幸粋€能夠獲得該類實(shí)例對應(yīng)的鎖),從而有效避免了類成員變量的訪問沖突(只要所有可能訪問類成員變量的方法均被聲明為 synchronized)。

在 Java 中,不光是類實(shí)例,每一個類也對應(yīng)一把鎖,這樣我們也可將類的靜態(tài)成員函數(shù)聲明為 synchronized ,以控制其對類的靜態(tài)成員變量的訪問。

synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為synchronized ,由于在線程的整個生命期內(nèi)它一直在運(yùn)行,因此將導(dǎo)致它對本類任何 synchronized 方法的調(diào)用都永遠(yuǎn)不會成功。當(dāng)然我們可以通過將訪問類成員變量的代碼放到專門的方法中,將其聲明為 synchronized ,并在主方法中調(diào)用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。

2. synchronized 塊:通過 synchronized關(guān)鍵字來聲明synchronized 塊。語法如下:

synchronized(syncObject) {

//允許訪問控制的代碼

}

synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實(shí)例或類)的鎖方能執(zhí)行,具體機(jī)制同前所述。由于可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。

對synchronized(this)的一些理解

一、當(dāng)兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內(nèi)只能有一個線程得到執(zhí)行。另一個線程必須等待當(dāng)前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。

二、然而,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

三、尤其關(guān)鍵的是,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

四、第三個例子同樣適用其它同步代碼塊。也就是說,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結(jié)果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

五、以上規(guī)則對其它對象鎖同樣適用。

解決安全問題的原理

只要將操作共享數(shù)據(jù)的語句在某一時段讓一個線程執(zhí)行完,在執(zhí)行過程中,其他線程不能進(jìn)來執(zhí)行就可以解決這個問題。

如何保障共享數(shù)據(jù)的線程安全呢?

java中提供了一個解決方式:就是同步代碼塊。

格式:

synchronized(對象) { //任意對象都可以。這個對象就是共享數(shù)據(jù)。

需要被同步的代碼;

}

---------------------------------------------------------------

同步:★★★★★

好處:解決了線程安全問題。Synchronized

弊端:相對降低性能,因?yàn)榕袛噫i需要消耗資源,產(chǎn)生了死鎖。

同步的第二種表現(xiàn)形式:?//對共享資源的方法定義同步

同步函數(shù):其實(shí)就是將同步關(guān)鍵字定義在函數(shù)上,讓函數(shù)具備了同步性。

同步函數(shù)是用的哪個鎖呢? //synchronized(this)用以定義需要進(jìn)行同步的某一部分代碼塊

通過驗(yàn)證,函數(shù)都有自己所屬的對象this,所以同步函數(shù)所使用的鎖就是this鎖。This.方法名

當(dāng)同步函數(shù)被static修飾時,這時的同步用的是哪個鎖呢?

靜態(tài)函數(shù)在加載時所屬于類,這時有可能還沒有該類產(chǎn)生的對象,但是該類的字節(jié)碼文件加載進(jìn)內(nèi)存就已經(jīng)被封裝成了對象,這個對象就是該類的字節(jié)碼文件對象。

所以靜態(tài)加載時,只有一個對象存在,那么靜態(tài)同步函數(shù)就使用的這個對象。

這個對象就是?類名.class

同步代碼塊和同步函數(shù)的區(qū)別?

同步代碼塊使用的鎖可以是任意對象。

同步函數(shù)使用的鎖是this,靜態(tài)同步函數(shù)的鎖是該類的字節(jié)碼文件對象。

在一個類中只有一個同步的話,可以使用同步函數(shù)。如果有多同步,必須使用同步代碼塊,來確定不同的鎖。所以同步代碼塊相對靈活一些。

-------------------------------------------------------

★考點(diǎn)問題:請寫一個延遲加載的單例模式?寫懶漢式;當(dāng)出現(xiàn)多線程訪問時怎么解決?加同步,解決安全問題;效率高嗎?不高;怎樣解決?通過雙重判斷的形式解決。

//懶漢式:延遲加載方式。

當(dāng)多線程訪問懶漢式時,因?yàn)閼袧h式的方法內(nèi)對共性數(shù)據(jù)進(jìn)行多條語句的操作。所以容易出現(xiàn)線程安全問題。為了解決,加入同步機(jī)制,解決安全問題。但是卻帶來了效率降低。

為了效率問題,通過雙重判斷的形式解決。

class Single{

private static Single s = null;

private Single(){}

public static Single getInstance(){ //鎖是誰?字節(jié)碼文件對象;

if(s == null){

synchronized(Single.class){

if(s == null)

s = new Single();

}

}

return s;

}

}

---------------------------------------------------------

等待喚醒機(jī)制:涉及的方法:

wait:將同步中的線程處于凍結(jié)狀態(tài)。釋放了執(zhí)行權(quán),釋放了資格。同時將線程對象存儲到線程池中。

notify:喚醒線程池中某一個等待線程。

notifyAll:喚醒的是線程池中的所有線程。

注意:

1:這些方法都需要定義在同步中。

2:因?yàn)檫@些方法必須要標(biāo)示所屬的鎖。

你要知道 A鎖上的線程被wait了,那這個線程就相當(dāng)于處于A鎖的線程池中,只能A鎖的notify喚醒。

3:這三個方法都定義在Object類中。為什么操作線程的方法定義在Object類中?

因?yàn)檫@三個方法都需要定義同步內(nèi),并標(biāo)示所屬的同步鎖,既然被鎖調(diào)用,而鎖又可以是任意對象,那么能被任意對象調(diào)用的方法一定定義在Object類中。

wait和sleep區(qū)別:?分析這兩個方法:從執(zhí)行權(quán)和鎖上來分析:

wait:可以指定時間也可以不指定時間。不指定時間,只能由對應(yīng)的notify或者notifyAll來喚醒。

sleep:必須指定時間,時間到自動從凍結(jié)狀態(tài)轉(zhuǎn)成運(yùn)行狀態(tài)(臨時阻塞狀態(tài))。

wait:線程會釋放執(zhí)行權(quán),而且線程會釋放鎖。

sleep:線程會釋放執(zhí)行權(quán),但不是不釋放鎖。

線程的停止:通過stop方法就可以停止線程。但是這個方式過時了。

停止線程:原理就是:讓線程運(yùn)行的代碼結(jié)束,也就是結(jié)束run方法。

怎么結(jié)束run方法?一般run方法里肯定定義循環(huán)。所以只要結(jié)束循環(huán)即可。

第一種方式:定義循環(huán)的結(jié)束標(biāo)記。

第二種方式:如果線程處于了凍結(jié)狀態(tài),是不可能讀到標(biāo)記的,這時就需要通過Thread類中的interrupt方法,將其凍結(jié)狀態(tài)強(qiáng)制清除。讓線程恢復(fù)具備執(zhí)行資格的狀態(tài),讓線程可以讀到標(biāo)記,并結(jié)束。

---------< java.lang.Thread >----------

interrupt():中斷線程。

setPriority(int newPriority):更改線程的優(yōu)先級。

getPriority():返回線程的優(yōu)先級。

toString():返回該線程的字符串表示形式,包括線程名稱、優(yōu)先級和線程組。

Thread.yield():暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程。

setDaemon(true):將該線程標(biāo)記為守護(hù)線程或用戶線程。將該線程標(biāo)記為守護(hù)線程或用戶線程。當(dāng)正在運(yùn)行的線程都是守護(hù)線程時,Java 虛擬機(jī)退出。該方法必須在啟動線程前調(diào)用。

join:臨時加入一個線程的時候可以使用join方法。

當(dāng)A線程執(zhí)行到了B線程的join方式。A線程處于凍結(jié)狀態(tài),釋放了執(zhí)行權(quán),B開始執(zhí)行。A什么時候執(zhí)行呢?只有當(dāng)B線程運(yùn)行結(jié)束后,A才從凍結(jié)狀態(tài)恢復(fù)運(yùn)行狀態(tài)執(zhí)行。

LOCK的出現(xiàn)替代了同步:lock.lock();………lock.unlock();

Lock接口:多線程在JDK1.5版本升級時,推出一個接口Lock接口。

解決線程安全問題使用同步的形式,(同步代碼塊,要么同步函數(shù))其實(shí)最終使用的都是鎖機(jī)制。

到了后期版本,直接將鎖封裝成了對象。線程進(jìn)入同步就是具備了鎖,執(zhí)行完,離開同步,就是釋放了鎖。

在后期對鎖的分析過程中,發(fā)現(xiàn),獲取鎖,或者釋放鎖的動作應(yīng)該是鎖這個事物更清楚。所以將這些動作定義在了鎖當(dāng)中,并把鎖定義成對象。

所以同步是隱示的鎖操作,而Lock對象是顯示的鎖操作,它的出現(xiàn)就替代了同步。

在之前的版本中使用Object類中wait、notify、notifyAll的方式來完成的。那是因?yàn)橥街械逆i是任意對象,所以操作鎖的等待喚醒的方法都定義在Object類中。

而現(xiàn)在鎖是指定對象Lock。所以查找等待喚醒機(jī)制方式需要通過Lock接口來完成。而Lock接口中并沒有直接操作等待喚醒的方法,而是將這些方式又單獨(dú)封裝到了一個對象中。這個對象就是Condition,將Object中的三個方法進(jìn)行單獨(dú)的封裝。并提供了功能一致的方法await()、signal()、signalAll()體現(xiàn)新版本對象的好處。

< java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();

--------------------------------------------------------

class BoundedBuffer {

final Lock lock = new ReentrantLock();

final Condition notFull =?lock.newCondition();

final Condition notEmpty =?lock.newCondition();

final Object[] items = new Object[100];

int putptr, takeptr, count;

public void put(Object x) throws InterruptedException {

lock.lock();

try {

while (count == items.length)

notFull.await();

items[putptr] = x;

if (++putptr == items.length) putptr = 0;

++count;

notEmpty.signal();

}

finally {

lock.unlock();

}

}

public Object take() throws InterruptedException {

lock.lock();

try {

while (count == 0)

notEmpty.await();

Object x = items[takeptr];

if (++takeptr == items.length) takeptr = 0;

--count;

notFull.signal();

return x;

}

finally {

lock.unlock();

}

}

}

集合框架

集合框架:★★★★★,用于存儲數(shù)據(jù)的容器。

對于集合容器,有很多種。因?yàn)槊恳粋€容器的自身特點(diǎn)不同,其實(shí)原理在于每個容器的內(nèi)部數(shù)據(jù)結(jié)構(gòu)不同。

集合容器在不斷向上抽取過程中。出現(xiàn)了集合體系。

在使用一個體系時,原則:參閱頂層內(nèi)容。建立底層對象。

------------------------------------------------------------

--< java.util >-- List接口:

List本身是Collection接口的子接口,具備了Collection的所有方法?,F(xiàn)在學(xué)習(xí)List體系特有的共性方法,查閱方法發(fā)現(xiàn)List的特有方法都有索引,這是該集合最大的特點(diǎn)。

List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重復(fù)。

|--ArrayList:底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,線程不同步,ArrayList替代了Vector,查詢元素的速度非???。

|--LinkedList:底層的數(shù)據(jù)結(jié)構(gòu)是鏈表,線程不同步,增刪元素的速度非???。

|--Vector:底層的數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,線程同步的,Vector無論查詢和增刪都巨慢。

可變長度數(shù)組的原理:

當(dāng)元素超出數(shù)組長度,會產(chǎn)生一個新數(shù)組,將原數(shù)組的數(shù)據(jù)復(fù)制到新數(shù)組中,再將新的元素添加到新數(shù)組中。

ArrayList:是按照原數(shù)組的50%延長。構(gòu)造一個初始容量為 10 的空列表。

Vector:是按照原數(shù)組的100%延長。

------------------------------------------------------------

--< java.util >-- Set接口

數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)的存儲方式;

Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一種,迭代器

|--HashSet:底層數(shù)據(jù)結(jié)構(gòu)是哈希表,線程是不同步的。無序,高效;

HashSet集合保證元素唯一性:通過元素的hashCode方法,和equals方法完成的。

當(dāng)元素的hashCode值相同時,才繼續(xù)判斷元素的equals是否為true。

如果為true,那么視為相同元素,不存。如果為false,那么存儲。

如果hashCode值不同,那么不判斷equals,從而提高對象比較的速度。

|--LinkedHashSet:有序,hashset的子類。

|--TreeSet:對Set集合中的元素的進(jìn)行指定順序的排序。不同步。TreeSet底層的數(shù)據(jù)結(jié)構(gòu)就是二叉樹。

對于ArrayList集合,判斷元素是否存在,或者刪元素底層依據(jù)都是equals方法。

對于HashSet集合,判斷元素是否存在,或者刪除元素,底層依據(jù)的是hashCode方法和equals方法。

------------------------------------------------------------

Map集合:

|--Hashtable:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是線程同步的。不可以存儲null鍵,null值。

|--HashMap:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是線程不同步的??梢源鎯ull鍵,null值。替代了Hashtable.

|--TreeMap:底層是二叉樹結(jié)構(gòu),可以對map集合中的鍵進(jìn)行指定順序的排序。

Map集合存儲和Collection有著很大不同:

Collection一次存一個元素;Map一次存一對元素。

Collection是單列集合;Map是雙列集合。

Map中的存儲的一對元素:一個是鍵,一個是值,鍵與值之間有對應(yīng)(映射)關(guān)系。

特點(diǎn):要保證map集合中鍵的唯一性。

5,想要獲取map中的所有元素:

原理:map中是沒有迭代器的,collection具備迭代器,只要將map集合轉(zhuǎn)成Set集合,可以使用迭代器了。之所以轉(zhuǎn)成set,是因?yàn)閙ap集合具備著鍵的唯一性,其實(shí)set集合就來自于map,set集合底層其實(shí)用的就是map的方法。

把map集合轉(zhuǎn)成set的方法:

Set keySet();

Set entrySet();//取的是鍵和值的映射關(guān)系。

Entry就是Map接口中的內(nèi)部接口;

為什么要定義在map內(nèi)部呢?entry是訪問鍵值關(guān)系的入口,是map的入口,訪問的是map中的鍵值對。

---------------------------------------------------------

取出map集合中所有元素的方式一:keySet()方法。

可以將map集合中的鍵都取出存放到set集合中。對set集合進(jìn)行迭代。迭代完成,再通過get方法對獲取到的鍵進(jìn)行值的獲取。

SetkeySet=map.keySet();Iteratorit=keySet.iterator();while(it.hasNext()){Objectkey=it.next();Objectvalue=map.get(key);System.out.println(key+":"+value);}

--------------------------------------------------------

取出map集合中所有元素的方式二:entrySet()方法。

SetentrySet=map.entrySet();Iteratorit=entrySet.iterator();while(it.hasNext()){Map.Entryme=(Map.Entry)it.next();System.out.println(me.getKey()+"::::"+me.getValue());}

--------------------------------------------------------

將非同步集合轉(zhuǎn)成同步集合的方法:Collections中的?XXX synchronizedXXX(XXX);

List synchronizedList(list);

Map synchronizedMap(map);

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {

return new SynchronizedMap<K,V>(m);

}

原理:定義一個類,將集合所有的方法加同一把鎖后返回。

List list = Collections.synchronizedList(new ArrayList());

Map<String,String> synmap = Collections.synchronizedMap(map);

Collection 和 Collections的區(qū)別:

Collections是個java.util下的類,是針對集合類的一個工具類,提供一系列靜態(tài)方法,實(shí)現(xiàn)對集合的查找、排序、替換、線程安全化(將非同步的集合轉(zhuǎn)換成同步的)等操作。

Collection是個java.util下的接口,它是各種集合結(jié)構(gòu)的父接口,繼承于它的接口主要有Set和List,提供了關(guān)于集合的一些操作,如插入、刪除、判斷一個元素是否其成員、遍歷等。

-------------------------------------------------------

自動拆裝箱:java中數(shù)據(jù)類型分為兩種 : 基本數(shù)據(jù)類型 引用數(shù)據(jù)類型(對象)

在 java程序中所有的數(shù)據(jù)都需要當(dāng)做對象來處理,針對8種基本數(shù)據(jù)類型提供了包裝類,如下:

int-->Integerbyte-->Byteshort-->Shortlong-->Longchar-->Characterdouble-->Doublefloat-->Floatboolean-->Boolean

jdk5以前基本數(shù)據(jù)類型和包裝類之間需要互轉(zhuǎn):

基本---引用 Integer x = new Integer(x);

引用---基本 int num = x.intValue();

1)、Integer x = 1; x = x + 1; 經(jīng)歷了什么過程?裝箱 à 拆箱 à 裝箱;

2)、為了優(yōu)化,虛擬機(jī)為包裝類提供了緩沖池,Integer池的大小 -128~127 一個字節(jié)的大小

3)、String池:Java為了優(yōu)化字符串操作 提供了一個緩沖池;

----------------------------------------------------------

泛型:jdk1.5版本以后出現(xiàn)的一個安全機(jī)制。表現(xiàn)格式:< >

好處:

1:將運(yùn)行時期的問題ClassCastException問題轉(zhuǎn)換成了編譯失敗,體現(xiàn)在編譯時期,程序員就可以解決問題。

2:避免了強(qiáng)制轉(zhuǎn)換的麻煩。

泛型中的通配符:可以解決當(dāng)具體類型不確定的時候,這個通配符就是???;當(dāng)操作類型時,不需要使用類型的具體功能時,只使用Object類中的功能。那么可以用 ? 通配符來表未知類型。

-------------------------------------------------------------------------------------------------------------------------------

反射技術(shù)

反射技術(shù):其實(shí)就是動態(tài)加載一個指定的類,并獲取該類中的所有的內(nèi)容。并將字節(jié)碼文件中的內(nèi)容都封裝成對象,這樣便于操作這些成員。簡單說:反射技術(shù)可以對一個類進(jìn)行解剖。

反射的好處:大大的增強(qiáng)了程序的擴(kuò)展性。

反射的基本步驟:

1、獲得Class對象,就是獲取到指定的名稱的字節(jié)碼文件對象。

2、實(shí)例化對象,獲得類的屬性、方法或構(gòu)造函數(shù)。

3、訪問屬性、調(diào)用方法、調(diào)用構(gòu)造函數(shù)創(chuàng)建對象。

獲取這個Class對象,有三種方式:

1:通過每個對象都具備的方法getClass來獲取。弊端:必須要創(chuàng)建該類對象,才可以調(diào)用getClass方法。

2:每一個數(shù)據(jù)類型(基本數(shù)據(jù)類型和引用數(shù)據(jù)類型)都有一個靜態(tài)的屬性class。弊端:必須要先明確該類。

前兩種方式不利于程序的擴(kuò)展,因?yàn)槎夹枰诔绦蚴褂镁唧w的類來完成。

3:使用的Class類中的方法,靜態(tài)的forName方法。

指定什么類名,就獲取什么類字節(jié)碼文件對象,這種方式的擴(kuò)展性最強(qiáng),只要將類名的字符串傳入即可。

// 1. 根據(jù)給定的類名來獲得 用于類加載

String classname = "cn.itcast.reflect.Person";// 來自配置文件

Class clazz = Class.forName(classname);// 此對象代表Person.class

// 2. 如果拿到了對象,不知道是什么類型 用于獲得對象的類型

Object obj = new Person();

Class clazz1 = obj.getClass();// 獲得對象具體的類型

// 3. 如果是明確地獲得某個類的Class對象 主要用于傳參

Class clazz2 = Person.class;

反射的用法

1)、需要獲得java類的各個組成部分,首先需要獲得類的Class對象,獲得Class對象的三種方式:

Class.forName(classname)?用于做類加載

obj.getClass() 用于獲得對象的類型

類名.class 用于獲得指定的類型,傳參用

2)、反射類的成員方法:

Class clazz = Person.class;

Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});

method.invoke();

3)、反射類的構(gòu)造函數(shù):

Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})

con.newInstance(params...)

4)、反射類的屬性:

Field field = clazz.getField(fieldName);

field.setAccessible(true);

field.setObject(value);

獲取了字節(jié)碼文件對象后,最終都需要創(chuàng)建指定類的對象:

創(chuàng)建對象的兩種方式(其實(shí)就是對象在進(jìn)行實(shí)例化時的初始化方式):

1,調(diào)用空參數(shù)的構(gòu)造函數(shù):使用了Class類中的newInstance()方法。

2,調(diào)用帶參數(shù)的構(gòu)造函數(shù):先要獲取指定參數(shù)列表的構(gòu)造函數(shù)對象,然后通過該構(gòu)造函數(shù)的對象的newInstance(實(shí)際參數(shù))?進(jìn)行對象的初始化。

綜上所述,第二種方式,必須要先明確具體的構(gòu)造函數(shù)的參數(shù)類型,不便于擴(kuò)展。所以一般情況下,被反射的類,內(nèi)部通常都會提供一個公有的空參數(shù)的構(gòu)造函數(shù)。

------------------------------------------------------

// 如何生成獲取到字節(jié)碼文件對象的實(shí)例對象。

Class clazz = Class.forName("cn.itcast.bean.Person");//類加載

// 直接獲得指定的類型

clazz = Person.class;

// 根據(jù)對象獲得類型

Object obj =?new?Person("zhangsan", 19);

clazz = obj.getClass();

Object obj = clazz.newInstance();//該實(shí)例化對象的方法調(diào)用就是指定類中的空參數(shù)構(gòu)造函數(shù),給創(chuàng)建對象進(jìn)行初始化。當(dāng)指定類中沒有空參數(shù)構(gòu)造函數(shù)時,該如何創(chuàng)建該類對象呢?請看method_2();

publicstaticvoidmethod_2()throwsException{Classclazz=Class.forName("cn.itcast.bean.Person");

//既然類中沒有空參數(shù)的構(gòu)造函數(shù),那么只有獲取指定參數(shù)的構(gòu)造函數(shù),用該函數(shù)來進(jìn)行實(shí)例化。

//獲取一個帶參數(shù)的構(gòu)造器。

Constructorconstructor=clazz.getConstructor(String.class,int.class);

//想要對對象進(jìn)行初始化,使用構(gòu)造器的方法newInstance();

Objectobj=constructor.newInstance("zhagnsan",30);

//獲取所有構(gòu)造器。

Constructor[]constructors=clazz.getConstructors();//只包含公共的constructors=clazz.getDeclaredConstructors();//包含私有的for(Constructorcon:constructors){System.out.println(con);}}

------------------------------------------------------

反射指定類中的方法:

//獲取類中所有的方法。

publicstaticvoidmethod_1()throwsException{Classclazz=Class.forName("cn.itcast.bean.Person");Method[]methods=clazz.getMethods();//獲取的是該類中的公有方法和父類中的公有方法。methods=clazz.getDeclaredMethods();//獲取本類中的方法,包含私有方法。for(Methodmethod:methods){System.out.println(method);}}

//獲取指定方法;

publicstaticvoidmethod_2()throwsException{Classclazz=Class.forName("cn.itcast.bean.Person");

//獲取指定名稱的方法。

Methodmethod=clazz.getMethod("show",int.class,String.class);

//想要運(yùn)行指定方法,當(dāng)然是方法對象最清楚,為了讓方法運(yùn)行,調(diào)用方法對象的invoke方法即可,但是方法運(yùn)行必須要明確所屬的對象和具體的實(shí)際參數(shù)。

Objectobj=clazz.newInstance();method.invoke(obj,39,"hehehe");//執(zhí)行一個方法}

//想要運(yùn)行私有方法。

publicstaticvoidmethod_3()throwsException{Classclazz=Class.forName("cn.itcast.bean.Person");

//想要獲取私有方法。必須用getDeclearMethod();

Methodmethod=clazz.getDeclaredMethod("method",null);

// 私有方法不能直接訪問,因?yàn)闄?quán)限不夠。非要訪問,可以通過暴力的方式。

method.setAccessible(true);//一般很少用,因?yàn)樗接芯褪请[藏起來,所以盡量不要訪問。

}

//反射靜態(tài)方法。

publicstaticvoidmethod_4()throwsException{Classclazz=Class.forName("cn.itcast.bean.Person");Methodmethod=clazz.getMethod("function",null);method.invoke(null,null);}

全套java基礎(chǔ)教程:java全套視頻教程基礎(chǔ)java?

來源:知乎

原文:https://zhuanlan.zhihu.com/p/62938699

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容