Java基础总结回顾
1. 说明
1.1 编译与运行
- 编译:是指将编写的 Java 源文件翻译成 JVM 认识的 class 文件,在这个过程中, javac 编译器会检查所写的程序是否有错误,有错误就会提示出来,如果没有错误就会编译成功
- 运行:是指将 class文件 交给 JVM 去运行,此时 JVM 会去执行编写的程序
1.2 main 方法
主方法,写法是固定格式不可以更改。main 方法是程序的入口点或起始点,无论我们编写多少程序,JVM在运行的时候,都会从 main 方法这里开始执行
1.3 keywords 关键字
指在程序中,Java 已经定义好的单词,具有特殊含义。如 public 、class 、static 、void 等,这些单词已经被 Java 定义好,全部都是小写字母
1.4 标识符
指在程序中,自己定义的内容,如类的名字、方法的名字和变量的名字等等
命名规则: 硬性要求
- 标识符可以包含 英文字母26个(区分大小写) 、 0-9数字 、 $(美元符号) 和 _(下划线)
- 标识符不能以数字开头
- 标识符不能是关键字
命名规范: 软性建议
- 类名规范:首字母大写,后面每个单词首字母大写(大驼峰式)
- 方法名规范: 首字母小写,后面每个单词首字母大写(小驼峰式)
- 变量名规范:全部小写
2. 常量、变量、数据类型、运算符
2.1 常量
是指在 Java 程序中固定不变的数据
2.2 变量
常量是固定不变的数据,那么在程序中可以变化的量称为变量,Java 中要求一个变量每次只能保存一个数据,必须要明确保存的数据类型
变量定义的格式包括三个要素: 数据类型 、 变量名 、 数据值
数据类型 变量名 = 数据值;
变量名称:在同一个大括号范围内,变量的名字不可以相同
变量赋值:定义的变量,不赋值不能使用
2.3 数据类型
Java的数据类型分为两大类:
- 基本数据类型:包括 整数 、 浮点数 、 字符 、 布尔
- 引用数据类型:包括 类 、 数组 、 接口
四类八种基本数据类型:
2.4 数据类型转换
Java 程序中要求参与的计算的数据,必须要保证数据类型的一致性,如果数据类型不一致将发生类型的转换
2.4.1 自动转换
将 取值范围小的类型 自动提升为 取值范围大的类型,byte、short、char 运算时直接提升为 int
public static void main(String[] args) {
byte a = 1;
int b = a + 1;
System.out.println(b);
}
2.4.2 强制转换
将 取值范围大的类型 强制转换成 取值范围小的类型 。自动转换是 Java 自动执行的,而强制转换需要自己手动执行
数据类型 变量名 = (数据类型)被转数据值;
// double 类型数据强制转成 int 类型,直接去掉小数点
int i = (int)1.5;
public static void main(String[] args) {
// short 类型变量,内存中 2 个字节
short s = 1;
/*
出现编译失败
s 和 1 做运算的时候,1 是 int 类型,s 会被提升为 int 类型
s+1 后的结果是 int 类型,将结果在赋值会 short 类型时发生错误
short 内存 2 个字节,int 类型 4 个字节
必须将 int 强制转成 short 才能完成赋值
*/
s = s + 1; // 编译失败
s = (short)(s+1); // 编译成功
}
- 浮点转成整数,直接取消小数点,可能造成数据损失精度
- int 强制转成 short 砍掉2个字节,可能造成数据丢失
2.5 运算符
2.5.1 位运算符
2.5.2 赋值运算符
2.5.3 三元运算符
数据类型 变量名 = 布尔类型表达式?结果1:结果2;
2.5.4 instanceof
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)
(Object reference variable) instanceof (class/interface type);
Object name = "James";
Object age = 17;
boolean resultName = name instanceof String; // 由于 name 是 String 类型,所以返回 true
boolean resultAge = age instanceof String; // 由于 age 是 Integer 类型,所以返回 false
其中左边 obj 为一个对象,右边 Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果 result 都返回 true,否则返回false。
注:编译器会检查 obj 是否能转换成右边的 Class 类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。
2.5.5 运算符优先级
3. 数组
3.1 概念
存储数据长度固定的容器,保证多个数据的数据类型要一致,数组有定长特性,长度一旦指定,不可更改
1. 数组存储的数据类型[] 数组名字 = new 数组存储的数据类型[长度];
2. 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
3. 数据类型[] 数组名 = {元素1,元素2,元素3...};
3.2 数组内存图
3.2.1 内存概述
内存是计算机中的重要原件,临时存储区域,作用是运行程序。编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。Java 虚拟机要运行程序,必须要对内存进行空间的分配和管理。
3.2.2 JVM 内存划分(简略)
1.8 之后,方法区由元空间(Metaspace)取代
3.2.3 两个独立数组内存图
3.3 数组工具类
- Arrays.sort:元素排序,会改变原数组
- Arrays.toString:返回指定数组内容的字符串表示形式
- Arrays.binarySearch:查找元素位置
- contains:查找元素是否存在
- Arrays.equals:数组比较
- Collections.min、Collections.max:获取最大值和最小值
int min = (int) Collections.min(Arrays.asList(numbers));
- Arrays.asList、addAll:数组合并
List list = new ArrayList(Arrays.asList(a)); list.addAll(Arrays.asList(b));
- Arrays.fill:数组填充
- System.arraycopy:数组扩容/复制
- retainAll: 数组交集
- removeAll:数组差集
4. 类与对象、封装、继承、多态
4.1 类与对象
类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物
- 属性:就是该事物的状态信息,成员变量:对应事物的属性,有默认值
- 行为:就是该事物能够做什么, 成员方法:对应事物的行为
对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为
类与对象的关系:
- 类是对一类事物的描述,是抽象的
- 对象是一类事物的实例,是具体的
- 类是对象的模板,对象是类的实体
4.2 成员变量和局部变量区别
- 在类中的位置不同:成员变量:类中,方法外;局部变量:方法中或者方法声明上(形式参数)
- 作用范围不一样:成员变量:类中;局部变量:方法中
- 初始化值的不同: 成员变量:有默认值;局部变量:没有默认值。必须先定义,赋值,最后使用
- 在内存中的位置不同: 成员变量:堆内存;局部变量:栈内存
- 生命周期不同: 成员变量:随着对象的创建而存在,随着对象的消失而消失;局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
4.3 封装 private
面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。封装用来防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问,this 代表当前对象的引用(谁调用就代表谁)
4.4 继承 super
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类。
子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为
4.5 继承之后的属性和行为
- 子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量。super,代表父类的存储空间标识(可以理解为父亲的引用)
- 子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。子类方法覆盖父类方法,必须要保证权限大于等于父类权限
- 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用
- Java只支持单继承,不支持多继承
4.6 抽象类 abstract
把没有方法主体的方法称为抽象方法。该方法的具体实现由子类提供。Java语法规定,如果一个类包含抽象方法,那么该类必须是抽象类
修饰符 abstract 返回值类型 方法名 (参数列表);
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。
4.7 多态
是指同一行为,具有多个不同表现形式
父类类型 变量名 = new 子类对象;
变量名.方法名();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法
4.8 引用类型转换
4.8.1 向上转型
多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。
父类类型 变量名 = new 子类类型();
4.8.2 向下转型
父类类型向子类类型向下转换的过程,这个过程是强制的
子类类型 变量名 = (子类类型) 父类变量名;
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。想要调用子类特有的方法,必须做向下转型。可以使用 instanceof 关键字,给引用变量做类型的校验
5. 修饰符、内部类
5.1 修饰符
5.1.1 权限修饰符
5.1.2 final
final: 不可改变。可以用于修饰类、方法和变量
- final 变量:变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值
- final 方:父类中的 final 方法可以被子类继承,但是不能被子类重写
- final 类:final 类不能被继承,没有类能够继承 final 类的任何特性
5.1.3 static
- 静态变量
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。 - 静态方法
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
5.1.4 synchronize
synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符
5.1.5 transient
序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型
5.1.6 volatile
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值
一个 volatile 对象引用可能是 null
public class MyRunnable implements Runnable{
private volatile boolean active;
public void run(){
active = true;
while (active){ // 第一行
// 代码
}
}
public void stop(){
active = false; // 第二行
}
}
/* 通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),
在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,
那么在 第二行 的 active 值为 false 时循环不会停止。
但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
*/
5.2 内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类
5.2.1 成员内部类
定义在类中方法外的类
class 外部类 {
class 内部类{
}
}
内部类可以直接访问外部类的成员,包括私有成员。外部类要访问内部类的成员,必须要建立内部类的对象。
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
5.2.2 匿名内部类
内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象,匿名内部类必须继承一个父类或者实现一个父接口
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
6. String 类、Math 类、Collections 类
6.1 String 类
字符串不变:字符串的值在创建后不能被更改
public boolean equals (Object anObject)
:将此字符串与指定对象进行比较public boolean equalsIgnoreCase (String anotherString)
:将此字符串与指定对象进行比较,忽略大小写compareTo、compareToIgnoreCase
:字符串比较regionMatches
:比较字符串区域相等public int length ()
:返回此字符串的长度public String concat (String str)、+
:将指定的字符串连接到该字符串的末尾public char charAt (int index)
:返回指定索引处的 char值public int indexOf (String str)
:返回指定子字符串第一次出现在该字符串内的索引public String substring (int beginIndex)
:返回一个子字符串,从 beginIndex 开始截取字符串到字符串结尾public String substring (int beginIndex, int endIndex)
:返回一个子字符串,从 beginIndex 到 endIndex 截取字符串。含 beginIndex,不含 endIndexpublic char[] toCharArray ()
:将此字符串转换为新的字符数组public byte[] getBytes ()
:使用平台的默认字符集将该 String编码转换为新的字节数组public String replace (CharSequence target, CharSequence replacement) 、replaceFirst、replaceAll
:将与 target 匹配的字符串使用 replacement 字符串替换public String[] split(String regex)
:将此字符串按照给定的 regex(规则)拆分为字符串数组StringBuffer.reverse
:字符串反转delete(StringBuffer)
:字符串删除public boolean startsWith(String prefix)
:判断是否以某字符串开头
6.2 Math类
- public static double abs(double a) :返回 double 值的绝对值
- public static double ceil(double a) :返回大于等于参数的最小的整数
- public static double floor(double a) :返回小于等于参数最大的整数
- public static long round(double a) :返回最接近参数的 long。(相当于四舍五入方法)
6.3 Collections 类
- 排序
- 查找,替换操作
- 同步控制(不推荐,需要线程安全的集合类型时请考虑使用 JUC 包下的并发集合)
排序操作
void reverse(List list)//反转
void shuffle(List list)//随机排序
void sort(List list)//按自然排序的升序排序
void sort(List list, Comparator c)//定制排序,由Comparator控制排序逻辑
void swap(List list, int i , int j)//交换两个索引位置的元素
void rotate(List list, int distance)//旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面
查找,替换操作
int binarySearch(List list, Object key)//对List进行二分查找,返回索引,注意List必须是有序的
int max(Collection coll)//根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
int max(Collection coll, Comparator c)//根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)
void fill(List list, Object obj)//用指定的元素代替指定list中的所有元素
int frequency(Collection c, Object o)//统计元素出现次数
int indexOfSubList(List list, List target)//统计target在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target)
boolean replaceAll(List list, Object oldVal, Object newVal)//用新元素替换旧元素
同步控制
Collections 提供了多个 synchronizedXxx()
方法,该方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题
HashSet
,TreeSet
,ArrayList
, LinkedList
, HashMap
, TreeMap
都是线程不安全的。Collections 提供了多个静态方法可以把他们包装成线程同步的集合,但效率非常低,需要线程安全的集合类型时考虑使用 JUC 包下的并发集合
synchronizedCollection(Collection<T> c) //返回指定 collection 支持的同步(线程安全的)collection。
synchronizedList(List<T> list)//返回指定列表支持的同步(线程安全的)List。
synchronizedMap(Map<K,V> m) //返回由指定映射支持的同步(线程安全的)Map。
synchronizedSet(Set<T> s) //返回指定 set 支持的同步(线程安全的)set。
6.4 Comparator 比较器
排序简单的说就是两个对象之间比较大小,在 JAVA 中提供了两种比较实现的方式,一种是比较死板的采用 java.lang.Comparable 接口去实现,一种是灵活的当我需要做排序的时候在去选择的 java.util.Comparator 接口完成
-
public static
void sort(List list) 这个方法完成的排序,实际上要求了被排序的类型需要实现 Comparable 接口完成比较的功能 -
public static
void sort(List list,Comparator<? super T> ) 方法灵活的完成,这个里面就涉及到了 Comparator 这个接口
位于 java.util 包下,排序是 comparator 能实现的功能之一,该接口代表一个比较器,比较器具有可比性!需要比较两个对象谁排在前谁排在后:public int compare(String o1, String o2) :比较其两个参数的顺序
两个对象比较的结果有三种:大于,等于,小于
如果要按照升序排序, 则 o1 小于 o2,返回(负数),相等返回0,o1 大于o2返回(正数) 如果要按照降序排序 则 o1 小于 o2,返回(正数),相等返回0,o1大于o2返回(负数) -
Comparable 和 Comparator 两个接口的区别
- Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。只能在类中实现 compareTo() 一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过 Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器
- Comparator:强行对某个对象进行整体排序。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set 或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序
7. 异常
7.1 非检查性异常
7.2 检查性异常
7.3 异常方法
7.4 声明自定义异常
- 所有异常都必须是 Throwable 的子类
- 如果希望写一个检查性异常类,则需要继承 Exception 类
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类
// 自定义异常类,继承Exception类
public class InsufficientFundsException extends Exception{
//此处的amount用来储存当出现异常(取出钱多于余额时)所缺乏的钱
private double amount;
public InsufficientFundsException(double amount){
this.amount = amount;
}
public double getAmount(){
return amount;
}
}
7.5 通用异常
- JVM(Java虚拟机) 异常:由 JVM 抛出的异常或错误。如:NullPointerException 类,ArrayIndexOutOfBoundsException 类,ClassCastException 类
- 程序级异常:由程序或者 API 程序抛出的异常。如 IllegalArgumentException 类,IllegalStateException 类
8. 时间处理
8.1 格式化时间 SimpleDateFormat、printf
public class Main{
public static void main(String[] args){
Date date = new Date();
String strDateFormat = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);
System.out.println(sdf.format(date)); // 2015-03-27 21:13:23
// printf 的使用
System.out.printf("全部日期和时间信息:%tc%n",date); // 星期一 九月 10 10:43:36 CST 2012
}
}
8.2 获取某个时间点 Calendar
public class Main {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
int day = cal.get(Calendar.DATE);
int month = cal.get(Calendar.MONTH) + 1;
int year = cal.get(Calendar.YEAR);
int dow = cal.get(Calendar.DAY_OF_WEEK);
int dom = cal.get(Calendar.DAY_OF_MONTH);
int doy = cal.get(Calendar.DAY_OF_YEAR);
System.out.println("当期时间: " + cal.getTime()); // Fri Mar 27 21:44:15 CST 2015
System.out.println("日期: " + day); // 27
System.out.println("月份: " + month); // 3
System.out.println("年份: " + year); // 2015
System.out.println("一周的第几天: " + dow); // 6, 星期日为一周的第一天输出为 1,星期一输出为 2,以此类推
System.out.println("一月中的第几天: " + dom); // 27
System.out.println("一年的第几天: " + doy); // 86
}
}
8.3 LocalDateTime 代替 Calendar
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime); // 2021-12-22T08:56:53.923
System.out.println(localDateTime.plusYears(2)); // 加2年
System.out.println(localDateTime.plusDays(2)); // 加两天
System.out.println(localDateTime.minusYears(2)); // 减两年
System.out.println(localDateTime.minusDays(2)); // 减两天
System.out.println(localDateTime.toString()); // 转字符串 结果:2021-12-22T08:56:53.923
System.out.println(localDateTime.toLocalDate()); // 获取日期(LocalDate) 结果:2021-12-22
System.out.println(localDateTime.toLocalTime()); // 获取时间(LocalTime) 结果:08:56:53.923
System.out.println(localDateTime.getDayOfMonth()); // 获取当前时间月份的第几天
System.out.println(localDateTime.getDayOfWeek()); // 获取当前周的第几天
System.out.println(localDateTime.getDayOfYear()); // 获取当前时间在该年属于第几天
System.out.println(localDateTime.getYear()); // 获取当前时间的年份
System.out.println(localDateTime.getMonthValue()); // 获取当前时间的月份(阿拉伯文)
System.out.println(localDateTime.getMonth()); // 获取当前时间的月份(英文)
System.out.println(localDateTime.getHour()); // 获取当前时间的小时数
System.out.println(localDateTime.getMinute()); // 获取当前时间的分钟数
// 构造时间
LocalDateTime startTime = LocalDateTime.of(2021, 1, 1, 20, 31, 20);
LocalDateTime endTime = LocalDateTime.of(2021, 1, 3, 20, 31, 20);
// 比较时间
System.out.println(localDateTime.isAfter(startTime)); // 结果:true
System.out.println(localDateTime.isBefore(endTime)); // 结果:false
//获取毫秒数(使用 Instant)
System.out.println(localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
//获取秒数(使用 Instant)
System.out.println(localDateTime.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond());
// LocalDateTime 获取秒数
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
// LocalDateTime 获取毫秒数
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 获取本月的第一天的0点0分0秒和最后一天的23点59分59秒
LocalDateTime beginMonth = localDateTime.with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0);
LocalDateTime endMonth = localDateTime.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59);
// LocalDateTime 转 Date
Date date = Date.from(localDateTime.toInstant(ZoneOffset.of("+8")));
// Date 转 LocalDateTime
date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
}
8.4 Instant 代替 Date
时区需要加 8 小时
public static void main(String[] args) {
Instant instant = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
System.out.println(instant); // 2021-12-22T08:59:57.491Z
}
8.5 DateTimeFormatter 代替 SimopleDateFormat
时间要使用 LocalDateTime
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dtf.format(LocalDateTime.now());
System.out.println(format); // 2021-12-22 09:04:47
}
8.6 日期比较
- 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值
- 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true
- 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口
9. 正则、标签、finalize
9.1 正则
9.1.1 语法
9.1.2 Matcher
9.1.2.1 索引方法
9.1.2.2 查找方法
- matches 和 lookingAt 方法都用来尝试匹配一个输入序列模式。它们的不同是 matches 要求整个序列都匹配,而lookingAt 不要求
- lookingAt 方法虽然不需要整句都匹配,但是需要从第一个字符开始匹配
public class RegexMatches{
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static final String INPUT2 = "ooooofoooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
private static Matcher matcher2;
public static void main( String[] args ){
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
matcher2 = pattern.matcher(INPUT2);
System.out.println("Current REGEX is: "+REGEX); // foo
System.out.println("Current INPUT is: "+INPUT); // fooooooooooooooooo
System.out.println("Current INPUT2 is: "+INPUT2); // ooooofoooooooooooo
System.out.println("lookingAt(): "+matcher.lookingAt()); // true
System.out.println("matches(): "+matcher.matches()); // false
System.out.println("lookingAt(): "+matcher2.lookingAt()); // false
}
}
9.1.2.3 替换方法
9.1.2.4 PatternSyntaxException
PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误
9.2 标签
Java 中的标签是为循环设计的,是为了在多重循环中方便的使用 break 和coutinue
public class Main {
public static void main(String[] args) {
String strSearch = "This is the string in which you have to search for a substring.";
String substring = "substring";
boolean found = false;
int max = strSearch.length() - substring.length();
// 标签
testlbl:
for (int i = 0; i <= max; i++) {
int length = substring.length();
int j = i;
int k = 0;
while (length-- != 0) {
if(strSearch.charAt(j++) != substring.charAt(k++)){
continue testlbl;
}
}
found = true;
break testlbl; // break 到标签位置
}
if (found) {
System.out.println("发现子字符串。");
}
else {
System.out.println("字符串中没有发现子字符串。");
}
}
}
9.3 finalize
在对象被垃圾收集器析构(回收)之前调用,用来清除回收对象。如:可以使用 finalize() 来确保一个对象打开的文件被关闭了。在 finalize() 方法里,你必须指定在对象销毁时候要执行的操作。
protected void finalize(){
// 在这里终结代码
}
/* 关键字 protected 是一个限定符,它确保 finalize() 方法不会被该类以外的代码调用。
当然,Java 的内存回收可以由 JVM 来自动完成。如果你手动使用,则可以使用上面的方法
*/
10. IO
10.1 IO 流
10.2 字节流
10.2.1 FileInputStream
该流用于从文件读取数据,它的对象可以用关键字 new 来创建
// 可以使用字符串类型的文件名来创建一个输入流对象来读取文件
InputStream is = new FileInputStream("E://a.txt");
// 也可以使用一个文件对象来创建一个输入流对象来读取文件。我们首先得使用 File() 方法来创建一个文件对象
File file = new File("E://a.txt");
InputStream in = new FileInputStream(file);
int len = 0;
while ((len = fis.read()) != -1){
System.out.println(len); // 228 189 160 229 165 189
}
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1){
System.out.println(new String(bytes,0,len)); // 你好...
}
fis.close();
10.2.2 FileOutputStream
该类用来创建一个文件并向文件中写数据。如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件
// 使用字符串类型的文件名来创建一个输出流对象
OutputStream os = new FileOutputStream("E://b.txt");
// 使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象
File file = new File("E://a.txt");
OutputStream os = new FileOutputStream(file);
os.write(97); // a
byte[] bytes = {65,66,67,68,69};
os.write(bytes); // ABCDE
os.write("你好".getBytes()); // 你好
os.close();
10.3 字符流
10.3.1 FileReader
FileReader fr = new FileReader("E://a.txt");
char[] chars = new char[1024];
int len = 0;
while ((len = fr.read(chars)) != -1){
System.out.println(new String(chars,0,len)); // 你好...
}
fr.close();
10.3.2 FileWriter
FileWriter fw = new FileWriter("E://a.txt");
FileWriter fw = new FileWriter("E://a.txt",true); // 续写开关 true:不会创建新的文件覆盖源文件,可以续写
char[] chars = {'a','b','c','d'};
fw.write(chars); // abcd
fw.write("你好"); // abcd你好
fw.flush();
fw.close();
10.4 缓冲流
// 写入文件
BufferedWriter out = new BufferedWriter(new FileWriter("E://runoob.txt"));
out.write("菜鸟教程");
out.close();
// 读取文件
BufferedReader br = new BufferedReader(new FileReader("E://runoob.txt"));
String str;
while ((str = br.readLine()) != null){
System.out.println(str); // 菜鸟教程
}
11. Collection
11.1 集合框架
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
- 接口: 是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
- 实现(类): 是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap
- 算法: 是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现
11.2 集合接口
Set 和 List 的区别:
- Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素
- Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>
- List 和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector>
11.3 集合实现类
java.util 包中定义的类:
10.4 遍历
推荐使用 entrySet 和 forEach 方法
public static void main(String[] args) {
Map<String, String> map = new HashMap<>(16);
map.put("张三","13");
map.put("李四","14");
map.put("王五","16");
map.put("赵六","13");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
map.forEach((key,value) -> {
System.out.println(key + " " + value);
});
}
11.5 允许空值情况
11.6 ArrayList
11.7 LinkedList
Java LinkedList(链表) 类似于 ArrayList,是一种常用的数据容器。与 ArrayList 相比,LinkedList 的增加和删除的操作效率更高,而查找和修改的操作效率较低。
以下情况使用 ArrayList :
- 频繁访问列表中的某一个元素
- 只需要在列表末尾进行添加和删除元素操作
以下情况使用 LinkedList :
- 你需要通过循环迭代来访问列表中的某些元素
- 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作
11.8 HashMap
进阶部分见:https://blog.csdn.net/ACE_U_005A/article/details/123276268