Effective java (一)

说实话这本书我买了挺久了,刚工作的时候买的,刚开始看的时候,有些看不懂,然后就搁置了,最近又拿出来翻一翻,这回能看懂一些了,其实有些还是看不太懂.我简单得做一下小章总结.

创建与销毁对象(一)

1.静态工厂方法代替构造函数

是什么 : 为了让客户获得它的一个实例,最通常的方法就是提供一个公有的构造函数,还有一种是提供一个公有的静态工厂方法返回的一个实例,静态工厂函数其实就是一个普通的静态方法.

//静态工厂方法
public static <K,V> HashMap<K,V> newTest(){
    return new HashMap<K,V>
}

代替的好处 :

        静态工厂方法有名字,构造函数的参数没有确切的描述返回的是什么的时候,使用静态工厂函数要比构造函数更容易使用与阅读表达更清晰.

        静态工厂函数每次调用的时候不要求非得创建一个新的对象,这样可以避免创建一些不必要的重复对象,.(如果程序要频繁的创建相同的对象,并且创建的代价比较高的话.这项技术会极大的损耗性能).用静态工厂函数可以保证类是一个singleton,使非可变类可以保证"不会有两个相等的实例存在"

      静态工厂函数与构造函数不同,静态工厂函数可以返回一个原返回类型的子类型的对象.一个API可以返回同一个对象,而这个API又可以不是公开的,这样的接口久比较简洁,已经隐藏起来了实现类,

缺点:

      静态工厂函数的主要缺点是,类如果不含公有的或者受保护的构造函数,就不能被子类化.

      静态工厂函数和其他的静态方法没有任何区别.在API文档中,它们不会像构造函数那样明确的标注出来,静态工厂方法代表的是一种规范的背离,因为在文档中表明一个静态工厂函数比较困难的,所以尽量遵守命名规范来将这种缺点减到最小.

如果能用构造函数的话尽量用构造函数.毕竟这是java提供的规范.

2.私有构造函数强化singleton

singleton是java设计模式中常用的一种,也就是单例模式.singleton是一个无法实例化的对象,在任何时候,只能由JVM创建一个singleton(对象)实例。如果实例不存在,通过创建类的新实例的方法建立一个类来执行这个模式;如果存在类的一个实例,就只会返回那个对象的一个引用。也就是每个类只有一个实例.

实现singleton有两种方法,

//第一种,公有静态成员是一个final域
public class Elvis{
    public static final Elvis INSTANC = new Elvis();
    
    private Elvis(){
        .....
    }
}

//第二种,提供了公有的静态工厂方法,而不是公有静态的final域
public class Elvis{
    private static final Elvis INSTANC = new Elvis();

    private Elvis(){
        .....
    }
    
    public static Elvis getInstance(){
        return INSTANC;
    }
}

//标准的singleton模式不使用直接静态变量实例化进行声明,它实例化构造器中的一个静态实例变量,而不查看它是否已经存在
public class Elvis{
    private static final Elvis INSTANC = null;
    private Elvis(){
        .....
    }
    
    public static Elvis getInstance(){
        if(INSTANC == null){
            INSTANC = new Elvis();
        }
        return INSTANC;
    }
}

对于静态方法 Elvis.getInstance的调用,都会返回同一个对象的实例,所以不会有别的Elvis实例被创建.

如果要使singlton能够被序列化,仅仅在声明中加上 "implement Serializable"还不够,还要提供一个readResolve方法,否则一个序列化的实例在反序列化的时候都会创建一个新的实例,防止这种情况的话在Elvis类中添加readResolve()方法.


//第二种,提供了公有的静态工厂方法,而不是公有静态的final域
public class Elvis{
    private static final Elvis INSTANC = new Elvis();

    private Elvis(){
        .....
    }
    
    public static Elvis getInstance(){
        return INSTANC;
   }
    
   private object readResolve() throws ObjectStreamException {
        return INSTANC;
    }
}

3.私有构造函数强化不可实例化的能力

企图通过将一个类做成抽象类来强制该类不能实例化是行不通的,这个类可以被子类化,并且该类的子类可以被实例化,让这个类包含显示的私有构造函数,这个类就不能实例化了.也就是 private 使类不能实例化了.

//这样的类不能实例化
public class UtilsClass{
    private UtilsClass(){
        ....
    }
}

4.避免创建重复的对象

重复使用同一个对象,而不是每次需要的时候就创建一个功能性等价的对象.如果一个对象是不可变得,那么这个对象是一直可以被调用的.

对于同时提供了静态工厂方法和构造函数,优先使用静态工厂方法,来避免创建重复的对象.

但是如果在提倡保护性拷贝的时候,因重用对象造成的代价远远大于因创建重复对象而导致的代价.在要求保护性拷贝而没有实行保护性拷贝,将会导致潜在的错误和安全漏洞,而不必要地创建对象仅仅会影响程序的风格和性能.

5.消除过期的对象引用

     如果一个栈先是增长,然后再收缩,那么从栈弹出的对象不会被当做垃圾回收,即使使用栈的客户程序不在引用这些对象,也不会被回收,就是因为栈内部维护着这些对象过期的引用.过期引用就是指永远也不会解除的引用.这种情况随着垃圾回收器活动增加,或者不断增加内存的占用,程序的性能的降低会逐渐表现出来,这样的内存泄漏可能会导致磁盘分页,甚至崩盘,也就是程序失败(OutOfMemoryError)错误.

class StaticTest
{
    private static Vector v = new Vector(10);
    public void init()
    {
        for (int i = 1; i < 100; i++)
        {
            Object object = new Object();
            v.add(object);
            object = null; //清除对象的引用,不清除会导致内存泄漏
        }
    }
}

 JVM垃圾回收机制:

    Java中的对象是在堆中分配,对象的创建有2中方式:new或者反射。对象的回收是通过垃圾收集器,JVM的垃圾收集器简化了程序员的工作,但是却加重了JVM的工作,这是Java程序运行稍慢的原因之一,因为GC为了能正确释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都要进行监控,监控对象的状态是为了更加准确、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。

     内存泄泄漏通常不会表现成明显的失败,可以在系统中存在很多年,只有通过检查代码,或借助Heap剖析工具才能发现内存泄漏问题。所以要尽量在内存泄漏发生之前就知道如何预测此类问题。

6.避免使用终结函数

      调用终结函数 : Syatem.gc   和  System.runFinalization

      在java中是有垃圾回收机制的,当一个对象变得不可到达的时候,垃圾回收器会回收该对象相关的存储空间.

      终结函数并不能够保证及时得执行,对象变得不可到达,然后到终结函数的执行,这段时间的长度是不确定的,任意的,时间关键的任务不应该由终结函数来完成.执行终结函数的线程优先级,比该应用程序的其他线程的优先级要低的多.不要依赖一个终结函数来更新关键性的永久状态,不能保证会被执行甚至会不会被执行都不知道.

      显示的终止方法通常与try{ } finally{ }结构结合起来使用,以确保及时终止 . 除非是作为安全网,或者是为了终止非关键的本地资源,否则不要使用终结方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值