Forgetful Alann

In youth we learn, in age we understand.

0%

Java类型与变量

Java中的基本类型


Java中共有8中基本类型:

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

整型


Java中没有无符号整型,所有的数据类型存储位数也与平台无关,整型存储位数与范围如下:

类型 存储字节数 范围
byte 1字节 -2^7 ~ 2^7-1
short 2字节 -2^15 ~ 2^15-1
int 4字节 -2^31 ~ 2^31-1
long 8字节 -2^63 ~ 2^63-1

其中byte类型类似于C中的char类型,Java程序中可以使用十进制,八进制,十六进制以及二进制的形式来表示这些数值:

  • 八进制:以数字0开头,如 017
  • 十六进制:以0x或0X开头,如 0X4a
  • 二进制(自Java7开始):以0b或0B开头,如 0B1011,还可以用下划线来进行分割,以便更好的阅读,编译器会自动去除下划线,如 0B1001_0011

此外,在表示长整型数值时,应当在数值后添加一字母l或L,来显示的表明该数值为long类型.

浮点型


浮点类型及存储位数:

类型 存储字节数 范围
float 4字节 大约 ± 3.402 823 47E+38F (有效位数为 6 ~ 7 位)
double 8字节 大约 ± 1.797 693 134 862 315 70E+308 (有效位数为 15 位)

浮点数可以使用带小数点的小数如:3.14,或科学计数法,如: 3.1412E2,以及十六进制,如:0x4ap-3,来表示,在十六进制表示法中,p用来分隔尾数(4a)与指数(-3),且尾数用十六进制表示,而指数用十进制表示,并以2为基数,例如 0x4ap-3=(4*16+10)*2^-3.

在表示float类型是,应在数值后添加字母f或F来显示的表明该数值为float类型,否则Java默认将该数值当做double型来处理(double类型数值后也可添加字母d或D).

字符型char


Java中的char类型原本设计用来存储单个字符,char变量中存储字符时采用UTF-16编码格式,UTF-16一个代码单元占用16位,可以用来存储大多数unicode编码中的字符,但对于其他的字符,则需要至少2个UTF-16代码单元,因此,char变量并不能表示一个字符,其真是的含义是表示一个UTF-16代码单元,因此char变量的含义如下:

  • 代表一个UTF-16代码单元
  • 占用2字节

布尔型boolean


Java中用true与false表示布尔型,且布尔型与其他类型不能相互转换。

字符串String


Java中提供了一个预定义类String用来表示字符串,字符串之间可以使用加号(+)进行拼接,如:

1
"hello" + "java";

String类中没有提供修改当前字符串的方法。

字符串与编码

Java使用unicode编码,String类中使用一个char数组来保存字符串,这个char数组使用了UTF-16编码格式来保存unicode字符。

获取字符串的长度

String中提供了获取字符串长度的方法:

1
public int length();

而该方法只是简单的返回内char数组的长度,因此,该方法实际返回的是该字符串使用UTF-16编码格式编码后的代码单元数量,由于大多数字符使用UTF-16格式编码都只产生一个代码单元,因此该方法一般不会产生问题,但不够严谨。

一串字符串的字符数应该使用字符串中unicode码点数(code point)来表示,因此,应该这样来获取字符串的长度:

1
2
3
4
String str = "Hello World";
int length = str.codePointCount(0, str.length());
// 或者
length = str.codePoints().toArray().length;

判断字符串相等

不能依赖运算符==来判断两个字符串是否相等,因为字符串是一个对象,两个相同的字符串可能是两个不同的对象,而使用==来比较两个对象时,实际比较的是这两个对象的地址是否相等。

String对象中提供了用于比较字符串是否相等的方法:

1
public boolean equals(Object obj);

变量与常量


Java是强类型编程语言,所有的变量在使用前都必须先进行声明和初始化。

变量声明


声明一个变量时需指定变量的类型与变量名,例如:

1
2
3
4
int num;
double radius;
boolean isMale;
String name;

变量的初始化


变量可以在声明的同时进行初始化:

1
String str = "this is a string";

也可以在声明之后再初始化,但在使用该变量前,必须先进行初始化:

1
2
String str;
str = "this is a string";

常量


与变量类似,常量使用final关键字进行声明,常量在进行初始化时,也可以先声明,以后再初始化,但只能初始化一次:

1
2
3
4
final double PI = 3.14125;
//等同于
final double PI;
PI = 3.14125;

变量中的引用与值


对于基本类型变量,该变量存储的是相应类型的值,而对于对象变量,该变量存储的是相应对象的引用,在Java中,传递变量或将变量赋值给其他变量时,总是会复制变量存储的内容来进行传递,对于基本类型变量,总是会复制变量的值,而对于对象变量,只是单纯的复制了存储在变量中的引用,因此在传递变量给方法时,会有值传递与引用传递,而其本质都是传递存储在变量中的内容。

大数值类


基本的数值类型表示的数值范围有限,在java.math包中定义了两个分别表示整型和浮点型的大数值类:BigInteger与BigDecimal,它们可以表示任意精度的数值,并且在类中提供了相应的算数运算方法。

数组


Java中的数组可以是原始类型数组,也可以是对象数组。

数组的声明与初始化


