1 考虑使用静态方法获得对象

获得一个对象实例最常见的方式是通过构造函数. 有另外一个方法, 应该成为每一个程序员工具箱中重要的一个工具 : 使用静态方法获得对象的实例. 一个类, 可以向外暴露一个简单的静态方法, 这个方法返回值是这个类的一个实例. 这样的例子很多, 例如Boolean这个类当中的valueOf方法, 通过静态方法,将一个布尔值转换为Boolean对象本身:

public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}

需要注意的是,这里所说的静态方法, 跟我们所说的静态工厂设计模式不是一回事.

一个类可以通过静态方法, 替代或者是作为一种补充形式, 实现得到其实例的目的. 当然,这样做,既有好处, 也有弊端.

一个好处是, 通过合理的命名静态方法, 可以更好的做到见名知义, 而不像是构造函数, 仅仅能使用类名.这样直接导致代码更加直观,提高了代码可读性. 例如:
Integer类的构造方法:BigInteger(int, int, Random), 返回的是一个规定位数的最大可能素数, 但显然构造函数并没有指明返回值的意义, 那么如果替换成静态方法: BigInteger.probablePrime就会更好些, 实际上, 在1.4版本之后, 这个方法被加上了.

一个类只能有一个特定签名的构造函数, 程序员们可以通过改变构造函数的参数列表来获取多个构造函数. 但是这样做并不好, 使用这样API的用户, 如果不参照JavaDoc, 永远记不清楚那个构造参数代表什么意义, 最终导致调用构造函数时出错.
相对而言, 通过见名知义的静态方法得到类的实例, 就不存在上述缺点. 因此,当一个类中, 存在构造方法参数个数相同, 仅仅是参数类型不同的构造函数时, 考虑使用静态工厂方法, 通过方法名称区分各个方法之间的区别,是一个非常赞的方式.

第二个好处是:
不同于构造函数, 静态方法获取类的实例, 不会每次调用的时候, 都去创建一个新的对象. 这样, 对于不可变类, 就可以使用它的预加载实例,或者反复的使用创建它时缓存的实例, 而不是每次都创建一个新的对象. 这个技术在布尔类中的Boolean.valueOf(boolean)方法中有着淋漓尽致的体现, 这个类从来不会创建新的对象, 实际上, 你可以看JDK中是这么定义布尔这个类的”public final class Boolean”. 这个技术, 很类似于”享元设计模式”, 他能在程序需要频繁创建相同对象, 且对象创建成本较大时候, 显著提高性能.

静态方法返回相同的对象, 能够严格的控制在某个时刻, 那个对象的实例存在, 这称作实例受控”instance-controlled”. 编写实例受控类有几个方面的必要:实例受控类可以控制一个类是否是单例模式还是不可实例化的类. 它还可以确保不可变类不存在两个equals的实例, 有了这样前提, 我们就可以调用==代替equals来提高程序的运行效率.

第三个好处是:
使用静态方法得到类的实例, 可以返回类的任意子类对象, 这样给了程序员很大的自由, 去选择方法返回的类型.

一个典型的应用是在类非public的情况下, 通过API来得到类的实例, 这样会使得代码变得非常简洁.

第四个好处是:
在创建参数化类型的实例的时候, 能让代码变得更简洁.

当让它也有他的缺点:
一是:若果一个类不含有共有的或者protected权限的构造函数, 它就不能被继承.
二是:他们与其他的静态方法没有任何区别.

注: 不可变类
从字面意思来理解就是不会发生变化的类,那么是什么不会发生变化呢,其实就是类的状态,也就是不变类的实例一旦被创建,其状态就不会发生变化,举个例子:如果人是一个class,那么我们中的每一个都是人这个类的具体的instance,如果人这个类只有一个状态就是生身父母,那么它就是一个不变类,因为每一个人在出生的那一刹那,生身父母就已经被设置了值,而且终生都不会发生变化。
不变类有什么好处呢?

1) 不变类是线程安全的,由于不变类的状态在创建以后不再发生变化,所以它可以在线程之间共享,而不需要同步。
2) 不变类的instance可以被reuse

创建类的实例需要耗费CPU的时间,当这个实例不再被引用时,将会被垃圾回收掉,这时候,又需要耗费CPU的时间。对于不变类而言,一个好处就是可以将常用的实例进行缓存,从而减少了对象的创建。举个例子,对于布尔型,最常用的便是true and false。JDK中的Boolean类就是一个不变类,并且对这两个实例进行了缓冲。

public final class Boolean implements java.io.Serializable{

    /** 
     * The <code>Boolean</code> object corresponding to the primitive 
     * value <code>true</code>. 
     */

    public static final Boolean TRUE = new Boolean(true);

    /** 
     * The <code>Boolean</code> object corresponding to the primitive 
     * value <code>false</code>. 
     */

public static final Boolean FALSE = new Boolean(false);

// 这个方法不会创建新的对象,而是重用已经创建好的instance

  public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
 }
}

3) 不变类的某些方法可以缓存计算的结果

hashCode这个方法来自于Object这个类,这个方法用来返回对象的hashCode,主要用于将对象放置到hashtable中时,来确定这个对象的存储位置。对于一个不变类的实例,它的hashCode也是不变的,所以就可以缓存这个计算的结果,来提高性能,避免不必要的运算,JDK中的String类就是一个例子。

public final class String{

/** Cache the hash code for the string */
private int hash; // Default to 0

public int hashCode() {
int h = hash;
if (h == 0) {
       // compute the value
       hash = h; // cache the value
        }
        return h;
    }
}

在JDK中, String, the primitive wrapper classes, and BigInteger and BigDecimal都是不变类。

如果一个类是不变类,这个类是不是就不能有改变状态的方法呢?

答案当然是否定的,String是一个不变类,仍然有replace,replaceAll这样的方法,而String仍然是一个不变类,那是因为在这些改变状态的方法中,每次都是新创建一个String对象。

如果大家理解了不变类,那也就不难理解为什么在做String的concatenate时,应当用StringBuffer而不是用+的操作符。

如何正确使用String呢?

1) 不要用new去创建String对象。

如果使用new去创建String,那么每次都会创建一个新对象。

    public static void main(String[] args) {

        String A1 = "A";
        String A2 = "A";  // It won't create a new object
        checkInstance(A1, A2);  // Result:  They are same instances
        String B1 = new String("A"); // create a new object
        String B2 = new String("A"); // creat a new object
        checkInstance(B1, B2); // Result:  They are different instances
    }

    private static void checkInstance(String a1, String a2) {

        if (a1 == a2) {
            System.out.println("They are same instances");
        } else {
            System.out.println("They are different instances");
        }
    }

2) 应当用StringBuffer来做连接操作

因为String是一个不变类,那么在做连接操作时,就会创建临时对象来保存中间的运算结果,而StringBuffer是一个mutable class,这样就不需要创建临时的对象来保存结果,从而提高了性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值