这篇文章主要介绍了Java基于final修饰数据过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

final是Java中的一个重要关键字,它可以修饰数据、方法和类,本篇将从final修饰的数据角度对final做出总结。

final修饰的数据代表着:永远不变。意思是,一旦你用final修饰一块数据,你之后就只能看看它,你想修改它,没门。

我们不希望改变的数据有下面两种情况:

永不改变的编译时常量。

//编译时知道其值

private final int valueOne = 9;

在运行时(不是编译时)被初始化的值,且之后不希望它改变。

//在编译时不能知道其值

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

设置成常量有啥好处呢?

很简单,让编译器觉得简单,就是最大的好处。比如把PI设置成final,且给定值为3.14,编译器自然会觉得这个东西不会再被修改了,是足够权威的。那么,编译器就会在运行之前(编译时)就把这3.14代入所有的PI中计算,这样在真正运行的时候,速度方面当然会快一点。

有初始值的final域

即声明为final且当场就给定初始值的域。

private final int valueOne = 9;

final+基本数据类型

final修饰的基本数据类型变量存储的数值永恒不变。

/*基本类型变量*/

//带有编译时数值的final基本类型

private final int valueOne = 9;

private static final int VALUE_TWO = 99;

public static final int VALUE_THREE = 39;

//!false:fd1.valueOne++;

//!false:fd1.VALUE_TWO++;

//!false:fd1.VALUE_THREE++;

康康上面醒目的三句false语句,很好地印证了我们之前说的:数值不让改!!!

需要注意的是,按照惯例,下面是定义常量的典型方式:

//典型常量的定义方式

public static final int VALUE_THREE = 39;

public修饰符使其可被用于包之外。

static使数据只有一份。

final表示其无法被更改

名称全为大写英文字母,以下划线隔开。

final+引用数据类型

我们之前说过,基本类型存数值,引用类型存地址值。那么既然final+基本数据类型不让改数值,聪明的我们稍微一联想就明白,final+引用数据类型就是不让你改变量存储实际对象的地址值啦。(也就是不能再让它指向新的对象,很专一)

private Value v1 = new Value(1);

private final Value v2 = new Value(22);

private static final Value V_3 = new Value(333);

//引用变量并不是常量,存储地址可以改变

fd1.v1 = new Value(10);

//v2是引用变量,final修饰之后表示地址不能改变,但是实际对象的值是可以改变的

fd1.v2.i++;

//!false:fd1.v2 = new Value(3);

//V_3与v2类似,是静态和非静态的区别,下面会说明

fd1.V_3.i++;

//!false:fd1.V_3 = new Value(10);

}

通过例子,确实也证明上面所说,一个以final修饰的引用数据类型变量,无法再指向一个新的对象,因为它所存储的地址值已经无法被更改,但是并不影响它指向的实际对象。就拿一个比较典型的引用类型来举例,我们知道数组就是一种典型的引用类型,数组的引用变量存储的是数组再堆中的地址,堆中存放的就是数组每个索引的数值。

/*引用变量之数组*/

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

引用变量a被指定为final,所以它里面的地址值不能再改,也就无法再让它指向一个新的数组。

//!false:fd1.a = new int[]{2,3,4,5,6,7};

