二、基本数值类型、数组和类型转换

文章目录

  • 基本数值类型、数组和类型转换
    • 1.1 整数类型
    • 1.2 浮点数类型
    • 1.3 布尔类型
    • 1.4 字符类型
    • 1.5 数组类型
      • 1.5.1 一维数组
      • 1.5.2 多维数组
    • 1.6 数据类型的转换
      • 1.6.1 自动类型转换
      • 1.6.2 强制类型转换

基本数值类型、数组和类型转换

本文为书籍《Java编程的逻辑》1和《剑指Java:核心原理与应用实践》2阅读笔记

1.1 整数类型

整数类型有byteshortintlong,分别占1、2、4、8个字节(一个字节占8 bit),取值范围如下表所示:

类型名存储空间取值范围
byte1 byte − 2 7 ∼ 2 7 − 1 -2^7\sim2^{7}-1 27271
short2 bytes − 2 15 ∼ 2 15 − 1 -2^{15}\sim2^{15}-1 2152151
int4 bytes − 2 31 ∼ 2 31 − 1 -2^{31}\sim2^{31}-1 2312311
long8 bytes − 2 63 ∼ 2 63 − 1 -2^{63}\sim2^{63}-1 2632631
byte b = 23;
short s = 3333;
int i = 9999;
long l = 32323;

在给long类型赋值时,如果常量超过了int的表示范围,需要在常量后面加大写或小写字母L,即Ll,例如:

long a = 3232343433L;

之所以需要加Ll,是因为数字常量默认为是int类型。

1.2 浮点数类型

小数类型有floatdouble,占用的内存空间分别是 4 4 4 8 8 8字节,有不同的取值范围和精度,double表示的范围更大,精度更高,具体如下表所示:

类型名存储空间取值范围
float4 bytes − 3.40 3 38 ∼ 3.40 3 38 -3.403^{38}\sim3.403^{38} 3.403383.40338
double8 bytes − 1.79 8 308 ∼ 1.79 8 308 -1.798^{308}\sim1.798^{308} 1.7983081.798308

对于double,直接把熟悉的浮点数表示赋值给变量即可,但对于float,需要在数字后面加大写字母F或小写字母f。这是由于小数常量默认是double类型。

double d = 333.33;
float f = 333.33f;

1.3 布尔类型

布尔(boolean)类型很简单,直接使用truefalse赋值,分别表示真和假,例如:

boolean b = true;
b = false;

1.4 字符类型

