内容摘自https://www.liaoxuefeng.com/wiki/1252599548343744/1255883729079552
基本数据类型
- 整数类型:byte,short,int,long
- 浮点数类型:float,double
- 字符类型:char
- 布尔类型:boolean
计算机内存的最小存储单元是字节byte,一个字节就是8个二进制数,即8个bit,它的二进制表示范围从00000000~11111111,换算成十进制是0 ~ 255,换算成十六进制00 ~ ff
不同数据类型占用的字节数不同
byte:-128 ~ 127
short: -32768 ~ 32767
int: -2147483648 ~ 2147483647
long: -9223372036854775808 ~ 9223372036854775807
int test=123;
long test2=123L;
float f=3.14f;
double d=3.1415;
boolean b=1==2;
char a='A';
char zh='中';
引用类型
除了基本类型的变量,剩下的都是引用类型,例如String,数组类型…
String s = "hello";
数组类型
数组所有元素初始化为默认值,整型0,浮点型0.0,布尔false
数组一旦创建,大小不可改变
int[] ns = new int[5];
ns[0] = 68;
ns[1] = 79;
ns[2] = 91;
ns[3] = 85;
ns[4] = 62;
//ns.length
int[] ns = { 68, 79, 91, 85, 62 };
int[] ns;
ns = new int[] { 68, 79, 91, 85, 62 };
遍历数组
int[] ns = { 68, 79, 91, 85, 62 };
for(int i=0;i<ns.length;i++){
int n=ns[i];
System.out.println(n);
}
for(int n : ns){
System.out.println(n);
}
排序
常用的排序算法有冒泡排序、插入排序和快速排序等。
JDK内置了排序功能,Arrays.sort()
import java.util.Arrays;
public class Datatype {
public static void main(String[] args) {
int[] ns = new int[5];
ns[0] = 68;
ns[1] = 79;
ns[2] = 91;
ns[3] = 85;
ns[4] = 62;
for(int n : ns){
System.out.print(n+",");
}
System.out.println();
Arrays.sort(ns);
for(int n : ns){
System.out.print(n+",");
}
}
}
//68,79,91,85,62,
//62,68,79,85,91,
多维数组
int[][] ns = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
int[][][] ns = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
},
{
{10, 11},
{12, 13}
},
{
{14, 15, 16},
{17, 18}
}
};
常量
定义变量时,如果加上final修饰符,这个变量就变成了常量
final double PI=3.14;
常量在定义时进行初始化后就不可再次赋值,再次赋值会导致编译错误。
var关键字
Java10之后支持var关键字
有时候类型名字太长,
StringBuilder sb = new StringBuilder();
这个时候,如果想省略变量类型,可以使用var关键字:
var sb = new StringBuilder();
实际上会自动变成:
StringBuilder sb = new StringBuilder();
四则运算
整数的除法只保留结果的整数部分,%表示求余运算
int x=3/2;//1
int y=3/2;//1
溢出
整数存在范围限制,如果计算结果超出了范围,就会产生溢出,溢出不会出错,会得到一个奇怪的结果
int x = 2147483640;
int y = 15;
int sum = x + y;
System.out.println(sum); // -2147483641
原码、反码和补码
https://www.hello-algo.com/chapter_data_structure/number_encoding/
原码:将数字的二进制表示的最高位视为符号位,其中0表示正数,1表示负数,其余位表示数字的值
反码:正数的反码与其原码相同,负数的反码是对其原码除符号位外的所有位取反
补码:正数的补码与其原码相同,负数的补码是在反码的基础上加1
数字是以补码的形式存储在计算机中的。
原码虽然直观,但存在局限性。
- 负数的原码不能直接用于运算。为了解决这个问题,引入反码。先将原码转换为反码,并在反码下计算,然后将结果从反码转换为原码。
- 数字0的原码有+0和-0两者表示方式。同样的,反码的正负0也存在歧义,计算机进一步引入了补码。-0的反码基础上加1会产生进位,溢出的第9位会被舍弃,所以-0的补码与+0的补码相同。
字符编码
https://www.hello-algo.com/chapter_data_structure/character_encoding/#344-utf-8
ASCII
是最早出现的字符集,使用7位二进制数(一个字节的低7位)表示一个字符,最多能表示128个不同的字符。ASCII码包括英文的大小写、数字0~9、一些标点符号,以及一些控制字符(如换行符和制表符)
随着计算机的全球化,诞生了一种能够表示更多语言的「EASCII」字符集。它在 ASCII 的 7 位基础上扩展到 8 位,能够表示 256 个不同的字符。
GBK
中国国家标准总局于 1980 年发布了「GB2312」字符集,其收录了 6763 个汉字,基本满足了汉字的计算机处理需要。
GB2312 无法处理部分罕见字和繁体字。「GBK」字符集是在 GB2312 的基础上扩展得到的,它共收录了 21886 个汉字。在 GBK 的编码方案中,ASCII 字符使用一个字节表示,汉字使用两个字节表示。
Unicode
字符集与标准过多,带来很多问题:
- 字符集只定义特定语言的字符,无法在多语言环境下正常工作
- 同一种语言存在多种字符集标准,如果两台计算机使用不同的编码标准,在信息传递时就会出现乱码
如果推出一个足够完整的字符集,将世界范围内的所有语言和符号都收录其中,就可以解决跨语言环境和乱码问题。Unicode应运而生。
Unicode 字符集中,常用的字符占用 2 字节,有些生僻的字符占用 3 字节甚至 4 字节。
UTF-8
目前,UTF-8 已成为国际上使用最广泛的 Unicode 编码方法。它是一种可变长度的编码,使用 1 到 4 字节来表示一个字符,根据字符的复杂性而变。ASCII 字符只需 1 字节,拉丁字母和希腊字母需要 2 字节,常用的中文字符需要 3 字节,其他的一些生僻字符需要 4 字节。
除了 UTF-8 之外,常见的编码方式还包括以下两种。
- UTF-16 编码:使用 2 或 4 字节来表示一个字符。所有的 ASCII 字符和常用的非英文字符,都用 2 字节表示;少数字符需要用到 4 字节表示。对于 2 字节的字符,UTF-16 编码与 Unicode 码点相等。
- UTF-32 编码:每个字符都使用 4 字节。这意味着 UTF-32 比 UTF-8 和 UTF-16 更占用空间,特别是对于 ASCII 字符占比较高的文本。
从存储空间占用的角度看,使用 UTF-8 表示英文字符非常高效,因为它仅需 1 字节;使用 UTF-16 编码某些非英文字符(例如中文)会更加高效,因为它仅需 2 字节,而 UTF-8 可能需要 3 字节。
从兼容性的角度看,UTF-8 的通用性最佳,许多工具和库优先支持 UTF-8 。
移位操作
https://blog.csdn.net/fengqing5578/article/details/88224394
左移<< :就是该数对应二进制码整体左移,左边超出的部分舍弃,右边补零。举个例子:253的二进制码1111 1101,在经过运算253<<2后得到1111 0100。很简单
右移>> :该数对应的二进制码整体右移,左边的用原有标志位补充,右边超出的部分舍弃。
无符号右移>>> :不管正负标志位为0还是1,将该数的二进制码整体右移,左边部分总是以0填充,右边部分舍弃。
正数的左移与右移,负数的无符号右移,就是相应的补码移位所得,在高位补0即可。 负数的右移,就是补码高位补1,然后按位取反加1即可。
自己写的测试
public class Datatype {
public static void main(String[] args) {
// int n=7;// 00000000 00000000 00000000 00000111 = 7
// int a=n >> 1;// 00000000 00000000 00000000 00000011 = 3
// int b=n >> 2;// 00000000 00000000 00000000 00000001 = 1
// int c=n >> 3;// 00000000 00000000 00000000 00000000 = 0
// System.out.println(a+" "+b+" "+c+" ");
// int n=7;// 00000000 00000000 00000000 00000111 = 7
// int a=n << 1;// 00000000 00000000 00000000 00001110 = 14
// int b=n << 2;// 00000000 00000000 00000000 00011100 = 28
// int c=n << 3;// 00000000 00000000 00000000 00111000 = 56
// System.out.println(a+" "+b+" "+c+" ");
// 负数的原码到补码:符号位不变,其他取反加1
// 负数的补码到原码:符号位不变,其他取反加1
// 移位,右移,移补码,符号位不变,左边补1
// int n=-7;
// //原码10000000 00000000 00000000 00000111 = 7
// //补码11111111 11111111 11111111 11111001
// int a=n >> 1;
// //补码11111111 11111111 11111111 11111100
// //原码10000000 00000000 00000000 00000110 = -4
// int b=n >> 2;
// //补码11111111 11111111 11111111 11111110
// //原码10000000 00000000 00000000 00000010 = -2
// int c=n >> 3;
// //补码11111111 11111111 11111111 11111110
// //原码10000000 00000000 00000000 00000001 = -1
// System.out.println(a+" "+b+" "+c+" ");
// int n=-536870912;
// //原码10100000 00000000 00000000 00000000 = -536870912
// //补码11100000 00000000 00000000 00000000
// int a=n >> 1;
// //补码11110000 00000000 00000000 00000000
// //原码10001000 00000000 00000000 00000000 = -268435456
// int b=n >> 2;
// //补码11111000 00000000 00000000 00000000
// //原码10000100 00000000 00000000 00000000 = -134217728
// int c=n >> 3;
// //补码11111100 00000000 00000000 00000000
// //原码10000010 00000000 00000000 00000000 = -67108864
// System.out.println(a+" "+b+" "+c+" ");
// int n=-536870912;
// //原码10100000 00000000 00000000 00000000 = -536870912
// //补码11100000 00000000 00000000 00000000
// int a=n << 1;
// //补码11000000 00000000 00000000 00000000
// //原码10100000 00000000 000000000 00000000 = -1073741824
// int b=n << 2;
// //补码11000000 00000000 00000000 00000000
// //原码10000000 00000000 00000000 00000000 = -2147483648
// int c=n << 3;
// //补码10000000 00000000 00000000 00000000
// //原码10000000 00000000 00000000 00000000 = 0
// System.out.println(a+" "+b+" "+c+" ");
}
}
位运算
位运算是按位进行与、或、非和异或的运算
与运算:同时为1,结果为1
n = 0 & 0; // 0
n = 0 & 1; // 0
n = 1 & 0; // 0
n = 1 & 1; // 1
或运算:只要任意为1,结果为1
n = 0 | 0; // 0
n = 0 | 1; // 1
n = 1 | 0; // 1
n = 1 | 1; // 1
非运算:0和1互换
n = ~0; // 1
n = ~1; // 0
异或运算:两个数不同,结果为1 ,否则0
n = 0 ^ 0; // 0
n = 0 ^ 1; // 1
n = 1 ^ 0; // 1
n = 1 ^ 1; // 0
类型自动提升和强制转型
在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型。例如,short和int计算,结果总是int,原因是short首先自动被转型为int
public class Main {
public static void main(String[] args) {
short s = 1234;
int i = 123456;
int x = s + i; // s自动转型为int
short y = s + i; // 编译错误!
}
}
也可以将结果强制转型,即将大范围的整数转型为小范围的整数。强制转型使用(类型),例如,将int强制转型为short
int i = 12345;
short s = (short) i; // 12345
超出范围的强制转型会得到错误的结果,原因是转型时,int的两个高位字节直接被扔掉,仅保留了低位的两个字节
浮点数运算
浮点数运算和整数运算相比,只能进行加减乘除,不能做位运算和移位运算
浮点数虽然表示的范围大,但是浮点数常常无法精确表示
比如:浮点数0.1在计算机中无法精确表示,因为十进制的0.1换算成二进制是一个无限循环小鼠,无论用float还是double,都只能存储一个0.1的近似值,但0.5可以精确地表示
double x = 1.0 / 10;
double y = 1 - 9.0 / 10;
// 观察x和y是否相等:
System.out.println(x);
System.out.println(y);
//0.1
//0.09999999999999998
比较两个浮点数是否相等常常会出现错误的结果。正确的比较方法是判断两个浮点数之差的绝对值是否小于一个很小的数
// 比较x和y是否相等,先计算其差的绝对值:
double r = Math.abs(x - y);
// 再判断绝对值是否足够小:
if (r < 0.00001) {
// 可以认为相等
} else {
// 不相等
}
三元运算符
三元运算符b ? x : y,它根据第一个布尔表达式的结果,分别返回后续两个表达式之一的计算结果。
int n=-100;
int x=n>=0 ? n : -n;
System.out.println(x);
//100