业务层勿用继承,不要为了方便舍弃了性能。TʌT不好意思我错了
生活随笔
收集整理的這篇文章主要介紹了
业务层勿用继承,不要为了方便舍弃了性能。TʌT不好意思我错了
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
很多人喜歡在action 或service或dao層繼承一些公共的東西 比如jdbc或一些其他的東西 我看過(guò)一些小源碼也經(jīng)常這樣 廢話不多說(shuō) 直入正題
直入正題前先科普一下TheardLocal類(lèi) 懂的人直接跳
線程不安全指的是一個(gè)帶有類(lèi)成員變量(狀態(tài))的類(lèi)的單列被多個(gè)線程訪問(wèn)時(shí)才會(huì)造成線程不安全,TheardLocal簡(jiǎn)單來(lái)說(shuō)就是一個(gè)map (線程ID,對(duì)象),具體就不多說(shuō)了,需要詳細(xì)了解的請(qǐng)百度。
TheardLocal的出現(xiàn)解決了這一問(wèn)題,現(xiàn)在很多框架都運(yùn)用了這個(gè)技術(shù),將所有的成員變量都放在TheardLocal內(nèi),這樣就不會(huì)出現(xiàn)線程安全了,這也是為什么Spring jdbcTemplate的事物管理不會(huì)存在多線程安全問(wèn)題。(你沒(méi)發(fā)現(xiàn)你所有的注入用的都是這一個(gè)單列對(duì)象嗎)還有很多很多地方都是這樣的。
現(xiàn)在SpringMvc等使用的是方法及傳慘,方法體有獨(dú)自的棧,不存在線程安全,這樣就可以讓你的action無(wú)論多少個(gè)請(qǐng)求都只實(shí)列化一次并且不會(huì)造成線程安全。
上面這一段只 為告訴你 減少實(shí)例對(duì)象 使用單列模式 不然下面的沒(méi)必要看了 因?yàn)槟康木褪菫榱藴p少實(shí)例對(duì)象
正題
四個(gè)很簡(jiǎn)單的java類(lèi)
[code="java"]public class Animal {
public Animal(){
System.out.println(1);
}
}
[code="java"]public class Dog extends Animal{
}
[code="java"]public class Pig extends Animal{
}
[code="java"]public class Test {
public static void main(String[] args) {
new Dog();
new Pig();
}
}
輸出的肯定是兩個(gè)1
這能證明什么呢?
Animal 被實(shí)例化了兩次 如果你的項(xiàng)目中action多達(dá)100個(gè) 甚至1000個(gè) 那么這個(gè)類(lèi)被實(shí)例化的次數(shù)會(huì)隨著你的action數(shù)量變得越來(lái)越多,如果你使用的是單列還好,如果是多列那這個(gè)次數(shù)就等于 請(qǐng)求數(shù)*子類(lèi)
請(qǐng)使用注入的方式,因?yàn)樗皇且粋€(gè)對(duì)象的引用,10000個(gè)引用它在內(nèi)存中還是那么大。
不要為了那么兩行代碼的方便性影響了性能
使用繼承前先想好它可能會(huì)有多少個(gè)子類(lèi),太多了就用注入,也就多兩行代碼。
樓主目前做的兩個(gè)項(xiàng)目中業(yè)務(wù)層都沒(méi)有用過(guò)繼承,雖然幾乎每個(gè)類(lèi)都用了jdbc但是都是注入進(jìn)來(lái)的。
實(shí)踐驗(yàn)證真理 額 我承認(rèn)我錯(cuò)了 不過(guò)也學(xué)到很多東西 感謝大家的打擊
下面是我的實(shí)踐
第一段
public class Animal {
public void getInfo(){
//一大堆代碼
}
//還可以加N多方法運(yùn)行結(jié)果也一致
}
public class Dog extends Animal{
}
public class Pig {
public Animal animal;
}
第一種運(yùn)行方式 繼承
public static void main(String[] args) {
Long begin = new Date().getTime();
List<Dog> l = new ArrayList<Dog>();
for (int i = 0; i < 1000000; i++) {
Dog d = new Dog();
l.add(d);//添加到一個(gè)集合里避免無(wú)引用被垃圾回收
}
Long runTime = new Date().getTime()-begin;
System.out.println(runTime);
}
第二種運(yùn)行方式 注入
public static void main(String[] args) {
Long begin = new Date().getTime();
List<Pig> l = new ArrayList<Pig>();
Animal animal = new Animal();
for (int i = 0; i < 1000000; i++) {
Pig d = new Pig();
d.animal = animal;
l.add(d);//添加到一個(gè)集合里避免無(wú)引用被垃圾回收
}
Long runTime = new Date().getTime()-begin;
System.out.println(runTime);
}
兩個(gè)運(yùn)行結(jié)果占用內(nèi)存一致時(shí)間幾乎一致
證明一個(gè)非靜態(tài)方法在內(nèi)存中只會(huì)占一個(gè)地址 與靜態(tài)的區(qū)別在于靜態(tài)是系統(tǒng)啟動(dòng)時(shí)分配 非靜態(tài)是第一次實(shí)例時(shí)分配 無(wú)論后續(xù)實(shí)例多少次它只會(huì)占用一個(gè)內(nèi)存地址 所以測(cè)試時(shí)應(yīng)該獨(dú)立啟動(dòng)運(yùn)行 不然第二步驟實(shí)例Animal類(lèi)時(shí)其實(shí)一點(diǎn)時(shí)間也沒(méi)花內(nèi)存也沒(méi)變
第二段
將Animal類(lèi)添加一個(gè)非靜態(tài)成員變量
public Integer age = new Integer(10);
兩個(gè)運(yùn)行結(jié)果 第二種運(yùn)行時(shí)間內(nèi)存占用比第一種小一倍
證明一個(gè)類(lèi)在實(shí)例化的時(shí)候會(huì)為成員變量分配內(nèi)存空間 而方法不會(huì)
第三段
將Animal類(lèi)添加一個(gè)方法引用age
與第二段一致
證明方法在使用成員變量時(shí)只是引用不是復(fù)制
第四段
將Animal類(lèi)添加一個(gè)構(gòu)造函數(shù)
public Animal(){
//打印
}
注入的方式構(gòu)造函數(shù)運(yùn)行一次
繼承的方式隨子類(lèi)實(shí)例次數(shù)
最后總結(jié)
1一個(gè)類(lèi)在實(shí)例化時(shí)
非靜態(tài)并且有值的成員變量(int long String這些類(lèi)型在不使用構(gòu)造傳參時(shí) 如果參數(shù)一致在內(nèi)存中也會(huì)存在一個(gè))會(huì)在分配在內(nèi)存中 以后每次實(shí)例也都會(huì)
非靜態(tài)方法只會(huì)在第一次實(shí)例化時(shí)分配 以后每次的實(shí)例都只是引用
2父類(lèi)在很多子類(lèi)繼承時(shí)構(gòu)造函數(shù)不要過(guò)于復(fù)雜,因?yàn)闃?gòu)造函數(shù)在每次實(shí)例化時(shí)都會(huì)運(yùn)行一次
3一個(gè)類(lèi)如果構(gòu)造函數(shù)是空并且也沒(méi)有非靜態(tài)不為空的成員變量那么
new 一個(gè)類(lèi)一百次 和new一個(gè)類(lèi)一次 加100此空循環(huán) 無(wú)論內(nèi)存占用還是速度都一致?
直入正題前先科普一下TheardLocal類(lèi) 懂的人直接跳
線程不安全指的是一個(gè)帶有類(lèi)成員變量(狀態(tài))的類(lèi)的單列被多個(gè)線程訪問(wèn)時(shí)才會(huì)造成線程不安全,TheardLocal簡(jiǎn)單來(lái)說(shuō)就是一個(gè)map (線程ID,對(duì)象),具體就不多說(shuō)了,需要詳細(xì)了解的請(qǐng)百度。
TheardLocal的出現(xiàn)解決了這一問(wèn)題,現(xiàn)在很多框架都運(yùn)用了這個(gè)技術(shù),將所有的成員變量都放在TheardLocal內(nèi),這樣就不會(huì)出現(xiàn)線程安全了,這也是為什么Spring jdbcTemplate的事物管理不會(huì)存在多線程安全問(wèn)題。(你沒(méi)發(fā)現(xiàn)你所有的注入用的都是這一個(gè)單列對(duì)象嗎)還有很多很多地方都是這樣的。
現(xiàn)在SpringMvc等使用的是方法及傳慘,方法體有獨(dú)自的棧,不存在線程安全,這樣就可以讓你的action無(wú)論多少個(gè)請(qǐng)求都只實(shí)列化一次并且不會(huì)造成線程安全。
上面這一段只 為告訴你 減少實(shí)例對(duì)象 使用單列模式 不然下面的沒(méi)必要看了 因?yàn)槟康木褪菫榱藴p少實(shí)例對(duì)象
正題
四個(gè)很簡(jiǎn)單的java類(lèi)
[code="java"]public class Animal {
public Animal(){
System.out.println(1);
}
}
[code="java"]public class Dog extends Animal{
}
[code="java"]public class Pig extends Animal{
}
[code="java"]public class Test {
public static void main(String[] args) {
new Dog();
new Pig();
}
}
輸出的肯定是兩個(gè)1
這能證明什么呢?
Animal 被實(shí)例化了兩次 如果你的項(xiàng)目中action多達(dá)100個(gè) 甚至1000個(gè) 那么這個(gè)類(lèi)被實(shí)例化的次數(shù)會(huì)隨著你的action數(shù)量變得越來(lái)越多,如果你使用的是單列還好,如果是多列那這個(gè)次數(shù)就等于 請(qǐng)求數(shù)*子類(lèi)
請(qǐng)使用注入的方式,因?yàn)樗皇且粋€(gè)對(duì)象的引用,10000個(gè)引用它在內(nèi)存中還是那么大。
不要為了那么兩行代碼的方便性影響了性能
使用繼承前先想好它可能會(huì)有多少個(gè)子類(lèi),太多了就用注入,也就多兩行代碼。
樓主目前做的兩個(gè)項(xiàng)目中業(yè)務(wù)層都沒(méi)有用過(guò)繼承,雖然幾乎每個(gè)類(lèi)都用了jdbc但是都是注入進(jìn)來(lái)的。
實(shí)踐驗(yàn)證真理 額 我承認(rèn)我錯(cuò)了 不過(guò)也學(xué)到很多東西 感謝大家的打擊
下面是我的實(shí)踐
第一段
public class Animal {
public void getInfo(){
//一大堆代碼
}
//還可以加N多方法運(yùn)行結(jié)果也一致
}
public class Dog extends Animal{
}
public class Pig {
public Animal animal;
}
第一種運(yùn)行方式 繼承
public static void main(String[] args) {
Long begin = new Date().getTime();
List<Dog> l = new ArrayList<Dog>();
for (int i = 0; i < 1000000; i++) {
Dog d = new Dog();
l.add(d);//添加到一個(gè)集合里避免無(wú)引用被垃圾回收
}
Long runTime = new Date().getTime()-begin;
System.out.println(runTime);
}
第二種運(yùn)行方式 注入
public static void main(String[] args) {
Long begin = new Date().getTime();
List<Pig> l = new ArrayList<Pig>();
Animal animal = new Animal();
for (int i = 0; i < 1000000; i++) {
Pig d = new Pig();
d.animal = animal;
l.add(d);//添加到一個(gè)集合里避免無(wú)引用被垃圾回收
}
Long runTime = new Date().getTime()-begin;
System.out.println(runTime);
}
兩個(gè)運(yùn)行結(jié)果占用內(nèi)存一致時(shí)間幾乎一致
證明一個(gè)非靜態(tài)方法在內(nèi)存中只會(huì)占一個(gè)地址 與靜態(tài)的區(qū)別在于靜態(tài)是系統(tǒng)啟動(dòng)時(shí)分配 非靜態(tài)是第一次實(shí)例時(shí)分配 無(wú)論后續(xù)實(shí)例多少次它只會(huì)占用一個(gè)內(nèi)存地址 所以測(cè)試時(shí)應(yīng)該獨(dú)立啟動(dòng)運(yùn)行 不然第二步驟實(shí)例Animal類(lèi)時(shí)其實(shí)一點(diǎn)時(shí)間也沒(méi)花內(nèi)存也沒(méi)變
第二段
將Animal類(lèi)添加一個(gè)非靜態(tài)成員變量
public Integer age = new Integer(10);
兩個(gè)運(yùn)行結(jié)果 第二種運(yùn)行時(shí)間內(nèi)存占用比第一種小一倍
證明一個(gè)類(lèi)在實(shí)例化的時(shí)候會(huì)為成員變量分配內(nèi)存空間 而方法不會(huì)
第三段
將Animal類(lèi)添加一個(gè)方法引用age
與第二段一致
證明方法在使用成員變量時(shí)只是引用不是復(fù)制
第四段
將Animal類(lèi)添加一個(gè)構(gòu)造函數(shù)
public Animal(){
//打印
}
注入的方式構(gòu)造函數(shù)運(yùn)行一次
繼承的方式隨子類(lèi)實(shí)例次數(shù)
最后總結(jié)
1一個(gè)類(lèi)在實(shí)例化時(shí)
非靜態(tài)并且有值的成員變量(int long String這些類(lèi)型在不使用構(gòu)造傳參時(shí) 如果參數(shù)一致在內(nèi)存中也會(huì)存在一個(gè))會(huì)在分配在內(nèi)存中 以后每次實(shí)例也都會(huì)
非靜態(tài)方法只會(huì)在第一次實(shí)例化時(shí)分配 以后每次的實(shí)例都只是引用
2父類(lèi)在很多子類(lèi)繼承時(shí)構(gòu)造函數(shù)不要過(guò)于復(fù)雜,因?yàn)闃?gòu)造函數(shù)在每次實(shí)例化時(shí)都會(huì)運(yùn)行一次
3一個(gè)類(lèi)如果構(gòu)造函數(shù)是空并且也沒(méi)有非靜態(tài)不為空的成員變量那么
new 一個(gè)類(lèi)一百次 和new一個(gè)類(lèi)一次 加100此空循環(huán) 無(wú)論內(nèi)存占用還是速度都一致?
轉(zhuǎn)載于:https://www.cnblogs.com/shhaoran/archive/2013/02/04/2924524.html
總結(jié)
以上是生活随笔為你收集整理的业务层勿用继承,不要为了方便舍弃了性能。TʌT不好意思我错了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 美国巨头ins全面效仿TikTok引用户
- 下一篇: hibernate继承映射之每个具体类一