字符类型char用于表示一个字符,这个字符可以是中文字符,也可以是英文字符,char占用的内存空间是两个字节。字符型常量值的表示形式有如下几种:

  1. 用单引号括起来的单个字符的常量值,如'a''9'等,注意:"""是错误的,里面不能没有内容,必须有单个字符;
  2. 转义字符'\n''\t'等;
  3. 直接使用Unicode值,格式是'\u××××',其中××××表示一个16进制的整数;
  4. 直接使用十进制整型常量值,如10098等。
public class TestCharacter{public static void main(String[] args){char c1 ='a';char c2 ='\"'char c3 ='\u0043'; char c4 =100;System.out.printIn("c1:" + c1);System.out.printIn("c2:" + c2);System.out.println("c3:" + c3);System.out.printIn("c4:" + c4);}
}

大部分的常用字符用一个char就可以表示,但有的特殊字符用一个char表示不了,字符型底层依然是以整型(相当于无符号整型)存储的,关于char更多其他细节,后面会展开。

1.5 数组类型

1.5.1 一维数组

基本类型的数组有3种赋值形式,如下所示:

int[] arr = {1,2,3}; // 第一种
int[] arr = new int[]{1,2,3}; // 第二种
int[] arr = new int[3]; // 第三种
arr[0]=1; arr[1]=2; arr[2]=3;

1种和第2种都是预先知道数组的内容,而第3种是先分配长度,然后再给每个元素赋值。第3种形式中,即使没有给每个元素赋值,每个元素也都有一个默认值,这个默认值跟数组类型有关,数值类型的值为0booleanfalsechar为空字符。

数组长度也可以动态确定,如下所示:

int length = ... ; //根据一些条件动态计算
int arr = new int[length];

数组长度虽然可以动态确定,但定了之后就不可以再改变。数组有一个length属性,是只读属性。还有一个小细节,不能在给定初始值的同时给定长度,即如下格式是不允许的:

int[] arr = new int[3]{1,2,3}

我们可以这么理解,因为初始值已经决定了长度,再给个长度,如果还不一致,计算机将无所适从。数组类型和基本类型是有明显不同的,一个基本类型变量,内存中只会有一块对应的内存空间。但数组有两块:一块用于存储数组内容本身,另一块用于存储内容的位置。用一个例子来说明,有一个int变量a,以及一个int数组变量arr,其代码、变量对应的内存地址和内存内容如下表所示:

代码内存地址内存数据
int a=100;1000100
int[] arr={1,2,3}20003000
30001
30042
30083

基本类型a的内存地址是1000,这个位置存储的就是它的值100。数组类型arr的内存地址是2000,这个位置存储的值是一个位置30003000开始的位置存储的才是实际的数据"1, 2, 3"

为什么数组要用两块空间?不能只用一块空间吗?我们来看下面这段代码:

int[] arrA = {1,2,3};
int[] arrB = {4,5,6,7};
arrA = arrB;

这段代码中,arrA初始的长度是3arrB的长度是4,后来将arrB的值赋给了arrA。如果arrA对应的内存空间是直接存储的数组内容,那么它将没有足够的空间去容纳arrB的所有元素。用两块空间存储就简单得多,arrA存储的值就变成了和arrB的一样,存储的都是数组内容{4,5,6,7}的地址,此后访问arrA就和arrB是一样的了,而arrA {1,2,3}的内存空间由于不再被引用会进行垃圾回收,如下所示:

  arrA          {1,2,3}\\arrB   ->   {4,5,6,7}

由上也可以看出,给数组变量赋值和给数组中元素赋值是两回事,给数组中元素赋值是改变数组内容,而给数组变量赋值则会让变量指向一个不同的位置。

我们说数组的长度是不可以变的,不可变指的是数组的内容空间,一经分配,长度就不能再变了,但可以改变数组变量的值,让它指向一个长度不同的空间,就像上例中arrA后来指向了arrB一样。

1.5.2 多维数组

当要存储一组数据时,可以考虑使用一维数组,那么当有多组数据需要存储和处理时,就需要用到多维数组。

数组的标记是中括号,用一个中括号来表示一维数组,如果要声明二维数组,那么就需要用两个中括号来表示。语法格式如下所示:

  • 格式1:元素数据类型[][] 数组名; // 推荐

  • 格式2:元素数据类型[] 数组名[];

  • 格式3:元素数据类型 数组名[][];

示例代码:

int[][] arr;
int[] arr[];
int arr[][];

和一维数组一样,二维数组的初始化同样分为静态初始化和动态初始化。动态初始化又分为固定列数和不固定列数两种情况。

所谓静态初始化,是指在编译期间,就确定了行数和列数,并且也明确了每个元素的值。语法格式如下所示:

  • 格式1:元素数据类型 [][] 数组名 = new 元素数据举型 [][] {{ 元素1, 元素2, ......}, { 元素1, 元素2, ......},......};
  • 格式2:元素数据类型 [][] 数组名 = {{ 元素1, 元素2, ......}, { 元素1, 元素2, ......},......};

需要指出的是,格式2已将声明和初始化合二为一,格式1可以将声明和初始化分开。

int[][] arr =new int[][]{{10,20,30,40,50},{45,6,8}};
int[][] arr = {{10,20,30,40,50},{45,6,8}};

从如上所示的代码中可以看出,arr中相当于有两个一维数组,分别是{10, 20, 30, 40, 50}{45, 6, 8},如果分别把{10, 20, 30, 40, 50}{45, 6, 8}看成一个整体,那么arr就相当于有两个元素,即arr.length=2

第一个数组元素arr[0]的元素是{10, 20, 30, 40, 50},而很明显arr[0]又是一个一维数组,其长度为5,即arr[0].length=5。第二个元素arr[1]的元素值是{45,6,8},而arr[1]也是一个一维数组,其长度为3,即arr[1].length=3

二维数组再在内存中存储的格式如下:arr是二维数组类型的变量,里面有两个元素,存储的是首地址,而carr[1]均是一个一维数组,因此arr[0]arr[1]中仍然存储一维数组的首地址。

多维数组存储

所谓动态初始化,是指在对数组初始化时,只是确定数组的行数和列数,甚至行数和列数都需要在程序运行期间才能确定。当确定完数组的行数和列数之后,数组的元素是默认值。动态初始化又分为两种,一种是每行的列数可以相同,另一种是每行的列数可以不同。

  • 语法格式1:元素数据类型[][] 数组名 = new 元素数据类型[行数][列数];。语法格式中,行数和列数是固定的,固定列数,即里面所有一维数组的元素个数是一致的。示例代码:int [][] arr=new int[3][2]arr指向一个长度为3的数组对象,其中的每个元素都为存储的一维数组的首地址。每个一维数组中的元素都有默认值,相当于:{{0, 0}, {0, 0}, {0, 0}}
  • 语法格式2:元素数据类型[][] 数组名 = new 元素数据类型[行数][];。语法格式中,行数固定但是列数不固定。不固定列数,即里面所有一维数组的元素个数可以不相同。示例代码:int [][]=new int[3][],使用一维数组时必须先初始化,因为此时一维数组值为null。相当于:{null, null, null}

1.6 数据类型的转换

根据开发需要,不同数据类型的值经常需要进行相互转换,我们需要掌握基本数据类型的转换。Java语言只支持布尔型之外的七大基本数据类型间的转换,它们之间的转换类型分为自动类型转换强制类型转换

1.6.1 自动类型转换

当我们将一个基本数据类型的值直接赋给另一个不同类型的基本数据类型的变量时,如果赋值成功,则说明此时系统进行了一次自动类型转换,Java语言规范将其称为Wideding Conversion。如果赋值失败,则说明系统不能进行自动类型转换。自动类型转换需要满足目标类型的表示范围大于源类型的示数范围的要求,这就相当于将一个体积为2立方厘米的立方体放在体积为5立方厘米的立方体盒子中。

基本数据类型的自动转换关系如下图所示,根据箭头指向,左边类型的值可以自动转换成右边类型,反之,则不可以。

基本数据类型的自动转换关系

自动类型转换的注意事项。

  1. 当多种类型的数据进行混合运算时,系统首先自动将所有数据转换成容量最大的数据类型,再进行计算。例如,float字节数比long字节数小,但是float的容量更大。
  2. byteshortchar之间不会相互转换,它们在计算时首先会转换为int类型。
  3. 布尔类型不能与其他数据类型进行运算。
  4. 当把任何基本数据类型的值和字符串(String)进行"+“运算时,此时的”+"不再是加法的意思,而是表示连接运算。此时,运算的结果是String型。

1.6.2 强制类型转换

在一些开发场景中,我们也需要面对将上图中箭头右边类型转换为左边类型的情况,这时候就要进行强制转换,否则编译会报错,代码如下所示:

int a=200;
byte b = a; //编译报错

可以试想一下,如果将一个体积为5立方厘米的立方体放在体积为2立方厘米的立方体盒子中,正常来讲,是不是放不进去。如果要放进去,则要削去一部分体积,从而造成数据丢失。所以Java语言规范将强制类型转换称为Narrow Conversion。强制类型转换的语法格式如下所示:

(目标类型)数据值

示例代码:

int num = 98
short s = (short)num;
System.out.println(s); //结果:98
double d=9.95;
int i = (int)d;
System.out.printIn(i); //结果:9

具体规则如下所示:

  1. 如果目标类型和源类型都为整型,如将32int类型强转为8byte类型,则需要截断前面的24位,只保留右边8位。例如,int255强制转为byte 时,将会得到-1
  2. 目标类型是整型,源类型是浮点型,将直接截断浮点型的小数部位,这会造成精度损失。例如:int iValue=(int )12.5,将其强转后最终得到的iValue的值是12

  1. [1]马俊昌.Java编程的逻辑[M].北京:机械工业出版社,2018. ↩︎

  2. [2]尚硅谷教育.剑指Java:核心原理与应用实践[M].北京:电子工业出版社,2023. ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/448019.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux进程信号处理:深入理解与应用(1)

🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:its 6pm but I miss u already.—bbbluelee 0:01━━━━━━️💟──────── 3:18 🔄 ◀️…

江科大stm32学习笔记10——对射式红外传感器

一、接线 上电之后可以看到对射式红外传感器亮两个灯,如果此时用挡光片挡住两个黑色方块中间的部分,则只亮一个灯。 二、代码 将4-1的工程文件夹复制粘贴一份,重命名为“5-1 对射式红外传感器计次”,打开keil,右键添…

【FPGA Verilog】各种加法器Verilog

1bit半加器adder设计实例 module adder(cout,sum,a,b); output cout; output sum; input a,b; wire cout,sum; assign {cout,sum}ab; endmodule 解释说明 (1)assign {cout,sum}ab 是连续性赋值 对于线网wire进行赋值,必须以assign或者dea…

银行数据仓库体系实践(16)--数据应用之财务分析

总账系统 在所有公司中,财务分析的基础都是核算,那在银行的系统体系中,核算功能在业务发生时由业务系统如核心、贷款、理财中实现登记,各业务系统会在每天切日后统计当天各机构的核算科目的发生额与余额,并统一送到总账…

day35 柠檬水找零 根据身高重建队列 用最少数量的箭引爆气球

题目1:860 柠檬水找零 题目链接:860 柠檬水找零 题意 一杯柠檬水5美元,每位顾客只买一杯柠檬水,支付5美玉,10美元,20美元,必须正确找零 开始时并没有零钱 若可以正确找零,则返回…

【教程】苹果上架常见要求的有哪些?

引言 苹果上架要求是苹果公司对于提交应用程序到苹果商店上架的要求和规定。这些要求主要是为了保证用户体验、应用程序的质量和安全性。开发者在准备提交应用程序之前,务必了解并遵守苹果上架要求,以确保应用程序能够通过苹果公司的审核。 1. 合法合规…

[C++]类和对象(中)

一:类的六个默认成员函数 如果一个类中什么成员都没有,简称为空类。空类中并不是什么都没有,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为…

Transformer 自然语言处理(四)

原文:Natural Language Processing with Transformers 译者:飞龙 协议:CC BY-NC-SA 4.0 第十章:从头开始训练变换器 在本书的开头段落中,我们提到了一个名为 GitHub Copilot 的复杂应用,它使用类似 GPT 的…

【持续更新】2024牛客寒假算法基础集训营1题解 | JorbanS

文章目录 [A - DFS搜索](https://ac.nowcoder.com/acm/contest/67741/A)[B - 关鸡](https://ac.nowcoder.com/acm/contest/67741/B)[C - 按闹分配](https://ac.nowcoder.com/acm/contest/67741/C)[E - 本题又主要考察了贪心](https://ac.nowcoder.com/acm/contest/67741/E)[F -…

STM32 DMA的基本原理和工作机制解析

STM32微控制器中的DMA(Direct Memory Access,直接内存访问)是一种用于高效数据传输的特殊硬件功能。DMA允许外设之间直接进行数据传输,而无需CPU的干预。下面,我将为您详细解释STM32 DMA的基本原理和工作机制。 ✅作者…

【python接口自动化】- 对接各大数据库

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

【Qt】—— Hello World程序的实现

目录 (一)使⽤"按钮"实现 1.1 纯代码方式实现 1.2 可视化操作实现 (二)使⽤"标签"实现 2.1 纯代码方式实现 2.2 可视化操作实现 (一)使⽤"按钮"实现 1.1 纯代码方式实…