java指針,Java指針異常

本文目錄一覽:

java中指針怎麼理解?

實際上,java力圖使程序員忘記指針,這包括2個方面:

第一,java限制指針,去除了指針運算。

第二,java從語法上努力隱藏指針,讓指向某對象的指針看起來更像那個對象本身!

是的,所有的java書籍都讓人忘記了指針這回事,我們彷彿只跟對象打交道。偶爾,會被迫分清引用和

對象的關係。這就是目前的情形。多麼好的想法!對象可比那些個不知所以的指針親和多了!這是一種偉大的抽象!

這裡,我們也更願意把引用和對象混淆。是的,為什麼不呢?那樣,整個世界都是對象,太好理解了!

可事實上,為了節省內存,java不能把引用(指針)完全廢除。要知道,複製一個引用(指針)要比

複製整個對象有效得多!所以我們不得不面對引用和對象共存的事實。

下面我就好好分析分析:

指針已經被抽象成了引用,現在指針不能夠隨心所欲的運算,並且看起來就像個對象,完全沒有了指針

的模樣。但它畢竟和對象還是不同的,還要經過一層「轉換」(從指向的那個對象里取數據)。如果我們

在引用滿天飛的時候總想著這樣一層轉換,真的是很不舒服。比如:

String key=”name”;

String value=”hyq”;

HashMap map=new HashMap();

map.put(key,value);

你得想著:key只是個引用,value也是個引用,map還是個引用,我們剛剛做的是把key和value

這2個引用放進了map(也是個HashMap對象的引用)中,到時候我就可以通過map這個引用取得

裡面的對應於key引用的value引用!

你不暈我就服了。

一旦你這樣想,你每時每刻都要面對這樣的繞口令。因為我們對對象的操作全部要通過引用!java沒有提供語法讓你直接得到對象!(指的是直接定址)這一點通過比較原始類型很好理解,int i=8,那麼

i就是8,不是什麼指針,要先找到放著8那塊內存的地址再把8拿出來。這樣多直接,多方便啊!

所以,我們對引用最好也這麼來理解,就輕鬆多了。

還是上面的例子,key就是個String,value也是個String,map是個HashMap,我們把key和value

放進map里,將來可以按key取出value。——多簡單!

其實,這樣的理解是很符合人的思維習慣的,我相信大多數人剛學java時都會自然而然的這麼理解,

但是我們一定要注意在什麼時候不能這麼理解。只要記住什麼時候不能這麼理解,我們就不會因為

這種「近似」的理解方式而犯錯,而同時從這種理解方式里得到了方便和好處。

把引用直接當作對象本身的好處是簡單直接,容易理解,而「誤差」的地方就在於,假設只有這個引用

可以修改此對象。換句話說,當別的引用修改了對象的時候,我們毫不知情並很感費解。比如:

String name=null;

HashMap map=new HashMap();

map.put(“name”,name);

//do a lot of things

name=”hyq”;

當我們再從map里取出name的時候,發現它已經被賦值為hyq了!放進去的時候明明是啥都沒有啊!

咋就變了訥?

引用到name那個對象的不只你map一個阿!

在同一個函數里出現這種情況還不是很常見,我們一般也不必這麼寫,更多的是出現在函數調用、傳參的時候,這樣更加隱蔽,不易發現,也讓代碼可讀性下降。比如:

String name=null;

HashMap map=new HashMap();

map.put(“name”,name);

alterName(name);

在alterName函數里我們修改了name對象,這會直接影響到函數外的map。

所以,當我們把引用和對象故意混淆時,一定要記住什麼時候應該分清楚。

對象的使用不外乎以下幾種情況:

1

String name=new String(“hyq”);

然後使用name,引用生命周期一結束,對象失效(無法被取用)了事。這裡只有name一個引用指向此對象,隨便怎麼弄都不會出事。

2

String name=new String(“hyq”);

String anotherName=name;

這裡假設只有name會修改對象,並且在anotherName引用此對象前做完所有修改,anotherName只是取用這個對象調用方法。在這種情況下,也不會出事。這也是我們經常遇到的情況,並且一般都是在函數調用傳參時出現。注意傳參實際上就是String anotherName=name;

這裡尤其要注意的是2個引用的生命周期:name修改對象的時候另一個引用還沒出世,而等它出世後

發現它又不會修改對象,怎一個爽字了得!

3

String name=new String(“hyq”);

