1. 基本数据类型
概念:
- java是一门强调类型的语言,所以对java语言来说,数据类型是一个很重要的概念。
- 数据类型分为基本类型和引用类型,基本数据类型分为数值型和非数值型。
- 基本数据类型一共有8个分别为:
- 字节型
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 - 单精度浮点型
float,占4字节,范围是-3.4E38到3.4E38 - 双精度浮点型
double,占8字节,范围是-1.7E308到1.7E308 - 字符型
char,占2字节,是一个Unicode字符。 - 布尔型
boolean,占1字节,仅存false或true这两个值。
- 字节型
- 引用数据类型包括类,接口,数组等。
1字节位图
源码: /javase-start/
- src:
c.y.type.BasicDataTypeTest.build()
/**
* @author yap
*/
public class BasicDataTypeTest {
@Test
public void build() {
byte byteNum = 100;
System.out.println(byteNum);
short shortNum = 100;
System.out.println(shortNum);
int intNum = 100;
System.out.println(intNum);
long longNum = 100L;
System.out.println(longNum);
float floatNum = 100.0F;
System.out.println(floatNum);
double doubleNum = 100.0;
System.out.println(doubleNum);
boolean flag = false;
System.out.println(flag);
char character = 'A';
System.out.println(character);
}
1.1 整数型
概念:
- 整数常量均默认为int类型。
- 因为整数常量都是确定的值,所以在编译期间,javac会对整数常量先进行范围检查:
- 如果通过检查,则直接赋值,不涉及任何转换工作。
- 如果不通过则尝试进行类型转换,转换失败则会报错。
- 如果常量本身超出默认类型范围,javac不通过:
System.out.println(10000000000);:整数常量"10000000000",被认为是int类型,数值超过int最大值,javac报错。System.out.println(10000000000L);:整数常量"10000000000L",直接被认为是long类型,javac通过。
源码: /javase-start/
1.2 浮点型
概念:
- 为什么叫浮点数: 3.14是个浮点数,但因为java支持科学计数法,所以3.14可以写成
0.314e1、0.0314e2、31.4e-1等等,你会发现在不改变数值的最终结果的前提下,小数点的位置,其实是可以随意浮动的,这就是为何叫做浮点数的原因。 - 浮点数天生不精确:
- 1到10之间只可能有10个整数,却有无穷多个浮点数,用有限的容器来存储无限的可能,就一定会有精度受损的时候,如
syout(2.00 - 1.10);。 - 因为浮点数天生不精确,所以绝对不能用浮点数进行比较判断是否相等,如果非要进行特别精确的计算,可以使用
java.math.BigDecimal中的subtract()来完成。
- 1到10之间只可能有10个整数,却有无穷多个浮点数,用有限的容器来存储无限的可能,就一定会有精度受损的时候,如
- 浮点数默认类型: 浮点数常量默认为double类型,因为浮点数天生不精准,所以javac无法对浮点数常量进行范围检查,也就表示所有的double类型数据,都无法直接被float接收。
源码: /javase-start/
1.3 字符型
概念: char类型可以直接赋值整数,也同样会在赋值前接受范围检查,因为char遵循的是Unicode标准,所以它支持的范围是0-65535,在这个范围内,便可成功赋值,此时char类型变量中存储的是字符集中对应位置上的字符。
源码: /javase-start/
1.4 布尔型
概念: 布尔类型虽然占据1字节,但是它占据这8bit(1byte)中的一位,为了区别数字类型,它存在于最高位,即符号位,其余7bit都是0,处于无用状态。
源码: /javase-start/
1.5 基本类型转换
概念:
- 转换原则:
- 八大基本数据类型之间(除了boolean之外)都是可以互相转换的。
- 由小到大自动转,由大到小需强转。
- int(4) -> long(8):无论你int是多少,long都装得下。
- long(8) -> int(4):int有可能装不下long的值。
- 转换格式:
- 比如,将A转为B,则可以写:
B b = (B)A;
- 比如,将A转为B,则可以写:
- 浮点数与整数的转换:
- 浮点数转成整数的时候,会自动将小数点后面的小数全部割弃。
- 整数转成浮点数的时候,会在整数后面补充
.0作为小数部分
- char以数字的方式参与转换:
- char类型可以和其他类型之间进行转换,是以字符集中,对应字符的编号数字来参与转换的。
- 不同类型的计算原则:
- 不同类型之间计算,结果一定返回最大类型。
- char类型可以进行数学计算,此时char类型先将字符转换为字符集中对应字符的位置编号,然后再进行计算。
源码: /javase-start/
2. 引用数据类型
概念: 除了基本数据类型之外,都是引用数据类型,包括类、数组、接口等等。
2.1 String类型
概念: java.lang.String 是我们学到的第一个引用数据类型,表示字符串。
- 格式:变量类型 变量名 = new 构造函数();
- 理解:变量类型 变量名 = new 变量类型();
- eg:
A a = new A(); - eg:
String str = new String("Hello");
- eg:
- 特权:String可以使用基本数据类型的声明方式。
java.lang 这个包下的所有的类可以直接使用。
源码: /javase-start/
- src:
c.y.type.StringTest.build()
/**
* @author yap
*/
public class StringTest {
@Test
public void build() {
String strA = "abc";
String strB = new String("abc");
System.out.println(strA);
System.out.println(strB);
}
}
2.2 API与API文档
概念: API(Application Programming Interface)就是应用程序编程接口,而API文档是记录这些接口的工具,习惯性翻阅API文档来学习一个类,是一个程序神的必备技能。
- API官方概念
- JDK8官网API文档
- API学习方法:
- 名称:代码需要使用名字去调用它,但是不需要记忆。
- 修饰:是否为静态?非静态方法使用实例调用,静态方法使用类名调用。
- 用途:这个必须记住,否则就跟没学一样。
- 参数:要求传入什么类型的变量,就传入什么类型的变量,不需要记忆。
- 返回值:有返回值就用一个对应类型的变量去接收它的返回值,不需要记忆。
3. 正则表达式概念
概念:
- 正则表达式,又称为规则表达式,
Regular Expression,在代码中一般简写为regex或者RE,是对字符串操作的一种逻辑公式,是用事先定义好的一些特定字符、及这些特定字符的组合,组成的一个"规则字符串模板",用来表达对字符串的一种过滤逻辑。 - 正则表达式很灵活、有逻辑,可以迅速地用极简单的方式达到字符串的复杂控制。
- 一个正则表达式由三部分组成:
- 普通字符:数字和字母,如
abc、123等。 - 特殊字符:具有功能的特殊字符,也称为元字符,如
\d,\s等。 - 限定字符:限定个数的字符,如
{10}、{5, 9}、+、?等。
- 普通字符:数字和字母,如
- 字符串对空格是敏感的,不要在字符串中随意使用空格。
^和$表示一个正则的开始和结束的精准定位,^表示开头,$表示结尾,需要视情况选择是否使用。
3.1 普通字符
概念:
[abc]:匹配 "abc" 中的任意一个字符- 成功案例:
"a"或"b" - 失败案例:
"d"或"ab"
- 成功案例:
[^abc]:匹配除 "abc" 以外的任意一个字符- 成功案例:
"d"或"e" - 失败案例:
"a"或"de"
- 成功案例:
[a-z]:匹配a到z之间的任意一个字符- 成功案例:
"a"或"b" - 失败案例:
"A"或"38"
- 成功案例:
[^a-z]:匹配除了a到z之间的任意一个字符- 成功案例:
"A"或"38" - 失败案例:
"a"或"b"
- 成功案例:
"|" 表示或者,[]不能省略。
3.2 特殊字符
概念:
.:匹配除\n和\r之外的任意一个字符- 成功案例:
"a"或"%" - 失败案例:
"\n"或"\r"
- 成功案例:
\d:匹配一个数字字符,等价于[0-9]- 成功案例:
"0"或"9" - 失败案例:
"e"或"10"
- 成功案例:
\D:匹配一个非数字字符,等价于[^0-9]- 成功案例:
"e"或"10" - 失败案例:
"0"或"9"
- 成功案例:
\n:匹配一个换行符- 成功案例:
"\n" - 失败案例:
"\\n"或"a"
- 成功案例:
\t:匹配一个制表符- 成功案例:
"\t" - 失败案例:
"\\t"或"a"
- 成功案例:
\w:匹配Unicode字母、数字和下划线- 成功案例:
"_"或"a" - 失败案例:
"\t"或"&"
- 成功案例:
\W:匹配除了Unicode字母、数字和下划线之外的字符- 成功案例:
"\t"或"&" - 失败案例:
"_"或"a"
- 成功案例:
3.3 限定字符
概念:
{n}:恰好匹配n次{n,}:至少匹配n次{n,m}:匹配n到m次,n<=m,注意逗号和两个数之间不能有空格*:匹配前面的子表达式任意次,等价于{0,}+:匹配前面的子表达式一次或多次,等价于{1,}?:匹配前面的子表达式零次或一次,等价于{0,1}
n和m均为非负整数。
3.4 正则三大用途
概念:
- 数据验证:用RE和某个字符串进行匹配,通过的返回布尔类型结果来分析该字符串是否满足规则。
- 配合字符串的
matches()完成验证。 "18210210122".matches("^1\\d{10}$")
- 配合字符串的
- 替换文本:用RE来识别文档中的特定文本,完全删除它,或者用其他文本替换它。
- 配合字符串的
replaceAll()完成替换。 "My Name Is 9527".replaceAll("[a-z]", "-");- 这里不要使用 "^" 或者 "$",的格式,否则将只会替换字符串的第一个或最后一个满足要求的元素。
- 配合字符串的
- 提取子串:用RE从某个字符串中提取一部分内容,这部分内容称为子字符串。
- 配合字符串的
split()完成字符串切割。 "Test A. Test B. Test C.".split("\\.\\s*");- 这里不要使用 "^" 或者 "$",的格式,否则将只会替换字符串的第一个或最后一个满足要求的元素。
- 配合字符串的
4. JVM内存分布
概念:
- java程序在运行的时候,绝大部分的数据都在一块叫做运行时数据区(Runtime Data Area)的内存区域中活动。
- 运行时数据区,被划分成三块小的区域,分别被称为:
- 栈内存:stack,相当于小区物业,空间小,功能少,访问方便。
- 堆内存:heap,相当于小区住宅区,空间大,功能多,访问麻烦。
- 方法区:Method Area,相当于小区广场,公共区域,所有人都可以访问。
4.1 内存地址
概念:
- 基本数据类型全都分布在栈内存中。
- 引用数据类型的值分布在堆内存中,内存地址分布在栈内存中。
- 内存地址也叫引用或者句柄,就像住宅区居民楼的门牌号,全部登记在物业,这样当我去找赵四的时候,只需要去栈中查找赵四家的门牌号就可以直接找到他家,并不需要去一个门一个门去敲问。
源码: 分析如下三行代码在内存中的分布:
int a = 100;
double b = 10.5;
String str = new String("java");
4.2 相等比较之==
概念:
- 基本类型在使用
==进行比较的时候,直接按照数学规则比较变量值。 - 基本类型在使用
==进行比较的时候,会将参与比较的双方都转换成同一类型,然后再进行比较,转换的目标类型,以参与比较的双方类型中,字节数大的一方为准。 - 引用类型在使用
==进行比较的时候,比较的是内存地址。
源码: /javase-start/
- src:
c.j.type.StringTest.compareReference()
@Test
public void compareReference() {
String str01 = new String("yap");
String str02 = new String("yap");
// str01 和 str02 有着不同的内存地址,返回F
System.out.println(str01 == str02);
}
4.3 相等比较之equals()
- 基本类型没有方法,所以无法使用
equals()方法进行比较。 equals()方法来自于Object类(继承),原本的作用也是对内存地址进行比较,但是String类对其进行了重新改造(Override),使其变成了比较类型和值的一个方法。- String类中的
equals()方法先比较内存地址,如果内存地址不同,则比较字符串的内容。
5. String工具类
概念: 一个String对象的长度和内容都是不可变的,虽然使用"+"可以达到改变内容的目的,但实质会产生一个或多个新的字符串,如果这种改变很频繁,那就会特别浪费内存,如果你的操作中需要频繁进行字符串的拼接,不建议使用 "+"。
时间戳:距离1970年1月1日 0点0时0分 一个毫秒数。
源码: /javase-start/
- src:
c.y.type.StringToolTest.plusSignStitchingTimeConsuming()
/**
* @author yap
*/
public class StringToolTest {
@Test
public void plusSignStitchingTimeConsuming() {
// 获取时间戳:距离1970年1月1日 0点0时0分 一个毫秒数。
long startTime = System.currentTimeMillis();
String str = "";
for (int i = 0; i < 100000; i++) {
str = str + i;
}
long endTime = System.currentTimeMillis();
System.out.println("总耗时:" + (endTime - startTime) + "毫秒");
}
5.1 String拓展类
概念:
- StringBuilder是jdk1.5版本提出来的一个类,它是一个可变长的字符串类,可以预分配缓冲区,我们可以通过它来进行频繁的字符串拼接操作。
- 创建方式:
StringBuilder stringBuilder = new StringBuilder("a"); - 拼接方式:
append()。 - 虽然在JDK1.8版本中,"+"的底层代码,也是在调用StringBuilder这个类的append()方法,但是多次调用"+"的时候,会创建多次StringBuilder,一样会导致效率低下,这里的优化仍未做到最好,所以在效率上,使用StringBuilder仍然要比使用"+",更优秀。
StringBuffer是JDK1.0时代就存在的老员工了,它可以算是StringBuilder的亲生哥哥,它和StringBuilder的方法都是类似的,唯一的区别是,StringBuffer是线程安全的,而StringBuilder是线程不安全的。
源码: /javase-start/
- src:
c.y.type.StringToolTest.stringBuilderStitchingTimeConsuming()
@Test
public void stringBuilderStitchingTimeConsuming() {
long startTime = System.currentTimeMillis();
StringBuilder stringBuilder = new StringBuilder("");
for (int i = 0; i < 100000; i++) {
stringBuilder.append(i);
}
long endTime = System.currentTimeMillis();
System.out.println("总耗时:" + (endTime - startTime) + "毫秒");
}
5.2 String拓展类常用API
概念: StringBuilder和StringBuffer的api方法类似,这里以StringBuilder为例:
replace(n1, n2, "a"):将n1到n2之间的元素,全部替换成字符串"a"。insert(n1, "a"):在n1之后,插入字符串"a"。delete(n1, n2):将n1到n2之间的元素,全部删除。deleteCharAt(n1):删除n1位置上的元素。substring(n1, n2):截取出n1到n2之间的所有元素并返回。reverse():水平翻转字符串。toString():以字符串形式展示。
以上范围均包括n1,但是不包括n2。
6. 包装类
概念: 八个基本数据类型都有相对应的引用数据类型,叫做包装类。
Byte/Short/Integer/Long/Float/Double的父类是Number。Number的兄弟类是Boolean,Character。
源码: /javase-start/
- src:
c.y.type.PackingTypeTest.build()
/**
* @author yap
*/
public class PackingTypeTest {
@Test
public void build() {
System.out.println(new Byte((byte) 100));
System.out.println(new Short((short) 200));
System.out.println(new Integer(10000));
System.out.println(new Long(10000000L));
System.out.println(new Double(12.5));
System.out.println(new Float(12.5F));
System.out.println(new Character('a'));
// System.out.println(new Boolean(true));
// Boolean类型包装了更建议的一种声明方式
System.out.println(Boolean.TRUE);
}
6.1 装箱
概念: 基本类型转成对应包装类的过程叫做装箱。
- 在jdk1.5版本之前,需要我们手动装箱。
Integer.valueOf(num)
- 在jdk1.5版本之后,JVM自动拆装箱,代码上直接使用等号赋值即可。
源码: /javase-start/
- src:
c.y.type.PackingTypeTest.manualBoxing()
@Test
public void manualBoxing() {
int num = 10;
Integer result = Integer.valueOf(num);
System.out.println(result);
}
6.2 拆箱
概念: 包装类转成对应基本类型的过程叫做拆箱。
- 在jdk1.5版本之前,需要我们手动拆箱。
num.intValue()
- 在jdk1.5版本之后,JVM自动拆装箱,代码上直接使用等号赋值即可。
源码: /javase-start/
- src:
c.y.type.PackingTypeTest.manualUnBoxing()
@Test
public void manualUnBoxing() {
Integer num = new Integer(10);
int result = num.intValue();
System.out.println(result);
}u03-数据类型.md