您的位置:首页 > 编程语言 > Java开发

Java学习篇之---修饰符final详解

2015-11-23 04:30 471 查看
Java学习篇之---[b]修饰符final详解[/b]
最近又翻看了一遍Java的基础知识,发现当初自己关于修饰符final的理解就曾经迷茫过,为了帮助Java初学者更好度过迷茫期,特此献上此文(此文将重点讲解final修饰的变量,至于final修饰的类和方法,由于比较简单,就不再下面列出了)。

一、概述:

final关键字可用于修饰类、变量和方法。final修饰变量时,表示该变量一旦获得了初始值就不可被改变(可以赋初值,但是不可以被改变),final既可以修饰成员变量(包括类变量和实例变量),也可以修饰局部变量、形参。

二、final成员变量:

1) 类变量:

final修饰类变量,要么在定义该类变量时指定初始值;要么在静态初始化块中指定初始值。

/*正确代码演示*/
public class FinalClassTest{
final static int a=210;//在定义该类变量时指定初始值;
final static int b;

static{
b=211;//在静态初始化块中指定初始值;
}
}

/*错误代码演示*/
public class FinalClassErrorTest{
final static int aa=110;
final static int bb;
//系统不会为final成员变量(类变量和实例变量)进行隐形初始化;而此类变量既没有在定义时指定初始值,又没有在静态初始化块中指定初始值,所以非法。

final static int cc;

static{
aa=111;//类变量已经定义了初始值,不能再次赋值,因此此语句非法;
}

public void finalClassChange(){
bb=112;//在普通方法中为类变量赋值,因此此语句非法;
}
}



2) 实例变量:

final修饰实例变量,要么在定义该实例变量时指定初始值;要么在普通初始化块中指定初始值;要么在构造器中指定初始值。

/*正确代码演示*/
public class FinalInstanceTest{
final int c=310;//在定义该实例变量时指定初始值;
final int d;
final int e;

{
d=311;//在普通初始化块中指定初始值;
}

public FinalInstanceTest(){
e=312;//在构造器中指定初始值;
}
}

/*错误代码演示*/
public class FinalInstanceErrorTest{
final int cc=410;
final int dd;
//系统不会为final成员变量(类变量和实例变量)进行隐形初始化;而此实例变量既没有在定义时指定初始值,又没有在普通初始化块中指定初始值,又没有在构造器中赋值,所以非法。

final int ee;

{
cc=411;//实例变量已经定义了初始值,不能再次赋值,因此此语句非法;
}

public void finalInstanceChange(){
dd=412;//在普通方法中为实例变量赋值,因此此语句非法;
}

public FinalInstanceErrorTest(){

}
}



三、final局部变量:

系统不会对局部变量进行隐形初始化,需要程序员显性初始化。

public class FinalLocalTest{

public void invokTest(final int f){

f=510;//对final修饰的形参变量赋值,非法;

//该方法被调用时,由系统根据传入的参数来对形参完成初始化;

}

public void mainTest(){

final int g=511;//定义final变量时指定初始值,合法;

final int h;

h=512;//第一次赋初始值,合法;

}
}


四、final修饰基本类型变量和引用类型变量的区别:

final修饰基本类型变量时,不能对基本类型变量重新赋值;对于引用类型而言,它保存的只是一个引用,final只保证这个引用类型变量所引用的地址不变,即一直引用同一个对象,但是这个对象的成员可以改变;



class Student{
privte int age;
public Student(int age){

this.age=age;

}
//此处省略age的setter和getter方法;
}

public class FinalReferenceTest{

public static void main(String[]  args){
//final修饰数组变量,iArray是一个引用变量;
 final int[] iArray={5,6,7,8};
 Arrays.sort(iArray);//对数组元素进行排序,合法;
iArray[3]=9;//对数组元素赋值,合法;
iArray=null;//对iArray重新赋值,非法;
final Student st=new Student(21);
st.setAge(23);//改变Student对象的age实例变量,合法;
st=null;//对st重新赋值,非法;
}
}


五、可执行"宏替换"的final变量:

对于一个final变量而言,不管是类变量、实例变量还是局部变量,只要该变量满足以下三条,则final变量就不再是一个变量,而是相当于是一个直接值:

1、使用final修饰符修饰;

2、在定义该final变量时指定了初始值;

3、该初始值可以在编译时就确定下来。

public class MacroFinalTest{
public static void main(String[] args){
final String domainName="pplns.com";
final String domain="pplns"+".com";
System.out.println(domainName==domain);//返回值为true;

final String domainPrefix="pplns";
final String domainSuffix=".com";
final String myDomain=domainPrefix+domainSuffix;
System.out.println(domainName==myDomain);//返回值为true;
}
}



public class MacroTest{
public static void main(String[] args){
String domainName="pplns.com";
String domain="pplns"+".com";
System.out.println(domainName==domain);//返回值为true;
String domainPrefix="pplns";
String domainSuffix=".com";
String myDomain=domainPrefix+domainSuffix;
System.out.println(domainName==myDomain);//返回值为false;
}
}



以上特意用final修饰的变量和无final修饰的变量进行对比,从而发现不同之处。

Java通过一个常量池来管理曾经用过的字符串常量,例如执行String domain="pplns.com";语句之后,常量池中就缓存了一个字符串“pplns.com”;如果程序再执行String domainName="pplns.com";,系统将会让domainName直接指向常量池中“pplns”字符串,因此domain==domainName将返回true;但是在上例MacroTest类中,myDomain是由两个变量拼接而成,而变量在编译期间是不会确定下来,只有在运行期间才会确定下来,所以domainName==myDomain返回的是false;而在上例MacroFinalTest类中,domainPrefix和domainSuffix是由final修饰的变量,所以这两个变量在编译期间就会当作“宏变量”,即常量来处理,所以myDomain在编译期间实际是由"pplns"和".com"拼接而成,所以domainName==myDomain返回的是true。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: