您现在的位置: 万盛学电脑网 >> 程序编程 >> 网络编程 >> jsp编程 >> 正文

java中final, finally, finalize的区别

作者:佚名    责任编辑:admin    更新时间:2022-06-22

   final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载。

  final变量定义: 变量一经初始化就不能指向其它对象。指向的存储地址不可修改,但指向的对象本身是可以修改的。

  先说final变量初始化:

  很多文章都这么说:其初始化可以在两个地方,一是其定义处,二是在构造函数中,两者只能选其一。

  胡说八道!

  final变量可以在任何可以被始化的地方被始化,但只能被初始化一次.一旦被初始化后就不能再次赋

  值(重新指向其它对象),作为成员变量一定要显式初始化,而作为临时变量则可以只定义不初始化(当然也不能引用)

  即使是作为一个类中的成员变量,也还可以在初始化块中初始化,所以"其初始化可以在两个地方,一是其定义处,

  二是在构造函数中,两者只能选其一"是错误的.

  作为成员变量时,final字段可以设计不变类,是不变类的一个必要条件但不是一个充要条件.至少可以保证字段不

  会以setXXX()这样的方式来改变.但无法保证字段本身不被修改(除非字段本身也是不变类);

  对于方法参数的final变量:

  对于方法参数的变量定义为final,90%以上的文章都说"当你在方法中不需要改变作为参数的对象变量时,明确使

  用final进行声明,会防止你无意的修改而影响到调用方法外的变量。"

  胡说八道!

  我不知道这个修改是说重新赋值还是修改对象本身,但无论是哪种情况,上面的说法都是错误的.

  如果是说重新赋值,那么:

代码如下  

public static void test(int[] x){
x = new int[]{1,2,3};
}

int[] out = new int[]{4,5,6};
test(out);
System.out.println(out[0]);
System.out.println(out[1]);
System.out.println(out[2]);

  调用test(out);无论如何也不会影响到外面变量out.你加不加final根本没有意义.final只会强迫方法内

  多声明一个变量名而已,即把x = new int[]{1,2,3};改成int y = new int[]{1,2,3}; 其它没有任何实际意义.

  如果说是修改对象本身:

代码如下   public static void test(final int[] x){
x[0] = 100;
}
int[] out = new int[]{4,5,6};
test(out);
System.out.println(out[0]);

  难道你用final修饰就不可以修改了?所以说对于方法参数中final是为了不影响调用方法外的变量那是胡说八道的.

  那我们到底为什么要对参数加上final?其实对方法参数加final和方法内变量加上final的作用是相同的,即为了将它们

  传给内部类回调方法:

代码如下  

abstract class ABSClass{
public abstract void m();
}

  现在我们来看,如果我要实现一个在一个方法中匿名调用ABSClass.应该:

代码如下  

public static void test(String s){
//或String s = "";
ABSClass c = new ABSClass(){
public void m(){
int x = s.hashCode();

System.out.println(x);

}
};
//其它代码.
}

  注意这里,一般而言,回调方法基本上是在其它线程中调用的.如果我们在上面的

代码如下  

ABSClass c = new ABSClass(){
public void m(){
int x = s.hashCode();

System.out.println(x);

}
};

  后面直接调用c.m();应该是没有意义的.但这不重要,重要的是只要有可能是在其它线程中调用,那我们就必须

  为s保存引用句柄.

  我们先来看GC工作原理,JVM中每个进程都会有多个根,每个static变量,方法参数,局部变量,当然这都是指引用类型.

  基础类型是不能作为根的,根其实就是一个存储地址.

  GC在工作时先从根开始遍历它引用的对象并标记它们,如此递归到最末梢,所有根都遍历后,没有被标记到的对象说明没

  有被引用,那么就是可以被回收的对象(有些对象有finalized方法,虽然没有引用,但JVM中有一个专门的队列引用它

  们直到finalized方法被执行后才从该队列中移除成为真正没有引用的对象,可以回收,这个与本主题讨论的无关,包括

  代的划分等以后再说明).这看起来很好.

  但是在内部类的回调方法中,s既不可能是静态变量,也不是方法中的临时变量,也不是方法参数,它不可能作为根,在内部类

  中也没有变量引用它,它的根在内部类外部的那个方法中,如果这时外面变量重指向其它对象,则这个对象就失去了引用,

  可能被回收,而由于内部类回调方法大多数在其它线程中执行,可能还要在回收后还会继续访问它.这将是什么结果?

  而使用final修饰符不仅会保持对象不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.所以这才是final

  变量和final参数的根本意义.

  finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch子句就会执行,然后控制就会进入 finally 块(如果有的话)。

  我们翻遍上古秘籍,最终在北京山顶洞人的失传宝典《呼呼,擦!》中发现了一个据称绝对干净的擦法,那就是------------

  一下一下擦!

  具体操作办法如下:

  代码

代码如下   void f(){
final Connection conn = ...;
try{
final Statement stmt = ...;
try{
final ResultSet rset = ...;
try{
...
}
finally{rset.close();}
}
finally{stmt.close();}
}
finally{conn.close();}
}

  其诀窍就是,每建立一个需要清理的资源,就用一个try-finally来保证它可以被清理掉。

  如此,任何时候,你都是屁股干干静静地离开卫生间。

  哪。好多圣人门徒跟我说:这样一下一下擦,姿势非常不雅观(看看那嵌套的try块吧),有违古礼。我们反对!

  靠,你说孔丑儿古还是山顶洞人古??

  屁股还泛着味儿呢,还拽什么“雅”?

  而且,要是死要面子,也可以拉个帘子,擦的时候别让人看见嘛。比如:

  代码

代码如下