String anotherName=name;

代碼和上面一樣,但是這裡要麼2個引用都會修改對象,要麼只有一個修改但會影響到另一個。這個時候無論如何你不能再把引用當對象了,你必須分清楚它們。你必須小心仔細,不能有絲毫疏忽。

當然,這種寫法和風格無論如何是不值得提倡的,若非必要(沒辦法)請勿模仿!因為必然有一個引用

在不知情的情況下被人修改了對象,等它用的時候會大吃一驚,而這個對象是在什麼時候被什麼人修改的,極難排查。

(上面例子舉得不好,String類是不變類,汗!)

StringBuffer name=new StringBuffer(“hyq”);

StringBuffer anotherName=name;

//do a lot of things

anotherName.append(“is my gf”);

你可能寫得爽,一時痛快就這麼寫了,你也知道是什麼人在什麼時候修改了對象,但是別人呢?

要知道,這裡可能不是相隔幾行代碼這麼簡單,可能是嵌套了好幾層函數調用!你把那個anotherName傳到第5層函數裡面,然後喪心病狂的修改了那個對象,除了天知地知你知,鬼

都看不出來!

java引用與C語言指針的區別是什麼?

java引用與C語言指針的區別有以下幾方面:

1、現象

指針在運行時可以改變其所指向的值,而引用一旦和某個對象綁定後就不再改變,總是指向最初的對象。

2、編譯

程序在編譯時分別將指針和引用添加到符號表上,符號表上記錄的是變數名及變數所對應地址。指針變數在符號表上對應的地址值為指針變數的地址值,而引用在符號表上對應的地址值為引用對象的地址值。符號表生成後就不會再改,因此指針可以改變指向的對象(指針變數中的值可以改),而引用對象不能改。

3、類型

引用其值為地址的數據元素,java封裝了的地址,可以轉成字元串查看,長度可以不必關心;C指針是一個裝地址的變數,長度一般是計算機字長,可以認為是個int。

4、內存佔用

所佔內存:引用聲明時沒有實體,不佔空間。C指針如果聲明後會用到才會賦值,如果用不到不會分配內存。

5、內存溢出

JAVA引用的使用許可權比較小,不會產生內存溢出。C指針是容易產生內存溢出的,所以程序員要小心使用,及時回收。

6、本質

JAVA中的引用和C中的指針本質上都是想通過一個別名,找到要操作的目標(變數對象等),方便在程序里操作。所不同的是JAVA的辦法更安全,使用更加方便些,但沒有了C的靈活,高效。

java中指針操作是什麼意思

眾所周知,在java裡面是沒有指針的。那為何此處還要說java裡面的「指針」呢?我們知

道在C/C++中,指針是指向內存中的地址,該地址就是存儲變數的值。該地址所存儲的變數值是「公有」的,此處的「公有」是對於擁有該地址的變數而言。它

們都可以訪問該地址的內容,並且可對其就行修改,一經修改則所有指向該地址的變數值也將改變。那麼在Java裡面何來的指針?在java裡面沒有指針的定

義。但是java裡面的「指針」無處不在。下面將進行介紹。我們知道JAVA裡面用的最多的就是對象,我們經常將一個對象傳遞給不同的變數,例如:

Student s1 = new Student();

Student s2 = s1;

此時s1和s2是指向同一個對象的,也就是s1和s2引用同一個對象,我們知道java裡面創建一個對象是存放在堆的,當我們new一個對象的時候其實是

在堆中開闢了一個存儲該對象的空間,返回是的存儲該對象在堆中的地址,所以在java中我們所謂的對象引用就是指針,只是沒有像C/C++中給出了一個明

確的定義。java是為了避免指針帶來的使用上的麻煩,所以就使用對象的引用來代替了指針。上面的例子中,當我們在s1中進行修改Student中的屬性

的時候,那麼當s2取Student中屬性的值的時候便是取得了s1修改後的值,這是因為s1和s2是指向堆中的同一塊內容,所以只要其中一個變數修改了

堆中的值,則其他的變數將取得堆中最後更新的值。所以我們可以知道,s2=s1並不是又在堆中創建了一塊內存,而只是把一個對象的地址賦給了s2,此時還

是只是創建了一個對像,而不是兩個。在實際開發中會經常碰到這些,假設創建一個MapString,Object類型的對象,它的

value是一個對象,而key是一個字元串,定義如下:

