主要学习创建和销毁对象:
1.何时以及如何创建对象
2.何时以及如何避免创建对象
3.如何确保它们能够适时地销毁
4.如何管理对象销毁之前必须进行的清理动作
获取类的实例的常用方法有:
1.公有的构造器
2.公有的静态工厂方法
下面通过boolean类(基本类型boolean的包装类)的简单示例来学习:
静态工厂方法相对于构造器的优势:
1.有名称
具有适当名称的静态工厂方法更易使用,产生的代码更易阅读。可用名称来突出它们之间的区别。
如构造器<code>biginteger(int,int,random)</code>返回的biginteger可能为素数,若用名为<code>biginteger.probableprime</code>的静态工厂方法来表示,显得更加清楚。
2.不必每次调用它们的时候都创建一个新对象
不可变类可以使用预先构建好的实例,或者是将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象。
静态工厂方法为重复的调用返回相同的对象。
3.可返回原返回类型的任何子类型的对象
4.创建参数化类型实例时,可使代码变得更加简洁
由于《effective java》这本书在编写的时候,jdk1.7还没有推出,因此在调用参数化类的构造器时,类型参数都必须要指明。而静态工厂方法能替我们实现类型推导的功能。
静态工厂方法的缺点:
1.类如果不含公有的或受保护的构造器,就不能被子类化。
2.静态工厂方法和其他的静态方法实际上没有任何区别。
静态工厂和构造器的局限性:<code>不能很好地扩展到大量的可选参数</code>
对于有大量的参数的类的编写:
此方法虽可行,但如果有许多参数时,客户端代码很难编写,并且难以阅读。
javabeans模式创建实例容易,代码易读。但有很严重的缺点:
1.构造过程中可能出现不一致的状态,调试困难。
2.因为有set方法,使得在javabeans模式中,不能将类变为不可变的,需要额外的努力来确保它的线程安全。
易写易读,模拟了具名的可选参数。build方法可检验约束条件。
singleton表示仅仅被实例化一次的类。
实现singleton的方法:
1.public static final域实现
缺点:利用反射机制可调用到私有构造方法
如何防止调用私有构造方法,修改构造方法,在创建第二个实例的时候抛出异常即可。
2.静态工厂方法实现
这个方法相比于之前的方法的优势是,灵活性,不需要更改api的前提下,可以改变该类是否应该为singleton。
使singleton类变成为可序列化的:
实现serializable接口
需要声明所有实例为瞬时的(transient)
提供一个<code>readresolve()</code>方法。
3.编写一个包含单个元素的枚举类型来实现
优点:简洁,并提供了序列化机制,而且能保证不会被多次实例化(即使是面对复杂的序列化或是发射攻击的时候)----->实现singleton的最佳方法
在缺少显式构造器的情况下,编译器会自动提供一个公有的,无参的缺省构造器。
通过将类做成抽象类来实现不可实例化的目的是不可取的。继承抽象类,子类也可以被实例化。同时也会误导用户,以为是为了继承而设计的。
正确做法是:将构造器显式地声明为私有的。
最好能重用对象,而不是在每次需要的时候创建一个相同功能的新对象。
重用不可变对象。
重用那些已知不会被修改的可变对象。
用一个静态的初始化器来避免上面那种效率低下的情况。
自动装箱(jdk5引入):java编译器能在基本类型和包装类之间自动转换。如<code>int</code>和<code>integer</code>,<code>double</code>和<code>double</code>等等。 相关学习链接: <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html">1.https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html</a> <a href="https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html">2.https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html</a>
运行结果:
结论:优先使用基本类型而不是装箱基本类型,当心无意识的自动装箱。
注意: 很多规定只是建议,不要矫枉过正,犯了教条主义的错误,一定要与实际的开发情况结合,实事求是。
不要错误地认为“应该尽可能地避免创建对象”,应该是“避免创建不必要的对象”,注意是不必要的! 通过维护自己的对象池(object pool)来避免创建对象并不是一种好的做法,除非池中的对象非常重要。
手工管理内存的语言:c或c++
具有垃圾回收功能的语言:java,简化程序员的工作
上面这段代码存在内存泄露的问题,当栈先是增长,然后弹出,从栈中弹出的对象都不会被当做垃圾回收。
栈内部维护着这些对象的过期引用,也就是永远不会被解除的引用。栈数组中下标大于或等于size的元素的引用都是过期的引用。
在支持垃圾回收的语言中, 内存泄露(也就是无意识的对象保持)很隐蔽。
修复办法:一旦对象引用过期,就清空这些引用。
注意:清空对象引用应该是一种例外,而不是一种规范行为。
容易导致内存泄露的几种情形:
类自己管理内存
缓存
监听器和其他回调
终结方法(finalizer):不可预测,危险,一般情况下是不必要的。
终结方法的缺点:
不能保证会被及时地执行,而且根本不会保证它们会被执行。(所以不应该依赖终结方法来更新重要的持久状态)
严重的性能损失
终止类的对象中封装的资源(文件或线程),只需提供一个显式的终止方法。不需要编写终结方法。
例子:
inputstream,outputstream,java.sql.connection的close方法
java.util.timer的cancel方法
一般与<code>try-catch</code>结合起来使用,以确保及时终止
原文地址:http://www.cnblogs.com/johntsai/p/5281805.html