许多程序设计语言都有自己的办法告诉编译器某个数据是“常数”。常数主要应用于下述两个方面:
  (1) 编译期常数,它永远不会改变
  (2) 在运行期初始化的一个值,我们不希望它发生变化
  对于编译期的常数,编译器(程序)可将常数值“封装”到需要的计算过程里。也就是说,计算可在编译期间提前执行,从而节省运行时的一些开销。在Java中,这些形式的常数必须属于基本数据类型(Primitives),而且要用final关键字进行表达。在对这样的一个常数进行定义的时候,必须给出一个值。
无论static还是final字段,都只能存储一个数据,而且不得改变。
  若随同对象句柄使用final,而不是基本数据类型,它的含义就稍微让人有点儿迷糊了。对于基本数据类型,final会将值变成一个常数;但对于对象句柄,final会将句柄变成一个常数。进行声明时,必须将句柄初始化到一个具体的对象。而且永远不能将句柄变成指向另一个对象。然而,对象本身是可以修改的。Java对此未提供任何手段,可将一个对象直接变成一个常数(但是,我们可自己编写一个类,使其中的对象具有“常数”效果)。这一限制也适用于数组,它也属于对象。
下面是演示final字段用法的一个例子:

// The effect of final on fields

class Value {
int i = 1;
} public class FinalData {
// Can be compile-time constants
final int i1 = 9;
static final int I2 = 99;
// Typical public constant:
public static final int I3 = 39;
// Cannot be compile-time constants:
final int i4 = (int)(Math.random()*20);
static final int i5 = (int)(Math.random()*20); Value v1 = new Value();
final Value v2 = new Value();
static final Value v3 = new Value();
//! final Value v4; // Pre-Java 1.1 Error:
// no initializer
// Arrays:
final int[] a = { 1, 2, 3, 4, 5, 6 }; public void print(String id) {
System.out.println(
id + ": " + "i4 = " + i4 +
", i5 = " + i5);
}
public static void main(String[] args) {
FinalData fd1 = new FinalData();
//! fd1.i1++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(); // OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++; // Object isn't constant!
//! fd1.v2 = new Value(); // Error: Can't
//! fd1.v3 = new Value(); // change handle
//! fd1.a = new int[3]; fd1.print("fd1");
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData();
fd1.print("fd1");
fd2.print("fd2");
}
}

  由于i1和I2都是具有final属性的基本数据类型,并含有编译期的值,所以它们除了能作为编译期的常数使用外,在任何导入方式中也不会出现任何不同。I3是我们体验此类常数定义时更典型的一种方式:public表示它们可在包外使用;Static强调它们只有一个;而final表明它是一个常数。注意对于含有固定初始化值(即编译期常数)的fianl static基本数据类型,它们的名字根据规则要全部采用大写。也要注意i5在编译期间是未知的,所以它没有大写。
不能由于某样东西的属性是final,就认定它的值能在编译时期知道。i4和i5向大家证明了这一点。它们在运行期间使用随机生成的数字。例子的这一部分也向大家揭示出将final值设为static和非static之间的差异(文末对此结合实例作出了更加详细的解答)。只有当值在运行期间初始化的前提下,这种差异才会揭示出来。因为编译期间的值被编译器认为是相同的。这种差异可从输出结果中看出:

fd1: i4 = 15, i5 = 9
Creating new FinalData
fd1: i4 = 15, i5 = 9
fd2: i4 = 10, i5 = 9

  注意对于fd1和fd2来说,i4的值是唯一的,但i5的值不会由于创建了另一个FinalData对象而发生改变。那是因为它的属性是static,而且在载入时初始化,而非每创建一个对象时初始化。
  从v1到v4的变量向我们揭示出final句柄的含义。正如大家在main()中看到的那样,并不能认为由于v2属于final,所以就不能再改变它的值。然而,我们确实不能再将v2绑定到一个新对象,因为它的属性是final。这便是final对于一个句柄的确切含义。我们会发现同样的含义亦适用于数组,后者只不过是另一种类型的句柄而已。将句柄变成final看起来似乎不如将基本数据类型变成final那么有用。

