一、数据类型初阶
1、概述
- Java定义了基本数据类型、引用数据类型和自定义类型。
- 本主题将介绍Java的八种基本数据类型和引用数据类型中的String类型。
基本数据类型如下表所示:
类型 | 占用空间 | 取值范围 |
---|---|---|
byte(字节型) | 1字节 | -128~127 |
short(短整型) | 2字节 | -216~216-1 |
int(整型) | 4字节 | -231~231-1 |
long(长整型) | 8字节 | -9223372036854775808~9223372036854775807 |
float(单精度) | 4字节 | -3.402823510^38~ 3.402823510^38-1 |
double(双精度) | 8字节 | -1.79769310^308~ 1.7976931310^308 |
char(字符型) | 1字节 | 0~65535 |
boolean(布尔型) | 1或4字节 | false、true |
2、栈空间
- 栈空间存取数据的效率高。
- 栈中的数据按 “先进后出” 的方式管理。
- 栈空间存储空间较小,不能存放大量的数据。
- JVM将基本类型的数据存放在栈空间。
3、堆空间
- 堆空间存取数据的效率最低。
- 数据存放的位置随机分配。
- 堆空间存储数据的空间大,能存放大容量的数据。
二、变量的定义和变量使用的原因
1、什么是变量
- 变量就是可变的量。
- 常量就是不可变的量。
- 字面量:Java的变量和常量中存放的具体的数据称为字面量。
2、为什么使用变量
计算机的高级语言普遍使用变量来管理内存中存储的数据。
描述:图一是栈空间中存储基本数据类型的示意图,栈空间最上面有一个数据是字符‘男’,这个数据存储在栈空间中的一个地址表示空间中,比如,0x3a50:0x是十六进制的表示方式,3a50是具体的内存单元在栈空间中的地址。如果在写程序时,通过内存地址来读取这些数据,是非常抽象、难以理解、难以记忆的。为此,高级语言使用变量来操作内存中的数据,而不直接使用这些地址进行操作。图二所示,把数据‘男’,设一个变量sex来表示,我们在程序中或调用变量名sex来操作男,那么计算机底层会将sex和这个数据实际的地址进行一一对应,这样程序员只需要记住这个变量名就可以很方便的操作内存中该数据,这就是变量使用的意义。
3、变量管理引用类型的数据
引用类型的数据是存放在堆空间中的,堆空间中有个数组,这个数组在堆空间中的地址是aa00,如何操作这个数组呢?Java语言是采取以下处理方式,首先在栈空间中定义一个变量,这个变量名叫scores,这个变量存放的数据是堆空间中这个数组的地址aa00,栈中使用十六进制0xaa00来表示,这样我们在操作这个数组时,通过使用栈中的scores这个变量,调用该变量中保存的数组,即堆空间中该数组地址来操作数组。
三、变量的命名、定义和初始化
1、变量的命名
- 首字母是英文字母、$或下划线,由字母、数字、下划线组成。
- 变量的命名遵循见名知义的原则。
- Java变量名建议不用中文。
- 变量名首字母建议不用大写字母。
- 用驼峰命名法命名多个单词组成的变量名。例如:sumScore
- 变量名不要使用Java关键字。
2、变量的定义
定义变量:每个变量必须属于一种数据类型。
格式: 类型 变量名1,变量2,……,变量n;
示例:
byte score;//保存单科分数
short age;//保存年龄
int sumScore;//保存总分
long fileSize;//保存文件长度
float x,y;
double result;//保存运算结果
char sex;保存性别
boolean isContinue;//表示是否继续
String name;//表示姓名
3、变量的初始化
变量的初始化用赋值语句等号,将等号右侧的数据存储在左侧的变量中。
age = 23;
score = 70+5;
i = 10/5;
result = Math.pow(2,5)+3.5;
sex = '男';
isContinue = true;
name = "张"+"大飞";
四、用变量简化计算
【示例-1】保存中间结果,用分步骤计算简化复杂运算
计算 (sqrt(20)+sqrt(10))/(sqrt(20)-sqrt(10)) =
要求:显示结果保留小数点后1位,即对小数点后第2位四舍五入。
方案一:整体计算
第一步:精确结果
代码
public class Test01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("(sqrt(20)+sqrt(10))/(sqrt(20)-sqrt(10))="+
(Math.sqrt(20)+Math.sqrt(10))/(Math.sqrt(20)-Math.sqrt(10)));
}
}
结果:5.828427124746191
第二步:保留一位小数
代码
public class Test01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("(sqrt(20)+sqrt(10))/(sqrt(20)-sqrt(10))="+
Math.round(10*(Math.sqrt(20)+Math.sqrt(10))/(Math.sqrt(20)-Math.sqrt(10)))/10.0);
}
}
结果:5.8
方案二:分布计算
代码
public class Test01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
double sqrt20=Math.sqrt(20);//将20的平方根保存在sqrt20中
double sqrt10=Math.sqrt(10);//将10的平方根保存在sqrt10中
double result=(sqrt20+sqrt10)/(sqrt20-sqrt10);
result=Math.round(result*10)/10.0;
System.out.println("(sqrt(20)+sqrt(10))/(sqrt(20)-sqrt(10))="+result);
}
}
结果:5.8
五、用变量保存多种类型的数据
【示例-2】不同类型的变量存放对应类型的数据,变量的值可以改变。
预期结果见下图:
代码
public class Test02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String name="张飞";
char sex='男';
short age=35;
//float height=1.99f;
String type="豪放的";
System.out.println("嗨,大家好!俺叫"+name+",今年"+age+"岁,俺是一个"+type+sex+"士");
name="王菲";
sex='女';
age=33;
type="文静的";
System.out.println("嗨,大家好!俺叫"+name+",今年"+age+"岁,俺是一个"+type+sex+"士");
}
}
结果:
嗨,大家好!俺叫张飞,今年35岁,俺是一个豪放的男士
嗨,大家好!俺叫王菲,今年33岁,俺是一个文静的女士
六、变量的作用域
- Java用一对大括号作为语句块的范围,称为作用域。
- 作用于中德变量不能重复定义。
- 离开作用域,变量所分配的内存空间将被JVM回收。
【示例-1】对于以下代码,若将注释符号去掉,结果怎样?
public static void main(String[] args) {
{
String name="张三";
// String name="张三";
}
}
如果将注释符号去掉,大括号中将出现两个完全一样的变量name,因此,按照以上介绍的知识点,会出现变量重复定义的语法错误。在程序中,将注释符号去掉后,会报错出现红色波浪线,这是语法错误的标志,将光标移动到此位置会出现提示,具体见下图所示:
点击修改建议,修改后两个变量名不一致了,就不会有语法错误了,下图所示:
这个案例说明:在同一作用域下变量不能重复定义。
【示例-2】对于以下代码,第12和第13行是否会有语法错误?
在程序中检验:
代码
public class Test03 {
public static void main(String[] args) {
{//语句块(1)
String name="张三";
System.out.println(name);
}//语句块(1)结束
String name="张三";
System.out.println(name);
}
}
运行结果:
张三
张三
程序能够运行出结果,证明此代码是没有语法错误的。
分析:有两个变量都叫name,但是第一个name作用域在语句块(1)中,离开了这个语句块,语句块中所有定义的变量所占用的空间都将被Java虚拟机回收。那么,在语句块(1)之外,再次定义变量name,就不会出现重复定义变量的语法错误。
【示例-3】对于以下代码,将第12行的注释符号去掉,结果如何?
在程序中检验:
代码
public class Test04 {
public static void main(String[] args) {
String name="张三";
System.out.println(name);
{//语句块(1)
String name="张三";
System.out.println(name);
}//语句块(1)结束
}
}
将注释符号去掉后,语句块(1)中的name报错,出现语法错误的红色波浪线,将光标移到报错位置,提示重复的局部变量name。第一个name的作用域是从main函数开始到main函数结束,在main函数中再次定义重复的变量就会出现变量重复定义的问题,修改语句块(1)中的变量名就不会有问题了。
七、基本数据类型的包装类
1、概述
Java为基本数据类型提供了对应的类,这些类称作包装类。如下表所示:
包装类的类型 | 说明 |
---|---|
Byte类 | byte类型的包装类 |
Short类 | short类型的包装类 |
Integer类 | int类型的包装类 |
Long类 | long类型的包装类 |
Float类 | float类型的包装类 |
Double类 | double类型的包装类 |
Character类 | char类型的包装类 |
Boolean类 | boolean类型的包装类 |
2、为什么使用包装类
- 包装类中封装了一些很实用的方法和常量。例如:Byte.MIN_VALUE是Byte类中的一个常量,存放了byte类型数据的最小值。
- 包装类在集合中用来定义集合元素的类型。
3、包装类的常用方法和常量
Integer
- Integer.MIN_VALUE:int类型的最小值:-2^31
- Integer.MAX_VALUE:int类型的最大值:2^31-1
- int Integer.parselnt(String sInteger);
作用:将字符串类型的整数转换为int类型的数据。
- String Integer.toBinaryString(int value);
作用:将十进制数转换为二进制,返回结果String类型。- String Integer.toHexString(int value);
作用:将十进制数转换为十六进制,返回结果String类型。
Long
- Long.MIN_VALUE:long类型的最小值
- Long.MAX_VALUE:long类型的最大值
- long Long.parseLong(String sLong);
作用:将字符串类型的整数转换为long类型的数据。
- String Long.toBinaryString(long value);
作用:将十进制数转换为二进制,返回结果String类型。- String Long.toHexString(long value);
作用:将十进制数转换为十六进制,返回结果String类型。
Double
- Double.MAX_VALUE:double类型的最大值
- double Double.parseDouble(String sDouble);
作用:将字符串类型的浮点数转换为double类型的数据。
- String Double.toBinaryString(double value);
作用:将十进制数转换为二进制,返回结果String类型。- String Double.toHexString(double value);
作用:将十进制数转换为十六进制,返回结果String类型。
【示例】
<1> 获取byte类型的最大、最小值,并测试Byte.parseByte方法。
<2>获取int类型的最大、最小值,并测试Integer.parseInt、Integer.toBinaryString等方法。
代码
public class Test05 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(Byte.MIN_VALUE+"~"+Byte.MAX_VALUE);
System.out.println(Byte.parseByte("108")+10);
System.out.println(Integer.MIN_VALUE+"~"+Integer.MAX_VALUE);
System.out.println(Integer.parseInt("50000")+5);
System.out.println(Integer.toBinaryString(16));
System.out.println(Integer.toHexString(16));
}
}
结果:
-128~127
118
-2147483648~2147483647
50005
10000
10
八、二进制补码
1、概述
- 计算机系统的内部以二进制形式存储数据。
- 在Java程序中输入的十进制的数据都会被自动转换为二进制,Java内部也以二进制来进行数值运算,但返回的结果是十进制。
2、补码规则
- 在计算机系统中,数值一律用二进制的补码来存储。
- 二进制的最高位是符号位,0表示正数,1表示负数。
- 正数的值是其本身,负数的值是最高位(符号位)不变,其它位逐位取反,再加1。
- 两数相加,若最高位(符号位)有进位,则进位被舍弃。
例如: (1101)2 最高位是1,因此是负数
0010 逐位取反
0011 加1
(1101)2 = -3
二进制数 | 十进制数补码 | 十进制值 |
---|---|---|
0000 | 0 | 0 |
0001 | +1 | 1 |
0010 | +2 | 2 |
0011 | +3 | 3 |
0100 | +4 | 4 |
0101 | +5 | 5 |
0110 | +6 | 6 |
0111 | +7 | 7 |
1000 | -8 | 8 |
1001 | -7 | 9 |
1010 | -6 | 10 |
1011 | -5 | 11 |
1100 | -4 | 12 |
1101 | -3 | 13 |
1110 | -2 | 14 |
1111 | -1 | 15 |
例如:4位二进制补码中,5-3的结果是2
0101 5
+ 1101 -3
————————————————————
0010 2
3、为什么使用补码
- 可以将符号位和其他位统一处理。
- 最高位不再表示数值,而是作为符号位,正好将数值折半,即一半是0至正数,一半是负数。
- 减法也可以按加法来处理。
例如:
(1)4位二进制数共有16个数,用补码表示,则一半是07,一半是-1-8。
(2)8位二进制数共有256个数,用补码表示,则一半是0127,一半是-1-128。
例如:7-3 可以表示为7+(-3),二进制表示为:
0111 7
+ 1101 -3
————————————————————
0100 4
4、补码运算的特征
- 计算机中正数和负数的关系是取反加一。
【示例】在四位二进制数中,已知3的二进制值是0011,若要求-3,则:
0011 3
1100 逐位取反
1101 +1
则-3的二进制值是1101。
- 补码运算是封闭的:运算结果保留在补码范围之内,超范围就溢出。
【示例】四位二进制的补码运算中,请计算5+4的结果:
0101 5
+ 0100 4
————————————————————
1001 -7
- 4位二进制补码最多能表示2^4(16)个数,数的范围是-8~7。
- 8位二进制补码最多能表示2^8(256)个数,数的范围是-128~127。
- 16位二进制补码最多能表示2^16(65536)个数,数的范围是-32768~32767。
- 32位二进制补码最多能表示232个数,数的范围是-231~2^31-1。
5、补码运算的原理
正数+负数=模。
模:某种类型数据的总数。
例如:
4位二进制数的模是2^4=16
8位二进制数的模是2^8=256
16位二进制数的模是2^16=65536
32位二进制数的模是2^32
【示例】在4位二进制中,7+(-7) = 16
0111
+ 1001
——————————————
10000
因此,负数=模-正数,这就是逐位取反加1的原因。
-7 = 16 - 7
10000
- 00111
——————————————
01001