- 浏览: 81916 次
- 性别:
- 来自: 成都
-
最新评论
-
cfczdws:
唉,还有好多要学~~
css 文档流 父级对象 同级对象 -
chinalitianwu:
很有帮助 对于我这样的菜鸟来说
ServletContext与ApplicationContext -
gaoddhan:
讲的不错
hashcode 和equal -
bestree007:
execute()不是回调函数吗?
回调函数 -
talin2010:
真的很详细
JSP/Servlet编码设置详解
转自:http://zangweiren.iteye.com/blog/212592
final、finally和finalize的区别是什么?
这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。final、finally和finalize虽然长得像孪生三兄弟一样,但是它们的含义和用法却是大相径庭。这一次我们就一起来回顾一下这方面的知识。
final关键字
我们首先来说说final。它可以用于以下四个地方:
定义变量,包括静态的和非静态的。
定义方法的参数。
定义方法。
定义类。
我们依次来回顾一下每种情况下final的作用。首先来看第一种情况,如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,即它是个常量;如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的,这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。在第二种情况下,final的含义与第一种情况相同。实际上对于前两种情况,有一种更贴切的表述final的含义的描述,那就是,如果一个变量或方法参数被final修饰,就表示它只能被赋值一次,但是JAVA虚拟机为变量设定的默认值不记作一次赋值。
被final修饰的变量必须被初始化。初始化的方式有以下几种:
在定义的时候初始化。
final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。
静态final变量可以在静态初始化块中初始化,不可以在初始化块中初始化。
final变量还可以在类的构造器中初始化,但是静态final变量不可以。
通过下面的代码可以验证以上的观点:
Java代码
public class FinalTest {
// 在定义时初始化
public final int A = 10;
public final int B;
// 在初始化块中初始化
{
B = 20;
}
// 非静态final变量不能在静态初始化块中初始化
// public final int C;
// static {
// C = 30;
// }
// 静态常量,在定义时初始化
public static final int STATIC_D = 40;
public static final int STATIC_E;
// 静态常量,在静态初始化块中初始化
static {
STATIC_E = 50;
}
// 静态变量不能在初始化块中初始化
// public static final int STATIC_F;
// {
// STATIC_F = 60;
// }
public final int G;
// 静态final变量不可以在构造器中初始化
// public static final int STATIC_H;
// 在构造器中初始化
public FinalTest() {
G = 70;
// 静态final变量不可以在构造器中初始化
// STATIC_H = 80;
// 给final的变量第二次赋值时,编译会报错
// A = 99;
// STATIC_D = 99;
}
// final变量未被初始化,编译时就会报错
// public final int I;
// 静态final变量未被初始化,编译时就会报错
// public static final int STATIC_J;
}
public class FinalTest {
// 在定义时初始化
public final int A = 10;
public final int B;
// 在初始化块中初始化
{
B = 20;
}
// 非静态final变量不能在静态初始化块中初始化
// public final int C;
// static {
// C = 30;
// }
// 静态常量,在定义时初始化
public static final int STATIC_D = 40;
public static final int STATIC_E;
// 静态常量,在静态初始化块中初始化
static {
STATIC_E = 50;
}
// 静态变量不能在初始化块中初始化
// public static final int STATIC_F;
// {
// STATIC_F = 60;
// }
public final int G;
// 静态final变量不可以在构造器中初始化
// public static final int STATIC_H;
// 在构造器中初始化
public FinalTest() {
G = 70;
// 静态final变量不可以在构造器中初始化
// STATIC_H = 80;
// 给final的变量第二次赋值时,编译会报错
// A = 99;
// STATIC_D = 99;
}
// final变量未被初始化,编译时就会报错
// public final int I;
// 静态final变量未被初始化,编译时就会报错
// public static final int STATIC_J;
}
我们运行上面的代码之后出了可以发现final变量(常量)和静态final变量(静态常量)未被初始化时,编译会报错。
用final修饰的变量(常量)比非final的变量(普通变量)拥有更高的效率,因此我们在实际编程中应该尽可能多的用常量来代替普通变量,这也是一个很好的编程习惯。
当final用来定义一个方法时,会有什么效果呢?正如大家所知,它表示这个方法不可以被子类重写,但是它这不影响它被子类继承。我们写段代码来验证一下:
Java代码
class ParentClass {
public final void TestFinal() {
System.out.println("父类--这是一个final方法");
}
}
public class SubClass extends ParentClass {
/**
* 子类无法重写(override)父类的final方法,否则编译时会报错
*/
// public void TestFinal() {
// System.out.println("子类--重写final方法");
// }
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.TestFinal();
}
}
class ParentClass {
public final void TestFinal() {
System.out.println("父类--这是一个final方法");
}
}
public class SubClass extends ParentClass {
/**
* 子类无法重写(override)父类的final方法,否则编译时会报错
*/
// public void TestFinal() {
// System.out.println("子类--重写final方法");
// }
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.TestFinal();
}
}
这里需要特殊说明的是,具有private访问权限的方法也可以增加final修饰,但是由于子类无法继承private方法,因此也无法重写它。编译器在处理private方法时,是按照final方法来对待的,这样可以提高该方法被调用时的效率。不过子类仍然可以定义同父类中的private方法具有同样结构的方法,但是这并不会产生重写的效果,而且它们之间也不存在必然联系。
最后我们再来回顾一下final用于类的情况。这个大家应该也很熟悉了,因为我们最常用的String类就是final的。由于final类不允许被继承,编译器在处理时把它的所有方法都当作final的,因此final类比普通类拥有更高的效率。而由关键字abstract定义的抽象类含有必须由继承自它的子类重载实现的抽象方法,因此无法同时用final和abstract来修饰同一个类。同样的道理,final也不能用来修饰接口。final的类的所有方法都不能被重写,但这并不表示final的类的属性(变量)值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰,请看下面的例子:
Java代码
public final class FinalTest {
int i = 10;
public static void main(String[] args) {
FinalTest ft = new FinalTest();
ft.i = 99;
System.out.println(ft.i);
}
}
public final class FinalTest {
int i = 10;
public static void main(String[] args) {
FinalTest ft = new FinalTest();
ft.i = 99;
System.out.println(ft.i);
}
}
运行上面的代码试试看,结果是99,而不是初始化时的10。
finally语句
接下来我们一起回顾一下finally的用法。这个就比较简单了,它只能用在try/catch语句中,并且附带着一个语句块,表示这段语句最终总是被执行。请看下面的代码:
Java代码
public final class FinallyTest {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
System.out.println("程序抛出了异常");
} finally {
System.out.println("执行了finally语句块");
}
}
}
public final class FinallyTest {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
System.out.println("程序抛出了异常");
} finally {
System.out.println("执行了finally语句块");
}
}
}
运行结果说明了finally的作用:
程序抛出了异常
执行了finally语句块
请大家注意,捕获程序抛出的异常之后,既不加处理,也不继续向上抛出异常,并不是良好的编程习惯,它掩盖了程序执行中发生的错误,这里只是方便演示,请不要学习。
那么,有没有一种情况使finally语句块得不到执行呢?大家可能想到了return、continue、break这三个可以打乱代码顺序执行语句的规律。那我们就来试试看,这三个语句是否能影响finally语句块的执行:
Java代码
public final class FinallyTest {
// 测试return语句
public ReturnClass testReturn() {
try {
return new ReturnClass();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
return null;
}
// 测试continue语句
public void testContinue() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
continue;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
// 测试break语句
public void testBreak() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
// 测试return语句
ft.testReturn();
System.out.println();
// 测试continue语句
ft.testContinue();
System.out.println();
// 测试break语句
ft.testBreak();
}
}
class ReturnClass {
public ReturnClass() {
System.out.println("执行了return语句");
}
}
public final class FinallyTest {
// 测试return语句
public ReturnClass testReturn() {
try {
return new ReturnClass();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
return null;
}
// 测试continue语句
public void testContinue() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
continue;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
// 测试break语句
public void testBreak() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
// 测试return语句
ft.testReturn();
System.out.println();
// 测试continue语句
ft.testContinue();
System.out.println();
// 测试break语句
ft.testBreak();
}
}
class ReturnClass {
public ReturnClass() {
System.out.println("执行了return语句");
}
}
上面这段代码的运行结果如下:
执行了return语句
执行了finally语句
0
执行了finally语句
1
执行了finally语句
2
执行了finally语句
0
执行了finally语句
1
执行了finally语句
很明显,return、continue和break都没能阻止finally语句块的执行。从输出的结果来看,return语句似乎在finally语句块之前执行了,事实真的如此吗?我们来想想看,return语句的作用是什么呢?是退出当前的方法,并将值或对象返回。如果finally语句块是在return语句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被执行呢?因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的。
finalize方法
最后,我们再来看看finalize,它是一个方法,属于java.lang.Object类,它的定义如下:
Java代码
protected void finalize() throws Throwable { }
protected void finalize() throws Throwable { }
众所周知,finalize()方法是GC(garbage collector)运行机制的一部分,关于GC的知识我们将在后续的章节中来回顾。
在此我们只说说finalize()方法的作用是什么呢?
finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。
请看下面的示例:
Java代码
public final class FinallyTest {
// 重写finalize()方法
protected void finalize() throws Throwable {
System.out.println("执行了finalize()方法");
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}
public final class FinallyTest {
// 重写finalize()方法
protected void finalize() throws Throwable {
System.out.println("执行了finalize()方法");
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}
运行结果如下:
执行了finalize()方法
程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才有了上面的输出结果。调用System.gc()等同于调用下面这行代码:
Java代码
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
调用它们的作用只是建议垃圾收集器(GC)启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到JAVA虚拟机停止运行,有些对象的finalize()可能都没有被运行过,那么怎样保证所有对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:
Java代码
public static void runFinalizersOnExit(boolean value) {
//other code
}
public static void runFinalizersOnExit(boolean value) {
//other code
}
给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已经不被赞成使用了。
由于finalize()属于Object类,因此所有类都有这个方法,Object的任意子类都可以重写(override)该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。
通过以上知识的回顾,我想大家对于final、finally、finalize的用法区别已经很清楚了。
final、finally和finalize的区别是什么?
这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。final、finally和finalize虽然长得像孪生三兄弟一样,但是它们的含义和用法却是大相径庭。这一次我们就一起来回顾一下这方面的知识。
final关键字
我们首先来说说final。它可以用于以下四个地方:
定义变量,包括静态的和非静态的。
定义方法的参数。
定义方法。
定义类。
我们依次来回顾一下每种情况下final的作用。首先来看第一种情况,如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,即它是个常量;如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的,这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。在第二种情况下,final的含义与第一种情况相同。实际上对于前两种情况,有一种更贴切的表述final的含义的描述,那就是,如果一个变量或方法参数被final修饰,就表示它只能被赋值一次,但是JAVA虚拟机为变量设定的默认值不记作一次赋值。
被final修饰的变量必须被初始化。初始化的方式有以下几种:
在定义的时候初始化。
final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。
静态final变量可以在静态初始化块中初始化,不可以在初始化块中初始化。
final变量还可以在类的构造器中初始化,但是静态final变量不可以。
通过下面的代码可以验证以上的观点:
Java代码
public class FinalTest {
// 在定义时初始化
public final int A = 10;
public final int B;
// 在初始化块中初始化
{
B = 20;
}
// 非静态final变量不能在静态初始化块中初始化
// public final int C;
// static {
// C = 30;
// }
// 静态常量,在定义时初始化
public static final int STATIC_D = 40;
public static final int STATIC_E;
// 静态常量,在静态初始化块中初始化
static {
STATIC_E = 50;
}
// 静态变量不能在初始化块中初始化
// public static final int STATIC_F;
// {
// STATIC_F = 60;
// }
public final int G;
// 静态final变量不可以在构造器中初始化
// public static final int STATIC_H;
// 在构造器中初始化
public FinalTest() {
G = 70;
// 静态final变量不可以在构造器中初始化
// STATIC_H = 80;
// 给final的变量第二次赋值时,编译会报错
// A = 99;
// STATIC_D = 99;
}
// final变量未被初始化,编译时就会报错
// public final int I;
// 静态final变量未被初始化,编译时就会报错
// public static final int STATIC_J;
}
public class FinalTest {
// 在定义时初始化
public final int A = 10;
public final int B;
// 在初始化块中初始化
{
B = 20;
}
// 非静态final变量不能在静态初始化块中初始化
// public final int C;
// static {
// C = 30;
// }
// 静态常量,在定义时初始化
public static final int STATIC_D = 40;
public static final int STATIC_E;
// 静态常量,在静态初始化块中初始化
static {
STATIC_E = 50;
}
// 静态变量不能在初始化块中初始化
// public static final int STATIC_F;
// {
// STATIC_F = 60;
// }
public final int G;
// 静态final变量不可以在构造器中初始化
// public static final int STATIC_H;
// 在构造器中初始化
public FinalTest() {
G = 70;
// 静态final变量不可以在构造器中初始化
// STATIC_H = 80;
// 给final的变量第二次赋值时,编译会报错
// A = 99;
// STATIC_D = 99;
}
// final变量未被初始化,编译时就会报错
// public final int I;
// 静态final变量未被初始化,编译时就会报错
// public static final int STATIC_J;
}
我们运行上面的代码之后出了可以发现final变量(常量)和静态final变量(静态常量)未被初始化时,编译会报错。
用final修饰的变量(常量)比非final的变量(普通变量)拥有更高的效率,因此我们在实际编程中应该尽可能多的用常量来代替普通变量,这也是一个很好的编程习惯。
当final用来定义一个方法时,会有什么效果呢?正如大家所知,它表示这个方法不可以被子类重写,但是它这不影响它被子类继承。我们写段代码来验证一下:
Java代码
class ParentClass {
public final void TestFinal() {
System.out.println("父类--这是一个final方法");
}
}
public class SubClass extends ParentClass {
/**
* 子类无法重写(override)父类的final方法,否则编译时会报错
*/
// public void TestFinal() {
// System.out.println("子类--重写final方法");
// }
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.TestFinal();
}
}
class ParentClass {
public final void TestFinal() {
System.out.println("父类--这是一个final方法");
}
}
public class SubClass extends ParentClass {
/**
* 子类无法重写(override)父类的final方法,否则编译时会报错
*/
// public void TestFinal() {
// System.out.println("子类--重写final方法");
// }
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.TestFinal();
}
}
这里需要特殊说明的是,具有private访问权限的方法也可以增加final修饰,但是由于子类无法继承private方法,因此也无法重写它。编译器在处理private方法时,是按照final方法来对待的,这样可以提高该方法被调用时的效率。不过子类仍然可以定义同父类中的private方法具有同样结构的方法,但是这并不会产生重写的效果,而且它们之间也不存在必然联系。
最后我们再来回顾一下final用于类的情况。这个大家应该也很熟悉了,因为我们最常用的String类就是final的。由于final类不允许被继承,编译器在处理时把它的所有方法都当作final的,因此final类比普通类拥有更高的效率。而由关键字abstract定义的抽象类含有必须由继承自它的子类重载实现的抽象方法,因此无法同时用final和abstract来修饰同一个类。同样的道理,final也不能用来修饰接口。final的类的所有方法都不能被重写,但这并不表示final的类的属性(变量)值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰,请看下面的例子:
Java代码
public final class FinalTest {
int i = 10;
public static void main(String[] args) {
FinalTest ft = new FinalTest();
ft.i = 99;
System.out.println(ft.i);
}
}
public final class FinalTest {
int i = 10;
public static void main(String[] args) {
FinalTest ft = new FinalTest();
ft.i = 99;
System.out.println(ft.i);
}
}
运行上面的代码试试看,结果是99,而不是初始化时的10。
finally语句
接下来我们一起回顾一下finally的用法。这个就比较简单了,它只能用在try/catch语句中,并且附带着一个语句块,表示这段语句最终总是被执行。请看下面的代码:
Java代码
public final class FinallyTest {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
System.out.println("程序抛出了异常");
} finally {
System.out.println("执行了finally语句块");
}
}
}
public final class FinallyTest {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
System.out.println("程序抛出了异常");
} finally {
System.out.println("执行了finally语句块");
}
}
}
运行结果说明了finally的作用:
程序抛出了异常
执行了finally语句块
请大家注意,捕获程序抛出的异常之后,既不加处理,也不继续向上抛出异常,并不是良好的编程习惯,它掩盖了程序执行中发生的错误,这里只是方便演示,请不要学习。
那么,有没有一种情况使finally语句块得不到执行呢?大家可能想到了return、continue、break这三个可以打乱代码顺序执行语句的规律。那我们就来试试看,这三个语句是否能影响finally语句块的执行:
Java代码
public final class FinallyTest {
// 测试return语句
public ReturnClass testReturn() {
try {
return new ReturnClass();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
return null;
}
// 测试continue语句
public void testContinue() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
continue;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
// 测试break语句
public void testBreak() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
// 测试return语句
ft.testReturn();
System.out.println();
// 测试continue语句
ft.testContinue();
System.out.println();
// 测试break语句
ft.testBreak();
}
}
class ReturnClass {
public ReturnClass() {
System.out.println("执行了return语句");
}
}
public final class FinallyTest {
// 测试return语句
public ReturnClass testReturn() {
try {
return new ReturnClass();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
return null;
}
// 测试continue语句
public void testContinue() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
continue;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
// 测试break语句
public void testBreak() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
// 测试return语句
ft.testReturn();
System.out.println();
// 测试continue语句
ft.testContinue();
System.out.println();
// 测试break语句
ft.testBreak();
}
}
class ReturnClass {
public ReturnClass() {
System.out.println("执行了return语句");
}
}
上面这段代码的运行结果如下:
执行了return语句
执行了finally语句
0
执行了finally语句
1
执行了finally语句
2
执行了finally语句
0
执行了finally语句
1
执行了finally语句
很明显,return、continue和break都没能阻止finally语句块的执行。从输出的结果来看,return语句似乎在finally语句块之前执行了,事实真的如此吗?我们来想想看,return语句的作用是什么呢?是退出当前的方法,并将值或对象返回。如果finally语句块是在return语句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被执行呢?因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的。
finalize方法
最后,我们再来看看finalize,它是一个方法,属于java.lang.Object类,它的定义如下:
Java代码
protected void finalize() throws Throwable { }
protected void finalize() throws Throwable { }
众所周知,finalize()方法是GC(garbage collector)运行机制的一部分,关于GC的知识我们将在后续的章节中来回顾。
在此我们只说说finalize()方法的作用是什么呢?
finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。
请看下面的示例:
Java代码
public final class FinallyTest {
// 重写finalize()方法
protected void finalize() throws Throwable {
System.out.println("执行了finalize()方法");
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}
public final class FinallyTest {
// 重写finalize()方法
protected void finalize() throws Throwable {
System.out.println("执行了finalize()方法");
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}
运行结果如下:
执行了finalize()方法
程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才有了上面的输出结果。调用System.gc()等同于调用下面这行代码:
Java代码
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
调用它们的作用只是建议垃圾收集器(GC)启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到JAVA虚拟机停止运行,有些对象的finalize()可能都没有被运行过,那么怎样保证所有对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:
Java代码
public static void runFinalizersOnExit(boolean value) {
//other code
}
public static void runFinalizersOnExit(boolean value) {
//other code
}
给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已经不被赞成使用了。
由于finalize()属于Object类,因此所有类都有这个方法,Object的任意子类都可以重写(override)该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。
通过以上知识的回顾,我想大家对于final、finally、finalize的用法区别已经很清楚了。
发表评论
-
java浅克隆和深克隆的定义
2011-02-27 17:42 1160转自: http://wxg6203.iteye.co ... -
Java 异常类别
2010-07-15 21:34 914java中的所有异常都继承java.lang.Throwabl ... -
回调函数
2010-05-17 11:14 1131转自: http://summerbell.itey ... -
Java 反射
2010-04-20 16:01 1193转自:http://summernight.iteye.com ... -
深入探讨类加载器
2010-04-20 11:33 794转自:http://www.ibm.com/developer ... -
Java内部类可见性
2010-04-20 10:27 1084转自:http://zhangjunhd.blog.51cto ... -
Hashtable和HashMap的区别
2010-04-20 10:14 1296转自:http://edu.codepub.com/2009/ ... -
hashcode 和equal
2010-04-20 10:10 1276转自:http://lawrenst.iteye.com/bl ... -
运算符
2010-04-20 09:42 1017转自:http://zangweiren.itey ... -
多线程
2010-04-20 09:40 907转自:http://zangweiren.iteye.com/ ... -
继承、多态、重载和重写
2010-04-20 09:37 1008转自:http://zangweiren.itey ... -
基本类型
2010-04-20 09:33 1171转自:http://zangweiren.iteye.com/ ... -
日期和时间的处理
2010-04-19 22:54 832转自:http://zangweiren.iteye.com/ ... -
String杂谈
2010-04-19 18:51 774转自:http://zangweiren.iteye.com/ ... -
传了值还是传了引用
2010-04-19 18:40 646转自:http://zangweiren.iteye.com/ ... -
到底创建了几个String对象
2010-04-19 18:15 747转自:http://zangweiren.iteye.com/ ... -
类的初始化顺序
2010-04-19 17:42 454转自: http://zangweiren.iteye.com ... -
path,classpath,java_home设置详解
2010-04-19 10:31 3605转自于: http://blog.csdn.net/yinyu ...
相关推荐
java毕业设计源码,可供参考
Windows下的FRP图形化客户端,对应FRP版本0.61.1,需要64位操作系统
基于优化EKF的PMSM无位置传感器矢量控制研究_崔鹏龙.pdf
旧物置换网站的开发过程中,采用B / S架构,主要使用Java技术进行开发,结合最新流行的springboot框架。中间件服务器是Tomcat服务器,使用Mysql数据库和Eclipse开发 环境。该旧物置换网站包括管理员、用户、卖家。其主要功能包括管理员:首页、个人中心、用户管理、卖家管理、旧物类型管理、旧物信息管理、置换交易管理、系统管理等,卖家后台:首页、个人中心、旧物类型管理、旧物信息管理、置换交易管理。前台首页;首页、旧物信息、网站公告、个人中心、后台管理等,用户后台:首页、个人中心、旧物信息管理、置换交易管理、用户可根据关键字进行信息的查找自己心仪的信息等。 (1)用户功能需求 用户进入前台系统可以查看首页、旧物信息、网站公告、个人中心、后台管理等操作。前台首页用例如图3-1所示。 (2)管理员功能需求 管理员登陆后,主要功能模块包括首页、个人中心、用户管理、卖家管理、旧物类型管理、旧物信息管理、置换交易管理、系统管理等功能。 关键词:旧物置换网站,Mysql数据库,Java技术 springboot框架
项目工程资源经过严格测试运行并且功能上ok,可实现复现复刻,拿到资料包后可实现复现出一样的项目,本人系统开发经验充足(全栈全领域),有任何使用问题欢迎随时与我联系,我会抽时间努力为您解惑,提供帮助 【资源内容】:包含源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可实现复现;设计报告也可借鉴此项目;该资源内项目代码都经过测试运行;功能ok 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 【提供帮助】:有任何使用上的问题欢迎随时与我联系,抽时间努力解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 下载后请首先打开说明文件(如有);整理时不同项目所包含资源内容不同;项目工程可实现复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
航天模拟器文件、蓝图、代码
两级式单相光伏并网仿真研究:MATLAB 2021a版本下的DC-DC变换与桥式逆变技术实现功率跟踪与并网效果优化,基于Matlab 2021a的两级式单相光伏并网仿真研究:实现最大功率跟踪与稳定的直流母线电压,两级式单相光伏并网仿真(注意版本matlab 2021a) 前级采用DC-DC变电路,通过MPPT控制DC-DC电路的pwm波来实现最大功率跟踪,mppt采用扰动观察法,后级采用桥式逆变,用spwm波调制。 采用双闭环控制,实现直流母线电压的稳定和单位功率因数。 并网效果良好,thd满足并网要求,附带仿真说明文件 ,两级式单相光伏并网仿真; MATLAB 2021a; DC-DC变换电路; MPPT控制; 扰动观察法; 桥式逆变; SPWM波调制; 双闭环控制; 直流母线电压稳定; 单位功率因数; 并网效果; THD。,MATLAB 2021a双闭环控制两级式单相光伏并网仿真研究
光伏MPPT仿真研究:光照强度和温度对太阳能电池输出特性的影响及调整策略,助力光伏发电学习。,光伏MPPT仿真研究:光照强度和温度对太阳能电池输出特性的影响及调整策略学习指南,光伏mppt仿真:通过调整太阳光照, 温度等因素 , 光照强度和温度对太阳能电池输出特性的影响。 可用于学习光伏发电 ,光伏MPPT仿真;太阳光照调整;温度影响;光照强度;太阳能电池输出特性。,光伏MPPT仿真:光照与温度对太阳能电池输出特性的影响研究
随着互联网技术的高速发展,人们生活的各方面都受到互联网技术的影响。现在人们可以通过互联网技术就能实现不出家门就可以通过网络进行系统管理,交易等,而且过程简单、快捷。同样的,在人们的工作生活中,也就需要互联网技术来方便人们的日常工作生活,实现工作办公的自动化处理,实现信息化,无纸化办公。 本课题在充分研究了在Springboot框架基础上,采用B/S模式,以Java为开发语言,MyEclipse为开发工具,MySQL为数据管理平台,实现的内容主要包括首页,个人中心,综合管理等功能。
航天模拟器文件、蓝图、代码
西门子Smart PLC四轴搬运取料机案例程序:从新手到项目的跃升之路,西门子Smart PLC四轴搬运取料机运动控制案例程序——PLC通信与伺服电机自动化控制解决方案,西门子200smart运动控制四轴搬运取料机案例程序 该程序为两台smart plc通过通讯控制四轴伺服电机的搬运取料机案例工程案例程序。 包含200smar_PLC程序+项目电气接线图(PDF图纸)+程序流程说明+触摸屏程序(步科) 程序包括伺服电机的启动,停止,原点定位,回归原点,位置控制以及方向控制。 包括了所有控制伺服电机的指令,里面有指令的用法的详细解释和程序说明。 拿来就能用的案例程序,结合程序案例中学习,就会轻松快速的掌握。 让你从新手直接能做项目。 动作流程: 客户上好料盒,M1轴伺服跑到第一片料的位置,气缸将料推出到上位置, M2轴在上料位置取件后移动到直线电机的,加工位置,m2轴上通过有上料下料的气缸, 用真空吸住料后m2轴移动到一个二维平台的加工位置,把带加工的料放到加工位置后, 激光器开始加工,加工完成后,通过M2轴把料取下,移动到成品放料位置,放料后, M3轴将成品料推送到M4
航天模拟器文件、蓝图、代码
基于双碳背景下阶梯式碳交易机制与电制氢的综合能源系统热电优化策略研究与求解分析,基于双碳背景下阶梯式碳交易机制与电制氢的综合能源系统热电优化策略及经济性研究,考虑阶梯式碳交易机制与电制氢的综合能源系统热电优化 “双碳”背景下,为提高能源利用率,优化设备的运行灵活性,进一步降低综合能源系统(IES)的碳排放水平,提出一种IES低碳经济运行策略。 首先考虑IES参与到碳交易市场,引入阶梯式碳交易机制引导IES控制碳排放;接着细化电转气(P2G)的两阶段运行过程,引入电解槽、甲烷反应器、氢燃料电池(HFC)替传统的P2G,研究氢能的多方面效益;最后提出热电比可调的热电联产、HFC运行策略,进一步提高IES的低碳性与经济性。 基于此,构建以购能成本、碳排放成本、弃风成本最小的低碳经济运行目标,将原问题转化为混合整数线性问题,运用CPLEX商业求解器进行求解,通过设置多个运行情景,对比验证了所提策略的有效性。 关键词:氢能;阶梯式碳交易机制;热电比可调;综合能源系统;低碳经济 ,关键词:阶梯式碳交易机制;综合能源系统(IES);热电优化;设备运行灵活性;碳排放水平;电转气(P2G);电解槽;氢
MMC分布式储能系统:实现恒功率与恒电压控制的无缝切换技术,MMC分布式储能系统实现恒功率与恒电压控制的无缝切换技术,mmc分布式储能 恒功率控制 恒电压控制 无缝切 ,核心关键词:MMC分布式储能; 恒功率控制; 恒电压控制; 无缝切换。,MMC分布式储能系统:恒功率与恒电压控制的无缝切换技术
多频多快拍稀疏贝叶斯学习目标方位序贯估计_牛海强.pdf
交错并联Boost PFC仿真电路模型:双闭环控制方式下的输出电压与电感电流优化控制,优良波形及Simulink仿真实现,交错并联Boost PFC仿真电路模型:双闭环控制方式下的电压外环与电感电流内环优化,优质波形表现于Simulink仿真中,交错并联Boost PFC仿真电路模型 采用输出电压外环,电感电流内环的双闭环控制方式 交流侧输入电流畸变小,波形良好,如效果图所示 simulink仿真 matlab simulink仿真模型 无报告哈 ,核心关键词:交错并联Boost PFC仿真电路模型;双闭环控制方式;输出电压外环;电感电流内环;交流侧输入电流畸变小;波形良好;Simulink仿真;Matlab Simulink仿真模型。,基于Simulink仿真的交错并联Boost PFC双闭环控制模型优化研究
基于53#三菱PLC与组态王系统的音乐喷泉控制系统设计与组态设计探讨,基于53#三菱PLC的组态王音乐喷泉控制系统设计与实现:音乐喷泉组态设计的探索与实践,53#三菱PLC和组态王音乐喷泉控制系统设计音乐喷泉组态设计音乐喷泉 ,53#三菱PLC; 组态王音乐喷泉控制系统设计; 音乐喷泉组态设计; 音乐喷泉,三菱PLC与组态王协同音乐喷泉控制系统设计
(要求1)基于随机博弈的无人机集群动态对抗决策.pdf
基于特征值与特征向量的计算,实现MATLAB代码进行参与因子分析研究,特征值与特征向量计算:MATLAB代码实现因子分析的方法与步骤,特征值、左右特征向量计算,参与因子分析MATLAB代码 ,特征值; 左右特征向量计算; 参与因子分析; MATLAB代码,MATLAB中特征值与左右特征向量计算,助力因子分析
基于Matlab的无线充电仿真研究:四套模型解析——LLC谐振恒压输出、LCC-S拓扑磁耦合谐振恒压输出、LCC-P拓扑磁耦合谐振恒流输出及S-S拓扑补偿模型探究,基于Matlab的无线充电仿真研究:四套模型深度解析——LLC谐振器恒压输出与磁耦合谐振无线电能传输技术,无线充电仿真 simulink 磁耦合谐振 无线电能传输 MCR WPT lcc ss llc拓扑补偿 基于matlab 一共四套模型: 1.llc谐振器实现12 24V恒压输出 带调频闭环控制 附参考和讲解视频 2.lcc-s拓扑磁耦合谐振实现恒压输出 附设计过程和介绍 3.lcc-p拓扑磁耦合谐振实现恒流输出 附设计过程 4.s-s拓扑补偿 带原理分析,仿真搭建讲解和参考,可依据讲解自行修改参数建模 四套打包 ,无线充电仿真; Simulink; 磁耦合谐振; 无线电能传输; MCR; WPT; LLC拓扑补偿; LCC-S拓扑; 调频闭环控制; 设计过程; 恒压输出; 恒流输出; 参数建模。,基于Matlab Simulink的无线充电仿真模型:MCR WPT的LLC、LCC-S、LCC-P及S-S拓扑研