摘要:字符串字符串是存儲在字符串常量池中的。面試題假設(shè)字符串常量池中不存在字符串,那么創(chuàng)建了幾個對象答兩個堆空間的值字符數(shù)組和字符串常量池中的實體。程序運行期間,靜態(tài)存儲的數(shù)據(jù)將隨時等候調(diào)用。中的數(shù)組會自動記性范圍檢查會造成少量的內(nèi)存開銷。
字符串
字符串是存儲在字符串常量池中的。例如以下的兩個字符串的內(nèi)存地址值是一樣的:
String str1 = "hello" + "world"; String str2 = "helloworld"; System.out.println(str1 == str2); // true System.out.println(str1.equals(str2)); // true String str3 = "hello"; String str4 = "world"; String str5 = str3 + str4; System.out.println(str5 == str2); // false System.out.println(str5.equals(str2)); // true
在以上的代碼中str2和str5的地址值不相同,如果我們對str5使用intern()方法即:
String str6 = str5.intern(); // native方法 System.out.println(str6 == str2); // true
就可以返回true。
面試題:假設(shè)字符串常量池中不存在字符串"hello",那么String s = new String("hello")創(chuàng)建了幾個對象?
答:兩個堆空間的value值(字符數(shù)組)和字符串常量池中的hello實體。我們可以通過查看new String(String str)的源碼:
/** The value is used for character storage. */ private final char value[]; /** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) { this.value = original.value; this.hash = original.hash; }用句柄操作對象
java中一切皆對象,但是我們操作的實際上是指向這個對象的句柄(Handle),這個句柄也叫做引用(Reference)或者指針(Pointer)。我們可以將這一情形想象成用遙控器(Handler)操作電視機(Object)。沒有電視機,遙控器。
即使沒有電視機,遙控器也可以多帶帶存在。即句柄是可以多帶帶存在的(并不指向任何實體)。例如:
String s;
以上的java代碼創(chuàng)建的僅僅是句柄而不是對象。此時如果向s發(fā)送一條消息,將會或者一個運行時異常,因此更安全的做法是:創(chuàng)建一個句柄的時候進行顯式初始化:
String s = "";java程序運行時數(shù)據(jù)的存放位置
Register。處理器內(nèi)部(最快),由于數(shù)量有限,所以寄存器是根據(jù)需要有編譯器分配的。我們對它沒有直接的控制權(quán),也不可能在程序中找到寄存器的任何蹤跡。
Stack。駐留與常規(guī)RAM區(qū)域,速度僅次于寄存器。我們可以通過它的“堆棧指針”獲得直接的處理支持。(指針下移創(chuàng)建新的內(nèi)存;指針上移釋放內(nèi)存)。創(chuàng)建程序時java編譯器必須準確知道堆棧內(nèi)保存的所有數(shù)據(jù)的“長度”以及“存在的時間”(必須生成相應(yīng)的代碼,以便于向上或者向下移動指針)。這一限制無疑影響了程序的靈活性,所以java將對象的句柄保存在堆棧中,但是對象并不存放在其中。
Heap。一種常規(guī)用途的內(nèi)存池(也是在RAM區(qū)域),保存java對象。Heap最吸引人的地方在于:編譯器并不必要知道要從堆中分配多少存儲空間,也不必要知道存儲的數(shù)據(jù)要在堆中停留多長時間——用堆保存數(shù)據(jù)會得到更大的靈活性。然而every coin have two slices,在堆中分配存儲空間會花費更長的時間!
靜態(tài)存儲。“靜態(tài)”(Static)指的是“位于固定位置”。程序運行期間,靜態(tài)存儲的數(shù)據(jù)將隨時等候調(diào)用。我們可以用static關(guān)鍵字指出一個對象的特定元素是靜態(tài)的,但是java對象本身永遠不會置入靜態(tài)存儲空間。
常數(shù)存儲。常數(shù)存儲通常直接置于一個程序代碼內(nèi)部。這樣做是安全的,因為他們永遠不會被改變。有的常數(shù)需要嚴格保護,可以考慮將他們置入只讀存儲器(ROM)。
非RAM存儲:將數(shù)據(jù)完全保存子啊一個程序之外。對典型的2個例子就是“流式對象”和“固定對象”。
流式對象:對象-->字節(jié)流-->另一臺機器
固定對象:對象-->磁盤
基本數(shù)據(jù)類型基本數(shù)據(jù)類型由于比較常用,而堆棧的效率又高于堆。所以基本數(shù)據(jù)類型都是保存在堆棧中。對于基本數(shù)據(jù)類型我們不需要用new,而是創(chuàng)建了一個并非句柄的“自動變量”,該變量容納了具體的值,并保存在堆中可以更高效的存取。
java中的數(shù)組在C、C++中使用數(shù)組是非常危險的,因為那些數(shù)組只是內(nèi)存塊,如果程序訪問自己內(nèi)存塊之外的數(shù)據(jù)或者在初始化之前使用內(nèi)存會產(chǎn)生不可預(yù)料的后果。在C++中應(yīng)該盡量避免使用數(shù)組而換用Standard TemplateLibrary中更安全的容器。java中的數(shù)組會自動記性范圍檢查會造成少量的內(nèi)存開銷。但是我們可以換來更高的工作效率。
變量作用域變量的作用域是由花括號的位置決定的。
在C、C++中以下的代碼是合法的:
{ int x = 10; { int x = 100; // 不合法Duplicate local variable x } }
但是在java中編譯器會認為變量x已經(jīng)被定義,所以C、C++能將一個變量“隱藏”在一個更大的作用域中,java的設(shè)計者認為這樣使程序產(chǎn)生了混淆。
注意區(qū)分成員變量和局部變量成員變量都有默認值,而局部變量必須進行初始化。
文檔注釋文檔注釋只能為public和protected的成員處理文檔,private和default的不會被javadoc提取。文檔注釋中可以嵌入html,例如:
異常方法拋出異常的時候,該方法會從棧上立即被取出,而異常再度丟給棧上的方法(也就是調(diào)用方),如果調(diào)用方?jīng)]有對異常進行處理而是繼續(xù)拋出異常,調(diào)用方就會從棧上彈出,異常再度交給此時的棧頂方法,如此一路下去……
finally中的代碼有一種情況下是執(zhí)行不到的:finally的前面出現(xiàn)了System.exit(0)。
static只能修飾類的成員(變量和方法),不能修飾局部變量。static變量存放在方法區(qū)。隨著類的加載而加載,存在方法區(qū)中,隨著類的消失而消失,生命周期最長。如果沒有給定初值,static變量會被默認置0.(或者null)。
Q:如果一個類被標記為final,再將該類中的方法標記位final是不是很多余?
A:不只是多余,而且是多了很多!如果一個類為final,那么它根本就沒有子類,根本不可能覆寫父類中的方法(只有繼承才有覆寫)。
工程目錄如下:
加載該配置文件應(yīng)該這樣寫:
public class Test { @org.junit.Test public void test() throws IOException { ClassLoader classLoader = this.getClass().getClassLoader(); InputStream is = classLoader.getResourceAsStream("org/gpf/conf/db.properties"); Properties properties = new Properties(); properties.load(is); properties.list(System.out); } }利用反射獲取父類的泛型
public class Personjava中的枚舉{ // some code... } public class Student extends Person { // some code... } Class> clazz = Student.class; Type type = clazz.getGenericSuperclass(); // org.gpf.Person ParameterizedType parameterizedType = (ParameterizedType) type; // type的子接口 for (Type c : parameterizedType.getActualTypeArguments()) { System.out.println(((Class>)c).getName()); // Class是Type接口的實現(xiàn)類 }
所謂枚舉,就是枚舉類的對象的個數(shù)是有限的,可以窮舉出來的類。實際上單例模式也可以使用枚舉來實現(xiàn)(Effective Java中的單例經(jīng)典實現(xiàn),枚舉只有一個成員)。jdk1.5之前需要自定義枚舉類,jdk1.5之后提供了enum關(guān)鍵字用于定義枚舉類。
例如季節(jié)是有限的:春夏秋冬。
// jdk1.5之前的枚舉類 public class Season { // 1.聲明final屬性 private final String seasonName; // 季節(jié)名 private final String seasonDescribe; // 季節(jié)描述 // 2.為保證實例的數(shù)目是確定的需要私有化構(gòu)造器,在構(gòu)造器中初始化final的屬性 private Season(String seasonName,String seasonDescribe) { this.seasonName = seasonName; this.seasonDescribe = seasonDescribe; } // 3.通過公用的方法調(diào)用屬性 public String getSeasonName() { return seasonName; } public String getSeasonDescribe() { return seasonDescribe; } // 4.內(nèi)部實例化枚舉類的對象 public static final Season SPRING = new Season("spring", " 春暖花開"); public static final Season SUMMER = new Season("summer", " 夏日炎炎"); public static final Season FALL = new Season("fall", " 秋高氣爽"); public static final Season WINTER = new Season("spring", " 白雪皚皚"); public String show() { return "Season [seasonName=" + seasonName + ", seasonDescribe=" + seasonDescribe + "]"; } }
我們可以使用以下的方式進行調(diào)用
Season season = Season.FALL; System.out.println(season.show()); System.out.println(season.getSeasonName() + "-->" + season.getSeasonDescribe());
jdk1.5之后我們可以使用enum關(guān)鍵字來簡化枚舉類的定義:
// jdk1.5之后的枚舉類 public enum Season { SPRING("spring", " 春暖花開"), SUMMER("summer", " 夏日炎炎"), FALL("fall", " 秋高氣爽"), WINTER("spring", " 白雪皚皚"); private final String seasonName; // 季節(jié)名 private final String seasonDescribe; // 季節(jié)描述 private Season(String seasonName,String seasonDescribe) { this.seasonName = seasonName; this.seasonDescribe = seasonDescribe; } public String getSeasonName() { return seasonName; } public String getSeasonDescribe() { return seasonDescribe; } public String show() { return "Season [seasonName=" + seasonName + ", seasonDescribe=" + seasonDescribe + "]"; } }
這樣使用枚舉類:
Season season = Season.FALL; System.out.println(season.show()); System.out.println(season.getSeasonName() + "-->" + season.getSeasonDescribe()); Season[] seasons = Season.values(); // 返回所有枚舉類的對象的數(shù)組 for (Season s : seasons) { System.out.println(s.getSeasonName()); } season = Season.valueOf("SUMMER"); // 返回枚舉類型的對象 System.out.println(season);
我們也可以讓枚舉類型實現(xiàn)接口:
// jdk1.5之后的枚舉類 public enum Season implements Info{ SPRING("spring", " 春暖花開"){ @Override public void show() { System.out.println(1); } }, SUMMER("summer", " 夏日炎炎"){ @Override public void show() { System.out.println(2); } }, FALL("fall", " 秋高氣爽"){ @Override public void show() { System.out.println(3); } }, WINTER("spring", " 白雪皚皚"){ @Override public void show() { System.out.println(4); } }; private final String seasonName; // 季節(jié)名 private final String seasonDescribe; // 季節(jié)描述 private Season(String seasonName,String seasonDescribe) { this.seasonName = seasonName; this.seasonDescribe = seasonDescribe; } public String getSeasonName() { return seasonName; } public String getSeasonDescribe() { return seasonDescribe; } @Override public void show() { System.out.println("Season [seasonName=" + seasonName + ", seasonDescribe=" + seasonDescribe + "]"); } }
以上的程序中每個枚舉類型的實例都各自實現(xiàn)自己的方法!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64732.html
摘要:如果一個程序只包含固定數(shù)量且其生命周期都是已知的對象,那么這是一個非常簡單的程序。 如果一個程序只包含固定數(shù)量且其生命周期都是已知的對象,那么這是一個非常簡單的程序。 1.泛型和類型安全的容器 通過使用泛型,可以在編譯期防止將錯誤類型的對象放置到容器中. 2.基本概念 Java容器類庫的用途是保存對象,并將其劃分為兩個不同的概念:Collection,Map. Collection...
摘要:迭代器通常被成為輕量級對象創(chuàng)建它的代價很小。與迭代器可以用于數(shù)組和所有對象,之所以能夠工作,是因為繼承了接口。 點擊進入我的博客 我覺得本章名字改成容器似乎更好理解,持有對象讓人感到一頭霧水我們需要在任意時刻和任意位置創(chuàng)建任意數(shù)量的對象,所以依靠創(chuàng)建命名的引用來持有對象已經(jīng)滿足不了需求。Java可以用數(shù)組和其他容器類來(List、Set、Queue、Map)來解決這個問題,不同的容器...
摘要:匿名函數(shù)的好處在于可以減少局部變量,以免污染現(xiàn)有的運行環(huán)境。另外通過,這三個符號運行的匿名函數(shù)比運行的匿名函數(shù)可以減少一個字符的使用但是我們通常使用加因為其他的操作符可能會帶來其他的影響更多可以參考 js中的立即執(zhí)行函數(shù) ( function(){…} )()和( function (){…} () )是兩種javascript立即執(zhí)行函數(shù)的常見寫法 問題: 為什么會出現(xiàn)上面的兩種不一...
摘要:所以那些匿名函數(shù)附近使用括號或一些一元運算符的慣用法,就是來引導(dǎo)解析器,指明運算符附近是一個表達式。 Immediately-invoked Function Expression(IIFE,立即調(diào)用函數(shù)),簡單的理解就是定義完成函數(shù)之后立即執(zhí)行。因此有時候也會被稱為自執(zhí)行的匿名函數(shù)(self-executing anonymous function)。 IIFE的叫法最早見于Ben...
閱讀 2008·2019-08-29 16:27
閱讀 1377·2019-08-29 16:14
閱讀 3380·2019-08-29 14:18
閱讀 3461·2019-08-29 13:56
閱讀 1260·2019-08-29 11:13
閱讀 2128·2019-08-28 18:19
閱讀 3447·2019-08-27 10:57
閱讀 2283·2019-08-26 11:39