Java基础总结回顾

1. 说明

1.1 编译与运行

  1. 编译:是指将编写的 Java 源文件翻译成 JVM 认识的 class 文件,在这个过程中, javac 编译器会检查所写的程序是否有错误,有错误就会提示出来,如果没有错误就会编译成功
  2. 运行:是指将 class文件 交给 JVM 去运行,此时 JVM 会去执行编写的程序

1.2 main 方法

主方法,写法是固定格式不可以更改。main 方法是程序的入口点或起始点,无论我们编写多少程序,JVM在运行的时候,都会从 main 方法这里开始执行

1.3 keywords 关键字

指在程序中,Java 已经定义好的单词,具有特殊含义。如 public 、class 、static 、void 等,这些单词已经被 Java 定义好,全部都是小写字母

1.4 标识符

指在程序中,自己定义的内容,如类的名字、方法的名字和变量的名字等等
命名规则: 硬性要求

  1. 标识符可以包含 英文字母26个(区分大小写) 、 0-9数字 、 $(美元符号) 和 _(下划线)
  2. 标识符不能以数字开头
  3. 标识符不能是关键字

命名规范: 软性建议

  1. 类名规范:首字母大写,后面每个单词首字母大写(大驼峰式)
  2. 方法名规范: 首字母小写,后面每个单词首字母大写(小驼峰式)
  3. 变量名规范:全部小写

2. 常量、变量、数据类型、运算符

2.1 常量

是指在 Java 程序中固定不变的数据
在这里插入图片描述

2.2 变量

常量是固定不变的数据,那么在程序中可以变化的量称为变量,Java 中要求一个变量每次只能保存一个数据,必须要明确保存的数据类型

变量定义的格式包括三个要素: 数据类型 、 变量名 、 数据值

数据类型 变量名 = 数据值;

变量名称:在同一个大括号范围内,变量的名字不可以相同
变量赋值:定义的变量,不赋值不能使用

2.3 数据类型

Java的数据类型分为两大类:

  1. 基本数据类型:包括 整数 、 浮点数 、 字符 、 布尔
  2. 引用数据类型:包括 类 、 数组 、 接口

四类八种基本数据类型:
在这里插入图片描述

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); // 编译成功
}

在这里插入图片描述

  1. 浮点转成整数,直接取消小数点,可能造成数据损失精度
  2. 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 数组工具类

  1. Arrays.sort:元素排序,会改变原数组
  2. Arrays.toString:返回指定数组内容的字符串表示形式
  3. Arrays.binarySearch:查找元素位置
  4. contains:查找元素是否存在
  5. Arrays.equals:数组比较
  6. Collections.min、Collections.max:获取最大值和最小值
    int min = (int) Collections.min(Arrays.asList(numbers));
    
  7. Arrays.asList、addAll:数组合并
    List list = new ArrayList(Arrays.asList(a));
    list.addAll(Arrays.asList(b));
    
  8. Arrays.fill:数组填充
  9. System.arraycopy:数组扩容/复制
  10. retainAll: 数组交集
  11. removeAll:数组差集

4. 类与对象、封装、继承、多态

4.1 类与对象

类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物

  1. 属性:就是该事物的状态信息,成员变量:对应事物的属性,有默认值
  2. 行为:就是该事物能够做什么, 成员方法:对应事物的行为

对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为

类与对象的关系:

  1. 类是对一类事物的描述,是抽象的
  2. 对象是一类事物的实例,是具体的
  3. 类是对象的模板,对象是类的实体

4.2 成员变量和局部变量区别

  1. 在类中的位置不同:成员变量:类中,方法外;局部变量:方法中或者方法声明上(形式参数)
  2. 作用范围不一样:成员变量:类中;局部变量:方法中
  3. 初始化值的不同: 成员变量:有默认值;局部变量:没有默认值。必须先定义,赋值,最后使用
    在这里插入图片描述
  4. 在内存中的位置不同: 成员变量:堆内存;局部变量:栈内存
  5. 生命周期不同: 成员变量:随着对象的创建而存在,随着对象的消失而消失;局部变量:随着方法的调用而存在,随着方法的调用完毕而消失

4.3 封装 private

面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。封装用来防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

将属性隐藏起来,若需要访问某个属性,提供公共方法对其访问,this 代表当前对象的引用(谁调用就代表谁)

4.4 继承 super

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类

子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为

4.5 继承之后的属性和行为

  1. 子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量。super,代表父类的存储空间标识(可以理解为父亲的引用)
  2. 子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。子类方法覆盖父类方法,必须要保证权限大于等于父类权限
  3. 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用
  4. 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: 不可改变。可以用于修饰类、方法和变量

  1. final 变量:变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值
  2. final 方:父类中的 final 方法可以被子类继承,但是不能被子类重写
  3. final 类:final 类不能被继承,没有类能够继承 final 类的任何特性

5.1.3 static

  1. 静态变量
    static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
  2. 静态方法
    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 类

字符串不变:字符串的值在创建后不能被更改
在这里插入图片描述

  1. public boolean equals (Object anObject) :将此字符串与指定对象进行比较
  2. public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象进行比较,忽略大小写
  3. compareTo、compareToIgnoreCase:字符串比较
  4. regionMatches:比较字符串区域相等
  5. public int length () :返回此字符串的长度
  6. public String concat (String str)、+ :将指定的字符串连接到该字符串的末尾
  7. public char charAt (int index) 返回指定索引处的 char值
  8. public int indexOf (String str) 返回指定子字符串第一次出现在该字符串内的索引
  9. public String substring (int beginIndex)返回一个子字符串,从 beginIndex 开始截取字符串到字符串结尾
  10. public String substring (int beginIndex, int endIndex)返回一个子字符串,从 beginIndex 到 endIndex 截取字符串。含 beginIndex,不含 endIndex
  11. public char[] toCharArray () :将此字符串转换为新的字符数组
  12. public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组
  13. public String replace (CharSequence target, CharSequence replacement) 、replaceFirst、replaceAll:将与 target 匹配的字符串使用 replacement 字符串替换
  14. public String[] split(String regex)将此字符串按照给定的 regex(规则)拆分为字符串数组
  15. StringBuffer.reverse:字符串反转
  16. delete(StringBuffer):字符串删除
  17. public boolean startsWith(String prefix) 判断是否以某字符串开头

6.2 Math类

  1. public static double abs(double a) :返回 double 值的绝对值
  2. public static double ceil(double a) :返回大于等于参数的最小的整数
  3. public static double floor(double a) :返回小于等于参数最大的整数
  4. public static long round(double a) :返回最接近参数的 long。(相当于四舍五入方法)

6.3 Collections 类

  1. 排序
  2. 查找,替换操作
  3. 同步控制(不推荐,需要线程安全的集合类型时请考虑使用 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() 方法,该方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题

HashSetTreeSetArrayList, 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 接口完成

  1. public static void sort(List list) 这个方法完成的排序,实际上要求了被排序的类型需要实现 Comparable 接口完成比较的功能

  2. 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返回(负数)

  3. 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 声明自定义异常

  1. 所有异常都必须是 Throwable 的子类
  2. 如果希望写一个检查性异常类,则需要继承 Exception 类
  3. 如果你想写一个运行时异常类,那么需要继承 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 日期比较

  1. 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值
  2. 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true
  3. 使用 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 的区别:

  1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素
  2. Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>
  3. 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

posted @ 2022-12-21 11:59  凡223  阅读(5)  评论(0编辑  收藏  举报