您的位置:首页 > 其它

static和他的好基友

2015-08-26 08:57 211 查看



static和他的好基友

--模范青蛙
谈及final和static这两个关键字,学过Java的人多少都应该对他们有些印象,至于了解的多少,跟个人的程度有关,笔者在此总结final和static旨在帮助同僚加深印象,或许我对他们的认识也有不足之处,在此希望查阅此博文的大神帮忙雅正。
首先我们来谈一下final这个关键字
下面先介绍一下我们的程序中都哪些地方会用到final这个关键字:
1.使用匿名内部类的时候
2.声明变量的时候
3.声明方法的时候
4.声明类的时候
5.声明常量
接下来我们分析一下在不同地方使用时,他们分别有什么作用:
1.使用匿名内部类的时候:
在匿名类中所有变量都必须是final变量。
因为当内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它的时候,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命,拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。
拷贝保证生命周期的延续,final保证引用一致性。这样就可以保证内部类的对象可以在其有限的生命里访问到外部类的局部变量。
2.声明变量的时候:
final变量是只读的。
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象,注意这里说的是引用所指向的地址不可变。
一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编译错误。
没有在声明时初始化final变量的称为空白final变量(blank final variable),它们必须在构造器中初始化,或者调用this()初始化。不这么做的话,编译器会报错“final变量(变量名)需要进行初始化”。
3.声明方法的时候:
在方法上使用final一般有两种目的:
1>觉得自己写的方法很牛..,不需要通过继承来做任何的改动。
2>是为了提高效率,final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
《Java编程思想》中说道:在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能就看不到内嵌调用带来的任何性能提升。所以在最近的Java版本中,不需要使用final方法进行这些优化了。

final修饰类中的方法可以被继承,但继承后不能被重写。
4.声明类的时候:如果你看到一个类被final修饰了,那就说明这个类是不可以被继承的(大多数被final修饰的类都是很牛..的类)有一点需要在这里提一下,被final修饰的类中的所有成员方法都会被隐式的指定为final方法(意思就是:不管你写方法的时候写或不写final,这个方法体前面都会默认有一个final修饰的,就是这么任性,记住吧),成员变量则不是这样,这个可以根据你自己的需要考虑是否将它设为final。
final和abstract这两个关键字是反相关的,final类就不可能是abstract的,这个你可以考虑一下,抽象的类中包含抽象的方法和非抽象的方法,那些抽象的方法是需要通过继承来实现抽象类中的抽象方法的,而final修饰的类时不可以被继承的,所以final修饰的类不可能是abstract。
Java中有许多类是final的,例如String, Interger以及其他包装类。它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销。
5.接口中声明的常量本身是final的。

注意:类的private方法会隐式地被指定为final方法。
曾经看到过这样一道面试题:

byte a=1;

byte b=1;

byte c=a+b;

System.out.println(c);

问运行程序会输出结果吗?如果不能,请在前两行代码分别添加一个关键字,使程序可以执行。

这道题看上去是1+1=2的问题,实际上隐含着自动类型转换的知识。

a,b可以自动类型提升为int类型的变量,执行第三行代码的时候,程序把一个int类型的值赋值给了byte类型的变量,这就是问题的根源。了解到这里,下面就好办了。前面不是说a和b自动类型提升了吗?我们只需要阻止他们类型提升就可以了。最简单的做法就是在变量类型前面加上final.

final byte a=1;

final byte b=3;

byte c=a+b;

这样程序就不会出错了。

下面我们来聊一下另一个关键字static

在《Java编程思想》中给static方法下了这样一个定义:

“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”

static关键字经常出现在我们的程序中的那个位置?

1.成员方法

2.成员变量

3.静态代码块

4.内部类(枚举,接口)

static的特点:

1)随着类的加载而加载,也会随着类的消失而消失,它的生命周期最长。

2)优先于对象存在。静态先存在(JVM加载类的时候就存在了),对象后存在。

3)被所有对象所共享。

4)可以直接被类名所调用。

1.static修饰成员方法时:

被static修饰的方法都是静态方法,可以直接通过类名调用。有的书籍上成称static方法是没有this的方法。这样说也是有道理的,因为静态方法的调用是不依赖任何对象的,没有了对象何谈this呢?也正是因为静态方法的这个特性,才有了在静态方法中不能访问类的非静态成员变量和非静态成员方法的限制。因为非静态的成员方法/变量都是需要依靠对象才能够被调用的。但是我们可以在非静态成员方法中访问静态成员方法/变量。

我们最常见的static方法就是main()方法了,一敲代码都是“public static void main(String[] args)”,这成了固定的模式,可是有没有想过为什么要这样写呢?

下面我来分析一下这行代码的本意:

1)为什么要用public---》因为main()是Java虚拟机调用的,因此必须为public

2)为什么是static静态的---》虚拟机在调用main()方法的时候没有创建任何对象,而又必须调用这个mian()他是程序的入口,所以把main()声明为static

3)为什么是void()---》虚拟机调用main()方法不需要返回值,所以声明为void

2.static修饰的成员变量

static修饰的成员变量也称为静态变量。

静态变量和非静态变量的区别是:

静态变量被所有的对象所共享,在内存中只有一个副本,它只在类初次加载时会被初始化。

非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

Java规定:static不允许用来修饰局部变量(至于为什么,自己没事可以琢磨一下)。

3.static代码块

可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。

4.内部类:在进行代码程序测试的时候,如果在每一个Java源文件中都设置一个主方法(主方法是应用程序的入口,必须具有),就会出现很多额外的代码。而且最主要的是这段主程序的代码对于Java文件来说,只是一个形式,其本身并不需要这种主方法。但是少了这个主方法又是万万不行的。在这种情况下,就可以将主方法写入到静态内部类中,从而不用为每个Java源文件都设置一个类似的主方法。这对于代码测试是非常有用。在一些中大型的应用程序开发中,则是一个常用的技术手段。

一个enum是不可能被改变的,它只是列举了一些值,共使用者选择,不可以被修改。

接口中定义常量时需要public static final

使用static想必大家都知道了,其实他还有一些弊端:

生命周期过长。访问上存在局限性(静态只能访问静态)这一点是无法避免的,如果没有这个局限性(你可以想象该是有多乱)

final和static

static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变。final变量经常和static关键字一起使用,作为常量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: