第5条:避免创建不必要的对象

本文探讨了如何避免在编程中创建不必要的对象,介绍了充分利用可重用对象的方法,包括使用不可变对象、缓存复杂计算结果、利用适配器模式以及注意基本类型与包装类型的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何避免创建不必要的对像?

充分利用可以重用的对象


1.若对象不可变,它就始终可以重用

先来一个极端的反面例子(一般程序员都不会无聊到这样做):

String s = new String("stringtest");

该语句没执行一次都会创建一个String实例,如果这在一个循环中,将会有很多String实例被创建,显然这是不必要的,显然这个代码应该这样写:

String s = "stringtest";

这种写法只用了一个String实例,而不是每次都创建一个实例。
这样写可以保证,对于说有在同一台虚拟机中运行的到吗,只要它们包含相同的字符串字面常量,该对象就会被重用。


2.可以重用那些一直不不会被修改的对象
例如一下代码,若要获得value,很明显每次都要经过一大堆运算

class Test{
    //省略构造函数
    public int calculateThatValue(){
        int value;//假设这是一个若赋值了就不变的,且要经过很复杂的运算才能算出来的值

        //假设这里是很复杂的一段代码,需要运行很长时间

        return value;
    }
}

然而我们可以这样改进,可以让运行效率变快,只运算一次,而不是每次需要都运算

class Test{
    private final int VALUE_COSTLONGTIME;//假设这是一个不变的,且要经过很复杂的运算才能算出来的值

    //省略构造函数
    //静态方法块,在类第一次被加载时候执行
    static{
        int value;

        //假设这里是很复杂的一段代码,需要运行很长时间

        VALUE_COSTLONGTIME = value;//把计算好的值赋值给final常量

    }
}

很明显,在这之前的例子讨论到的对象都是显然能被重用的,因为初始化之后不会再改变。

3.当对象重用与否不明显时,考虑使用适配器(也叫视图)来避免创建不必要对象

例如,Map接口的keySet方法返回该Map的对象的Set视图,其中包含该Map中所有的Key。
粗看起来,好像每次调用keySet都应该创建一个新的Set实例。其实不然,对于一个没定的Map对象,实际上每次调用keySet都返回同样的Set实例。

例,HashMap的keySet方法实现

public Set<K> keySet() {
        Set<K> ks = keySet;
        return (ks != null ? ks : (keySet = new KeySet()));
    }

可以看到,第一行实现代码是把keySet赋值给ks,return 后面是一个三元表达式,当ks不为空时返回ks,否则创建一个KeySet返回。(也就是keySet为空时创建一个KeySet对象返回)
keySet在HashMap中的定义

transient volatile Set<K>        keySet = null;

先解释一下两个修饰符

transient (是一个类型修饰符,只能用来修饰字段):在对象序列化的过程中,标记为transient的变量不会被序列化。
使用场景:假设某个类的成员变量是transient,那么当通过ObjectOutputStream把这个类的某个实例保存到磁盘上时,实际上transient变量的值是不会保存的。
当对象序列化的保存在存储器上时,不希望有些字段数据被保存,为了保证安全性,可以把这些字段声明为transient。

volatile(变量修饰符,只能修饰变量):volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

看完这里,应该就可以解释为什么keySet返回都是同一个对象。


4.避免无意识的使用自动装箱
基本类型优先,当心无意思的自动装箱

例: long 类型声明成Long


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值