声明数组时需要指定数组的类型,大小,数组名:

1
2
3
int[] arr = new int[10];
// 或者
int arr[] = new int[10];

也可以在声明的同时进行初始化:

1
2
3
4
5
6
int[] arr = {1, 2, 3};
//相当于
int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;

还可以声明一个匿名数组:

1
2
3
new int[]{1, 2, 3};
//将匿名数组存储给一个变量
int[] arr = new int[]{1, 2, 3};

多维数组


例如声明一个二维数组:

1
int[][] arr = new int[2][3];

在声明的同时进行初始化:

1
2
3
4
int[][] a = {
{1,2,3},
{1,2,3},
};

不规则数组


实际上Java只支持一维数组,当一维数组中的元素存储另一个数组时,即成为了多维数组,因此,可以创建不规则的多维数组:

1
2
3
4
int[][] arr = new int[3][];
arr[0] = new int[4];
arr[1] = new int[5];
arr[2] = new int[2];

数组的遍历


数组拥有length属性表示创建数组时的大小,利用该值可合法的遍历数组中的所有元素:

1
2
3
for(int i=0,i<arr.length;i++){
arr[i]++;
}

如果只需要访问数组中的元素,可以使用for each循环:

1
2
3
for(int item:arr){
System.out.println(item);
}

数组的拷贝


Java中一个数组变量存储的只是一个数组的引用,因此:

1
2
int[] arr = {1, 2, 3};
int[] arrCopy = arr;

像这样的只是拷贝了数组的引用,arr与arrCopy依然是一个数组,最通用的方法是遍历第一个数组中的所有元素并将它复制给第二个数组:

1
2
3
4
int[] arrCopy = new int[arr.length];
for(int i=0;i<arr.length;i++){
arrCopy[i] = arr[i];
}

不过Java中提供了几个方法用于这样的数组拷贝:

1
2
3
public static native void System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
public static int[] Arrays.copyOf(int[] src, int newLength);
Object.clone();

第一个拷贝方法必须先初始化目标数组;

对于第二个方法,Arrays类中,重载了所有基本类型的数组拷贝方法,对于对象数组的拷贝,还实现了泛型copyOf方法;

第三个拷贝方法是数组类重写了父类Object的clone()方法;

不过这些拷贝方法都只是浅拷贝,对于基本类型数组,不会产生问题,但对于对象数组,拷贝数组元素时,也只是复制了元素所存储的引用,因此,使用这些方法拷贝对象数组时,它们的元素依然指向相同的对象,这时可以遍历原始数组,分别对每个对象进行复制。

枚举类型


对于那些只有有限个可能值的集合,可以使用枚举类型:

1
2
3
4
// 定义枚举类
enum Color{RED, GREEN, BLUE};
// 使用枚举
Color blue = Color.BLUE;

Java包装类


Java中,基本类型不是对象,没有自己的方法,为了让这些基本类型拥有面向对象的特性,Java中为基本类型提供了包装类:

基本类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character

在每个基本类型的包装类中,提供了相应的属性(如最大值,最小值),以及实现了许多操作对象的方法。

自动装箱/拆箱

将基本类型转换为相应的包装类型即成为装箱,相反的过程成为拆箱,在需要的时候,Java编译器会为我们自动的进行装箱与拆箱,自动装箱/拆箱在两种情况下会进行:

  • 赋值
  • 方法调用

如:

1
2
Integer integer = 123;    //自动装箱 调用Integer.valueOf(123);
int i = integer; //自动拆箱 调用integer.intValue();

如上,编译器会根据需要自动的调用方法来进行装箱与拆箱,其中 valueOf(args) 是Integer累的静态方法,返回Integer对象。同样,在进行方法调用时,编译器会根据方法需要的参数类型进行自动装箱与拆箱。

类型转换


基本类型之间的强制转换


对于基本数值类型(byte, short, int, long, float, double),在需要时,低精度的数值类型会自动的往高精度的数值类型转换,此时无需手动转换,如果需要将高精度类型向低精度类型进行转换,可以手动进行强制转换:

1
2
double d = 3.14;
int i = (int)d; //强制转换为3

这种转换会根据转换的类型自动截断,不会进行四舍五入处理。

但布尔,字符型与数值型之间不能相互强制转换,但可以使用条件语句将布尔与数值型之间进行互转:

1
2
boolean bool = true;
int i = bool? 1:0; //使用三元运算符将布尔值转换为整型

基本类型转为对象


除了利用编译器的自动装箱机制,也可以手动的将基本类型转换为对象,如以 int 型为例:

  • 利用静态方法:
1
Integer integer = Integer.valueOf(123);
  • 利用构造方法:
1
Integer integer = new Integer(123);

字符串与基本类型之间的转换


每个包装类中提供了静态的 parseXXX方法用于将字符串转换为相应的基本类型,例如

1
2
String str = "123";
int i = Integer.parseInt(str);

还可以制定转换基数:

1
int i = Integer.parseInt("4a",16);   // i = 74

注意: 如果字符串中包含其他字符会抛出NumberFormatException异常。

当需要将对象转换为字符串是,只需调用字符串中的 toString() 方法即可,许多预定义类都继承或重写了该方法,在自定义类中,可根据需要重写该方法。