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,这样就不需要创建临时的对象来保存结果,从而提高了性能。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书重点:探索“对象导向程序所支持的C++对象模型”下的程序行为。对于“对象导向性质之基础实现技术”以及“各种性质背后的隐含利益交换”提供一个清楚的认识。检验由程序变形所带来的效率冲击。提供丰富的程序范例、图片,以及对象导向观念和底层对象模型之间的效率测量。 C++成山似海的书籍堆中,这一本不是婴幼儿奶粉,也不是较大婴儿奶粉,它是成人专用的低脂高钙特殊奶粉。 对于C++底层机制感兴趣的读者,这本书会给你“漫卷诗书喜欲狂”的感觉。 了解C++ Object Model,是学习Component ObjectModel的最短路线。 如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么Inside TheC++ Object Model正适合你。 目录: 本立道生(侯捷 译序) 前言(Stanley B.Lippman) 第0章 导读(译者的话) 第1章 关于对象(Object Lessons) 加上封装后的布局成本(Layout Costs for Adding Encapsulation) 1.1 C++模式模式(The C++ Object Model) 简单对象模型(A Simple Object Model) 表格驱动对象模型(A Table-driven Object Model) C++对象模型(The C++ Object Model) 对象模型如何影响程序(How the Object Model Effects Programs) 1.2 关键词所带来的差异(A Keyword Distinction) 关键词的困扰 策略性正确的struct(The Politically Correct Struct) 1.3 对象的差异(An Object Distinction) 指针的类型(The Type of a Pointer) 加上多态之后(Adding Polymorphism) 第2章 构造函数语意学(The Semantics of constructors) 2.1 Default Constructor的建构操作 “带有Default Constructor”的Member Class Object “带有Default Constructor”的Base Class “带有一个Virual Function”的Class “带有一个virual Base class”的Class 总结 2.2 Copy Constructor的建构操作 Default Memberwise Initialization Bitwise Copy Semantics(位逐次拷贝) 不要Bitwise Copy Semantics! 重新设定的指针Virtual Table 处理Virtual Base Class Subobject 2.3 程序转换语意学(Program Transformation Semantics) 明确的初始化操作(Explicit Initialization) 参数的初始化(Argument Initialization) 返回值的初始化(Return Value Initialization) 在使用者层面做优化(Optimization at the user Level) 在编译器层面做优化(Optimization at the Compiler Level) Copy Constructor:要还是不要? 摘要 2.4 成员们的初始化队伍(Member Initialization List) 第3章 Data语意学(The Semantics of Data) 3.1 Data Member的绑定(The Binding of a Data Member) 3.2 Data Member的布局(Data Member Layout) 3.3 Data Member的存取 Static Data Members Nonstatic Data Member 3.4 “继承”与Data Member 只要继承不要多态(Inheritance without Polymorphism) 加上多态(Adding Polymorphism) 多重继承(Multiple Inheritance) 虚拟继承(Virtual Inheritance) 3.5 对象成员的效率(Object Member Efficiency) 3.6 指向Data Members的指针(Pointer to Data Members) “指向Members的指针”的效率问题 第4章 Function语意学(The Semantics of Function) 4.1 Member的各种调用方式 Nonstatic Member Functions(非静态成员函数) Virtual Member Functions(虚拟成员函数) Static Member Functions(静态成员函数) 4.2 Virtual Member Functions(虚拟成员函数) 多重继承下的Virtual Functions 虚拟继承下的Virtual Functions 4.3 函数的效能 4.4 指向Member Functions的指针(Pointer-to-Member Functions) 支持“指向Virtual Member Functions”之指针 在多重继承之下,指向Member Functions的指针 “指向Member Functions之指针”的效率 4.5 Inline Functions 形式对数(Formal Arguments) 局部变量(Local Variables) 第5章 构造、解构、拷贝 语意学(Semantics of Construction,Destruction,andCopy) 纯虚拟函数的存在(Presence of a Pure Virtual Function) 虚拟规格的存在(Presence of a Virtual Specification) 虚拟规格中const的存在 重新考虑class的声明 5.1 无继承情况下的对象构造 抽象数据类型(Abstract Data Type) 为继承做准备 5.2 继承体系下的对象构造 虚拟继承(Virtual Inheritance) 初始化语意学(The Semantics of the vptr Initialization) 5.3 对象复制语意学(Object Copy Semantics) 5.4 对象的功能(Object Efficiency) 5.5 解构语意学(Semantics of Destruction) 第6章 执行期语意学(Runting Semantics) 6.1 对象的构造和解构(Object Construction and Destruction) 全局对象(Global Objects) 局部静态对象(Local Static Objects) 对象数组(Array of Objects) Default Constructors和数组 6.2 new和delete运算符 针对数组的new语意 Placement Operator new的语意 6.3 临时性对象(Temporary Objects) 临时性对象的迷思(神话、传说) 第7章 站在对象模型的类端(On the Cusp of the Object Model) 7.1 Template Template的“具现”行为(Template Instantiation) Template的错误报告(Error Reporting within a Template) Template中的名称决议方式(Name Resolution within a Template) Member Function的具现行为(Member Function Instantiation) 7.2 异常处理(Exception Handling) Exception Handling快速检阅 对Exception Handling的支持 7.3 执行期类型识别(Runtime Type Identification,RTTI) Type-Safe Downcast(保证安全的向下转型操作) Type-Safe Dynamic Cast(保证安全的动态转型) References并不是Pointers Typeid运算符 7.4 效率有了,弹性呢? 动态共享函数库(Dynamic Shared Libraries) 共享内存(Shared Memory)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值