class Student{

private String name;

private int age;

public void setAge(int age)

{

this.age = age;

}

public Student(String name)

{

this.name = name;

}

}

MapString,Student studentMap = new HashMapString,Student();

Student s1 = new Student(“張三”);

Student s2 = new Student(“李四”);

studentMap.put(s1.name,s1);

studentMap.put(s2.name,s2);

此處是一個學生姓名對應了一個

學生,所以此處的Map的key是學生姓名,value是一個學生對象。那麼就是將一個Student對象的引用賦給了Map中key所對應的

value,所以當程序在別處改變了s1/s2的值後,不必將s1和s2的信息更新到studentMap中,studentMap就會獲得key所對應

的value最新的值,例如:在程序的某處我們將s1的age修改成了「23」,我們不必將s1的最新信息更新到studentMap

中,studentMap就會獲得s1的最新值。這是因為已經將s1對象的引用賦給了studentMap中張三所對應的value,也就是將對象在堆中

的地址賦給了value。所以只要s1一更新,studentMap就可以獲得最新的值。

有時候這種情況會影響我們程序的執行和我們想想的會有偏差,當我們需要保存一個對象在某時刻的狀態時,按照一般的理解是將此時的對象賦給一個變數來進行

存儲,但是在java裡面這樣是行不通的!因為這樣直接將該對象賦給另一個變數只是將該對象的引用賦給了此變數,該變數的值並不能保持在此刻該對象的值,

會隨著程序的執行,該對象的改變而變化。所以達不到我們的目的。下面就舉個例子來說明解決該現象:

class Student{

private String name;

private int age;

public void setAge(int age)

{

this.age = age;

}

public Student(String name)

{

this.name = name;

}

public Student(Student student)

{

this.name = student.name;

this.age = student.age;

}

}

上面還是student類,基

本和上面一樣,只是多添加了一個構造函數——Student(Student

student),為什麼要多加這樣一個函數呢?這就是為了滿足我們上面的需求(保存對象某個時刻下的狀態),我們知道直接將一個對象賦給一個變數會存在

對象的引用,不能保存對象某時刻的狀態。同時也知道要想保存一個對象就要在堆中開闢一個空間,用於存放我們的對象。其實上面的需求可以看做當我們要保存某

時刻下對象的狀態,其實就是該對象的狀態不會隨以後對象的變化而變化,所以何不將當前某時刻下對象的狀態屬性全部都複製到一個新的對象中去!這樣保存下來

的屬性就不會受以後對象的變化而變化了。就上面的例子,舉例說明:

Student s1 = new Student(“王麻子”);

s1.age=23;

……..

//此時要保存s1此刻的狀態

Student s2 = new Student(s1);

此時s1和s2就不是指向堆中的一個地址了,因為s2不是直接將s1賦給它的,而是通過new出來的!上面說了new可以在堆中開闢一個存儲當前new的

對象的空間。這種操作可以實現將s1中的狀態全都轉移到s2中,所以在值的方面看s2和s1此時是一樣的,但是在堆中確實不一樣的,s1!=s2,因為

s1和s2的hashcode不一樣!但是s1.name.equal(s2.name)==ture,s1.age=s2.age。這不就實現了保存某

個對象某個時刻下的狀態了嗎?而切不會在受程序執行的影響!

到此已全部介紹完有關java「指針」,其實java「指針」就是對象的引用,而對象就是存放在堆中的。我們知道java中的內存分為堆內存(heap)

和棧內存(stack)。堆就是用來存放對象的,而棧則是存放一些數據基本類型的值,如int,float,double,char…….。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/246311.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 13:14
下一篇 2024-12-12 13:14

相關推薦

  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java Bean載入過程

    Java Bean載入過程涉及到類載入器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean載入的過程。 一、類載入器 類載入器是Java虛擬機…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • VSCode為什麼無法運行Java

    解答:VSCode無法運行Java是因為默認情況下,VSCode並沒有集成Java運行環境,需要手動添加Java運行環境或安裝相關插件才能實現Java代碼的編寫、調試和運行。 一、…

    編程 2025-04-29
  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29
  • Java 8 Group By 會影響排序嗎?

    是的,Java 8中的Group By會對排序產生影響。本文將從多個方面探討Group By對排序的影響。 一、Group By的概述 Group By是SQL中的一種常見操作,它…

    編程 2025-04-29

發表回復

登錄後才能評論