业务层勿用继承,不要为了方便舍弃了性能。TʌT不好意思我错了

很多人喜欢在action 或service或dao层继承一些公共的东西 比如jdbc或一些其他的东西 我看过一些小源码也经常这样 废话不多说 直入正题


直入正题前先科普一下TheardLocal类 懂的人直接跳

线程不安全指的是一个带有类成员变量(状态)的类的单列被多个线程访问时才会造成线程不安全,TheardLocal简单来说就是一个map (线程ID,对象),具体就不多说了,需要详细了解的请百度。

TheardLocal的出现解决了这一问题,现在很多框架都运用了这个技术,将所有的成员变量都放在TheardLocal内,这样就不会出现线程安全了,这也是为什么Spring jdbcTemplate的事物管理不会存在多线程安全问题。(你没发现你所有的注入用的都是这一个单列对象吗)还有很多很多地方都是这样的。

现在SpringMvc等使用的是方法及传惨,方法体有独自的栈,不存在线程安全,这样就可以让你的action无论多少个请求都只实列化一次并且不会造成线程安全。


上面这一段只 为告诉你 减少实例对象 使用单列模式 不然下面的没必要看了 因为目的就是为了减少实例对象


正题

四个很简单的java类


[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();
}
}
输出的肯定是两个1

这能证明什么呢?

Animal 被实例化了两次 如果你的项目中action多达100个 甚至1000个 那么这个类被实例化的次数会随着你的action数量变得越来越多,如果你使用的是单列还好,如果是多列那这个次数就等于 请求数*子类


请使用注入的方式,因为它只是一个对象的引用,10000个引用它在内存中还是那么大。

不要为了那么两行代码的方便性影响了性能

使用继承前先想好它可能会有多少个子类,太多了就用注入,也就多两行代码。


楼主目前做的两个项目中业务层都没有用过继承,虽然几乎每个类都用了jdbc但是都是注入进来的。















实践验证真理 额 我承认我错了 不过也学到很多东西 感谢大家的打击
下面是我的实践


第一段

public class Animal {
public void getInfo(){
//一大堆代码
}
//还可以加N多方法运行结果也一致
}

public class Dog extends Animal{
}

public class Pig {
public Animal animal;
}

第一种运行方式 继承
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);//添加到一个集合里避免无引用被垃圾回收
}

Long runTime = new Date().getTime()-begin;
System.out.println(runTime);
}

第二种运行方式 注入
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);//添加到一个集合里避免无引用被垃圾回收
}
Long runTime = new Date().getTime()-begin;
System.out.println(runTime);
}
两个运行结果占用内存一致时间几乎一致
证明一个非静态方法在内存中只会占一个地址 与静态的区别在于静态是系统启动时分配 非静态是第一次实例时分配 无论后续实例多少次它只会占用一个内存地址 所以测试时应该独立启动运行 不然第二步骤实例Animal类时其实一点时间也没花内存也没变


第二段
将Animal类添加一个非静态成员变量
public Integer age = new Integer(10);

两个运行结果 第二种运行时间内存占用比第一种小一倍
证明一个类在实例化的时候会为成员变量分配内存空间 而方法不会

第三段
将Animal类添加一个方法引用age
与第二段一致
证明方法在使用成员变量时只是引用不是复制

第四段
将Animal类添加一个构造函数
public Animal(){
//打印
}
注入的方式构造函数运行一次
继承的方式随子类实例次数


最后总结
1一个类在实例化时
非静态并且有值的成员变量(int long String这些类型在不使用构造传参时 如果参数一致在内存中也会存在一个)会在分配在内存中 以后每次实例也都会
非静态方法只会在第一次实例化时分配 以后每次的实例都只是引用

2父类在很多子类继承时构造函数不要过于复杂,因为构造函数在每次实例化时都会运行一次

3一个类如果构造函数是空并且也没有非静态不为空的成员变量那么
new 一个类一百次 和new一个类一次 加100此空循环 无论内存占用还是速度都一致 
posted on 2013-02-04 15:02  蜜雪薇琪  阅读(264)  评论(0编辑  收藏  举报