Final变量学习笔记

1. 理解Final变量

  1. final修饰的变量,不再是一个普通变量,而是一个直接量(编译常量)。
  2. 此变量在声明的时候就进行初始化,初始化的值在编译期就可以确定。

2. 为什么final变量在编译期就能知道它的确切值?

“`
package cn.sxt.oop.url;

public class FinalTest {
public static void main(String[] args) {

    final String str1 = "final" + "field";
    final String str2 = "Test" + 8;

    final String str3 = "Test" + String.valueOf(8);
    final int a = 2 + 3;
    final double b = 1.5 / 3;
    System.out.println("Test8" == str2);
    System.out.println("Test8" == str3);
}

}

“`编译后

这里写图片描述

从编译以后的结果可以看出,除了str3,其他变量的值在编译期间就可以确定下来的。由于str1和str2是一个被final修饰的变量,在编译期会把它们直接替换成”finalfield”和”java8”,当成编译常量使用(编译常量),则str1和str2便分别指向字符串常量池中的”finalfield”和”java8”,所以当”java8”和str2进行==比较的时候,相当于直接访问的这个常量,不需要在运行时确定,直接返回true。但是str3的值要在运行期才能确定,这样就不能指向常量池中的”java8“。
常量池是专门用于管理在编译期被确定并被保存在已编译的class文件中的一些数据。它包括了关于类、方法、接口中的常量,还包括字符串常量。
例如执行String a = “java”,就会在字符串常量区缓存一个”java”;当再执行String b =
“java”,b就直接指向刚刚缓存的”java”。所以a==b 返回true。

3.类的final变量和普通变量有什么区别?

true、false

为什么第一个结果输出是true?
因为,b是一个final修饰的变量,在使用b变量时,相当于,直接访问的这个变量b所指向常量池中的“hello”常量,在每次使用变量b时,相当于直接替换成常量“hello”即可,所以,当变量a与变量c进行比较的时候,变量c相当于替换成常量“hello2”,所以,输出true.
为什么第二个输出则是false那?
这是因为,String类型在java中属于引用类型,而对于引用类型,==”比较的是对象的内存地址,显然,尽管 a 与 e 对象的值相同,但是在内存中的地址是不同的,即两个对象是不一样的。因为常量池的存在。运行时常量池其实是属于方法区的一部分。通俗的说,a 和 e 其实都是都是指向 “hello2”这个常量,但是,这两个变量的地址确是不同。
补充:在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。
4. 与final变量一样,发生在编译期还有哪些操作?

①方法重载:这个是发生在编译时的。方法重载也被称为编译时多态,因为编译器可以根据参数的类型来选择使用哪个方法。补充(方法覆盖:这个是在运行时发生的。方法重载被称为运行时多态,因为在编译期编译器不知道并且没法知道该去调用哪个方法。JVM会在代码运行的时候做出决定)
②泛型(又称类型检验):这个是发生在编译期的。编译器负责检查程序中类型的正确性,然后把使用了泛型的代码翻译或者重写成可以执行在当前JVM上的非泛型代码。这个技术被称为“类型擦除“。换句话来说,编译器会擦除所有在尖括号里的类型信息,来保证和版本1.4.0或者更早版本的JRE的兼容性。
③@Override是一个简单的编译时注解,它可以用来捕获类似于在子类中把toString()写成tostring()这样的错误。在Java
5中,用户自定义的注解可以用注解处理工具(Anotation Process Tool ——APT)在编译时进行处理。到了Java
6,这个功能已经是编译器的一部分了。 ④继承—发生在编译时,因为它是静态的

5.面试题
1).使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
答:使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。
2).Final、finally和finallze的区别?

java在编译期可直接替换final变量
java 面试题问与答:编译时与运行时

阅读更多
换一批

没有更多推荐了,返回首页