- 數(shù)據(jù)類(lèi)型:
類(lèi)型 | 大小 | 取值范圍 |
---|---|---|
byte | 1字節(jié) | -128~127 (10000000~01111111) [-2^7 ~ 2^7-1] |
short | 2字節(jié) | -3276832767(100...011...) [-215~215-1] |
int | 4字節(jié) | 根據(jù)以上規(guī)律可推出(正好超過(guò)20億族阅,無(wú)法表示全球人數(shù)) |
float | 4字節(jié) | 根據(jù)以上規(guī)律可推出 |
long | 8字節(jié) | 根據(jù)以上規(guī)律可推出(足夠表示全球人數(shù)) |
double | 8字節(jié) | 根據(jù)以上規(guī)律可推出 |
char | 2字節(jié) | java采用Unicode,2個(gè)字節(jié)(16位)來(lái)表示一個(gè)字符 |
boolean | 未知 | true 、false |
二進(jìn)制
原碼:普通二進(jìn)制數(shù),第一位(8位)表示符號(hào)(1為負(fù)旅东,0為正), 其余位表示值,eg:110十艾。
正數(shù)情況:原碼 = 反碼 = 補(bǔ)碼
負(fù)數(shù)情況:
反碼:將原碼按位取反得到的值成為原碼的反碼抵代,eg:001。
補(bǔ)碼:將反碼+1忘嫉,eg:010荤牍。
1.二進(jìn)制轉(zhuǎn)十進(jìn)制的通用方法eg:
11101->12^4+123+1*22+02^1+12^0
2.正數(shù)二進(jìn)制轉(zhuǎn)十進(jìn)制(位1比較多情況)eg:
01110 ---取反得到反碼--->10001
---加1得到補(bǔ)碼---->10010
---0比較多直接用通用方法-->-1*2^4 + 2 = -14
----取絕對(duì)值--------->14
3.負(fù)數(shù)二進(jìn)制轉(zhuǎn)十進(jìn)制(位1比較多情況,負(fù)數(shù)二進(jìn)制是補(bǔ)碼形式)eg:
11110(補(bǔ)碼)---減1得到反碼---->11101(反碼)
---取反得到原碼---->00010(原碼)
---0比較多直接用通用方法-->2
---取相反值------>-2-
浮點(diǎn)數(shù)值不適用于出現(xiàn)舍入誤差的金融計(jì)算中庆冕。eg:
命令System.out.println(2.0-1.1) 得到的結(jié)果并不是想象中的0.9而是0.8999999999999.
原因是浮點(diǎn)數(shù)采用二進(jìn)制表示康吵,無(wú)法精確表示分?jǐn)?shù)1/10就像十進(jìn)制無(wú)法精確表示分?jǐn)?shù)1/3一樣.
如果需要在數(shù)值計(jì)算中保證精確的話,應(yīng)使用BigDecimal類(lèi).
4.&访递、~的特殊用法:
Unicode編碼表示為十六進(jìn)制其范圍從\u0000 到 \uffff晦嵌。eg: \u03c0表示希臘字母π。
短路與拷姿、短路或 &&惭载、|| 都是在第一個(gè)表達(dá)式如果能夠確定值后就沒(méi)必要執(zhí)行第二個(gè)表達(dá)式了。
StringBuilder 適用單線程响巢、StringBuffer允許多線程
數(shù)組拷貝 Arrays.copyOf()
兩個(gè)相等的對(duì)象hashCode值一定相等
Equals與hashCode方法的定義必須一致:如果x.equals(y)返回true描滔,那么x的hashCode()就必須與y的hashCode()相等。
eg:如果用定義的Employee.equals比較員工的ID抵乓,那么hashCode()就需要散列ID伴挚,而不是員工的姓名或存儲(chǔ)地址靶衍。-
對(duì)象克隆
默認(rèn)情況下是淺拷貝灾炭,也就是只拷貝普通成員變量和不可變的子對(duì)象(如String),它并不會(huì)拷貝其他可變對(duì)象颅眶。要想拷貝其他可變對(duì)象蜈出,
則需要實(shí)現(xiàn)深拷貝,即重寫(xiě)clone()方法涛酗。具體實(shí)現(xiàn)如下:
對(duì)于員工類(lèi):public class Employee implements Cloneable{//必須實(shí)現(xiàn)Cloneable接口
private String name;
private double salary;
private Date hireDay;public void Employee(String name,double salary,Date hireDay){ this.name = name; this.salary = salary; this.hireDay = hireDay; } public Employee clone() throws CloneNotSupportedException{ Employee cloned = (Employee)super.clone();//克隆了成員變量(salary)和String(name) cloned.hireDay = (Date)this.hireDay.clone();//克隆對(duì)象 return cloned; } } 調(diào)用方法如下: Employee employee = new Employee("neo",10000.0,new Date()); Employee cloned = employee.clone(); 這樣employee 和 cloned 對(duì)象就互不相干了铡原。
-
反射 -- 一切都是對(duì)象,類(lèi)也是對(duì)象商叹,而類(lèi)是Class類(lèi)的實(shí)例對(duì)象(類(lèi)類(lèi)型)
ArrayList list = new ArrayList();ArrayList<String> list1 = new ArrayList<String>(); list1.add("hello"); //list1.add(20);錯(cuò)誤的 Class c1 = list.getClass(); Class c2 = list1.getClass(); System.out.println(c1 == c2); //反射的操作都是編譯之后的操作 /* * c1==c2結(jié)果返回true說(shuō)明編譯之后集合的泛型是去泛型化的 * Java中集合的泛型燕刻,是防止錯(cuò)誤輸入的,只在編譯階段有效剖笙, * 繞過(guò)編譯就無(wú)效了 * 驗(yàn)證:我們可以通過(guò)方法的反射來(lái)操作卵洗,繞過(guò)編譯 */ try { Method m = c2.getMethod("add", Object.class); m.invoke(list1, 20);//繞過(guò)編譯操作就繞過(guò)了泛型 System.out.println(list1.size());//輸出2 System.out.println(list1);//輸出[hello,2] /*for (String string : list1) { System.out.println(string); }*///現(xiàn)在不能這樣遍歷 } catch (Exception e) { e.printStackTrace(); } }
-
代理
--為某個(gè)對(duì)象提供一個(gè)代理,以控制對(duì)這個(gè)對(duì)象的訪問(wèn)(代理類(lèi)負(fù)責(zé)請(qǐng)求的預(yù)處理弥咪、過(guò)濾过蹂、將請(qǐng)求分派給委托類(lèi)處理十绑、以及委托類(lèi)執(zhí)行完請(qǐng)求后的后續(xù)處理)。分為以下兩類(lèi): 靜態(tài)代理:在程序運(yùn)行前就已經(jīng)存在代理類(lèi)的字節(jié)碼文件酷勺,代理類(lèi)和委托類(lèi)的關(guān)系在運(yùn)行前就確定了本橙。 實(shí)現(xiàn)靜態(tài)代理的步驟: 1.創(chuàng)建業(yè)務(wù)邏輯方法的接口 2.代理類(lèi)和委托類(lèi)都實(shí)現(xiàn)該接口 3.代理類(lèi)擁有委托類(lèi)的對(duì)象并通過(guò)構(gòu)造方法傳進(jìn)來(lái)引用 4.代理類(lèi)調(diào)用業(yè)務(wù)方法,可在方法前進(jìn)行過(guò)濾脆诉,方法結(jié)束后進(jìn)行處理 動(dòng)態(tài)代理:代理類(lèi)的源碼是在運(yùn)行期間通過(guò)反射生成的甚亭,代理類(lèi)和委托類(lèi)的關(guān)系是在程序運(yùn)行時(shí)確定。 實(shí)現(xiàn)動(dòng)態(tài)代理的步驟: 1.創(chuàng)建一個(gè)實(shí)現(xiàn)InvocationHandler接口的類(lèi)库说,并實(shí)現(xiàn)invoke方法: public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) { super(); this.target = target; } /* * proxy 被代理對(duì)象 * method 被代理對(duì)象的方法 * args 方法的參數(shù) * 返回值:Object 方法的返回值 * */ @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { long starttime = System.currentTimeMillis(); System.out.println("汽車(chē)開(kāi)始行駛...."); Object methodReturnType = method.invoke(target,args); long endtime = System.currentTimeMillis(); System.out.println("汽車(chē)結(jié)束行駛.... 汽車(chē)行駛時(shí)間:" + (endtime - starttime) + "毫秒狂鞋!"); return methodReturnType; } } 2.創(chuàng)建被代理的類(lèi)及接口: public interface Moveable { void move(); } public class Car implements Moveable { @Override public void move() { //實(shí)現(xiàn)開(kāi)車(chē) try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽車(chē)行駛中...."); } catch (InterruptedException e) { e.printStackTrace(); } } } 3.創(chuàng)建代理類(lèi):Proxy.newProxyInstance(ClassLoader classLoader,Class[] interfaces, InvocationHandler h);//classLoader為null,表示使用默認(rèn)的類(lèi)加載器潜的。 Car car = new Car();//代理對(duì)象骚揍,委托類(lèi) InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /** * loader 類(lèi)加載器 * interfaces 實(shí)現(xiàn)接口 * h InvocationHandler */ Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h); 4.通過(guò)代理調(diào)用方法: m.move(); Object sysIActivityManager = mInstanceField.get(gDefaultFieldObj);//系統(tǒng)的IActivityManager Class<?> iActivityManagerProxy = Class.forName("android.app.IActivityManager");//代理對(duì)象 Object proxy = Proxy.newProxyInstance(sysIActivityManager.getClass().getClassLoader(),new Class[]{iActivityManagerProxy}, new MyHandler(sysIActivityManager));
異常
異常分為RuntimeException(由程序錯(cuò)誤導(dǎo)致的異常) 和 IOException(程序本身沒(méi)問(wèn)題,IO錯(cuò)誤)啰挪。-
Hashmap
1.默認(rèn)大小capacity=16 默認(rèn)加載因子loadFactory=0.75信不,默認(rèn)情況下,當(dāng)buckets桶的數(shù)量
大于 capacity * loadFactory=12(即桶的數(shù)量為13時(shí))亡呵,進(jìn)行resize抽活,將capacity擴(kuò)大到原來(lái)的2倍。
2.當(dāng)我們?cè)跇?gòu)造方法中傳一個(gè)大小后锰什,Hashmap會(huì)取大于參數(shù)大小的最小的2的次冪作為capacity下硕。
比如我傳一個(gè)15,則capacity=16.
原因:如果我們不以2的次冪作為capacity的話汁胆,比如capacity=15梭姓,當(dāng)我們進(jìn)行put操作時(shí),源碼如下:
上面的tab.length 其實(shí)就是capacity嫩码,index 就是得到table的索引誉尖,hash是經(jīng)過(guò)hash()函數(shù)處理的hash值
當(dāng)hash=8時(shí):
index = 0100&1110(15-1的二進(jìn)制)=0100
當(dāng)hash=9時(shí):
index = 0101&1110(15-1的二進(jìn)制)=0100
我們發(fā)現(xiàn),出現(xiàn)了hash碰撞铸题,并且索引為9的數(shù)組(table[9])是無(wú)法存數(shù)據(jù)的(因?yàn)槿?時(shí)被映射到了8)铡恕,
而且不僅僅是索引為9無(wú)數(shù)據(jù),而且只要是第四位為1(0001,0101,0111,1001,1101,1111等等)都無(wú)法存數(shù)據(jù)丢间,造成了一半的空間浪費(fèi)探熔。
當(dāng)capacity是2的次冪如16:
當(dāng)hash=8時(shí):
index = 0100&1111(16-1的二進(jìn)制)=0100
當(dāng)hash=9時(shí):
index = 0101&1111(16-1的二進(jìn)制)=0101
這樣就避免了空間的浪費(fèi)以及減少hash碰撞。 ArrayList
ArrayList 默認(rèn)大小為10烘挫,每次擴(kuò)容為原來(lái)大小的1.5倍
HashSet底層就是HashMap(數(shù)組加鏈表)诀艰、TreeSet底層就是TreeMap(紅黑樹(shù))Math
Math.ceil()用作向上取整。 Math.floor()用作向下取整。 Math.round() 我們數(shù)學(xué)中常用到的四舍五入取整
Math.round(11.5)的返回值是12涡驮,Math.round(-11.5)的返回值是-11暗甥。四舍五入的原理是在參數(shù)上加0.5然后進(jìn)行下取整
String
1 String str = "hello";
str = str + "world";
這兩句話會(huì)造成內(nèi)存泄漏;因?yàn)镾tring是不可變對(duì)象捉捅,所以在內(nèi)存中同時(shí)存在hello對(duì)象 和 helloworld對(duì)象撤防,
但str引用指向的是helloworld對(duì)象,導(dǎo)致hello對(duì)象沒(méi)有被引用棒口,而且一直存在常量池中寄月,從而導(dǎo)致內(nèi)存泄漏
解決方案:StringBuilder
2 String str = "hello "+"world "+"are you ok?";
這句話會(huì)創(chuàng)建一個(gè)對(duì)象,因?yàn)镴VM在編譯階段就確定了str的值為helloworldare you ok?
編譯階段還會(huì)進(jìn)行宏替換eg:
final int len = 10;
String str = "java 的長(zhǎng)度為 "+len;
以上也只會(huì)創(chuàng)建一個(gè)對(duì)象-
表達(dá)式
short s = 5; s = s - 2;上述代碼會(huì)編譯出錯(cuò)无牵,因?yàn)?是int 漾肮,s-2也是int,不能直接賦給s茎毁。 但是 short s = 5; s-=2;上述代碼不會(huì)出錯(cuò)克懊,因?yàn)閟-=2 等價(jià)于s = (short)(s-2) String str = "java.com.neo.lala"; String[] split = str.split(".");//這樣得不到想要的結(jié)果(改為str.split("\\.")) 因?yàn)閟plit方法的參數(shù)是正則表達(dá)式,而"."是匹配任何字符七蜘,所以需要轉(zhuǎn)義
-
樹(shù)
每個(gè)內(nèi)部節(jié)點(diǎn)均為 m 度的有序樹(shù),稱(chēng)作 m 叉樹(shù) 由 n 個(gè)節(jié)點(diǎn)構(gòu)成的二叉樹(shù),高度至少為?log2n? 不含 1 度節(jié)點(diǎn)的二叉樹(shù),稱(chēng)作真二叉樹(shù)(Proper bina ry tree ),否則稱(chēng)作非真二叉樹(shù) (Improper binary tree)谭溉。
-
簡(jiǎn)單工廠模式(最少知識(shí)原則)
提供創(chuàng)建對(duì)象的功能,不需要關(guān)心具體的實(shí)現(xiàn) 使用場(chǎng)景:創(chuàng)建對(duì)象 好處:降低模塊之間的耦合度 public class Factory { public static Api create(int type){ switch (type) { case 1: return new ImplA(); case 2: return new ImplB(); case 3: return new ImplC(); default: return new ImplC(); } } public <T extends Api> T creatProduct(Class<T> clz) { Api api=null; try { api=(Api) Class.forName(clz.getName()).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return (T)api; } }
-
工廠方法模式(抽象工廠模式)
需求:導(dǎo)出數(shù)據(jù)(數(shù)據(jù)庫(kù)文件橡卤、文本文件) 把對(duì)象的實(shí)現(xiàn)延遲到子類(lèi)完成 Android使用場(chǎng)景:Activity生命周期(在子類(lèi)加載具體的布局)扮念、MediaPlayer的創(chuàng)建、ArrayList的迭代器 public interface IFactory {//抽象工廠 IApi createApi(); } public class AndroidFactory implements IFactory{//具體工廠 @Override public IApi createApi() { return new AndroidApi(); } } public class IOSFactory implements IFactory{//具體工廠 @Override public IApi createApi() { return new IOSApi(); } } 使用:IFactory factory=new IOSFactory(); factory.createApi();
-
單例模式
枚舉(天生支持反序列化): 1 枚舉中的屬性必須放在最前面 2. 枚舉中可以和java類(lèi)一樣定義方法 3. 枚舉中的構(gòu)造方法必須是私有的 public enum EnumManager { SDCardManager(10){ @Override public EnumManager getSingle() { return SDCardManager; } }, HttpManager(1) { @Override public EnumManager getSingle() { return null; } }; public SdCardImpl getSingleton() { return new SdCardImpl(); } public abstract EnumManager getSingle(); private EnumManager(int type){ } } EnumManager.SDCardManager.getSingleton(); DCL(Double Check Lock)存在的問(wèn)題: public class DoubleCheckedLock { private static DoubleCheckedLock instance; public static DoubleCheckedLock getInstance() { if (instance == null) { //step1 synchronized (DoubleCheckedLock.class) { //step2 if(instance==null){ //step3 instance=new DoubleCheckedLock(); //step4 } } } return instance; } } Jdk5 以后支持處理器亂序執(zhí)行 匯編指令(為了優(yōu)化) 導(dǎo)致 指向地址和實(shí)例化堆區(qū) 順序不同碧库,eg: step4這一步分為兩步(正常是先a后b柜与、某些平臺(tái)編譯器會(huì)優(yōu)化導(dǎo)致先b后a): a實(shí)例化DoubleCheckedLock堆區(qū)順序不一樣 b.instance 指向堆區(qū)地址 (優(yōu)化情況先b后a) 比如線程A執(zhí)行到step4的b處時(shí)(此時(shí)instance不為空),cpu讓線程B執(zhí)行嵌灰,當(dāng)?shù)絪tep1的時(shí)候發(fā)現(xiàn)instance不為空弄匕,就直接返回。 但事實(shí)上線程B得到的instance是沒(méi)有實(shí)例化完成的導(dǎo)致錯(cuò)誤
-
建造者模式
核心思想:構(gòu)造方法私有伞鲫,在Builder的構(gòu)造方法里面初始化該類(lèi)使用內(nèi)部類(lèi)(保持和房子(目標(biāo)對(duì)象)一樣的參數(shù))來(lái)建造 public class Room { private String window; private String floor; private String doorl; private String chat; public void apply(WorkBuilder.RoomParmas parmas) { window=parmas.window; floor=parmas.floor; doorl=parmas.door; chat=parmas.chat; } } public class WorkBuilder{ private RoomParmas parmas; public WorkBuilder( ) { this.parmas = new RoomParmas(); } public WorkBuilder makeWindow(String window ) { parmas.window=window; return this; } public WorkBuilder makeFloor(String floorCorlor) { parmas.floor=floorCorlor; return this; } public WorkBuilder makeDoor(String door) { parmas.door=door; return this; } public Room makeChat(String chat) { parmas.chat=chat; return this; } public Room build() { Room room=new Room(); room.apply(parmas); return room; } class RoomParmas{ public String window; public String floor; public String door; public String chat; } }
-
原型模式
原型模式就是拷貝原型創(chuàng)建新對(duì)象(深拷貝) 目的:保護(hù)最原始的那一份存檔粘茄。隱藏復(fù)制過(guò)程 使用場(chǎng)景:類(lèi)初始化需要消耗很多資源签舞、new 一個(gè)對(duì)象需要很多數(shù)據(jù)準(zhǔn)備或訪問(wèn)權(quán)限秕脓、 一個(gè)對(duì)象需要提供給其他對(duì)象使用,但是可能會(huì)改變?cè)偷闹? 項(xiàng)目中登錄后保存session保存用戶(hù)的登錄信息儒搭、這些用戶(hù)信息在其他地方用來(lái)做 登錄校驗(yàn)吠架,信息顯示等。但是這些信息在其他地方是不允許修改的 public User getLoginUser(){ return loginUser.clone();/返回深拷貝 } 優(yōu)點(diǎn):原型模式是在內(nèi)存中二進(jìn)制流的拷貝搂鲫,要比直接new一個(gè)對(duì)象性能好很多傍药,特別是在循環(huán)體內(nèi)產(chǎn)生大量對(duì)象時(shí),原型模式可以更好的體現(xiàn)優(yōu)點(diǎn) 缺點(diǎn):直接在內(nèi)存中拷貝,是不會(huì)調(diào)用其構(gòu)造函數(shù)的拐辽。(注意<鹋病!)
-
策略模式
設(shè)置某一個(gè)策略就會(huì)擁有相應(yīng)的功能(有一個(gè)上下文對(duì)象來(lái)設(shè)置某一個(gè)策略) eg:Android 中的插值器 代碼中有大量if else 就可以考慮策略模式 public class Context { private IStrategy strategy; //構(gòu)造函數(shù)俱诸,要你使用哪個(gè)策略 public Context(IStrategy strategy){ this.strategy = strategy; } public void setStrategy(IStrategy strategy){ this.strategy = strategy; } public void operate(){ this.strategy.operate(); } } public class FirstStrategy implements IStrategy { @Override public void operate() { System.out.println("first"); } } public class SecondStrategy implements IStrategy { @Override public void operate() { System.out.println("second"); } }
狀態(tài)模式
和策略模式結(jié)構(gòu)一樣菠劝,但是行為跟狀態(tài)有關(guān)(有一個(gè)上下文對(duì)象來(lái)控制具體的狀態(tài))
eg:電視遙控器在開(kāi)機(jī)狀態(tài) 的各種操作(調(diào)音量、換頻道)才有效睁搭,在關(guān)機(jī)狀態(tài)無(wú)效
實(shí)用場(chǎng)景:用戶(hù)登錄狀態(tài)和未登錄狀態(tài)會(huì)有不一樣的響應(yīng)8险铩!T奥妗L蚧尽(非常實(shí)用)
public class PowerOn implements TVState{
@Override
public void nextChannel() {
System.out.println("下一頻道");
}
@Override
public void preChannel() {
System.out.println("上一頻道");
}
@Override
public void turnOn() {
System.out.println("正在開(kāi)機(jī)");
}
@Override
public void turnOff() {
System.out.println("關(guān)機(jī)");
}
}
public class PowerOff implements TVState{
@Override
public void nextChannel() {}
@Override
public void preChannel() {}
@Override
public void turnOn() {
System.out.println("開(kāi)機(jī)");
}
@Override
public void turnOff() {}
}
public class TvContext {
private TVState tvState=new PowerOff();
public void setTate(TVState tvState){
this.tvState=tvState;
}
public void turnOn(){
setTate(new PowerOn());
tvState.turnOn();
}
public void turnOff(){
setTate(new PowerOff());
tvState.turnOff();
}
public void nextChannel(){
tvState.nextChannel();
}
public void preChannel() {
tvState.preChannel();
}
}
-
責(zé)任鏈模式
當(dāng)前處理者必須持有下一個(gè)處理者的引用 使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免了請(qǐng)求的發(fā)送者和接受者之前的耦合關(guān)系锌唾。將這些對(duì)象連成一條鏈锄码,并沿著這條鏈傳遞該請(qǐng)求,直到有對(duì)象處理它為止 在安卓中的應(yīng)用:事件傳遞機(jī)制晌涕、有序廣播 優(yōu)點(diǎn):請(qǐng)求者和處理者關(guān)系解耦 缺點(diǎn):需要遍歷處理者巍耗,太多影響性能
-
命令模式
底層業(yè)務(wù)邏輯代碼用接口進(jìn)行隔離eg:登錄時(shí)只關(guān)心登錄成功和失敗、登錄具體邏輯應(yīng)該使用接口隔離 客戶(hù)端只是想要發(fā)出命令或者請(qǐng)求渐排,不關(guān)心請(qǐng)求的真正接收者是誰(shuí)炬太,也不關(guān)心具體如何實(shí)現(xiàn)
-
模板方法模式
定義一個(gè)操作中的算法框架,而將一些步驟延遲到子類(lèi)中驯耻,使得子類(lèi)不改變算法的結(jié)構(gòu)即可重復(fù)定義算法的某些特點(diǎn)步驟
-
觀察者模式
被觀察者一般會(huì)有一個(gè)列表來(lái)保存觀察者的引用亲族,并且提供增加和刪除的方法,通知的時(shí)候會(huì)遍歷這個(gè)列表可缚,回調(diào)所有的觀察者的方法
-
內(nèi)存分配
了解內(nèi)存分配的幾種策略: 1.靜態(tài)的 靜態(tài)的存儲(chǔ)區(qū):內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好霎迫,這塊的內(nèi)存在程序整個(gè)運(yùn)行期間都一直存在。 它主要存放靜態(tài)數(shù)據(jù)帘靡、全局的static數(shù)據(jù)和一些常量知给。 2.棧式的 在執(zhí)行函數(shù)(方法)時(shí),函數(shù)一些內(nèi)部變量的存儲(chǔ)都可以放在棧上面創(chuàng)建描姚,函數(shù)執(zhí)行結(jié)束的時(shí)候這些存儲(chǔ)單元就會(huì)自動(dòng)被釋放掉涩赢。 棧內(nèi)存包括分配的運(yùn)算速度很快,因?yàn)閮?nèi)置在處理器的里面的轩勘。當(dāng)然容量有限筒扒。 3.堆式的 也叫做動(dòng)態(tài)內(nèi)存分配。有時(shí)候可以用malloc或者new來(lái)申請(qǐng)分配一個(gè)內(nèi)存绊寻。在C/C++可能需要自己負(fù)責(zé)釋放(java里面直接依賴(lài)GC機(jī)制)花墩。 在C/C++這里是可以自己掌控內(nèi)存的悬秉,需要有很高的素養(yǎng)來(lái)解決內(nèi)存的問(wèn)題。java在這一塊貌似程序員沒(méi)有很好的方法自己去解決垃圾內(nèi)存冰蘑,需要的是編程的時(shí)候就要注意自己良好的編程習(xí)慣和泌。 區(qū)別:堆是不連續(xù)的內(nèi)存區(qū)域,堆空間比較靈活也特別大祠肥。 棧式一塊連續(xù)的內(nèi)存區(qū)域允跑,大小是有操作系統(tǒng)覺(jué)決定的。 堆管理很麻煩搪柑,頻繁地new/remove會(huì)造成大量的內(nèi)存碎片聋丝,這樣就會(huì)慢慢導(dǎo)致效率低下。 對(duì)于棧的話工碾,他先進(jìn)后出弱睦,進(jìn)出完全不會(huì)產(chǎn)生碎片入录,運(yùn)行效率高且穩(wěn)定温赔。 public class Main{ int a = 1;//堆內(nèi)存 Student s = new Student();//堆內(nèi)存 public void XXX(){ int b = 1;//棧里面 Student s2 = new Student();//s2一開(kāi)始是在常量池里面,后面才壓棧 } } 1.成員變量全部存儲(chǔ)在堆中(包括基本數(shù)據(jù)類(lèi)型健无,引用及引用的對(duì)象實(shí)體)---因?yàn)樗麄儗儆陬?lèi)旬迹,類(lèi)對(duì)象最終還是要被new出來(lái)的火惊。 2.局部變量的基本數(shù)據(jù)類(lèi)型和引用存儲(chǔ)于棧當(dāng)中,引用的對(duì)象實(shí)體存儲(chǔ)在堆中奔垦。-----因?yàn)樗麄儗儆诜椒ó?dāng)中的變量屹耐,生命周期會(huì)隨著方法一起結(jié)束。 我們所討論內(nèi)存泄露椿猎,主要討論堆內(nèi)存惶岭,他存放的就是引用指向的對(duì)象實(shí)體。
-
線程
Java語(yǔ)言自己可以創(chuàng)建兩種進(jìn)程“用戶(hù)線程”和“守護(hù)線程(Daemon)” 用戶(hù)線程:就是我們平時(shí)創(chuàng)建的普通線程 守護(hù)線程:主要是用來(lái)服務(wù)用戶(hù)線程. 7该摺0丛睢!當(dāng)線程只剩下守護(hù)線程的時(shí)候筐咧,JVM就會(huì)退出.但是如果還有其他的任意一個(gè)用戶(hù)線程還在鸯旁,JVM就不會(huì)退出 將線程轉(zhuǎn)換為守護(hù)線程可以通過(guò)調(diào)用Thread對(duì)象的setDaemon(true)方法來(lái)實(shí)現(xiàn)。在使用守護(hù)線程時(shí)需要注意一下幾點(diǎn): (1) thread.setDaemon(true)必須在thread.start()之前設(shè)置量蕊,否則會(huì)跑出一個(gè)IllegalThreadStateException異常铺罢。你不能把正在運(yùn)行的常規(guī)線程設(shè)置為守護(hù)線程。 (2) 在Daemon線程中產(chǎn)生的新線程也是Daemon的危融。 (3) 守護(hù)線程應(yīng)該永遠(yuǎn)不去訪問(wèn)固有資源畏铆,如文件雷袋、數(shù)據(jù)庫(kù)吉殃,因?yàn)樗鼤?huì)在任何時(shí)候甚至在一個(gè)操作的中間發(fā)生中斷 synchronized鎖代碼塊鎖的對(duì)象是同一個(gè)才會(huì)鎖住eg: void method(String str){ synchronized(str){ ... } } method("xxx"); method(new String("xxx")); 上面兩個(gè)方法同時(shí)執(zhí)行時(shí)代碼塊是不會(huì)被鎖住的辞居,因?yàn)閮蓚€(gè)str雖然內(nèi)容相同但是不是同一個(gè)對(duì)象。解決方法(字符串入池): synchronized(str.intern()){}
do{...}while(false)
do{
...
if (somethingIsWrong) break;
//more code
...
}while(false);
-
volatile
在線程中訪問(wèn)變量的時(shí)候蛋勺,為了提高效率瓦灶,會(huì)在線程中的私有空間中緩存這個(gè)變量。所以多個(gè)線程訪問(wèn)同一個(gè)變量的時(shí)候抱完,會(huì)在各自線程的私有空間中緩存贼陶,對(duì)變量的修改是對(duì)這個(gè)緩存進(jìn)行操作的。 但是從緩存更新到主存是需要時(shí)間的巧娱,所以多個(gè)線程對(duì)同一個(gè)變量進(jìn)行操作這個(gè)變量的值就是不可靠的碉怔,使用volatile關(guān)鍵字,就會(huì)使得緩存的值會(huì)立即更新到主存禁添,使得變量可見(jiàn)撮胧!
生產(chǎn)者消費(fèi)者
public class ThreadTest1 {
//產(chǎn)品
static class ProductObject{
//線程操作變量可見(jiàn)
public volatile static String value;
}
//生產(chǎn)者線程
static class Producer extends Thread{
Object lock;
public Producer(Object lock) {
this.lock = lock;
}
@Override
public void run() {
//不斷生產(chǎn)產(chǎn)品
while(true){
synchronized (lock) { //互斥鎖
//產(chǎn)品還沒(méi)有被消費(fèi),等待
if(ProductObject.value != null){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//產(chǎn)品已經(jīng)消費(fèi)完成老翘,生產(chǎn)新的產(chǎn)品
ProductObject.value = "NO:"+System.currentTimeMillis();
System.out.println("生產(chǎn)產(chǎn)品:"+ProductObject.value);
lock.notify(); //生產(chǎn)完成芹啥,通知消費(fèi)者消費(fèi)
}
}
}
}
//消費(fèi)者線程
static class Consumer extends Thread{
Object lock;
public Consumer(Object lock) {
this.lock = lock;
}
@Override
public void run() {
while(true){
synchronized (lock) {
//沒(méi)有產(chǎn)品可以消費(fèi)
if(ProductObject.value == null){
//等待,阻塞
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消費(fèi)產(chǎn)品:"+ProductObject.value);
ProductObject.value = null;
lock.notify(); //消費(fèi)完成铺峭,通知生產(chǎn)者墓怀,繼續(xù)生產(chǎn)
}
}
}
}
public static void main(String[] args) {
Object lock = new Object();
new Producer(lock).start();
new Consumer(lock).start();
}
}