Java成长之路(一)-基本数据类型

时间:2022-11-10 17:26:05

基础

关键字

Java关键字是事先定义的,有特别意义的标识符,有时又叫保留字,还有特别意义的变量。

Java的关键字对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名、方法名、类名、包名和参数。

abstract assert boolean break byte
case catch char class const
continue default do double else
enum extends final finally float
for goto if implements import
instanceof int interface long native
new package private protected public
return strictfp short static super
switch synchronized this throw throws
transient try void volatile while

具体含义可详见下面的附录表

标识符

标识符:就是用来标识变量名、函数名、数组名、文件名、类名等的有效字符序列。

标识符的几条规则:

  1. Java语言规定的标识符只能是大写字母、小写字母、下划线(_)、数字、美元符号($)的任意组合,且第一个字母不能为数字以免与数值字面值产生混淆。
  2. 不能是Java关键字和保留字,但可以包含关键字和保留字,如:void不合法,但Myvoid合法。
  3. Java是大小写敏感的,标识符也不例外。
  4. 标识符没有长度限制。

注:从JDK8开始,不建议单独使用下划线作为标识符。

'_' should not be used as an identifier, since it is a reserved keyword from source level 1.8

拓展:

  • 类名&接口:每个单词首字母大写,其他小写。(驼峰式命名)
  • 方法&变量:以小写字母开头,如果方法名由多个单词组成,则从第二个单词开始首字母大写。
  • 常量:常量名全部大写,各单词间以“_”连接。
  • 包名:全部小写。

常量

常量就是在程序的执行过程中其值不能改变的一个标识符。

在Java中,利用关键字final指示常量,关键字final表示这个变量只能被赋值一次。一旦被赋值之后,就不能够再更改了。习惯上,常量名使用全大写。

示例:

final int SCORE = 100;

变量

变量与常量是相反的,在执行过程中其值是可以改变的一个标识符。程序通过一个变量名来代表该变量存储的数据。变量都有一个作用域来定义变量的可见范围和生存期。

在Java中所有变量必须先声明后使用。变量声明的方法:

类型 标识符 = 值
  • 类型:Java中的任何一种数据类型,可以是下面的八种数据类型,对象等
  • 标识符:就是变量的名字,也可以理解成C++中的指针。

变量作用域

Java语言里大括号括起来的部分是一个代码块。代码块中的变量只在本代码块中可以使用,其嵌套的子代码块也可以使用。

注释

在Java的编写过程中我们需要对一些程序进行注释,除了自己方便阅读,更为别人更好理解自己的程序,所以我们需要进行一些注释,可以是编程思路或者是程序的作用,总而言之就是方便自己他人更好的阅读。

Java提供了三种注释方式:

  • // 注释一行
  • /* ...... */注释若干行
  • /**……*/文档注释

JDK提供了为自己的代码自动生成API网页的工具javadoc,其可以对文档注释中的内容进行解析,然后转换HTML格式的帮助文档。

字面值

在Java中,常量的值是通过使用表示常量的字面值(literal)创建的。例如,下面是一些字面值:

100 98.6 'X' "This is a test"

从左向右,第一个字面值标识了一个整数,下一个是浮点数值,第三个是字符常量,最后面一个是字符串。在可以使用某种类型的值得任何地方,都可以使用对应类型的字面值。

拓展:

从JDK7开始,可以使用二进制指定整型字面值。为此,使用0b或0B作为数值的前缀。例如使用二进制字面值指定十进制10:

int x = 0b1010;

从JDK7开始,在整型字面值中还可以嵌入一个或多个下划线。嵌入下划线可以使越多很大的整数变得更加容易,当编译字面值时,会丢弃下划线。例如:

int x = 1_2345_6789;

注意:下划线只能用于分隔数字,不能位于字面值的开头和结尾。然而,在两个数字之间使用多个下划线是允许的。

基本数据类型

Java语言定义了八种基本数据类型,而这八种数据类型又可以分为以下四组:

  • 整型:short、int、long 和 byte
  • 浮点型:float 和 double
  • 字符型:char
  • 布尔型:boolean

整型

Java语言包含字节型(byte)、短整型(short)、整型(int)、长整型(long)四种,整数类型可以使用十进制、八进制、十六进制来表示,默认是十进制,其它进制表示方式:

  • 0B表示二进制【JKD1.7】,首位以0B开始
  • 017表示八进制,首位以0开始
  • 0xAB表示十六进制数据,首位以0x开始

Java中的整型常量默认为int型。若要声明long型常量,则可以在末尾添加 L

整数类型 位数 值得范围
byte 8 -128 ~127
short 16 -3_2768 ~ 3_2767
int 32 -21_4748_3648 ~ 21_4748_3647
long 64 -2[^64-1] ~ 2[^64-1] - 1

注:从JDK1.7开始,数值型的字面值中的数字之间可以出现任何数量的下划线,例如1_123

在使用这些整型类型时,一定要注意不可以超过其取值范围;否则,就会产生溢出,从而取到其他不可预料的值。

int max = Integer.MAX_VALUE; //2147483647
int min = Integer.MIN_VALUE; //-2147483648
System.out.println(max+1); //输出:-2147483648
System.out.println(min-1); //输出:2147483647

注:Java中没有无符号整型类型。

浮点型

浮点型包括单精度浮点型(float)和双精度浮点型(double)两种类型。

浮点类型 位数 值得范围
float 32 ±1.4E-45 ~ ±3.4E+38
double 64 ±4.9E-324 ~±1.7E+308

在数字后带有字母F或f(float)、D或d(double),或者一个数字包括小数点或指数部分则该数字为浮点类型。

注:如果浮点值没有使用float关键字定义为float类型,则系统默认其类型为double型。

Java浮点类型常量有两种表示形式:十进制和科学计数法形式。其中十进制形式必须含有小数点,例如 2.13、34.0;科学计数法形式,例如3.54e2、2.7E2。

定义单精度浮点数时,不能写成类似float a = 20.1这种形式,需要在值后面加上 F或f,因为小数常量默认为double类型。

在实际的操作中,尤其是数学计算或需要经过多次计算才能得出结果,并且对结果的精度要求比较高的情况下,通常使用双精度型。

System.out.println(2.0-1.1);

上面的结果下意识会是输出为0.9,但实际输出为0.8999999999999999。其主要原因是浮点数值采用二进制系统表示,而在二进制系统中无法精确的表示分数 1/10 ,这就好像十进制无法精确地表示1/3一样。那如果需要精确计算该怎么办呢?如果需要在数值计算中不含有任何舍入误差,可以使用Java提供的BigDecimal类。

拓展:

Java中整型常量默认为int类型,为其分配4字节大小的空间。如果需要声明long类型的常量,可以在后面加L(小写也可以,但不建议):

int i = 3;
long L =3L;

Java中浮点类型常量默认为double型,如要声明一个常量为float型,则需在数字后面加F或f:

double d = 3.14;
float f = 3.14f;

float f = 3.4 语句是否错误?

“float f = 3.4”语句的写法是不正确的,因为3.4默认为double类型,double类型必须使用强制类型转换才可以,如“float f = (float)3.4”

char类型

字符型(char)可表示通常意义上的单个字符,占用两个字节可表示范围为0~65536。char类型的字面量要用单引号括起来。例如 ‘A' 是编码值为65所对应的字符常量。它与 “A” 不同,“A”是包含一个字符A的字符串。char类型的值可以表示为十六进制,其范围从\u0000\Uffff

Java中char型采用了Unicode编码,而Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,Unicode字符集有多个编码方式,分别是UTF-8UTF-16UTF-32。而UTF-8是使用最广的一种Unicode的实现方式。

拓展:尽管char被设计成容纳Unicode字符,但它也可以用作整数类型,可以对char类型的变量执行算术运算。

注意:UTF-8是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的Unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
  • 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的Unicode码。

拓展:

Unicode最初设计是作为一种固定宽度的 16 位字符编码。在 Java 编程语言中,基本数据类型char初衷是通过提供一种简单的、能够包含任何字符的数据类型来充分利用这种设计的优点。不过,现在看来,16 位编码的所有 65536 个字符并不能完全表示全世界所有正在使用或曾经使用的字符。于是,Unicode标准已扩展到包含多达 1112064 个字符。那些超出原来的 16 位限制的字符被称作增补字符Unicode标准 2.0 版是第一个包含启用增补字符设计的版本,但是,直到 3.1 版才收入第一批增补字符集。由于 J2SE 的 5.0 版必须支持 Unicode标准 4.0 版,因此它必须支持增补字符。

代码点(code point)是指与一个编码表中的某个字符对应的代码值。在Unicode标准中,代码点采用十六进制书写,并加上前缀U+,例如U+0041就是字母A的代码点。

Unicode代码点可以分为17个代码级别(code plane)。第一个代码级别称为基本的多语言级别,代码点从U+0000到U+FFFF。其余的16个级别,代码点从U+10000到U+10FFFF。在Java中,char类型用UTF-16编码描述一个代码单元。

Java 平台如何支持增补字符的呢?

JSR-204 专家组使用了一种分层的方法:

  • 使用基本类型int在低层 API 中表示代码点,例如Character类的静态方法。
  • 将所有形式的char序列均解释为 UTF-16 序列,并促进其在更高层级 API中的使用。
  • 提供 API,以方便在各种char和基于代码点的表示法之间的转换。

在Java1.5之后,增补字符使用两个char型变量来表示。第一个char型变量的范围称为“高代理部分”(high-surrogates range,从uD800到uDBFF,共1024个码位), 第二个char型变量的范围称为“低代理部分”(low-surrogates range,从”uDC00到”uDFFF,共1024个码位)。这两个char型变量就组成了所谓的surrogate pair(在底层实际上是使用一个int进行表示的)。

boolean类型

boolean(布尔)类型只有两个值:falsetrue,用来判断逻辑条件。整型值和布尔值之间不能进行相互转换。

类型转换

在编程过程中,可能需要将一种数据类型转换为另一种数据类型。Java为我们提供了两种数据类型转换方式:自动类型转换和强制类型转换。

自动类型转换

在运算时不需要用户指定目标数据类型,系统自己进行类型转换,但前提需要满足以下两个条件:

  • 两种类型互相兼容,例如int和long兼容,int和boolean不兼容。
  • 目标数据类型的范围大于被转换数据类型值得范围,例如long类型分配内存大小8字节,int类型是4字节,因此long类型的范围比int类型大。

当满足这两个条件时,会发生扩宽转换(widening conversion)。

特例:可以将整型常量直接赋给byte,short,char等类型变量,而不需要强制类型转换,只要不超出其表数范围。

简单类型除了boolean类型以外,其它的数据类型之间可以实现自动转换,但需要遵循一定规则,如下:

Java成长之路(一)-基本数据类型

强制类型转换

场景:

  • 两种类型互相兼容,但是目标数据类型的范围小于被转换数据类型值得范围。
  • 不兼容的两种类型。

语法:(目标数据类型)value

示例:byte a=(byte) 256;

int类型的值强制转换为byte类型。如果整数的值超出了byte类型的范围,结果将以byte类型的范围为摸(用整数除以byte范围后的余数)减少。

int x = 257;
byte b = (byte)x;//结果为1,257/128=2余1

当将浮点值赋给整数类型时会发生另一种不同类型的转换:截尾(truncation)。整数没有小数部分,当然会直接舍去,当然如果整数部分的数值太大,以至于无法保存到目标整数类型中,那么数值将以目标类型的范围为模减少。

表达式中的自动类型提升

除了赋值外,还可能在表达式中发生类型抓换。

byte a = 40;
byte b = 50;
byte c = 100;
int d = a * b / c;

中间部分a*b的结果很容易超出byte操作数的范围。为了解决这类问题,当对表达式求值时,Java自动将每个byte、short或char操作数提升为int类型。这意味着使用int类型而不是byte类型执行子表达式a*b。因此,尽管a和b都被指定为byte类型,中间表达式(50*40)的结果2000是合法的。