for (int i = 0; i < fd1.a.length; i++) {

fd1.a[i]++;

但是,它指向的数组里的每个元素却可以改动,因为数组中的元素并没有任何的限定。

final与static final

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

static final int INT_5 = rand.nextInt(20);

System.out.println(fd1);//fd1: i4 = 15,INT_518

FinalData fd2 = new FinalData("fd2");

System.out.println(fd2);//fd2: i4 = 13,INT_518

FinalData fd3 = new FinalData("fd3");

System.out.println(fd3);//fd3: i4 = 1,INT_5 = 18

上面示例分别创建了三个不同的对象,对其final 和final static 进行测试。

需要明确的是,两者都以final修饰,都不能被改变。

三个对象的i4值,没有用static修饰,不相同且不能改变。

而INT_5的值因为被static修饰,在类加载时已经被初始化,不随对象改变而改变。

空白final域

即声明为final却没有给定初始值的域。

private final String id;//空白final

如果只有上面的这句,编译器会报错,因为它没有初始化。

Variable 'id' might not have been initialized

所以,若定义了空白final域,一定记得在构造器中给它赋值!(必须在域的定义处或者每个构造器中以表达式对final进行赋值,因为系统不会为final域默认初始化)

//在构造器中为空白final域赋初值

public FinalData(){

id = "空白final默认id";

}

public FinalData(String id){

this.id = id;

}

不要试图在初始化之前访问域,不然会报错。

final让域可以根据对象的不同而不同,增加灵活性的同时,又保留不被改变的特性。

final修饰的参数

基本数据类型的参数

类似地,就是传入的参数不让改,只让读,这一点很好理解。

public int finalParamTest(final int i){

//!false:i++;

//不让改,只让读

return i+1;

}

但是,我又新增了许多测试,分别定义四种不同的参数传入该方法,发现传入param0和param1编译会报错。(非常疑惑,这部分书上没提,查了许多资料也没有理解清楚,希望大牛可以评论区指点迷津)

/*检测传入参数*/

int param0 = 5;

final int param1 = 10;

static final int PARAM_2 = 15;

static int param3 = 20;

//!false:System.out.println(fd1.finalParamTest(param0));

//!false:System.out.println(fd1.finalParamTest(param1));

//non-static field'param1' cannot be referenced from a static context

System.out.println(fd1.finalParamTest(PARAM_2));

System.out.println(fd1.finalParamTest(param3));

/*为什么形参列表里的参数用final修饰,但是用final修饰的param1无法传进去,

一定要static修饰?*/

引用数据类型的参数

public void finalReferenceTest(final FinalData fd){

//!false:fd = new FinalData();

//不能再指向新的对象,存储地址不准变

fd.param0++;

}

还是类似,不可以让这个引用类型的参数再指向新的对象,但是可以改变其实际指向对象的值。

最后的最后,下面的代码是根据《Thinking in Java》中的示例,结合自己的思想,将各个板块融合而成的超级无敌测试代码,冲冲冲!

package com.my.pac16;

import java.util.Arrays;

import java.util.Random;

/**

* @auther Summerday

*/

class Value{

int i;//package access

public Value(int i){

this.i =i;

}

}

/*final域在使用前必须被初始化:定义时,构造器中*/

public class FinalData {

/*检测传入参数*/

int param0 = 5;

final int param1 = 10;

static final int PARAM_2 = 15;

static int param3 = 20;

private static Random rand = new Random(47);

private final String id;//空白final

public FinalData(){

id = "空白final默认id";

}

public FinalData(String id){

this.id = id;

}

//带有编译时数值的final基本类型

private final int valueOne = 9;

private static final int VALUE_TWO = 99;

//典型常量的定义方式

public static final int VALUE_THREE = 39;

//在编译是不能知道其值

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

static final int INT_5 = rand.nextInt(20);

private Value v1 = new Value(1);

private final Value v2 = new Value(22);

private static final Value V_3 = new Value(333);

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

@Override

public String toString(){

return id+": "+"i4 = "+i4+",INT_5 = "+INT_5;

}

public int finalParamTest(final int i){

//!false:i++;

//不让改,只让读

return i+1;

}

public void finalReferenceTest(final FinalData fd){

//!false:fd = new FinalData();

//不能再指向新的对象,存储地址不准变

fd.param0++;

}

public static void main(String[] args) {

FinalData fd1 = new FinalData("fd1");

/*基本类型变量*/

//!false:fd1.valueOne++;

//!false:fd1.VALUE_TWO++;

//!false:fd1.VALUE_THREE++;

/*引用变量*/

fd1.v1 = new Value(10);

fd1.v2.i++

//!false:fd1.v2 = new Value(3);

System.out.println("fd1.v2.i = [" + fd1.v2.i + "]");

//!false:fd1.V_3 = new Value(10);

fd1.V_3.i++;

System.out.println("fd1.V_3.i = [" + fd1.V_3.i + "]");

/*引用变量之数组*/

System.out.println("before:fd1.a[] = " + Arrays.toString(fd1.a));

/*数组引用变量a是final修饰,

但是不代表它指向的数据值是final,

而是a存储的地址值不能改变

*/

//!false:fd1.a = new int[]{2,3,4,5,6,7};

for (int i = 0; i < fd1.a.length; i++) {

fd1.a[i]++;

}

System.out.println("after :fd1.a[] = " + Arrays.toString(fd1.a));

/*final 与static final*/

//下面示例分别创建了三个不同的对象,对其final 和final static 进行测试

/*可以发现,三个对象的i4值是随机生成且不能改变的,且不相同,

而INT_5的值不随对象改变而改变,因为被static修饰,在类加载时已经被初始化*/

System.out.println(fd1);//fd1: i4 = 15,INT_518

FinalData fd2 = new FinalData("fd2");

System.out.println(fd2);//fd2: i4 = 13,INT_518

FinalData fd3 = new FinalData("fd3");

System.out.println(fd3);//fd3: i4 = 1,INT_5 = 18

//!false:System.out.println(fd1.finalParamTest(param0));

//!false:System.out.println(fd1.finalParamTest(param1));

//non-static field'param1' cannot be referenced from a static context

System.out.println(fd1.finalParamTest(PARAM_2));

System.out.println(fd1.finalParamTest(param3));

/*为什么形参列表里的参数用final修饰,但是用final修饰的param1无法传进去,

一定要static修饰?*/

System.out.println("fd1.param0 = "+fd1.param0);

fd1.finalReferenceTest(fd1);

System.out.println("fd1.param0 = "+fd1.param0);

}

}

文章如有理解错误或叙述不到位,欢迎大家在评论区加以指正。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

java final修饰的数组_Java基于final修饰数据过程解析相关推荐

  1. java 中final修饰的变量_java中final修饰符的使用方法

    本文为大家分享了java中final修饰符的使用,供大家参考,具体内容如下 1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可 ...

  2. java字符串的字节数组_Java字节数组到字符串到字节数组

    我正在尝试将byte []转换为字符串,将byte []的字符串表示形式转换为byte []的转换...我将byte []转换为要发送的字符串,然后我期望我的Web服务(用python编写)将数据直接 ...

  3. java怎么复制动态数组_Java 数组排序复制等操作(Java Arraycopy)

    //手机终端 请上下左右 滑动屏幕 观看更全! //package Main; public class Arraycopy { public static void main(String[] ar ...

  4. java字符连接字符串数组_Java中连接字符串的最佳方法

    java字符连接字符串数组 最近有人问我这个问题–在Java中使用+运算符连接字符串是否对性能不利? 这让我开始思考Java中连接字符串的不同方法,以及它们如何相互对抗. 这些是我要研究的方法: 使用 ...

  5. java填充二维数组_Java用Arrays.fill()初始化二维数组的实现

    在最短路径问题上遇到了一个问题,对于二维int数组 map[][],需要初始化为int的最大值,不想用双重循环赋初值,想用Arrays.fill()填充但是失败了...... 首先说明,Arrays. ...

  6. java从控制台输入数组_Java将控制台输入的一行整数转成整型数组

    思路: 将一行数据按字符串的形式读取进来. 首先判断输入的字符串是不是空,为空的话,则不作任何操做. 其次,将字符串按照指定方式切分为字符串数组,此处是按照空格切分,由于输入是按空格区分的. 最后,尝 ...

  7. java字符串转字符串数组_Java字符串数组到字符串

    java字符串转字符串数组 Today we will look into how to convert Java String array to String. Sometimes we have ...

  8. java字符串转字符串数组_Java字符串数组

    java字符串转字符串数组 Java String array is used to hold fixed number of Strings. String array is very common ...

  9. java txt 二维数组_java 将一个二维数组存到txt文件里,然后再读取

    java 将一个二维数组存到txt文件里,然后再读取 mip版  关注:286  答案:3  悬赏:30 解决时间 2021-01-26 21:40 已解决 2021-01-26 04:05 将一个d ...

  10. java字符串如何转为数组_java如何将字符串转为数组

    java将字符串转为数组的方法是:可以通过split方法实现,该方法可以根据匹配给定的正则表达式来拆分字符串.具体用法:[String[] arr = str.split(",") ...

最新文章

  1. [译] JavaScript 中的 CSS:基于组件的样式的未来
  2. 互联网1分钟 |1128
  3. 《Python编程从入门到实践》记录之第2章 变量和简单数据类型总结(思维导图)
  4. 用聚合数据API快速写出小程序
  5. Maven 仓库使用与私有仓库搭建
  6. 15.用户故事与敏捷方法——Scrum与用户故事笔记
  7. jQuery里如何使用ajax发送请求
  8. ResourceExhaustedError 解决方案
  9. android中jni数据加密,Android jni字符串如何加密
  10. 【Oracle】执行计划详解
  11. 用tbtools基因家族分析《一》
  12. 波士顿学院计算机科学专业,波士顿学院计算机专业
  13. 【日语】日语一级句型强记
  14. boost::stacktrace::detail相关的测试程序
  15. Web3D开发者兼职副业平台推荐
  16. 如何将深度学习模型加载到android环境中
  17. 国家普通话智能测试软件,国家普通话水平智能测试系统
  18. G2评选ManageEngine为UEM的高效执行者和创新领导者
  19. 企业网络信息化建设解决方案
  20. 每日三个笑话-20151008

热门文章

  1. 黑苹果efi文件_台式机华硕主板黑苹果EFI引导文件分享amp;2020.12.2
  2. python模拟用户数据
  3. HBase的安装和配置
  4. 三菱PLC-信捷人机通信(编程)
  5. navicat 导入excel 闪退
  6. 各大厂面试云集的《520道LeetCode题Java版答案》
  7. matlab颜色选取与绘制?(附有颜色全表)
  8. 【C语言】 扫雷游戏(保姆级的实现过程)
  9. 管理系统中计算机er图怎么画,er图怎么画?数据库E-R图画法教程详解
  10. 计算机计算公式代码,简单的计算器代码