2. 空白final
  Java允许我们创建“空白final”,它们属于一些特殊的字段。尽管被声明成final,但却未得到一个初始值。无论在哪种情况下,空白final都必须在实际使用前得到正确的初始化。而且编译器会主动保证这一规定得以贯彻。然而,对于final关键字的各种应用,空白final具有最大的灵活性。举个例子来说,位于类内部的一个final字段现在对每个对象都可以有所不同,同时依然保持其“不变”的本质。下面列出一个例子:

// "Blank" final data members

class Poppet { }

public class BlankFinal {
final int i = 0; // Initialized final
final int j; // Blank final
final Poppet p; // Blank final handle
// Blank finals MUST be initialized
// in the constructor:
BlankFinal() {
j = 1; // Initialize blank final
p = new Poppet();
}
BlankFinal(int x) {
j = x; // Initialize blank final
p = new Poppet();
}
public static void main(String[] args) {
BlankFinal bf = new BlankFinal();
}
}

  现在强行要求我们对final进行赋值处理——要么在定义字段时使用一个表达 式,要么在每个构建器中。这样就可以确保final字段在使用前获得正确的初始化。

3. final自变量
  Java允许我们将自变量设成final属性,方法是在自变量列表中对它们进行适当的声明。这意味着在一个方法的内部,我们不能改变自变量句柄指向的东西。如下所示:

// Using "final" with method arguments

class Gizmo {
public void spin() {}
} public class FinalArguments {
void with(final Gizmo g) {
//! g = new Gizmo(); // Illegal -- g is final
g.spin();
}
void without(Gizmo g) {
g = new Gizmo(); // OK -- g not final
g.spin();
}
// void f(final int i) { i++; } // Can't change
// You can only read from a final primitive:
int g(final int i) { return i + 1; }
public static void main(String[] args) {
FinalArguments bf = new FinalArguments();
bf.without(null);
bf.with(null);
}
}

  注意此时仍然能为final自变量分配一个null(空)句柄,同时编译器不会捕获它。这与我们对非final自变量采取的操作是一样的。
  方法f()和g()向我们展示出基本类型的变量为final时会发生什么情况:我们只能读取自变量,不可改变它。

static final 与 final 与 static 的区别

我们先看个小例子,代码如下:

public final class EmployeeModel {
private final String firstName;
private final String lastName;
//按上面方式定义,运行正常
//进行如下改动
//private static final String firstName;
//private static final String lastName;
//结果出错,显示“空白终态字段 firstName 可能尚未初始化”
//再进行相应改动
   //private static String firstName;
//private static String lastName;
//结果运行正常
public EmployeeModel(String fn,String ln)
{
firstName=fn;
lastName=ln;
} public String getFirstName(){
return firstName;
} public String getLastName(){
return lastName;
}
}

对于以上3中情况结合上知识作出以下解释说明:

第一种情况:

  java 中final定义的成员变量并不一定必须在定义的时候初始化,final本身的含义是一旦赋值以后不可更改变量的值,final定义的变量只要在实际的类的对象在使用前得到初始化即可

故可在构造方法中进行初始化(2.空白final中的实例亦可说明该问题)

第二种情况:

  进行如下修改后便不会出现问题:

 private static final String firstName;
private static final String lastName;
static{
firstName = "";
lastName = "";
}

  原因是:static是独立于对象实例的,static的final变量,要么在静态代码块里面进行初始化,要么在定义的时候进行初始化。(JAVA没有实现静态的构造方法)
  而非static的final变量,要么在构造函数进行初始化,要么在实例代码块进行初始化。

  因此final如果没有在定义时初始化,则一定要在构造器里面初始化,该种情况将其声明成static后,它不能在构造器里面初始化,转而要用静态代码块才能初始化。(静态方法只能初始化静态变量)

