java核心技术36讲笔记 (2)

实现动态代理的方式很多,比如JDK自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类
似ASM、 cglib(基于ASM)、 Javassist等。

我们知道Spring AOP支持两种模式的动态代理, JDK Proxy或者cglib,如果我们选择cglib方式,你会发现对接口的依赖被克服了。

cglib动态代理采取的是创建目标类的子类的方式,因为是子类化,我们可以达到近似使用被调用者本身的效果。

int和Integer有什么区别?谈谈Integer的值缓存范围。

典型回答:
int是我们常说的整形数字,是Java的8个原始数据类型( Primitive Types, boolean、 byte 、 short、 char、 int、 foat、 double、 long)之一。 Java语言虽然号称一切都是对象,
但原始数据类型是例外。

Integer是int对应的包装类,它有一个int类型的字段存储数据,并且提供了基本操作,比如Math运算、 int和字符串之间转换等。在Java 5中,引入了自动装箱和自动拆箱功能
( boxing/unboxing), Java可以根据上下文,自动进行转换,极大地简化了相关编程。

关于Integer的值缓存,这涉及Java 5中另一个改进。构建Integer对象的传统方式是直接调用构造器,直接new一个对象。但是根据实践,我们发现大部分数据操作都是集中在有
限的、较小的数值范围,因而,在Java 5中新增了静态工厂方法valueOf,在调用它的时候会利用一个缓存机制,带来了明显的性能改进。按照Javadoc, 这个值默认缓存
是-128到127之间。

这种缓存机制并不是只有Integer才有,同样存在于其他的一些包装类,比如:

Boolean,缓存了true/false对应实例,确切说,只会返回两个常量实例Boolean.TRUE/FALSE。

Short,同样是缓存了-128到127之间的数值。

Byte,数值有限,所以全部都被缓存。

Character,缓存范围\'\u0000\' 到 \'\u007F\'。

注意事项:

[1] 基本类型均具有取值范围,在大数*大数的时候,有可能会出现越界的情况。

[2] 基本类型转换时,使用声明的方式。例: int result= 1234567890 * 24 * 365;结果值一定不会是你所期望的那个值,因为1234567890 * 24已经超过了int的范围,如果修改为: long result= 1234567890L * 24 * 365;就正常了。

[3] 慎用基本类型处理货币存储。如采用double常会带来差距,常采用BigDecimal、整型(如果要精确表示分,可将值扩大100倍转化为整型)解决该问题。

[4] 优先使用基本类型。原则上,建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,

[5] 如果有线程安全的计算需要,建议考虑使用类型AtomicInteger、 AtomicLong 这样的线程安全类。部分比较宽的基本数据类型,比如 foat、 double,甚至不能保证更新操作的原子性,
可能出现程序读取到只更新了一半数据位的数值。

[4].原则上, 建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,创建10万个Java对象和10万个整数的开销可不是一个数量级的,不管是内存使用还是处理速度,光是对象头
的空间占用就已经是数量级的差距了。

以我们经常会使用到的计数器实现为例,下面是一个常见的线程安全计数器实现。

class Counter { private fnal AtomicLong counter = new AtomicLong(); public void increase() { counter.incrementAndGet(); } }

如果利用原始数据类型,可以将其修改为

class CompactCounter { private volatile long counter; private satic fnal AtomicLongFieldUpdater<CompactCounter> updater = AtomicLongFieldUpdater.newUpdater(CompactCounter.class, "counter"); public void increase() { updater.incrementAndGet(this); } }

Java原始数据类型和引用类型局限性:

前面我谈了非常多的技术细节,最后再从Java平台发展的角度来看看,原始数据类型、对象的局限性和演进。
对于Java应用开发者,设计复杂而灵活的类型系统似乎已经习以为常了。但是坦白说,毕竟这种类型系统的设计是源于很多年前的技术决定,现在已经逐渐暴露出了一些副作用,例
如:

原始数据类型和Java泛型并不能配合使用
这是因为Java的泛型某种程度上可以算作伪泛型,它完全是一种编译期的技巧, Java编译期会自动将类型转换为对应的特定类型,这就决定了使用泛型,必须保证相应类型可以转换
为Object。

无法高效地表达数据,也不便于表达复杂的数据结构,比如vector和tuple我们知道Java的对象都是引用类型,如果是一个原始数据类型数组,它在内存里是一段连续的内存,而对象数组则不然,数据存储的是引用,对象往往是分散地存储在堆的不同位
置。这种设计虽然带来了极大灵活性,但是也导致了数据操作的低效,尤其是无法充分利用现代CPU缓存机制。

Vector、 ArrayList、 LinkedList有何区别?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwsgws.html