final关键字作用详解
在java中final关键字有第一无二的特性,就是只可以赋值一次,一旦赋值,就无法改变其值。利用好这个特性可以写出非常好的代码。
1 final关键字常用应用场景
1.1 单例模式
利用final只能赋值一次的特性,在Demo1类中设定一个SingletonHolder类来持有一个final类型的Demo1的静态类。这样是线程安全的单例模式。
示例代码:
package com.dashidan.lesson23;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 之一 单例模式
*/
public class Demo1 {
public static Demo1 getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
public final static Demo1 instance = new Demo1();
}
}
1.2 静态配置文件解析后的初始化
在项目中如果涉及多个部分合作,会将一部分配置工作分给对应的部门来专门配置。这样就要求配置文件是独立于代码的。需要在代码中将对应的配置文件转化成java对象。这样就需要保证配置文件中的数据唯一性和不可变性,来保证程序不会修改配置文件中的数据。比如在开发游戏的过程中会有很多策划配置表,这个表格是需要策划配置,并且程序不能修改。这种场景很适合将配置表的参数转化成final关键字来保证数据不被修改。加入一个get方法,只能读取该值。
示例代码:
package com.dashidan.lesson23;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 之一 单例模式
*/
public class Demo2 {
/**
* 解析配置后的数据对象 设置为final类型的
* 这样通过构造函数初始化以后 就无法改变其值
*/
private final int id;
private final int num;
public Demo2(int id, int num) {
this.id = id;
this.num = num;
}
public int getId() {
return id;
}
public int getNum() {
return num;
}
}
2 final关键字初始化
给final关键字定义的变量有2中初始化方式。
- 定义时初始化
- 构造函数初始化
示例代码
package com.dashidan.lesson23;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 之一 final关键字初始化
*/
public class Demo3 {
/** final 关键字 定义时初始化*/
final int num0 = 1;
/** final 关键字 构造函数初始化*/
final int num1;
Demo3(int n1) {
this.num1 = n1;
}
public int getNum0() {
return num0;
}
public int getNum1() {
return num1;
}
}
如果没有给final变量初始化,java编译器会报编译时错误:可能尚未初始化变量。 如果再次给final变量赋值,java编译器会报编译时错误:无法为最终变量分配值。
3 在构造函数中参数用final关键字修饰的作用
在一些开源代码中有些代码中会出现在构造函数的参数中的变量会用final关键字修饰。这样是为了防止修改传入进来的参数。
package com.dashidan.lesson23;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 final关键字在构造函数中的作用
*/
public class Demo4 {
public static void main(String[] args) {
int a = 100;
Test1 test1 = new Test1(a);
a++;
System.out.println("a " + a);
System.out.println("n " + test1.getN());
}
}
class Test1 {
int n = 0;
/** 构造函数中传入的参数采用final修饰*/
public Test1(final int num) {
this.n = num;
/** 这里无法改变 num的值, 会报错 */
// num = 2;
}
public int getN() {
return n;
}
}
4 final在集合中的应用
4.1 将集合类对象定义为final
将集合类对象定义为final, 表示该集合类无法重新赋值。但仍然可以对该集合进行添加和删除修改。
以ArrayList为例的示例代码:
package com.dashidan.lesson23;
import java.util.ArrayList;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 final在集合中的应用
*
*/
public class Demo5 {
public static void main(String[] args) {
final ArrayList<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
list.add(2);
list.remove(0);
/** 重新赋值会报错*/
// list = new ArrayList<>();
}
}
4.2 集合类中的对象设置为final
如果集合类中对象是基本类型变量,比如int,long等,用final类型修饰的话,可以修改,添加,移除集合中的对象数据。
示例代码:
package com.dashidan.lesson23;
import java.util.ArrayList;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 final在集合中的应用
*/
public class Demo6 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
final int a = 0;
final int b = 0;
final int c = 0;
list.add(a);
list.add(b);
list.add(c);
/** final对象可以移除 移除第一个final数据*/
list.remove(0);
/** 修改余下的第一个位*/
list.set(0, 100);
for (Integer aList : list) {
/** 遍历修改数据 由于 基本类型是值传递 这里 可以用原final值做修改操作*/
aList++;
System.out.println("n " + aList);
}
for (Integer aList : list) {
/** 输出原数据*/
System.out.println("aList " + aList);
}
}
}
运行结果:
n 101
n 1
aList 100
aList 0
从输出结果中可以印证以上分析。
如果集合类中的对象引用类型而不是基本类型。会怎样呢? 我们可以通过以下示例来验证一下.
package com.dashidan.lesson23;
import java.util.ArrayList;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 final在集合中的应用
*/
public class Demo7 {
public static void main(String[] args) {
ArrayList<Test2> list = new ArrayList<>();
final Test2 a = new Test2(1);
final Test2 b = new Test2(2);
final Test2 c = new Test2(3);
list.add(a);
list.add(b);
list.add(c);
/** final对象可以移除 移除第一个final数据*/
list.remove(0);
/** 修改余下的第一个位*/
list.set(0, new Test2(4));
for (Test2 test2 : list) {
/** 遍历修改数据 将集合对象中的索引 设置为 空*/
test2 = null;
}
for (Test2 aList : list) {
/** 输出集合中的数据 */
System.out.println("aList " + aList);
}
}
}
class Test2 {
int num;
public Test2(int num) {
this.num = num;
}
public int getNum() {
return num;
}
@Override
public String toString() {
return "Test2{" +
"num=" + num +
'}';
}
}
输出结果:
aList Test2{num=4}
aList Test2{num=3}
这个输出结果验证了,集合类中如果放入的是final修饰的对象,依然可以对该集合进行添加,删除操作。其中对集合对象置空的操作没有生效。再后续的遍历中依然能遍历出对象.
5 final在数组中的应用
将final关键字给数组设置后, 作用和final定义集合类类似。同样是无法再次给数组索引赋值,可以改变数组中的内容。
示例代码:
package com.dashidan.lesson23;
/**
* 大屎蛋教程网-dashidan.com
* <p>
* Java教程基础篇: 23.final关键字作用详解
* final关键字应用场景 final在数组中的应用
*/
public class Demo8 {
public static void main(String[] args) {
/** 定义一个final 数组*/
final int[] array = new int[3];
for (int i = 0; i < array.length; i++) {
/** 数组中赋值final类型数组*/
final int n = i;
array[i] = n;
}
/** 无法再次赋值, 会报错*/
// array = new int[3];
for (int i = 0; i < array.length; i++) {
/** 改变数组中的数据*/
array[i] = i * 10;
System.out.println(" array[i] " + array[i]);
}
}
}
输出结果
array[i] 0
array[i] 10
array[i] 20
由输出结果可见,即使给final类型的数组中初始化了final整型变量。依然可以改变数组中的内容。