精华内容
下载资源
问答
  • 最近看了关于java语言规范中关于final变量的介绍,一直很好奇为什么final定义的字段是jvm内部是如何处理的,今天写了一个测试类,看看用javac编译器编译出来的java class 字节码,以便连接final变量在jvm运行时候...

    最近看了关于java语言规范中关于final变量的介绍,一直很好奇为什么final定义的字段是jvm内部是如何处理的,今天写了一个测试类,看看用javac编译器编译出来的java class 字节码,以便连接final变量在jvm运行时候如何保证final变量的不变性。

    java class定义如下

    public class FinalVarClass {

    public void test(){

    final int a=1;

    int b=a;

    System.out.println(a);

    }

    }

    用javac 编译器进行编译(jdk版本1.6 ,操作系统 mac os x),用javap 进行字节码解析出来的结果如下

    {

    public FinalVarClass();

    Code:

    Stack=1, Locals=1, Args_size=1

    0:aload_0

    1:invokespecial#8; //Method java/lang/Object."":()V

    4:return

    LineNumberTable:

    line 2: 0

    LocalVariableTable:

    Start Length Slot Name Signature

    0 5 0 this LFinalVarClass;

    public void test();

    Code:

    Stack=2, Locals=3, Args_size=1

    0:iconst_1

    1:istore_1

    2:iconst_1

    3:istore_2

    4:getstatic#15; //Field java/lang/System.out:Ljava/io/PrintStream;

    7:iconst_1

    8:invokevirtual#21; //Method java/io/PrintStream.println:(I)V

    11:return

    LineNumberTable:

    line 5: 0

    line 6: 2

    line 7: 4

    line 8: 11

    LocalVariableTable:

    Start Length Slot Name Signature

    0 12 0 this LFinalVarClass;

    2 10 1 a I

    4 8 2 b I

    }

    在code里面,首先对final变量a进行赋值为1,以后对a的处理,直接转化为对常量1的操作。javac编译器编译出来的字节码中把所有对a的访问,转化为对常量1的操作。在字节码这一层直接进行的转化。

    思考:是不是可以通过修改字节码,人为的对a进行再次赋值

    实际上java语言设计者已经考虑到这个问题了,所以jvm在加载class文件的时候,会有一个校验过程,专门有次校验的。

    展开全文
  • 当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。...

    当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。

    那么final变量和普通变量到底有何区别呢?下面请看一个例子:

    public classTest {public static voidmain(String[] args) {

    String a= "hello2";final String b = "hello";

    String d= "hello";

    String c= b + 2;

    String e= d + 2;

    System.out.println((a==c));

    System.out.println((a==e));

    }

    }

    true

    false

    大家可以先想一下这道题的输出结果。为什么第一个比较结果为true,而第二个比较结果为fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。这种和C语言中的宏替换有点像。因此在上面的一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的  值。而对于变量d的访问却需要在运行时通过链接来进行。想必其中的区别大家应该明白了,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,比如下面的这段代码就不会进行优化:

    public classTest {public static voidmain(String[] args) {

    String a= "hello2";final String b =getHello();

    String c= b + 2;

    System.out.println((a==c));

    }public staticString getHello() {return "hello";

    }

    }

    这段代码的输出结果为false。

    展开全文
  • 通常final定义变量为常量。如:final double PI = 3.14;当在程序中使用PI这个常量时,它的值就是3.14,如在程序中再次对定义final的常量赋值,编译器将不能接受;final关键字定义变量必须在声明时对其进行赋值...

    final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。 通常final定义的变量为常量。如:

    final double PI = 3.14;

    当在程序中使用PI这个常量时,它的值就是3.14,如在程序中再次对定义为final的常量赋值,编译器将不能接受;

    final关键字定义的变量必须在声明时对其进行赋值操作。final除了可以修饰基本数据类型的常量,还可以修饰对象引用。由于数组也可以被用作一个对象引用,所以final可以修饰数组。一旦一个对象引用被修饰为final后,它只能恒定指向一个对象,无法将其改变为另一个对象。一个既是static又是final的字段只占据一段不能改变的存储空间。如下例:

    import static java.lang.System.out;

    import java.util.Random;

    class Test{

    int i = 0;

    }

    public class FinalData {

    static Random rand = new Random();

    private final int VALUE_1 = 9;//final定义的变量必须使用大写字母命名

    private static final int VALUE_2 = 10;//并且使用下划线进行连接;

    private final Test test = new Test();

    private Test test2 = new Test();

    private final int[] a = {1,2,3,4,5,6};

    private final int i4 = rand.nextInt(20);

    private static final int i5 = rand.nextInt(20);

    public String toString()

    {

    return i4 + "" + i5 + "";

    }

    public static void main(String[] args) {

    FinalData data = new FinalData();

    //data.test = new Test();

    //data.VALUE_2++;

    data.test2 = new Test();

    for(int i=0; i

    {

    //a[i] = 9;

    }

    out.println(data);

    out.println("data2");

    out.println(new FinalData());

    out.println(data);

    }

    }

    一个被定义为final的对象只能指向唯一一个对象,不可以将它指向其他对象,但是一个对象本身的值确实可以改变的,那么为了使一个常量真正做到不可更改,可以将常量说明为static final. 如下例:

    import static java.lang.System.out;

    import java.util.Random;

    public class FinalStaticData {

    private static Random rand = new Random();

    private final int a1 = rand.nextInt(10);

    private static final int a2 = rand.nextInt(10);

    public static void main(String[] args) {

    FinalStaticData fdata = new FinalStaticData();//实例化一个对象

    out.println("重新实例化对象调用a1的值:" + fdata.a1);

    out.println("重新实例化对象调用a2的值:" + fdata.a2);

    FinalStaticData fdata2 = new FinalStaticData();// 实例化新对象

    out.println("重新实例化对象调用a1的值:" + fdata2.a1);

    out.println("重新实例化对象调用a2的值:" + fdata2.a2);

    }

    }

    重新实例化对象调用a1的值:9

    重新实例化对象调用a2的值:2

    重新实例化对象调用a1的值:1

    重新实例化对象调用a2的值:2

    总结:

    定义为final常量不是恒定不变的,将随机数赋予final的变量,可以做到每次运行程序时改变a1的值,但是a2被定义为static final形式,所以内存中为a2开辟了一个恒定的区域,当再次实例化一个FianlStaticData对象时,仍然指向a2这块内存区域,所以a2的值保持不变。

    技巧:

    在JAVA中定义全局常量,通常使用public static final修饰,这样的常量只能在定义时被赋值。

    展开全文
  • 主要介绍了Javafinal变量使用总结,final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值,通常final定义的变量为常量,需要的朋友可以参考下
  • 通常final定义变量为常量。如:复制代码代码如下:final double PI = 3.14;当在程序中使用PI这个常量时,它的值就是3.14,如在程序中再次对定义final的常量赋值,编译器将不能接受;final关键字定义变量必须在...

    final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。 通常final定义的变量为常量。如:

    复制代码代码如下:

    final double PI = 3.14;

    当在程序中使用PI这个常量时,它的值就是3.14,如在程序中再次对定义为final的常量赋值,编译器将不能接受;

    final关键字定义的变量必须在声明时对其进行赋值操作。final除了可以修饰基本数据类型的常量,还可以修饰对象引用。由于数组也可以被用作一个对象引用,所以final可以修饰数组。一旦一个对象引用被修饰为final后,它只能恒定指向一个对象,无法将其改变为另一个对象。一个既是static又是final的字段只占据一段不能改变的存储空间。

    一个被定义为final的对象只能指向唯一一个对象,不可以将它指向其他对象,但是一个对象本身的值确实可以改变的,那么为了使一个常量真正做到不可更改,可以将常量说明为static final. 如下例:

    import static java.lang.System.out;

    import java.util.Random;

    public class FinalStaticData {

    private static Random rand = new Random();

    private final int a1 = rand.nextInt(10);

    private static final int a2 = rand.nextInt(10);

    public static void main(String[] args) {

    FinalStaticData fdata = new FinalStaticData();//实例化一个对象

    System.out.println("重新实例化对象调用a1的值:" + fdata.a1);

    System.out.println("重新实例化对象调用a2的值:" + fdata.a2);

    FinalStaticData fdata2 = new FinalStaticData();// 实例化新对象

    System.out.println("重新实例化对象调用a1的值:" + fdata2.a1);

    System.out.println("重新实例化对象调用a2的值:" + fdata2.a2);

    }

    }

    重新实例化对象调用a1的值:9

    重新实例化对象调用a2的值:2

    重新实例化对象调用a1的值:1

    重新实例化对象调用a2的值:2

    很多人都说在JAVA中用final来修饰方法参数的原因是防止方法参数在调用时被篡改,其实也就是这个原因,但理解起来可能会有歧义,我们需要注意的是,在final修饰的方法参数中,如果修饰的是基本类型,那么在这个方法的内部,基本类型的值是不能够改变的,但是如果修饰的是引用类型的变量,那么就需要注意了,引用类型变量所指的引用是不能够改变的,但是引用类型变量的值是可以改变的。

    代码:

    package com.jd.test;

    public class Test{

    public static void main(String hh[]){

    int i = 1;

    System.out.println(i);

    checkInt(i);

    System.out.println(i);

    }

    /**

    * 对于基本类型,基本类型的值在方法内部是不能够改变的

    * @param i

    */

    public static void checkInt(final int i)

    {

    //编译不通过,final修饰的局部变量i的值是不能够改变的

    // i=10;

    }

    }

    对于引用类型的变量,请看下面的代码:

    package com.jd.test;

    import com.jd.domain.User;

    /**

    *

    * final修饰参数的测试例子

    *

    * @author zhanghao10@jd.com

    * @since 2015-10-8

    */

    public class Test{

    public static void main(String hh[]){

    User user=new User();

    user.setId(1);

    user.setUserName("校长");

    user.setPassword("123456");

    checkInt(user);

    }

    /**

    * 对于基本类型,基本类型的值在方法内部是不能够改变的

    * @param i

    */

    public static void checkInt(final User user)

    {

    //user变量的引用是不能够改变的,否则的话,编译会报错

    // user=new User();

    //user变量的值是能够修改的,但所指向的引用是不能够改变的

    user.setUserName("小王");

    }

    }

    public class FinalTest1 {

    //-----------------成员变量------------------//

    //初始化方式一,在定义变量时直接赋值

    private final int i = 3;

    //初始化方式二,声明完变量后在构造方法中为其赋值

    //如果采用用这种方式,那么每个构造方法中都要有j赋值的语句

    private final int j;

    public FinalTest1() {

    j = 3;

    }

    //如果取消该构造方法的注释,程序就会报错,因此它没有为j赋值

    /*public FinalTest1(String str) {

    }*/

    //为了方便我们可以这样写

    public FinalTest1(String str) {

    this();

    }

    //下面的代码同样会报错,因为对j重复赋值

    /*public FinalTest1(String str1, String str2) {

    this();

    j = 3;//The final field j may already have been assigned

    }*/

    //初始化方式三,声明完变量后在构造代码块中为其赋值

    //如果采用此方式,就不能在构造方法中再次为其赋值

    //构造代码块中的代码会在构造函数之前执行,如果在构造函数中再次赋值,

    //就会造成final变量的重复赋值

    private final int k;

    {

    k = 4;

    }

    //-----------------类变量(静态变量)------------------//

    //初始化方式一,在定义类变量时直接赋值

    public final static int p = 3;

    //初始化方式二,在静态代码块中赋值

    //成员变量可以在构造函数中赋值,但是类变量却不可以。

    //因此成员变量属于对象独有,每个对象创建时只会调用一次构造函数,

    //因此可以保证该成员变量只被初始化一次;

    //而类变量是该类的所有对象共有,每个对象创建时都会对该变量赋值

    //这样就会造成变量的重复赋值。

    public final static int q;

    static {

    q = 3;

    }

    }

    展开全文
  • Java中接口里定义的成员变量必须是public static finaljava.基础知识首先你要弄清接口的含义.接口就是提供一种统一的'协议’,而接口中的属性也属于'协议’中的成员.它们是公共的,静态的,最终的常量.相当于全局常量。...
  • 1、final变量 final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常,由final定义的变量为常量。 例如,在类中定义PI值,可以使用如下语句: final double PI=3.14; 当在程序中使用...
  • Javafinal变量

    2014-10-10 21:08:03
    final变量定义: 变量一经初始化就不能指向其它对象。指向的存储地址不可修改,但指向的对象本身是可以修改的。  先说final变量初始化:  很多文章都这么说:其初始化可以在两个地方,一是其定义处,二是在构造...
  • 之前一直不明白内部内引用其外部类的变量时此变量必须加 final 修饰只是照着用就是,刚刚就特意百度了下,才明白原来是这么回事!以下内容转自 51CTO本文是Thinking In Java中其中一段的阅读总结。如果定义一个匿名...
  • javafinal变量的用法

    2019-09-29 18:33:33
    4.4 final变量 final变量的数值不能在初始化之后进行改变(你希望a=3,有很多用到a的场合, 你当然不能在程序中就用3来代替a)。 比如: final int h = 0; 想像有一个项目组主程序,定义了一个变量,PI=3.1415...
  • ”引发的争论1、单独写一个final的类,在里面定义finalstatic的全局变量,在其它程序里包含进来就可以了。2、类中的任何staticpublic的成员变量都是全局共享的。3、JAVA中不应该有所谓全局变量的概念,全局变量严重...
  • Java中的final变量、final方法和final类

    万次阅读 多人点赞 2018-12-13 17:39:24
    1、final变量 final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常,由final定义的变量为常量。例如,在类中定义PI值,可以使用如下语句: final double PI=3.14; 在Java定义全局...
  • 查了很多博客和帖子,发现这个帖子是把这个问题将得最清楚的(个人认为)转载自...public class TestFinal{//只有定义final User user 才不会报错为什么?public void test( User user){(new Thread(){public void...
  • 最近看了关于java语言规范中关于final变量的介绍,一直很好奇为什么final定义的字段是jvm内部是如何处理的,今天写了一个测试类,看看用javac编译器编译出来的java class 字节码,以便连接final变量在jvm运行时候...
  • 简单的说,当 test初始化之后,他内部的变量们是可以改变值的,但是test本身不能变成另一个 test。从内存模型角度说。test本身是一个指针,存在于 stack。test = new Test()后,虚拟机就在内存Heap中给test开辟了一...
  • Javafinal变量(转)

    2011-10-13 21:27:00
    final变量定义: 变量一经初始化就不能指向其它对象。指向的存储地址不可修改,但指向的对象本身是可以修改的。 先说final变量初始化: 很多文章都这么说:其初始化可以在两个地方,一是其定义处,二是在构造函数中,...
  • 详解Kotlin中的变量和方法...val 定义的是只读变量,相当于javafinal变量。变量的类型,如果可以根据赋值推测,可以省略。var name: String = "jason"name = "jame"val max = 10常量Java 定义常量用关键字 stat...
  • 展开全部final定义变量可以看做一个常量,不能被62616964757a686964616fe4b893e5b19e31333363373731改变;final定义的方法不能被覆盖;final定义的类不能被继承。final static 就是再加上static的特性就可以了...
  • 1 public class FinalTest1 { 2 //-----------------成员变量----------------... 3 //初始化方式一,在定义变量时直接赋值 4 private final int i = 3; 5 6 //初始化方式二,声明完变量后在构造方法中为其赋值 ...
  • finalJava中并不常用,然而它却为我们提供了诸如在C语言中定义常量的功能,不仅如此,final还可以让你控制你的成员、方法或者是一个类是否可被覆写或继承等功能,这些特点使finalJava中拥有了一个不可或缺的地位...
  • 之前一直不明白内部内引用其外部类的变量时此变量必须加 final 修饰只是照着用就是,刚刚就特意百度了下,才明白原来是这么回事! 以下内容转自 51CTO 本文是Thinking In Java中其中一段的阅读总结。如果定义一个...
  • 一、final变量 final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常,由final定义的变量为常量。例如,在类中定义PI值,可以使用如下语句: final double PI=3.14; 在Java定义全局常量...
  • final关键字我们并不陌生,但是final修饰的属性变量为什么必须在定义的时候或者构造函数中被初始化呢?...如果不在定义的时候或者构造函数中对final变量进行赋值的话,则生成的对象中final变量的值是
  • Java-final成员变量赋值

    2020-08-26 14:04:53
    java final关键字成员变量final声明方式final static 成员变量 final成员变量会在分配空间时定下来 final声明方式 final int a=10; final int a;...摘自文章:【小家javajava中为final变量赋值的几种方式

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,036
精华内容 2,014
关键字:

java定义final变量

java 订阅