第三种情况:

  定义为static类型变量后,若未进行初始化,JAVA将自己对其进行默认的初始化,如int类型默认为0.

java中的final与static的更多相关文章

  1. 理解Java中的final和static关键字

    回顾这两个关键字前,先考虑一个问题: Static变量存储在JVM中的位置,或者说static变量是如何被加载的? JVM会把类的静态方法和静态变量在类加载的过程中读入方法区(Method Area) ...

  2. [转] Java中的final、static、this、super

    final 关键字 final关键字主要用在三个地方:变量.方法.类. 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,则在对其初始化之后便 ...

  3. Java中的final和static

    final final可以用在类.方法.变量上. 1.final用在类上,表明当前类它不能被继承,没有子类. 2.final用在方法上,表明当前方法不能被override,不能被重写. 3.final ...

  4. 浅析Java中的final关键字(转载)

    自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...

  5. 关于Java中的final关键字

    Java中的final关键字是用来限制用户行为的,说白了,就是用来限制我们这些程序员的.final可以用来修饰:变量.方法.类. 1)Java final variable final用来修饰变量时, ...

  6. 深入理解Java中的final关键字

    Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...

  7. 浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  8. (转)深入理解Java中的final关键字

    转自:http://www.importnew.com/7553.html Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方 ...

  9. [转载]浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

随机推荐

  1. 基于keepalived 实现VIP转移,lvs,nginx的高可用

    转自:http://www.tuicool.com/articles/eu26Vz 一.Keepalived 高可用集群的解决方案 二.VRRP的有限状态机 三.利用keepalived 实现主从VI ...

  2. (中等) POJ 2948 Martian Mining,DP。

    Description The NASA Space Center, Houston, is less than 200 miles from San Antonio, Texas (the site ...

  3. greenDAO简介

    了解android开发的人应该都会知道,android的数据库开发主要用到sqlite.greenDAO应该算是当前最火的数据库开源框架了吧,它是一个移动开发的ORM(object / relatio ...

  4. 在IOS应用中从竖屏模式强制转换为横屏模式

    http://www.cnblogs.com/mrhgw/archive/2012/07/18/2597218.html 在 iPhone 应用里,有时我们想强行把显示模式从纵屏改为横屏(反之亦然), ...

  5. 学习wcf

    链接请看下面 第一部分:http://boytnt.blog.51cto.com/966121/796884 第二部分:http://boytnt.blog.51cto.com/966121/7969 ...

  6. iOS开发:创建真机调试证书 分类: ios相关 2015-04-10 10:22 149人阅读 评论(0) 收藏

    关于苹果iOS开发,笔者也是从小白过来的,经历过各种困难和坑,其中就有关于开发证书,生产证书,in_house证书,add_Hoc证书申请过程中的问题,以及上架发布问题.今天就着重说一下关于针对于苹果 ...

  7. leetcode--003 LRU cache

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABHAAAACmCAIAAAA9PO+sAAAgAElEQVR4nO3du3HbytvH8X8zqoB12A ...

  8. HTML CSS基础(三)

    3种列表:有序列表.无序列表和定义列表 表1 3种列表记忆 标签 语义 说明 ol ordered list 有序列表 ul unordered list 无序列表 dl definition lis ...

  9. TSP问题[动态规划]

    分析: 有用的量:城市集合V={a,b,c,d,--} 所以我们用 T(i,V) 表示从 城市 i 出发遍历集合 V 中的城市一遍且仅一遍后回到 i 所用的最少费用(这里可能表达不好,底下会看到,但是 ...

  10. linux设置好IP后,可以访问内网,不能访问外网

    1,设置网卡,ip vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 #描述网卡对应的设备别名,例如ifcfg-eth0的文件中它为et ...