java的四種引用
A. java內部類的修飾符有哪些
一、內部類可以為四種:
⒈ 靜態內部類
⒉ 成員內部類
⒊ 局部內部類
⒋
匿名內部類幾種內部類的共性:
A、內部類仍然是一個獨立的類,在編譯之後會內部類會被編譯成獨立的.class文件,但是前面冠以外部類的類命和$符號。
B、內部類不能用普通的方式訪問。內部類是外部類的一個成員,因此內部類可以自由地訪問外部類的成員變數,無論是否是private的。
1、靜態嵌套類:從技術上講,靜態嵌套類不屬於內部類。因為內部類與外部類共享一種特殊關系,更確切地說是對實例的共享關系。而靜態嵌套類則沒有上述關系。它只是位置在另一個類的內部,因此也被稱為頂級嵌套類。靜態的含義是該內部類可以像其他靜態成員一樣,沒有外部類對象時,也能夠訪問它。靜態嵌套類不能訪問外部類的成員和方法。 class Outer{ static class Inner{} } class Test { public static void main(String[] args){ Outer.Inner n = new Outer.Inner(); } }
2、成員內部類:形式如下
class Outer { class Inner{} }
編譯上述代碼會產生兩個文件:Outer.class和Outer$Inner.class。成員內部類內不允許有任何靜態聲明!下面代碼不能通過編譯。
class Inner{ static int a = 10;
}能夠訪問成員內部類的唯一途徑就是通過外部類的對象!
A、從外部類的非靜態方法中實例化內部類對象。 class Outer { private
int i = 10; public void makeInner(){ Inner in = new Inner();
in.seeOuter(); } class Inner{ public void seeOuter(){
System.out.print(i); } }
}表面上,我們並沒有創建外部類的對象就實例化了內部類對象,和上面的話矛盾。事實上,如果不創建外部類對象也就不可能調用makeInner()方法,所以到頭來還是要創建外部類對象的。可能試圖把makeInner()方法修飾為靜態方法,即static
public void
makeInner()。這樣不創建外部類就可以實例化外部類了!但是在一個靜態方法里能訪問非靜態成員和方法嗎?顯然不能。它沒有this引用。沒能跳出那條規則!但是如果在這個靜態方法中實例化一個外部類對象,再用這個對象實例化外部類完全可以!也就是下一條的內容。
B、從外部類的靜態方法中實例化內部類對象。
class Outer { private int i = 10; class Inner{ public void seeOuter(){
System.out.print(i);
} } public static void main(String[] args) { Outer out = new Outer();
Outer.Inner in = out.new Inner(); //Outer.Inner in = new Outer().new
Inner(); in.seeOuter(); }
}被注釋掉的那行是它上面兩行的合並形式,一條簡潔的語句。對比一下:在外部類的非靜態方法中實例化內部類對象是普通的new方式:Inner in =
new Inner();在外部類的靜態方法中實例化內部類對象,必須先創建外部類對象:Outer.Inner
in = new Outer().new
Inner();
C、內部類的this引用。普通的類可以用this引用當前的對象,內部類也是如此。但是假若內部類想引用外部類當前的對象呢?用「外部類名」.this;的形式,如下例的Outer.this。
class Outer { class Inner{ public void seeOuter(){
System.out.println(this); System.out.println(Outer.this); } }
}
D、成員內部類的修飾符。對於普通的類,可用的修飾符有final、abstract、strictfp、public和默認的包訪問。但是成員內部類更像一個成員變數和方法。可用的修飾符有:final、abstract、public、private、protected、strictfp和static。一旦用static修飾內部類,它就變成靜態內部類了。
3、方法內部類:顧名思義,把類放在方法內。
class Outer { public void doSomething(){ class Inner{ public void
seeOuter(){ } } }
}
A、方法內部類只能在定義該內部類的方法內實例化,不可以在此方法外對其實例化。
B、方法內部類對象不能使用該內部類所在方法的非final局部變數。因為方法的局部變數位於棧上,只存在於該方法的生命期內。當一個方法結束,其棧結構被刪除,局部變數成為歷史。但是該方法結束之後,在方法內創建的內部類對象可能仍然存在於堆中!例如,如果對它的引用被傳遞到其他某些代碼,並存儲在一個成員變數內。正因為不能保證局部變數的存活期和方法內部類對象的一樣長,所以內部類對象不能使用它們。下面是完整的例子:
class Outer { public void doSomething(){ final int a =10; class Inner{
public void seeOuter(){ System.out.println(a); } } Inner in = new
Inner(); in.seeOuter(); } public static void main(String[] args) { Outer
out = new Outer(); out.doSomething(); }
}
C、方法內部類的修飾符。與成員內部類不同,方法內部類更像一個局部變數。可以用於修飾方法內部類的只有final和abstract。
D、靜態方法內的方法內部類。靜態方法是沒有this引用的,因此在靜態方法內的內部類遭受同樣的待遇,即:只能訪問外部類的靜態成員。
4、匿名內部類:顧名思義,沒有名字的內部類。表面上看起來似乎有名字,實際那不是名字。
A、繼承式的匿名內部類。
class Car { public void drive(){ System.out.println("Driving a car!"); }
} class Test{ public static void main(String[] args) { Car car = new
Car(){ public void drive(){ System.out.println("Driving another car!"); }
}; car.drive(); } }結果輸出了:Driving another
car!
Car引用變數不是引用Car對象,而是Car匿名子類的對象。建立匿名內部類的關鍵點是重寫父類的一個或多個方法。再強調一下,是重寫父類的方法,而不是創建新的方法。因為用父類的引用不可能調用父類本身沒有的方法!創建新的方法是多餘的。簡言之,參考多態。B、介面式的匿名內部類。
interface Vehicle { public void drive(); } class Test{ public static
void main(String[] args) { Vehicle v = new Vehicle(){
public void drive(){ System.out.println("Driving a car!"); } };
v.drive(); }
}上面的代碼很怪,好像是在實例化一個介面。事實並非如此,介面式的匿名內部類是實現了一個介面的匿名類。而且只能實現一個介面。
C、參數式的匿名內部類。class
Bar{ void doStuff(Foo f){}}interface Foo{ void foo();}class Test{
static void go(){ Bar b = new Bar();
b.doStuff(new Foo(){ public void foo(){ System.out.println("foofy"); }
});
}}
二、許可權修飾符:public、protected、default、private。
修飾符:abstract、static、final。
public 使用對象:最廣,類、介面、變數、方法。
protected使用對象:變數、方法 注意:不能修飾類(外部類)。
default 使用對象:類、介面、變數、方法。(即預設,什麼也不寫)。
private 使用對象:變數、方法 注意:不能修飾類(外部類)。
abstract使用對象:類、介面、方法。
static 使用對象:類、變數、方法、初始化函數(注意:修飾類時只能修飾 內部類 )。
final 使用對象:類、變數、方法。
transient:告訴編譯器,在類對象序列化的時候,此變數不需要持久保存
volatile:指出可能有多個線程修改此變數,要求編譯器優化以保證對此變數的修改能夠被正確的處理。
native:用該修飾符定義的方法在類中沒有實現,而大多數情況下該方法的實現是用C、C++編寫的。
synchronized:修飾方法,多線程的支持。
B. JAVA的基本數據類型和引用數據類型的區別
一、作用的不同
1、引用類型一般都是通過new關鍵字創建對象,然後把這個對象賦予給相應的變數,最常用的引用類型是String類型,它也比較特殊,可以直接通過關鍵字new來創建對象,也可以通過字元串直接賦值,比如:
Strings=newString("abc");
Strings="abc";
2、基本類型就是直接賦頃扒值就可以了,比如:
inta=123;
floatb=123.0;
boolean=true;
二、參數方面傳遞的不同
引用類型是引用傳遞
基本類型是值傳遞
三、比較方面的不同
引用類型比較的是引用地址(沒有重寫equals方法)
基本類型比較的是值
五、類雀畝昌型的不同
1、引用類型分為四種
強引用(StrongReference)
軟引用(SoftRefernce)
弱引用(WeakReference)
虛引用(PhantomReference)
強引用-StrongReference
2、八種基本類型
整型byte8位
整型耐岩short16位
整型int32位
整型long64位
浮點型float32位
浮點型double64位
字元型char16位
布爾型boolean位數不確定
C. java中的虛引用,有什麼作用
從JDK1.2版本開始,把對象的引用分為四種級別,從而使程序能更加靈活的控制對象的生命周期。這四種級別由高到低依次為:強引用、軟引用、弱引用和虛引用。
強引用
如果一個對象具有強引用,那就類似於必不可少的生活用品,垃圾回收器絕不會回收它。當內存空 間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題。
軟引用(SoftReference)
如果一個對象只具有軟引用,那就類似於可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。
弱引用(WeakReference)
如果一個對象只具有弱引用,那就類似於可有可物的生活用品。弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它 所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先順序很低的線程, 因此不一定會很快發現那些只具有弱引用的對象。
虛引用(PhantomReference)
"虛引用"顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。虛引用主要用來跟蹤對象被垃圾回收的活動。
虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃 圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。程序可以通過判斷引用隊列中是 否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序如果發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動。
建立虛引用之後通過get方法返回結果始終為null,通過源代碼你會發現,虛引用通向會把引用的對象寫進referent,只是get方法返回結果為null.先看一下和gc交互的過程在說一下他的作用.
D. java四種引用,強軟弱虛 有大神在嗎
Java中四種引用的特點:
強引用(StrongReference)
當我們使用 new 這個關鍵字創建對象時創建出來的對象就是強引用(new出來對象為強引用) 如Object obj = new Object() 這個obj就是一個強引用了,如果一個對象具有強引用。垃圾回收器就不會回收有強引用的對象。如當jvm內存不足時,具備強引用的對象,虛擬機寧可會拋出OutOfMemoryError(內存空間不足),使程序終止,也不會靠垃圾回收器去回收該對象來解決內存。
2.軟引用(SoftReference)
如果一個對象只具有軟引用,那就類似於可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。
軟引用的作用:軟引用可用來實現內存敏感的高速緩存。
軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
3.弱引用(WeakReference)
如果一個對象只具有弱引用,那就類似於可有可物的生活用品。弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先順序很低的線程, 因此不一定會很快發現那些只具有弱引用的對象。
弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
4.虛引用(PhantomReference)
「虛引用」顧名思義,就是形同虛設,和其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有 虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之 關聯的引用隊列中。
ReferenceQueue queue = new ReferenceQueue ();
//虛引用對象
PhantomReference pr = new PhantomReference (object, queue);
程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動。
如果你還想深入了解的話給你推薦一個博文地址:
網頁鏈接
E. java三個引用類型
四種引用類型
所以在 JDK.1.2 之後,Java 對引用的概念進行了擴充,將引用分為了:強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)4 種,這 4 種引用的強度依次減弱。
一,強引用
Java中默認聲明的就是強引用,比如:
Object obj = new Object(); //只要obj還指向Object對象,Object對象就不會被回收
obj = null; //手動置null
只要強引用存在,垃圾回收器將永遠不會回收被引用的對象,哪怕內存不足時,JVM也會直接拋出OutOfMemoryError,不會去回收。如果想中斷強引用與對象之間的聯系,可以顯示的將強引用賦值為null,這樣一來,JVM就可以適時的回收對象了
二,軟引用
軟引用是用來描述一些非必需但仍有用的對象。在內存足夠的時候,軟引用對象不會被回收,只有在內存不足時,系統則會回收軟引用對象,如果回收了軟引用對象之後仍然沒有足夠的內存,才會拋出內存溢出異常。這種特性常常被用來實現緩存技術,比如網頁緩存,圖片緩存等。
在 JDK1.2 之後,用java.lang.ref.SoftReference類來表示軟引用。
下面以一個例子來進一步說明強引用和軟引用的區別:
在運行下面的Java代碼之前,需要先配置參數 -Xms2M -Xmx3M,將 JVM 的初始內存設為2M,最大可用內存為 3M。
首先先來測試一下強引用,在限制了 JVM 內存的前提下,下面的代碼運行正常
public class TestOOM {
public static void main(String[] args) {
testStrongReference();
}
private static void testStrongReference() {
// 當 new byte為 1M 時,程序運行正常
byte[] buff = new byte[1024 * 1024 * 1];
}
}
但是如果我們將
byte[] buff = new byte[1024 * 1024 * 1];
替換為創建一個大小為 2M 的位元組數組
byte[] buff = new byte[1024 * 1024 * 2];
則內存不夠使用,程序直接報錯,強引用並不會被回收
接著來看一下軟引用會有什麼不一樣,在下面的示例中連續創建了 10 個大小為 1M 的位元組數組,並賦值給了軟引用,然後循環遍歷將這些對象列印出來。
public class TestOOM {
private static List<Object> list = new ArrayList<>();
public static void main(String[] args) {
testSoftReference();
}
private static void testSoftReference() {
for (int i = 0; i < 10; i++) {
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主動通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
}
}
列印結果:
我們發現無論循環創建多少個軟引用對象,列印結果總是只有最後一個對象被保留,其他的obj全都被置空回收了。
這里就說明了在內存不足的情況下,軟引用將會被自動回收。
值得注意的一點 , 即使有 byte[] buff 引用指向對象, 且 buff 是一個strong reference, 但是 SoftReference sr 指向的對象仍然被回收了,這是因為Java的編譯器發現了在之後的代碼中, buff 已經沒有被使用了, 所以自動進行了優化。
如果我們將上面示例稍微修改一下:
private static void testSoftReference() {
byte[] buff = null;
for (int i = 0; i < 10; i++) {
buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主動通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
System.out.println("buff: " + buff.toString());
}
則 buff 會因為強引用的存在,而無法被垃圾回收,從而拋出OOM的錯誤。
如果一個對象惟一剩下的引用是軟引用,那麼該對象是軟可及的(softly reachable)。垃圾收集器並不像其收集弱可及的對象一樣盡量地收集軟可及的對象,相反,它只在真正 「需要」 內存時才收集軟可及的對象。
三,弱引用
弱引用的引用強度比軟引用要更弱一些,無論內存是否足夠,只要 JVM 開始進行垃圾回收,那些被弱引用關聯的對象都會被回收。在 JDK1.2 之後,用 java.lang.ref.WeakReference 來表示弱引用。
我們以與軟引用同樣的方式來測試一下弱引用:
private static void testWeakReference() {
for (int i = 0; i < 10; i++) {
byte[] buff = new byte[1024 * 1024];
WeakReference<byte[]> sr = new WeakReference<>(buff);
list.add(sr);
}
System.gc(); //主動通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((WeakReference) list.get(i)).get();
System.out.println(obj);
}
}
列印結果:
可以發現所有被弱引用關聯的對象都被垃圾回收了。
四,虛引用
虛引用是最弱的一種引用關系,如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,它隨時可能會被回收,在 JDK1.2 之後,用 PhantomReference 類來表示,通過查看這個類的源碼,發現它只有一個構造函數和一個 get() 方法,而且它的 get() 方法僅僅是返回一個null,也就是說將永遠無法通過虛引用來獲取對象,虛引用必須要和 ReferenceQueue 引用隊列一起使用。
public class PhantomReference<T> extends Reference<T> {
/**
* Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
那麼傳入它的構造方法中的 ReferenceQueue 又是如何使用的呢?
五,引用隊列(ReferenceQueue)
引用隊列可以與軟引用、弱引用以及虛引用一起配合使用,當垃圾回收器准備回收一個對象時,如果發現它還有引用,那麼就會在回收對象之前,把這個引用加入到與之關聯的引用隊列中去。程序可以通過判斷引用隊列中是否已經加入了引用,來判斷被引用的對象是否將要被垃圾回收,這樣就可以在對象被回收之前採取一些必要的措施。