先来看一段代码:

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】——销毁对象的更多相关文章

  1. Effective Java(1)-创建和销毁对象

    Effective Java(1)-创建和销毁对象

  2. Java的结构之美【1】——构造对象

    当我们遇到多个构造器參数的时候可能会想到用构件器,代码例如以下: /** * 构建器 * @author 阳光小强 * */ public class Lunch { private String c ...

  3. Effective Java 读书笔记之一 创建和销毁对象

    一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...

  4. effective java 第2章-创建和销毁对象 读书笔记

    背景 去年就把这本javaer必读书--effective java中文版第二版 读完了,第一遍感觉比较肤浅,今年打算开始第二遍,顺便做一下笔记,后续会持续更新. 1.考虑用静态工厂方法替代构造器 优 ...

  5. Effective Java 学习笔记之创建和销毁对象

    一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...

  6. 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器

    类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...

  7. Effective Java——(一)创建和销毁对象

    第一条 考虑用静态工厂方法代替构造器 什么叫静态工厂方法,就是通过在类中通过静态方法对对象初始化. 比如说 public class StaticFactory { private String na ...

  8. 【Effective Java】第二章-创建和销毁对象——1.考虑用静态工厂方法代替构造器

    静态工厂方法的优点: 可以赋予一个具有明确含义的名称 可以复用唯一实例,不必每次新建 可以返回原实例类型的子类对象 可以在返回泛型实例时更加简洁 缺点: 类如果不含有共有的或者受保护的构造器,就不能被 ...

  9. Effective Java(一)—— 创建和销毁对象

    在客户端(调用端)获取自身实例的方法: 公有的构造器: 类的静态工厂方法: 1. 使用静态工厂方法代替构造器 Boolean 是对基本类型 boolean 的包装类: public final cla ...

随机推荐

  1. 【iOS】苹果,百度Map定位使用与总结

    iOS中使用较多的3款地图,google地图.百度地图.苹果自带地图(高德).当中苹果自带地图在中国使用的是高德的数据.苹果在iOS 6之后放弃了使用谷歌地图,而改用自家的地图.在国内使用的较多的就是 ...

  2. [Unity3D]Unity3D游戏开发之ACT游戏三连击效果实现综述

    各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在研究了Unity3D Mecanim动画系统的重定向特性后,今天我们继续来探索Me ...

  3. 浅谈Storm流式处理框架(转)

    Hadoop的高吞吐,海量数据处理的能力使得人们可以方便地处理海量数据.但是,Hadoop的缺点也和它的优点同样鲜明——延迟大,响应缓慢,运维复杂. 有需求也就有创造,在Hadoop基本奠定了大数据霸 ...

  4. C++ Primer中文版(第5版)

    <C++ Primer中文版(第5版)> 基本信息 作者: (美)Stanley B. Lippman(斯坦利 李普曼)    Josee Lajoie(约瑟 拉乔伊)    Barbar ...

  5. 智能指针 shared_ptr 解析

    近期正在进行<Effective C++>的第二遍阅读,书里面多个条款涉及到了shared_ptr智能指针,介绍的太分散,学习起来麻烦.写篇blog整理一下. LinJM   @HQU s ...

  6. BGP协议学习总结

    BGP学习总结 BGP是目前使用的唯一的自治系统间的路由协议,它是一种矢量路由协议,基于TCP的179号端口,它采用单播增量更新的方式更新路由,与其他的路由协议不同的是,BGP只要TCP可达,就可以建 ...

  7. 京东商城招聘自动调价系统架构师 T4级别

    岗位级别:T4 岗位职责: 1.负责自动调价系统的架构设计 2.负责自动调价的预测.相关性算法设计 3.核心代码编写,代码review 任职要求: 1.熟悉数据挖掘.机器学习理论和算法 2.熟悉海量数 ...

  8. python手记(48)

    #!/usr/bin/env python # -*- coding: utf-8 -*- #http://blog.csdn.net/myhaspl #code:myhaspl@qq.com imp ...

  9. HDOJ 3516 Tree Construction

    四边形优化DP Tree Construction Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  10. php集成环境

    apache+php+mysql是常见php环境,在windows下也称为WAMP,对于初学者自选版本搭建总是会遇到一些麻烦,下面是收集到的一些集成环境安装: 1.AppServ (推荐,简洁精简) ...