`
yangxianjiangg
  • 浏览: 61315 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java中final的意义

阅读更多

1、如果一个数据既是static又是final,那么它会拥有一块无法改变的存储空间。

2、final data: 当final用于基本数据类型时,final让其值(value)保持不变,但是当用于object reference时,final仅让reference保持不变。也就是说当reference一旦被初始化用于代表某个对象时,便再也不能改变指向另一个对象,但对象本身的内容确实可以改变的。final对array的作用和对reference的作用一样。参考以下例子:

public class Test1{
    private final int li_int=12;
    private final InClass inClass1=new InClass(5);
    private final InClass inClass2=new InClass(8);
    public void modifiedFinal(int a){
    //下面语句出现编译错误,不能修改final基本类型的值
    //li_int = a; 
    //下面语句出现编译错误,不能将已经初始化的final变量指向另一个对象
    //inClass1=inClass2;
    //下面语句成功,虽然引用不能改变但final变量引用的对象本身内容是可以改变的
    inClass1.mod(a);
 }
 class InClass{
  int li_a=0;
  public InClass(int a){
   li_a=a; 
  } 
  public int mod(int b){
   li_a=b; 
   return li_a;
  }
 }
 public static void main(String args[]){
  Test1 test1=new Test1();
  test1.modifiedFinal(100);
  System.out.println(test1.inClass1.li_a);
 }
}

3、blank finals:java允许将数据成员声明为final,却不赋初值。但是,blank finals必须在使用之前初始化,且必须在构造函数中初始化。请参考以下例子:

public class Test2{
 //final变量一开始允许不赋值
 private final int li_int;
 public Test2(int a){
  //下面语句编译通过,对定义为空的final变量的赋值必须在构造方法中进行,而且必须要赋值,不赋值也报错
  li_int = a; 
 }
 public int mod(int a){
  //下面语句编译出错,对定义为空的final变量的赋值必须在构造方法中进行
  //li_int = a; 
  return li_int;
 } 
}

4、final arguments: 声明arguments为final,可以保证该argument不能再被指向它处,当argment是基本数据类型时,就意味着值不能改变。参考以下例子:

public class Test3{
 private  int li_int=12;
 private  InClass inClass1=new InClass(5);
 private  InClass inClass2=new InClass(8);
 public void modifiedFinal(final int a,final InClass in){
  //下面语句出现编译错误,不能修改final基本类型的值
  //a = 15; 
  //下面语句出现编译错误,不能将已经初始化的final变量指向另一个对象
  //in=inClass2;
  //下面语句成功,虽然引用不能改变但final变量引用的对象本身内容是可以改变的
  in.mod(a);
 }
 class InClass{
  int li_a=0;
  public InClass(int a){
   li_a=a; 
  } 
  public int mod(int b){
   li_a=b; 
   return li_a;
  }
 }
 public static void main(String args[]){
  int a=100;
  //内部类初始化
  Test3 test3=new Test3();
  Test3.InClass in=test3.new InClass(30);
  System.out.println(in.li_a);
  test3.modifiedFinal(a,in);
  System.out.println(in.li_a);
 } 
}

5、final methods: 可以锁住该method,不让继承类改变其意义(不允许子类覆写);允许编译器对此method作为inline method调用。参考以下例子:

public class Test4{
 private final int li_int=0;
 public final int pub_fi_mod(){
  return li_int;
 }
 protected final int pro_fi_mod(){
  return li_int;
 } 
 private final int pri_fi_mod(){
  return  li_int; 
 }
 private int pri_mod(){
  return li_int; 
 }
}

public class Test5 extends Test4{
 private int li_i=100;
 //下面的方法编译出错,不能覆盖final方法,只针对public和protected,子类中方法与父类中private的方法名相同不是覆盖,与父类中同方法名的方法没有任何关系(除了名字相同)。
 /*
 public int pub_fi_mod(){
  return li_i; 
 }
 protected int pro_fi_mod(){
  return li_i; 
 }*/
 private final int pri_fi_mod(){
  return  li_i; 
 }
 private int pri_mod(){
  return li_i; 
 }
 public static void main(String args[]){
  System.out.println(new Test5().pri_mod()); 
 }
}

6、fianl(method) vs private(method): class所有的private methods自然而然都是final,private methods仅仅是隐藏class中的某段程序代码而已,不能被overrid,即使子类中恰好有同名的method,也不会产生什么效果;其中两者的区别是在子类中可以出现与private方法有相同签名的方法,而public或protected的final方法不能被重写,但允许方法名相同但参数列表不同的重构方法出现。借用以上例子,将Test5修改后编译通过:

public class Test5 extends Test4{
 private int li_i=100;
 //下面的方法编译出错,不能覆盖final方法
 /*
 public int pub_fi_mod(){
  return li_i; 
 }
 protected int pro_fi_mod(){
  return li_i; 
 }
 */
 //但允许参数列表不同的重构方法出现
 public int pub_fi_mod(int a){
  return li_i; 
 }
 protected int pro_fi_mod(int a){
  return li_i; 
 }
 private final int pri_fi_mod(){
  return  li_i; 
 }
 private int pri_mod(){
  return li_i; 
 }
 public static void main(String args[]){
  System.out.println(new Test5().pri_mod()); 
 }
}

7、final classes: 当把一个class声明为final时,也就决定了此class将不能被继承(比如String类,此类为final类,具体可以参见其实现java.lang.String)。final classes的methods可以是final,也可以是非final的;其中的数据成员可以是final的也可以不是,他们将服从final data的原则。参考以下例子:

public final class Test6{
 private final int li_int=0;
 public int li_a=123;
 public final int mod(){
  return li_int;
 } 
 public int pri_mod(){
  return li_a; 
 }
 public static void main(String args[]){
  System.out.println(new Test6().pri_mod()); 
 }
}

//Test6是final类,所以Test7不能继承
public class Test7 extends Test6{
 private int li_int=0;
}

 

PS:从以上可以看出,final是将一个对象的地址不变,对基本类型的值保持不变(因为基本类型变量指向的物理地址存放value而对象变量指向的物理地址存放对象内容的地址)。

PS:以前读书时老师说java中final定义常量,只说对了一半,对基本类型是对的,对String也是对的,因为String虽然是对象,但不会出现String变量地址不变而其内容发生改变的情况(String是一个整体不能只改变其中的一个字符),所以也是对的,但对其他的对象只能保持其引用地址不变不能保证其内容不变,所以是错的。

再补充一些内容:

1、对final属性在声明时就赋值,而且赋的值是常量的话,那编译器会将所有用到此属性的地方都替换成常量,这个请参考下面的代码:

 

package com.xx.dryr.test1;

import java.lang.reflect.Field;

public class Test1Class1{

public final int x = 100;

public int f(Test1Class1 t1c11,Test1Class1 t1c12) throws Exception{

int i = t1c11.x;

System.out.println("i's value is "+i);

changeX(t1c11);

int j = t1c12.x;

System.out.println("j's value is "+j);

return j - i;

}

public static void changeX(Test1Class1 t1c1) throws Exception{

Class clazz = t1c1.getClass();

Field fieldX = clazz.getDeclaredField("x");

fieldX.setAccessible(true);

fieldX.setInt(t1c1, 300);

 

System.out.println("fieldX's vlaue is "+fieldX.getInt(t1c1));

}

public int test() throws Exception{

return f(this,this);

}

public static void main(String[] args) throws Exception{

Test1Class1 t1c1 = new Test1Class1();

System.out.println(t1c1.test());

}

}

运行结果是:

 

i's value is 100

fieldX's vlaue is 300

j's value is 100

0

虽然在changeX方法中,已经将x的值修改为300,但因为编译时所有使用到x的地方都使用100替换了,所以在运行时再怎么修改x的值都不会对使用到x的地方产生影响。

2、否则,对不是在编译时确定final属性值的情况下,final属性的值是可以改变的。请参考如下代码,对上面的代码稍微做了修改,让final属性x在构造方法中初始化:

 

package com.xx.dryr.test1;

import java.lang.reflect.Field;

public class Test1Class1{

public final int x ;

public Test1Class1(){

x = 100;

}

public int f(Test1Class1 t1c11,Test1Class1 t1c12) throws Exception{

int i = t1c11.x;

System.out.println("i's value is "+i);

changeX(t1c11);

int j = t1c12.x;

System.out.println("j's value is "+j);

return j - i;

}

public static void changeX(Test1Class1 t1c1) throws Exception{

Class clazz = t1c1.getClass();

Field fieldX = clazz.getDeclaredField("x");

fieldX.setAccessible(true);

fieldX.setInt(t1c1, 300);

System.out.println("fieldX's vlaue is "+fieldX.getInt(t1c1));

}

public int test() throws Exception{

return f(this,this);

}

public static void main(String[] args) throws Exception{

Test1Class1 t1c1 = new Test1Class1();

System.out.println(t1c1.test());

}

}

运行结果是:

 

i's value is 100

fieldX's vlaue is 300

j's value is 300

200

从上面的例子中可见,final属性的值还是可以被改变的,但只有在特殊情况下(没有在编译时被替换),使用特殊的方式(像反射这样的方式),final属性的值才可以被改变。所以说一般情况下说final属性的值是不允许被修改的还是可以说的,但必须得知道这些例外情况的。
分享到:
评论

相关推荐

    Java中final共2页.pdf.zip

    在本篇文章中,我们将深入探讨`final`关键字在Java中的使用和意义。 首先,`final`关键字用于声明一个不可变的对象。当应用于变量时,它表示该变量一旦被初始化后就不能再改变其值。例如: ```java final int ...

    Java关键字final、static使用总结

    在 Java 编程语言中,final 和 static 是两个非常重要的关键字,它们可以用来修饰类、方法、变量等,了解它们的使用方法和限制非常重要。本文将详细总结 final 和 static 的使用方法和限制。 一、final 关键字 ...

    final和static用法详解JAVA

    Java 中的 final 和 static 关键字详解 final 关键字是 Java 中的一种访问修饰符,用于修饰类、方法和变量,以确保它们不能被修改或继承。下面是 final 关键字的详细解释: 1. final 类 final 类不能被继承,也...

    javafinal和static总结.docx

    Java 中的 final 和 static 关键字详解 Java 中的 final 和 static 关键字是两个重要的关键字,它们在 Java 编程中扮演着重要的角色。本文将详细介绍 final 和 static 关键字的使用方法和注意事项。 一、final ...

    深入浅析Java中的final关键字

    Java中的`final`关键字是一个非常重要的概念,它用于声明不可变的类、方法或变量,以确保代码的稳定性和安全性。下面将详细讲解`final`关键字的用途和使用细节。 一、`final`关键字的基本用法 1. 修饰类 当一个类...

    final关键字和static_用法

    ### Java中的final关键字详解 #### 一、final的概述与用途 `final`关键字在Java中扮演着重要的角色,它通常被用来表示“不可变”的特性。`final`可以用来修饰类、方法以及变量,其核心目的是为了保护数据的安全性...

    Java常见笔试、面试题目深度剖析 final详解

    本篇文章将深入剖析`final`关键字在Java中的使用和意义,帮助读者理解其在面试和实际开发中的重要性。 1. **final变量** - `final`修饰的变量一旦赋值后,就不能再改变。这可以确保变量的值在整个程序运行期间保持...

    Java中static、this、super、final用法

    ### Java中static、this、super、final用法详解 #### 一、static关键字的使用 在Java编程语言中,`static`是一个非常重要的关键字,它主要用于定义类成员(包括变量和方法),使得这些成员能够在不创建类实例的...

    Java this、final等关键字总结

    Java中的关键字this、final以及super在编程中扮演着至关重要的角色。下面我们将深入探讨这些关键字的用法和意义。 首先,`this`关键字是Java中一个非常基础且实用的元素,它代表当前对象的引用。当类的成员变量与...

    ClassFinal是一款java class文件安全加密工具

    《Java ClassFinal:深入理解Java类文件安全加密技术》 在Java编程领域,源代码的安全性至关重要,尤其是在软件产品发布后,防止恶意逆向工程分析和非法篡改是每个开发者和企业关注的重点。为此,出现了专门针对...

    java中50个关键字的作用

    java中50个关键字的作用 Abstract break continue final protected ==

    Top 1000 Java Interview Questions

    17. **Java中默认构造器的存在意义:** - 默认构造器用于创建对象时初始化实例变量的默认值。 - 当类中没有定义任何构造器时,编译器会自动添加一个无参构造器。 18. **构造器返回的值:** - Java中的构造器没有...

    hibernate-release-5.2.10.Final

    JPA(Java Persistence API)元模型生成器是Hibernate 5.2.10.Final中的一个重要组件,它能自动生成JPA实体类的元模型,帮助开发者减少手动编写元模型代码的工作量。元模型是JPA中的一个重要概念,它包含了实体类的...

    MMAnalyzer 相关jar包,java中文分词

    在IT行业中,中文分词是自然语言处理(NLP)中的关键步骤,它涉及到将连续的汉字序列分割成有意义的词语单元,这对于信息检索、文本分析、机器翻译等多个领域至关重要。"MMAnalyzer"是一个专门针对Java开发的中文...

    JAVA中的保留关键字

    Java关键字是指被Java语言本身赋予特定意义的标识符,它们不能作为变量名或类名等自定义标识符使用。Java中有53个关键字,包括但不限于: - `abstract`:用于声明抽象类和抽象方法。 - `boolean`:表示布尔类型,...

    Java字节码加密工具

    本文将详细阐述Java字节码加密的相关知识点,以及如何利用名为"classfinal"的开源项目来加强代码的安全性。 一、Java字节码加密原理 1. 字节码混淆:混淆技术通过重命名类、方法和变量,使用无意义的字符串,使得...

    java练习题大全

    21. Java不支持传统意义上的多重继承,但可以使用接口来模拟多重继承的效果,因为一个类可以实现多个接口。 22. Java中char类型的取值范围是单个16位Unicode字符,即从U+0000到U+FFFF。 23. javadoc是一个Java文档...

    Java面试宝典2013版pdf

    Java拥有多种关键字,这些关键字在Java语言中具有特殊的意义。例如,“final”是一个关键字,用于声明一个变量的值不可更改。而“static”关键字用来创建类变量或类方法,即不依赖于任何对象的变量或方法。 基本...

    java编程常用英语单词解释

    在 Java 编程中,英语单词是必不可少的一部分。了解这些单词的解释将有助于我们更好地理解和使用 Java 语言。下面是 Java 编程常用英语单词的解释: 1. Abstract(关键字):抽象的,指的是不能被实例化的类或接口...

    hibernate-release-5.0.6.Final.zip

    《Hibernate 5.0.6.Final:持久化框架的核心技术与实践》 Hibernate,作为Java领域中的一个著名对象关系映射(ORM)框架,极大...深入理解和掌握这一版本的特性,对于提升Java Web应用的开发效率和质量具有重要意义。

Global site tag (gtag.js) - Google Analytics