尽管自动类型提升很有用,但是它们会导致难以理解的编译时错误。例如,下面的代码看起来是正确的,但是会导致问题:

byte a = 2;
byte b = 3;
byte c = a*b;// Type mismatch: cannot convert from int to byte
byte d = a*2;//Type mismatch: cannot convert from int to byte

上面的代码中在表达式过程中自动提升为int类型,所以结果也被提升为int类型。因此,现在表达式的结果是int类型,如果不适用强制类型转换,就不能将结果赋值给那个byte变量。如果能理解溢出产生的结果,就应当使用显式的强制类型转换。

类型提升规则:

如果对基本数据类型执行算术运算或按位运算时,只要类型比int小(即char、byte或short),在运行前都会自动转换为int。这样一来,最终生成的结果就是int类型。如果想把结果赋值给较小的类型,就必须使用强制类型转换。

通常,表达式中出现的最大的数据决定了表达式最终结果的数据类型。


拓展:

对象的向上/向下转型发生在多态的情况下,这在后期会着重说明!

基本数据类型的向上转型一般发生在自动类型转换,当然你可以将类型强制向上转型。而基本数据类型的向下转型(窄化)就必须通过强制类型来完成了,当然可能会伴随着溢出问题需要注意!

附录表

关键字 含义
abstract 表明类或者成员方法具有抽象属性
assert 断言,用来进行程序调试
boolean 基本数据类型之一,布尔类型
break 提前跳出一个块
byte 基本数据类型之一,字节类型
case 用在switch语句之中,表示其中的一个分支
catch 用在异常处理中,用来捕捉异常
char 基本数据类型之一,字符类型
class 声明一个类
const 保留关键字,没有具体含义
continue 回到一个块的开始处
default 默认,例如,用在switch语句中,表明一个默认的分支
do 用在do-while循环结构中
double 基本数据类型之一,双精度浮点数类型
else 用在条件语句中,表明当条件不成立时的分支
enum 枚举
extends 表明一个类型是另一个类型的子类型,这里常见的类型有类和接口
final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量
finally 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块
float 基本数据类型之一,单精度浮点数类型
for 一种循环结构的引导词
goto 保留关键字,没有具体含义
if 条件语句的引导词
implements 表明一个类实现了给定的接口
import 表明要访问指定的类或包
instanceof 用来测试一个对象是否是指定类型的实例对象
int 基本数据类型之一,整数类型
interface 接口
long 基本数据类型之一,长整数类型
native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
new 用来创建新实例对象
package
private 一种访问控制方式:私用模式
protected 一种访问控制方式:保护模式
public 一种访问控制方式:共用模式
return 从成员方法中返回数据
short 基本数据类型之一,短整数类型
static 表明具有静态属性
strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范[1]
super 表明当前对象的父类型的引用或者父类型的构造方法
switch 分支语句结构的引导词
synchronized 表明一段代码需要同步执行
this 指向当前实例对象的引用
throw 抛出一个异常
throws 声明在当前定义的成员方法中所有需要抛出的异常
transient 声明不用序列化的成员域
try 尝试一个可能抛出异常的程序块
void 声明当前成员方法没有返回值
volatile 表明两个或者多个变量必须同步地发生变化
while 用在循环结构中

拓展:

除了8中简单数据类型之外的所有数据类型都被称为引用数据类型,引用数据类型的大小统一为4个字节,记录的时其引用对象的地址(类似于就是C++中的指针),例如类、接口和数组等。

Java属于强类型语言,在定义变量时必须严格指定变量类型。Java类型主要分为简单类型和引用类型,简单类型变量直接存储变量值,而引用类型变量存储的却是地址,这一点在赋值的时候至关重要。

参考资料:

Java中的代码点和代码单元

在我写过的博客中有两篇博客是对资源的整理,可能对大家都有帮助,大家有兴趣的话可以看看!!


Java成长之路(一)-基本数据类型
Java成长之路(一)-基本数据类型

博文编号:20180315154750