final理解

基础

final在Java中是一个保留的关键字,可以声明成员变量、方法、类以及本地变量。一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编译错误。

1.修饰变量的时候 会使其变成只读的

2.修饰方法 该方法不能被重写 并且因为编译的时候已经静态绑定了,不需要在运行时再动态绑定 所以执行较快

3.修饰类 不能被继承 不可变类,可以在多线程环境下安全的共享,不用额外的同步开销等等。

好处

  1. final关键字提高了性能。JVM和Java应用都会缓存final变量。
  2. final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销,不可变性.
  3. 使用final关键字,JVM会对方法、变量及类进行优化

实例

JVM优化的特性

public class Test {
    public static void main(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)); //true
        System.out.println((a == e)); //false
    }
}


当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。

上方代码中b被final修饰 在编译期就会将 b + 2 自动替换为 hello + 2

不过,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,一下代码结果就会完全不一样.

public class Test {
    public static void main(String[] args)  {
        String a = "hello2";
        final String b = getHello();
        String c = b + 2;
        System.out.println((a == c)); /false
  
    }
      
    public static String getHello() {
        return "hello";
    }
}

与static对比

static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变。

public class Test {
    public static void main(String[] args)  {
        MyClass myClass1 = new MyClass();
        MyClass myClass2 = new MyClass();
        System.out.println(myClass1.i);
        System.out.println(myClass1.j);
        System.out.println(myClass2.i);
        System.out.println(myClass2.j);
  
    }
}
  
class MyClass {
    public final double i = Math.random();
    public static double j = Math.random();
}

运行这段代码就会发现,每次打印的两个j值都是一样的,而i的值却是不同的。从这里就可以知道final和static变量的区别了。

不可变

public class Test {
    public static void main(String[] args)  {
        final MyClass myClass = new MyClass();
        System.out.println(++myClass.i);
  
    }
}
  
class MyClass {
    public int i = 0;
}

 这段代码可以顺利编译通过并且有输出结果,输出结果为1。这说明引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的。

public class Test {
    public static void main(String[] args)  {
        MyClass myClass = new MyClass();
        StringBuffer buffer = new StringBuffer("hello");
        myClass.changeValue(buffer);
        System.out.println(buffer.toString());
    }
}
  
class MyClass {
      
    void changeValue(final StringBuffer buffer) {
        buffer.append("world");
    }
}

运行这段代码就会发现输出结果为 helloworld。很显然,用final进行修饰并没有阻止在changeValue中改变buffer指向的对象的内容 . 如果把final去掉了,然后在changeValue中让buffer指向了其他对象,也不会影响到main方法中的buffer,原因在于java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。

猜你喜欢

转载自blog.csdn.net/qq_30054997/article/details/81676701