Java学习篇之---修饰符final详解
2015-11-23 04:30
471 查看
Java学习篇之---[b]修饰符final详解[/b]
最近又翻看了一遍Java的基础知识,发现当初自己关于修饰符final的理解就曾经迷茫过,为了帮助Java初学者更好度过迷茫期,特此献上此文(此文将重点讲解final修饰的变量,至于final修饰的类和方法,由于比较简单,就不再下面列出了)。
一、概述:
final关键字可用于修饰类、变量和方法。final修饰变量时,表示该变量一旦获得了初始值就不可被改变(可以赋初值,但是不可以被改变),final既可以修饰成员变量(包括类变量和实例变量),也可以修饰局部变量、形参。
二、final成员变量:
1) 类变量:
final修饰类变量,要么在定义该类变量时指定初始值;要么在静态初始化块中指定初始值。
2) 实例变量:
final修饰实例变量,要么在定义该实例变量时指定初始值;要么在普通初始化块中指定初始值;要么在构造器中指定初始值。
三、final局部变量:
系统不会对局部变量进行隐形初始化,需要程序员显性初始化。
四、final修饰基本类型变量和引用类型变量的区别:
final修饰基本类型变量时,不能对基本类型变量重新赋值;对于引用类型而言,它保存的只是一个引用,final只保证这个引用类型变量所引用的地址不变,即一直引用同一个对象,但是这个对象的成员可以改变;
五、可执行"宏替换"的final变量:
对于一个final变量而言,不管是类变量、实例变量还是局部变量,只要该变量满足以下三条,则final变量就不再是一个变量,而是相当于是一个直接值:
1、使用final修饰符修饰;
2、在定义该final变量时指定了初始值;
3、该初始值可以在编译时就确定下来。
以上特意用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。
最近又翻看了一遍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。
相关文章推荐
- Java 反射机制学习资料
- 03 elasticsearch java api
- 开始看java的第一天
- 如何修改eclipse中@author的默认选项
- nf设计模式 - 修饰模式 (Decorator pattern) 的 Java 实现
- Java中的jar命令
- 关于思想,关于那些事
- Spring 上传文件
- Spring MVC 详解
- spring 两个 properties
- 使用Adobe Reader控件结合Java实现PDF打印功能
- Struts2学习笔记
- java中的值传递和引用传递
- 浅谈Struts2的命名空间及以传统形式返回json数据
- java文件输入输出
- Spring with Hibernate persistence and transactions
- Java基本数据类型与封装类的区别
- Java synchronized
- Java包 Package
- Java虚拟机类加载机制