数据类型与运算符
目录
字面常量
数据类型
基本数据类型:
1. 定义
2. 常见类型
3. 特点
4. 典型语言实现
引用数据类型:
1. 定义
2. 常见类型
3. 特点
4. 典型语言实现
三、核心区别总结
变量
概念
语法格式
整型变量
整型变量
长整型变量
短整型变量
字节型变量
浮点型变量
双精度浮点型
单精度浮点型
字符型变量
布尔型变量
类型转换
自动类型转换(隐式)
强制类型转换(显式)
类型提升
int与long之间
bytr与byte之间
字符串类型
int转成String
String转成int
字面常量
常量就是在程序运行期间,固定不变的量。
比如:System.Out.println("Hello World")
中的"Hello World"。
而字面常量也可以分为六种类型。
- 字符串常量:由“”括起来的,就是字符串常量,如"Hello World"、"1234"等。
- 整形常量:在程序中直接写的数字(没有小数点)就是整形常量,如1、520等。
- 浮点数常量:在程序中直接写的小数就是浮点数常量,如1.2、1.5等。
- 字符常量:由单引号‘ ’括起来的单个字符就是字符常量,如‘1’、‘B’等。
- 布尔常量:布尔常量只有true和false两个值。
- 空常量:空常量就是null。
ps:整形、浮点型、字符串、字符型以及布尔型,在Java语言中都被称为数据类型,而非字面常量。
数据类型
在Java语言中,数据类型主要分为两种:基本数据类型与引用数据类型。
基本数据类型:
1. 定义
基本数据类型是编程语言中预定义的、不可再分的简单数据类型,直接存储值本身。
2. 常见类型
- 数值型:整数(
int
)、浮点数(float
/double
)、字符(char
) - 逻辑型:布尔值(
bool
,true
/false
) - 其他:
byte
/short
/long
等
3. 特点
- 存储方式:直接存储在栈内存中,占用固定大小的空间。
-
- 例如:
int a = 10;
中,变量a
直接存储值10
。
- 例如:
- 赋值与传递:赋值时复制值,操作互不影响。
int x = 5;
int y = x; // y = 5,与x无关
x = 10; // y仍为5
- 比较操作:比较的是实际值。
5 == 5; // true
"5" == 5; // false(类型不同)
4. 典型语言实现
- Java:
int
,char
,boolean
,double
等(共8种基本类型)。 - JavaScript:无基本类型概念,所有数值均为引用类型(如
Number
对象)。
引用数据类型:
1. 定义
引用数据类型是用户自定义或语言内置的复杂类型,存储的是值的内存地址(即引用),实际值存储在堆内存中。
2. 常见类型
- 对象:如Java中的
String
、ArrayList
,Python中的list
、dict
。 - 函数/方法:如JavaScript中的函数。
- 数组:如
int[]
(Java)、Array
(JavaScript)。
3. 特点
- 存储方式:变量存储的是指向堆内存中对象的引用,而非值本身。
-
- 例如:
String s = "hello";
中,s
存储的是字符串对象的内存地址。
- 例如:
- 赋值与传递:赋值时复制引用,多个变量可能指向同一对象。
StringBuilder a = new StringBuilder("hi");
StringBuilder b = a; // b与a指向同一对象
a.append("!"); // b的值也变为"hi!"
- 比较操作:默认比较引用地址,需重写方法(如
equals()
)比较内容。
String s1 = new String("hello");
String s2 = new String("hello");
s1 == s2; // false(不同内存地址)
s1.equals(s2);// true(内容相同)
4. 典型语言实现
- Java:所有对象(包括
String
、数组)均为引用类型。 - Python:所有数据类型(如
list
,dict
)均为引用类型。 - JavaScript:对象、数组、函数均为引用类型。
三、核心区别总结
特性 | 基本数据类型 | 引用数据类型 |
存储位置 | 栈内存(直接存值) | 堆内存(存引用地址) |
赋值行为 | 复制值,操作互不影响 | 复制引用,可能共享同一对象 |
比较操作 | 直接比较值 | 默认比较地址,需手动比较内容 |
内存管理 | 由语言自动管理(栈) | 需垃圾回收机制(堆) |
可变性 | 通常不可变(如Java的 | 可变(如 |
但值得注意的是,与C语言不同,在Java中,无论是在16位系统还是在32位系统中,int都占用4个字节,long都占用8个字节。
同时,整型和浮点型都是带有符号的。
整型默认为int型,浮点型系统会默认为double类型。
变量
概念
首先在介绍变量前,我们需要先明白变量的概念,相信读过小学数学的人都知道,在数学中除了一些不变的量之外,也存在着一些可能经常改变的量。
比如,人的年龄、身高、成绩、函数计算结果之类的。
对于这些经常改变的量,在Java中,称之为变量。
而我们的数据类型就是用来定义不同种类变量的。
语法格式
定义变量的语法格式为:数据类型 变量名 = 初始值;
如int a = 100;
这里代码的意思就是,定义一个int型变量,并给它赋值为100。
同样的其他数据类型也可以这样定义变量。
整型变量
既然知道了变量的概念和语法格式,接下来我们就来讲解一下,整型变量相关知识。
首先,我们要清楚,整型变量分为整型变量、长整型变量、短整型变量与字节型变量四种。
整型变量
// 方式一:在定义时给出初始值
int a = 10;
System.Out.println(a);// 方式二:在定义时没有给初始值,但使用前必须设置初值
int b;
b = 10;
System.Out.println(b);// 使用方式二定义后,在使用前如果没有赋值,则编译期间会报错
int c;
System.Out.println(c);
c = 100;// int型变量所能表示的范围:
System.Out.println(Integer.MIN_VALUE);
System.Out.println(Integer.MAX_VALUE);
// 注意:在定义int性变量时,所赋值不能超过int的范围
int d = 12345678901234; // 编译时报错,初值超过了int的范围
ps:这里要注意以下几点:
- 在日常写代码的时候,我们更推荐使用方式一去定义变量,如果没有合适的初始值,可以将其设置为0。
- int的包装类型为Integer。
- 变量在使用之前是必须要赋予初始值的,否则代码编译时会报错。
长整型变量
int a = 10;
long b = 10; // long定义的长整型变量
long c = 10L; // 为了区分int和long类型,一般建议:long类型变量的初始值之后加L或者l
long d = 10l; // 一般更加以加大写L,因为小写l与1不好区分
// long型变量所能表示的范围:这个数据范围远超过 int 的表示范围. 足够绝大部分的工程场景使用.
System.Out.println(Long.MIN_VALUE);
System.Out.println(Long.MAX_VALUE);
ps:这里也要注意以下几点:
- 为了区分int和long类型,在长整型变量的初始值后要加L或者l,日常更推荐加L。
- long的包装类型为Long
短整型变量
short a = 10;
System.Out.println(a);
// short型变量所能表示的范围:
System.Out.println(Short.MIN_VALUE);
System.Out.println(Short.MAX_VALUE);
ps:注意事项:
- 使用时注意不要超过范围(一般使用比较少)
- short的包装类型为Short
字节型变量
byte b = 10;
System.Out.println(b);
// byte型变量所能表示的范围:
System.Out.println(Byte.MIN_VALUE);
System.Out.println(Byte.MAX_VALUE);
注意事项:
字节的包装类型为Byte
浮点型变量
浮点型变量分为双精度浮点型和单精度浮点型。
双精度浮点型
double d = 3.14;
System.Out.println(d);
在这里我们思考一个代码
int a = 1;
int b = 2;
System.out.println(a / b); // 输出 0.5 吗?
答案是不能。
因为在Java中,int除以int得到的结果还是int型数据,那么我们之前也学到了,int型数据是整数型,会直接舍弃小数部分,那么,如果我们想得到0.5该怎么办呢?
很简单,将int型换成double型就好啦!
double a = 1.0;
double b = 2.0;
System.out.println(a / b);//输出0.5
注意事项:
- 浮点数与整数在内存中的存储方式不同,不能单纯使用2的n次方的形式来计算
- double的包装类型为Double
- double 类型的内存布局遵守 IEEE 754 标准(和C语言一样), 尝试使用有限的内存空间表示可能无限的小数, 势必会存在一定的精度误差,因此浮点数是个近似值,并不是精确值。
单精度浮点型
float num = 1.0f; // 写作 1.0F 也可以
System.out.println(num);
注意事项:
- float 类型在 Java 中占四个字节, 同样遵守 IEEE 754 标准。
- 由于表示的数据精度范围较小, 一般在工程上用到浮点数都优先考虑 double, 不太推荐使用 float。
- float的包装类型为Float。
字符型变量
在学习字符型变量之前,我们要先了解,字符型变量是如何定义的。
char c1 = 'A'; // 大写字母
char c2 = '1'; // 数字字符
System.out.println(c1);
System.out.println(c2);
// 注意:java中的字符可以存放整形
char c3 = '帅';
System.out.println(c3);
其中需要注意的是,Java中使用单引号+单个字母的形式表示字符字面值。
而计算机中的字符本质上是一个整数,在我们之前学到的C语言中,使用ASCII码来表示字符,而在Java中,是使用Unicode来表示字符。
因此,在Java中,一个字符占用两个字节,表示的字符种类更多,其中也可以包括中文。
那么,当我们执行Javac
char ch = '呵';
System.out.println(ch);
这段代码时,会出现什么情况?
没错,可能会报错哦。
此时如何解决呢?这时我们只需要在执行Javac时加上-encoding UTF-8
选项即可。
这里要注意,char的包装类型为Character。
布尔型变量
布尔类型在我们的日常生产中其实常用来表示真假。
boolean b = true;
System.out.println(b);
b = false;
System.out.println(b);
注意事项:
- boolean 类型的变量只有两种取值, true 表示真, false 表示假。
- Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法。
- Java虚拟机规范中,并没有明确规定boolean占几个字节,也没有专门用来处理boolean的字节码指令,在Oracle公司的虚拟机实现中,boolean占1个字节。
- boolean的包装类型为Boolean。
类型转换
Java作为一个强类型编程语言,当不同类型的变量相互赋值时,会有严苛的校验。
int a = 10;
long b = 100L;
b = a; // 可以通过编译
a = b; // 编译失败
在Java中,当参与运算的数据类型不一致时,要进行类型转换。
而Java中的类型转换主要分为两种:自动类型转换和强制类型转换。
自动类型转换(隐式)
自动类型转换,就是字面意思,代码并不需要任何处理,在代码编译的过程中,编译器会自动对代码进行处理。
要注意的是,只有将数据范围小的转为数据范围大的时才会自动进行。
System.Out.println(1024); // 整型默认情况下是int
System.Out.println(3.14); // 浮点型默认情况下是double
int a = 100;
long b = 10L;
b = a; // a和b都是整形,a的范围小,b的范围大,当将a赋值给b时,编译器会自动将a提升为long类型,然后赋值
a = b; // 编译报错,long的范围比int范围大,会有数据丢失,不安全
float f = 3.14F;
double d = 5.12;
d = f; // 编译器会将f转换为double,然后进行赋值
f = d; // double表示数据范围大,直接将float交给double会有数据丢失,不安全
byte b1 = 100; // 编译通过,100没有超过byte的范围,编译器隐式将100转换为byte
byte b2 = 257; // 编译失败,257超过了byte的数据范围,有数据丢失
强制类型转换(显式)
与自动类型转换相反,强制类型转换也是如字面意思一样。
在进行操作时,代码需要经过一定的格式处理,才能完成转换。
当然,强制类型转换是将数据范围大的向数据范围小的进行转换。
int a = 10;
long b = 100L;
b = a; // int-->long,数据范围由小到大,隐式转换
a = (int)b; // long-->int, 数据范围由大到小,需要强转,否则编译失败
float f = 3.14F;
double d = 5.12;
d = f; // float-->double,数据范围由小到大,隐式转换
f = (float)d; // double-->float, 数据范围由大到小,需要强转,否则编译失败
a = d; // 报错,类型不兼容
a = (int)d; // double没有int表示的数据范围大,需要强转,小数点之后全部丢弃
byte b1 = 100; // 100默认为int,没有超过byte范围,隐式转换
byte b2 = (byte)257; // 257默认为int,超过byte范围,需要显示转换,否则报错
boolean flag = true;
a = flag; // 编译失败:类型不兼容
flag = a; // 编译失败:类型不兼容
但要注意的是:
- 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型。
- 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失。
- 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查。
- 强制类型转换不一定能成功,不相干的类型不能互相转换。
类型提升
当不同类型的数据之间进行运算时,Java内部会将数据类型小的提升到数据类型大的再进行运算。
int与long之间
int会被提升为long。
int a = 10;
long b = 20;
int c = a + b; // 编译出错: a + b==》int + long--> long + long 赋值给int时会丢失数据
long d = a + b; // 编译成功:a + b==>int + long--->long + long 赋值给long
bytr与byte之间
byte a = 10;
byte b = 20;
byte c = a + b;
System.out.println(c);
// 编译报错
Test.java:5: 错误: 不兼容的类型: 从int转换到byte可能会有损失
结论:
byte 和 byte 都是相同类型, 但是出现编译报错。
原因是, 虽然 a 和 b 都是 byte, 但是计算 a + b 会先将 a 和 b 都提升成 int, 再进行计算。
得到的结果也是 int, 这是赋给 c, 就会出现上述错误.
由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据,为了硬件上实现方便。
诸如 byte 和 short 这种低于 4 个字节的类型, 会先提升成 int, 再参与计算。
那么,正确应该怎么写呢?
byte a = 10;
byte b = 20;
byte c = (byte)(a + b);
System.out.println(c);
字符串类型
在Java中,我们使用String类型去定义字符串类型。
public static void main(String[] args) {
String s1 = "hello";
String s2 = " world";
System.out.println(s1);
System.out.println(s2);
System.out.println(s1+s2); // s1+s2表示:将s1和s2进行拼接
}
然而,在有些情况下,我们需要将字符串与整形数字之间进行转换,这时应该怎么办呢?
int转成String
int num = 10;
// 方法1
String str1 = num + "";
// 方法2
String str2 = String.valueOf(num);
String转成int
String str = "100";
int num = Integer.parseInt(str);