Java的结构之美【2】——销毁对象
先来看一段代码:
import java.util.Arrays;
import java.util.EmptyStackException; /**
* 2014年6月28日09:31:59
* @author 阳光小强
*
*/
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITAL_CAPACITY = 15; public Stack(){
elements = new Object[DEFAULT_INITAL_CAPACITY];
} public void push(Object obj){
ensureCapacity();
elements[size++] = obj;
} public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
} /**
* 假设长度超出了默认长度则加倍
*/
private void ensureCapacity(){
if(elements.length == size){
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
这段程序表面上看是没有不论什么错误的,可是它隐藏着一个“内存泄露”问题,随然每次都有pop()从栈里弹出对象,可是栈中的对象还是被引用着,所以不能够及时释放。将上面代码改动例如以下:
public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
再来看一段代码:
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader; public class IOTest {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("test.xml");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
if(br.ready()){
System.out.println(br.readLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
成功输出结果例如以下:
这段代码看似没有不论什么问题,可是却存在着内存泄露问题,我们没有关闭对应的资源
再来思考一个问题,代码例如以下:
public class IOTest {
public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么?
}
class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
}
}
}
}
上面对象能释放吗?线程能自己主动结束吗?
在搞清楚上面问题之前,我们将上面代码进行改动,先看例如以下代码:
public class IOTest {
private String data = "阳光小强";
public static void main(String[] args) {
IOTest test = new IOTest();
/*IOTest.MyThread myThread = test.new MyThread();
myThread.start();*/
test = null; //这个对象能释放吗?
//myThread = null; //线程能自己主动结束吗?为什么?
System.gc(); //启动垃圾回收器
while(true){
}
}
class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("对象销毁了");
}
}
在上面代码中我们重写了IOTest对象的finalize()方法,该方法是Object类的方法(protected),作用是当对象的垃圾回收器执行的时候回调该方法。
上面我们使用了System.gc()方法来通知垃圾回收器进行垃圾回收,执行的结果是输出了“对象销毁了".以下我们将上面代码中的凝视去掉,启动线程后再来执行一次。
public class IOTest {
private String data = "阳光小强";
public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么?
System.gc(); //启动垃圾回收器
while(true){
}
}
class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("对象销毁了");
}
}
能够看到”对象销毁了“这句话没有被输出到控制台,说明我们创建的IOTest对象没有被销毁,在非常多书上都会说,给一个对象赋null值,这个对象就会成为无主对象,就会被垃圾回收器回收,可是为什么这个线程和IOTest对象还是存在的?假设是这种话,我们应该考虑怎样节省我们的内存?再来看一段代码:
public class IOTest {
private String data = "阳光小强";
public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么?
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc(); //启动垃圾回收器
}
}
class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(i<5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("线程对象销毁了");
}
}
public void testUsed(){
while(true){
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("外部类对象销毁了");
}
}
输出结果:
从上面结果中我们能够看到,仅仅有当线程结束后,线程对象和启动线程的对象才干真正的被垃圾回收器回收,所以在内部类中定义线程类,启动线程,会一直持有外部类的引用。如今我们又会产生一个疑问,是不是全部的内部类都持有外部类的引用呢?以下我们再来做个试验:
public class IOTest {
private String data = "阳光小强";
public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
//myThread.start();
test = null; //这个对象能释放吗?
//myThread = null; //线程能自己主动结束吗?为什么?
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc(); //启动垃圾回收器
}
}
class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(i<5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("线程对象销毁了");
}
}
public void testUsed(){
while(true){
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("外部类对象销毁了");
}
}
在上面的代码中我没有启动线程,所以此时的MyThread就能够当成一个普通的内部类了,我将外部类的引用置为空,会发现没有不论什么结果输出(说明外部类没有被销毁)
public class IOTest {
private String data = "阳光小强";
public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
//myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么?
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc(); //启动垃圾回收器
}
}
class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(i<5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("线程对象销毁了");
}
}
public void testUsed(){
while(true){
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("外部类对象销毁了");
}
}
我再将内部类的引用和外部类的引用都置为空,则输出了以下结果:
至少我能够从上面现象中这样觉得,全部内部类都持有外部类的引用。这个结论还有待进一步的验证。。。
感谢你对“阳光小强"的关注,我的还有一篇博文非常荣幸參加了CSDN举办的博文大赛,假设你觉的小强的博文对你有帮助,请为小强投上你宝贵的一票,投票地址:http://vote.blog.csdn.net/Article/Details?articleid=30101091
Java的结构之美【2】——销毁对象的更多相关文章
- Effective Java(1)-创建和销毁对象
Effective Java(1)-创建和销毁对象
- Java的结构之美【1】——构造对象
当我们遇到多个构造器參数的时候可能会想到用构件器,代码例如以下: /** * 构建器 * @author 阳光小强 * */ public class Lunch { private String c ...
- Effective Java 读书笔记之一 创建和销毁对象
一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...
- effective java 第2章-创建和销毁对象 读书笔记
背景 去年就把这本javaer必读书--effective java中文版第二版 读完了,第一遍感觉比较肤浅,今年打算开始第二遍,顺便做一下笔记,后续会持续更新. 1.考虑用静态工厂方法替代构造器 优 ...
- Effective Java 学习笔记之创建和销毁对象
一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...
- 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器
类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...
- Effective Java——(一)创建和销毁对象
第一条 考虑用静态工厂方法代替构造器 什么叫静态工厂方法,就是通过在类中通过静态方法对对象初始化. 比如说 public class StaticFactory { private String na ...
- 【Effective Java】第二章-创建和销毁对象——1.考虑用静态工厂方法代替构造器
静态工厂方法的优点: 可以赋予一个具有明确含义的名称 可以复用唯一实例,不必每次新建 可以返回原实例类型的子类对象 可以在返回泛型实例时更加简洁 缺点: 类如果不含有共有的或者受保护的构造器,就不能被 ...
- Effective Java(一)—— 创建和销毁对象
在客户端(调用端)获取自身实例的方法: 公有的构造器: 类的静态工厂方法: 1. 使用静态工厂方法代替构造器 Boolean 是对基本类型 boolean 的包装类: public final cla ...
随机推荐
- [linux]ubuntu apt-get安装软件失败
1.首先查看 dns 配置 sudo vi /etc/resolv.conf nameserver 114.114.114.114 nameserver 8.8.8.8 2.修改 apt-get 源 ...
- ARM架构和编程-4
ARM中断异常处理: ARM系统中止品种:按中断处理降序排列优先级:重置.数据访问中止.高速中断请求.外部中断请求.预取中止.令.软件中断. ARM体系中的异常中断向量表: 0x0 复位 0x4 没有 ...
- INSTALL_FAILED_MEDIA_UNAVAILABLE错误处理
问题描写叙述: 在android手机上安装apk的时候,报错例如以下: Installation error: INSTALL_FAILED_MEDIA_UNAVAILABLE Please chec ...
- 祖国版Solowheel!IPS103 独轮思维车 - 三个月体验报告
http://tieba.baidu.com/f?kz=2308652773&mo_device=1
- HEVC码率控制浅析——HM代码阅读之二
上一篇文章主要讨论了RC的总体框架,本文开始分析具体的代码实现细节.分析的顺序按照总体框架来,即初始化-->更新. (1)m_cRateCtrl.init() #if M0036_RC_IMPR ...
- CI控制器调用内部方法并加载对应模板的做法
当我打开链接:http://localhost/3g/index/open/a/b? from=timeline后,推断链接中的from是否等于timeline,假设等于timeline.那么就调用控 ...
- 设计模式之迭代器模式(Iterator)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...
- HibernateReview Day1 - Introduction
Hibernate已经学过去大概有半个月了,然后默默的忘掉了……所谓Practice makes perfect. 我尽力重新拾起来. 1.什么是ORM 在介绍Hibernate之前,我们先学习下OR ...
- hdu - 4975 - A simple Gaussian elimination problem.(最大流量)
意甲冠军:要在N好M行和列以及列的数字矩阵和,每个元件的尺寸不超过9,询问是否有这样的矩阵,是独一无二的N(1 ≤ N ≤ 500) , M(1 ≤ M ≤ 500). 主题链接:http://acm ...
- android LinearLayout等view如何获取button效果
我们可以给LinearLayout以及一切继承自View的控件,设置View.onClickListener监听,例如LInearLayout. 但是我们发现LinearLayout可以执行监听方法体 ...