1. 异常处理
1.1 异常层次结构
-
所有异常类都是
java.lang.Exception
类的子类型。 -
Exception
类是Throwable
类的子类。还有另一个名称为Error
的子类,它派生自Throwable
类 -
Exception
类有两个主要的子类:IOException
类和RuntimeException
类
1.2 异常方法
以下是Throwable
类中可用的方法列表:
方法 | 描述 |
---|---|
String getMessage() |
返回有关已发生的异常的详细消息 |
Throwable getCause() |
返回由Throwable 对象表示的异常的原因 |
String toString() |
返回与getMessage() 结果连接的类名称 |
void printStackTrace() |
将toString() 的结果与堆栈跟踪一起打印到System.err (错误输出流) |
1.3 捕捉异常
使用规则
- 没有
try
语句就不能存在catch
子句 - 只要存在
try/catch
块,finally
子句就不是必须的 - 如果没有
catch
子句或finally
子句,则try
块不能出现 try
,catch
,finally
块之间不能出现任何代码
在方法中可使用try
和catch
关键字的组合捕获异常,将容易出现异常的代码放在try
块中。 发生异常时,异常由与其关联的catch
块处理。 每个try
块都应该紧跟一个catch
块或者一个块finally
基本语法
try {
// Protected code
} catch (ExceptionName e1) {
// Catch block
}
监听多种异常
如果抛出的异常的数据类型与ExceptionType1
匹配,则会在那里捕获它,如果不是,则异常传递给第二个catch
语句
try {
// Protected code
} catch (ExceptionName e1) {
// Catch block
} catch (ExceptionName e2) {
// Catch block
}
finally
语句
finally
块在try
块或catch
块之后,无论受保护的代码块是否发生异常,最终都会执行finally
块中的代码
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}finally {
// The finally block always executes.
}
当finally
语句块种有reutrn
语句时,返回值为finally
语句快的返回值
private static int Reu() {
try {
return 1;
}catch(Exception e) {
return 2;
}finally {
return 3; /* 不应在此语句块种有 return 语句*/
}
}
try-with-resources
语句
- 使用带有
try-with-resources
语句的类,它应该实现AutoCloseable
接口,并且它的close()
方法在运行时自动调用 - 在
try
块声明的资源被隐式声明为final
通常,当使用流,连接等任何资源时,要使用finally
块显式关闭它们,try-with-resources
自动关闭try/catch
块中使用的资源
try(FileReader fr = new FileReader("file path")) {
// use the resource
} catch () {
// body of catch
}
}
1.4 声明/抛出异常
-
如果一个方法没有捕获一个检查性异常,那么该方法必须使用
throws
关键字来声明 -
throws
关键字放在方法签名的尾部 -
使用
throw
关键字抛出一个异常,无论它是新实例化的还是刚捕获到的 -
当抛出异常时可以抛出定义的异常或是它的父类
抛出异常
// 处理异常
public static void main(String[] args) {
try {
withdraw(2);
} catch (RemoteException e) {
// TODO: handle exception
}
}
// 抛出异常
public static void withdraw(double amount) throws RemoteException{
throw new RemoteException();
}
抛出多个异常
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开
public void withdraw(double amount) throws RemoteException,ArrayStoreException
// Method implementation
throw new RemoteException();
}
抛出异常父类
当抛出异常父类时,不管有没有监听异常字类,一定要有监听父类异常
public static void main(String[] args) {
try {
withdraw(2);
} catch (RemoteException e) {
// TODO: handle exception
}catch(Exception ex) {
// TODO: handle exception
}
}
public static void withdraw(double amount) throws Exception{
throw new Exception();
}
public static void withdraw(double amount) throws RemoteException{
throw new RemoteException();
}
1.5 自定义异常
- 所有异常都必须是
Throwable
的子类 - 如果希望写一个检查性异常类,则需要继承
Exception
类 - 如果你想写一个运行时异常类,那么需要继承
RuntimeException
类
定义异常
public class CustomException extends Exception {
private String Message;
public CustomException(String ExceptionMsg) {
this.Message = ExceptionMsg;
super("自定义错误"+Message);
}
}
抛出异常
public static void withdraw(double amount) throws CustomException{
throw new CustomException("错误");
}
监听异常
public static void main(String[] args) {
try {
withdraw(1);
} catch (CustomException e) {
System.out.println(e.getMessage());
}
}
1.6 异常链
异常链:将异常发生的原因一个传一个的连起来,即把底层的异常信息传给上层,逐层抛出
public class exp {
public static void main(String[] args) {
try {
Fun2();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void Fun1() throws Exception{
throw new Exception("Fun1");
}
public static void Fun2() throws Exception{
try {
Fun1();
} catch (Exception e) {
throw new Exception("Fun2",e);
}
}
}
2. 字符串操作
2.1 String
类
字符串方法
方法 | 描述 |
---|---|
int length() | 返回字符串长度 |
String concat(String str) | 连接两个字符串,返回连接后的字符串 |
格式化字符串
String fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);
2.2 StringBuffer
类
StringBuffer
类的对象能够被多次的修改,并且不产生新的未使用对象
线程安全的情况下,则必须使用 StringBuffer
类
public class Test{
public static void main(String args[]){
StringBuffer sBuffer = new StringBuffer(":");
sBuffer.append("1");
sBuffer.append("2");
sBuffer.append("3");
System.out.println(sBuffer);
}
}
2.3 StringBuilder
类
StringBuilder
类的对象能够被多次的修改,并且不产生新的未使用对象
StringBuilder
的方法不是线程安全的(不能同步访问)
public class Test {
public static void main(String[] args) {
StringBuilder str1 = new StringBuilder("");
System.out.println(str1 + " " + str1.hashCode());
str1 = str1.append("libai");
System.out.println(str1 + " " + str1.hashCode());
str1 = str1.append("zhanyun");
System.out.println(str1 + " " + str1.hashCode());
}
}
3. 数值操作
3.1 Math
类
Java
的 Math
包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。方法都被定义为 static
形式,通过 Math
类可以在主函数中直接调用
Number
&Math
类常用的一些方法:
方法 | 描述 |
---|---|
double floor() | 对一个数进行下舍入,返回给定参数最大的整数,该整数小于或等给定的参数 |
double ceil() | 对一个数进行上舍入,返回值大于或等于给定的参数的最小整数 |
longround() | 将原来的数字加上 0.5 后再向下取整,返回最大的整数,长整型 |
4. 日期时间
4.1 Java
Date
类
java.util
包提供了 Date
类来封装当前的日期和时间
构造函数,初始化
Date
对象
使用当前日期和时间来初始化对象
Date date = new Date();
接收一个参数,该参数是从1970年1月1日起的毫秒数
Date date = new Date(long millisec)
方法列表
方法名 | 描述 |
---|---|
boolean after(Date date) | 调用此方法的Date 对象在指定日期之后,是返回true |
boolean before(Date date) | 调用此方法的Date 对象在指定日期之前,是返回true |
boolean equals(Object date) | 调用此方法的Date 对象和指定日期相等时候返回true |
long getTime( ) | 返回此 Date 对象表示的毫秒数 |
void setTime(long time) | 毫秒数设置时间和日期 |
使用
SimpleDateFormat
格式化日期
使用方式:
Date date = new Date();
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
String datetime = ft.format(date);
常用格式:
格式 | 示例 |
---|---|
y | 四位年份 |
M | 月份 |
H | 小时 (0~23) |
h | 小时(1~12) |
m | 分钟数 |
s | 秒数 |
S | 毫秒数 |
d | 一个月的日期 |
E | 星期几 |
W | 一个月中第几周 |
F | 一个月中第几周的周几 |
D | 一年中的日子 |
w | 一年中第几周 |
解析字符串为时间对象
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo1DateTime {
public static void main(String[] args) throws ParseException {
String date_str = "2021-03-26 23:15:05";
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = ft.parse(date_str);
System.out.println(date.toLocaleString());
}
}
4.2 Java
Calendar
类
导入import java.util.Calendar;
Calender
的月份是从0开始的,但日期和年份是从1开始的
创建日期对象
当前日期:
Calendar c = Calendar.getInstance();// 默认是当前日期
指定日期:
Calendar c1 = Calendar.getInstance(); // 创建Calendar对象
c1.set(2021,5,12); // 设置日期
设置日期(
set
)
参数设置:
public final void set(int year,int month,int date)
Calendar c1 = Calendar.getInstance(); // 创建Calendar对象
c1.set(2021,5,12); // 设置日期
利用字段类型设置:
Calendar c1 = Calendar.getInstance(); // 创建Calendar对象
c.set(Calendar.YEAR, 1999); // 设置年份,没有设置的默认当前日期时间
常量 | 描述 |
---|---|
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
设置日期(
add
)
Calendar c1 = Calendar.getInstance(); // 初始化对象,默认当前日期时间
c1.add(Calendar.DATE, 1); // 天数加 1
c1.add(Calendar.DATE, 1); // 天数减 1
/* 其他字段属性的add的意义以此类推 */
获取日期时间(
get
)
Calendar c1 = Calendar.getInstance();
// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1;
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
int day = c1.get(Calendar.DAY_OF_WEEK);
5. 集合框架
集合框架体系结构
- 集合框架位于
java.util
包中, 所以当使用集合框架的时候需要进行导包
5.1 集合接口
接口 | 描述 |
---|---|
Collection 接口 |
最基本的集合接口,一个Collection 代表一组Object ,即Collection 的元素;不提供直接继承自Collection 的类,只提供继承于的子接口(如List 和set ) |
List 接口 | 是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引访问List中的元素,允许有相同的元素 |
Set | 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素 |
SortedSet | 继承于Set保存有序的集合 |
Map | 将唯一的键映射到值 |
SortedMap | 继承于Map,使Key保持在升序排列 |
5.2 标准集合类
类名 | 描述 |
---|---|
AbstractCollection | 实现了大部分的集合接口 |
AbstractList | 继承于AbstractCollection 并且实现了大部分List接口 |
AbstractSequentialList | 继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问 |
LinkedList | 实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List,LinkedList 查找效率低 |
ArrayList | 实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的情况下不要使用 |
AbstractSet | 继承于AbstractCollection 并且实现了大部分Set接口 |
HashSet | 实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个 |
TreeSet | 实现了Set接口,可以实现排序等功能 |
AbstractMap | 实现了大部分的Map接口 |
HashMap | 实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步 |
TreeMap | 继承了AbstractMap,并且使用一颗树 |
5.3 Iterator
迭代器
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
引用
Iterator 类位于 java.util 包中,使用前需要引入它,语法格式如下:
import java.util.Iterator; // 引入 Iterator 类
操作示例
迭代器是有状态的,迭代器会逐个迭代集合中的元素,且会记录当前的位置
/ 引入 ArrayList 和 Iterator 类
import java.util.ArrayList;
import java.util.Iterator;
public class RunoobTest {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(12);
numbers.add(8);
numbers.add(2);
numbers.add(23);
Iterator<Integer> it = numbers.iterator(); // 1.获取迭代器对象
while(it.hasNext()) { // 2.检测集合中是否还有元素
Integer i = it.next(); // 3.获取下一个元素,并且更新迭代器的状态
if(i < 10) {
it.remove(); // 4.将迭代器返回的元素删除
}
}
System.out.println(numbers);
}
}
5.4 ArrayList
ArrayList
类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,可以添加或删除元素;继承了 AbstractList
,并实现了 List
接口
操作方法
方法名 | 描述 | 返回值 |
---|---|---|
add([int index,]E element) | 将元素插入到[指定位置的]数组 | 成功,返回 true |
addAll([int index,]Collection c) | 将给定集合中所有元素插入到[指定位置的]数组 | 成功,返回 true |
clear() | 清空数组 | 无 |
clone() | 用于拷贝一份动态数组,属于浅拷贝 | ArrayList 对象 |
isEmpty() | 判断动态数组是否为空 | 空,返回 true |
subList(int start_i, int end_i) | 截取一段,[起始位置,结束位置) | ArrayList 对象 |
contains(Object obj) | 判断元素是否在动态数组中 | 是,返回 true |
get(int index) | 通过索引值获取动态数组中的元素 | 索引元素 |
removeAll(Collection c) | 删除存在于指定集合中的动态数组元素 | 成功,返回 true |
remove(Object obj/int index) | 用于删除动态数组里的单个元素 | 成功,返回 true |
set(int index, E element) | 修改动态数组中指定索引的元素 | 返回修改前元素 |
sort(Comparator c) | 排序 | 无 |
removeIf(Lambda lab) | 删除所有满足特定条件的数组元素 | 成功,返回 true |
forEach(Consumer |
遍历动态数组中每一个元素 | 无 |
声明集合
ArrayList
类位于 java.util
包中,使用前需要引入它,语法格式如下:
E
: 泛型数据类型,用于设置objectName
的数据类型,只能为引用数据类型
import java.util.ArrayList; // 引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>(); // 初始化
List list1 = new ArrayList();
List<String> list2 = new ArrayList<String>();
操作集合元素
package day2;
import java.util.*;
public class MATH {
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add("赵云");
System.out.println(list1.get(0));
list1.set(0, "赵云2");
System.out.println(list1.get(0));
list1.remove(0);
System.out.println(list1.size());
List<String> list2 = new ArrayList<String>();
list2.add("李白");
System.out.println(list2.get(0));
list2.set(0, "李白2");
System.out.println(list2.get(0));
list2.remove(0);
System.out.println(list2.size());
}
}
如果要存储其他类型,而 <E>
只能为引用数据类型,这时我们就需要使用到基本类型的包装类
ArrayList<Integer> li=new Arraylist<>(); // 存放整数元素
ArrayList<Character> li=new Arraylist<>(); // 存放字符元素
示例:使用 ArrayList
存储数字(使用 Integer
类型)
import java.util.ArrayList;
public class RunoobTest {
public static void main(String[] args) {
ArrayList<Integer> myNumbers = new ArrayList<Integer>();
myNumbers.add(10);
myNumbers.add(15);
for (int i : myNumbers) {
System.out.println(i);
}
}
}
删除筛选过的元素
removeIf()
方法用于删除所有满足特定条件的数组元素
import java.util.*;
class Main {
public static void main(String[] args){
// 创建一个动态数组
ArrayList<String> sites = new ArrayList<>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
// 删除名称中带有 Tao 的元素
sites.removeIf(e -> e.contains("Tao"));
}
}
遍历集合元素
第一种方式:使用增强for
循环
package day2;
import java.util.*;
public class MATH {
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add("赵云");
System.out.println(list1.get(0));
list1.set(0, "赵云2");
System.out.println(list1.get(0));
list1.remove(0);
System.out.println(list1.size());
List<String> list2 = new ArrayList<String>();
list2.add("李白"); // 添加:添加到末尾
list2.add(0, "李白2"); // 添加:添加到指定索引除
System.out.println(list2.get(0) + " " + list2.get(1));
list2.set(0, "李白"); // 修改:第一个参数为索引位置,第二个为要修改的值
System.out.println(list2.get(0) + " " + list2.get(1));
list2.remove(0);
System.out.println(list2.size());
}
}
第二种方式:使用普通
for
循环
package day2;
import java.util.*;
public class MATH {
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add("赵云");
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
List<String> list2 = new ArrayList<String>();
list2.add("李白");
for (int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
第三种方式:使用迭代器进行相关遍历
package day2;
import java.util.*;
public class MATH {
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add("赵云");
Iterator<String> ite = list1.iterator();
while (ite.hasNext())// 判断下一个元素之后有值
{
System.out.println(ite.next());
}
List<String> list2 = new ArrayList<String>();
list2.add("李白");
Iterator<String> ite2 = list2.iterator();
while (ite2.hasNext())// 判断下一个元素之后有值
{
System.out.println(ite2.next());
}
}
}
第四种方式:使用
forEach
方法
package day2;
import java.util.*;
public class MATH {
public static void main(String[] args) {
// 创建一个数组
ArrayList<Integer> numbers = new ArrayList<>();
// 往数组中添加元素
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
// 将 lambda 表达式传递给 forEach
numbers.forEach((e) -> {
e = e * 10;
System.out.print(e + " ");
});
}
}
5.5 HashMap
HashMap
是一个散列表,继承于AbstractMap
,实现了 Map、Cloneable、java.io.Serializable
接口<它存储的内容是键值对(key-value
)映射,且元素是无序的;实现了 Map 接口,根据键的 HashCode
值存储数据;最多允许一条记录的键为 null
,不支持线程同步;
操作方法
方法 | 描述 | 返回值 |
---|---|---|
put(K k,V v) | 键不存在添加/存在修改键值 | 存在,返回旧的value值,反之返回null |
putIfAbsent(K k,V v) | 判断键是否存在,不存在添加 | 存在,返回旧的value值,反之返回null |
remove(K k[,V v]) | 移除键【,值】对应元素 | key存在,成功返回value值,反正返回null; value存在,成功返回true,反正返回false |
get(K k) | 返回指定键值 | key存在,成功返回value值,反正返回null |
getOrDefault(K k,V dv) | 返回指定键值 | key存在,成功返回value值,反正返回默认值 |
size() | 返回数量 | 集合为空则抛出异常 |
声明
HashMap
类位于 java.util
包中,使用前需要引入它,语法格式如下:
import java.util.HashMap; // 引入 HashMap 类
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
操作示例
package day2;
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
public static void main(String[] args) {
Map<Integer, String> SitesMap = new HashMap<Integer, String>();
SitesMap.put(1, "Google"); // 添加:添加元素(key,value)
SitesMap.put(2, "Runoob");
System.out.println(SitesMap.get(2)); // 根據key值获取元素,Google
SitesMap.remove(2); // 移除,根据key移除元素
int size = SitesMap.size(); // 获取元素数量
SitesMap.clear(); // 清空所有元素
System.out.println(SitesMap);
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
Sites.put(1, "Google");
Sites.put(2, "Runoob");
System.out.println(Sites.get(1));
System.out.println(Sites);
}
}
遍历
HashMap
第一种:使用增强for
遍历
package day2;
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
public static void main(String[] args) {
Map<Integer, String> SitesMap = new HashMap<Integer, String>();
SitesMap.put(1, "Google");
SitesMap.put(2, "Runoob");
// 输出 key 和 value
for (Integer i : SitesMap.keySet()) {
System.out.println("key: " + i + " value: " + Sites.get(i));
}
// 返回所有 value 值
for(String value: SitesMap.values()) {
// 输出每一个value
System.out.print(value + ", ");
}
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
Sites.put(1, "Google");
Sites.put(2, "Runoob");
// 输出 key 和 value
for (Integer i : Sites.keySet()) {
System.out.println("key: " + i + " value: " + Sites.get(i));
}
// 返回所有 value 值
for(String value: Sites.values()) {
// 输出每一个value
System.out.print(value + ", ");
}
}
}
第二种:使用forEach()
方法
import java.util.HashMap;
public class HashMapTest {
public static void main(String[] args) {
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
Sites.put(1, "Google");
Sites.put(2, "Runoob");
Sites.forEach((key, value) -> {
System.out.println(key + " " + value);
});
}
}
5.6 HashSet
5.7 数组排序
数值数组排序(
Comparator
接口)
按照数值大小排序
List<Integer> list = new ArrayList<Integer>();
...
Collections.sort(list);
字符串排序(
Comparator
接口)
按照国际编码排序
List<String> list = new ArrayList<String>();
...
Collections.sort(list);
自定义类型排序(
Comparator
接口)
对任意类型集合对象进行整体排序,排序时将此接口的实现传递给Collections.sort
方法或者Arrays.sort
方法排序.实现int compare(T o1, T o2);
方法,返回正数,零,负数各代表大于,等于,小于
条件排序:自定义比较器类
package day3;
import java.util.Comparator;
/**
* 比较器类
*/
public class CustomComparator implements Comparator<UserInfo> {
@Override
public int compare(UserInfo o1, UserInfo o2) {
// 升序
//return o1.getuId().compareTo(o2.getuId());
// 降序
return o2.getuId().compareTo(o1.getuId());
}
}
List<UserInfo> list = new ArrayList<UserInfo>();
...
Collections.sort(list,new CustomComparator());
条件排序:使用lambda
表达式
List<UserInfo> list = new ArrayList<UserInfo>();
...
Collections.sort(list,(s1,s2)->(s1.getuId()-s2.getuId()));
自定义排序(
Comparable
接口)
package day3;
public class UserInfo implements Comparable<UserInfo> {
private Integer uId;
private String uName;
...
@Override
public int compareTo(UserInfo o) {
// 升序
//return this.getuId() - o.getuId();
// 降序
return o.getuId() - this.getuId();
}
}
List<UserInfo> list = new ArrayList<UserInfo>();
...
Collections.sort(list);
6. 泛型(Generics
)
泛型是JDK 1.5
的一项新特性,它的本质是参数化类型的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
泛型的限制
- 泛型的类型参数只能是类类型,不能是简单类型(简单类型的包装类可以)
- 类型参数不能用于在方法中实例化其对象,如果需要实现这样的功能,可以使用反射
- 使用泛型时,类型参数不允许为静态
- 除非由无界通配符进行参数化,否则不允许转换为参数化类型
- 泛型类不允许直接或间接扩展
Throwable
类 - 泛型不能使用数组
- 泛型不能重载
6.1 泛型类
在类的申明时指定参数,即构成了泛型类。泛型类的类型参数部分可以有一个或多个类型参数,它们之间用逗号分隔。
声明泛型类
import java.util.List;
public class Genit<T> {
private List<T> list;
public T Install(T entity) {
list.add(entity);
return null;
}
}
何继承一个泛型类
如果不传入具体的类型,则子类也需要指定类型参数,
class Son<T> extends Test<T>{}
如果传入具体参数,则子类不需要指定类型参数
class Son extends Test<String>{}
6.2 泛型方法
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型
- 定义泛型方法时,必须在返回值前边加一个
<T>
,来声明这是一个泛型方法
定义泛型方法
public class GenericM {
public <T> void install(T c) {
System.out.println(c.toString());
}
}
调用泛型方法
public class GenericMain {
public static void main(String[] args) {
GenericM h = new GenericM();
h.install(1);
}
}
6.3 泛型接口
型接口与泛型类的定义基本一致
定义泛型接口
//定义一个泛型接口
public interface BaseService<T> {
T install(T entity);
List<T> queryList();
}
实现泛型接口
public class UserInfoService implements BaseService<UserInfo> {
@Override
public UserInfo install(UserInfo entity) {
return null;
}
@Override
public List<UserInfo> queryList() {
return null;
}
}
6.4 类型通配符
泛型上限通配符
通配符上界使用<? extends T>
的格式,意思是需要一个T
类型或者T
类型的子类
//只能传入number的子类或者number
public void showKeyValue2(List<? extends Number> list) {
for (Number number : list) {
System.out.print(number.intValue()+" ");
}
}
泛型下限通配符
通配符下界使用<? super T>
的格式,意思是需要一个T
类型或者T
类型的父类
//只能传入Integer的父类或者Integer
public void showKeyValue3(List<? super Integer> obj){
System.out.println(obj);
}
无限定通配符
无限定通配符使用<?>的格式,代表未知类型的泛型。 当可以使用Object
类中提供的功能或当代码独立于类型参数来实现方法时,这样的参数可以使用任何对象
public void showKeyValue1(List<?> list) {
for (Object item : list) {
System.out.print(item + " ");
}
}
<? extends T>
和<? super T>
的区别
<? extends T>
表示该通配符所代表的类型是T类型的子类<? super T>
表示该通配符所代表的类型是T类型的父类
7. 多线程(Thread
)
一个线程的生命周期
创建线程
Java
提供了三种创建线程的方法:
- 通过实现
Runnable
接口 - 通过继承
Thread
类本身 - 通过
Callable
和Future
创建线程
主要概念
- 线程同步
- 线程间通信
- 线程死锁
- 线程控制:挂起、停止和恢复
线程的优先级
Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY ),
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)
7.1 Thread
类
Thread
是一个线程类,位于java.lang
包下
方法列表
构造方法 | 描述 |
---|---|
new Thread() | 创建一个线程对象 |
new Thread(String name) | 创建一个具有指定名称的线程对象 |
new Thread(Runnable target) | 创建一个基于Runnable接口实现类的线程对象 |
new Thread(Runnable target ,String name) | 创建一个基于Runnable接口实现类且有名称的线程对象 |
实例方法 | 描述 |
---|---|
public void start() | 使该线程开始执行;Java 虚拟机调用该线程的 run 方法 |
public void run() | 若线程是Runnable对象构造,则调用Runnable 对象 run 方法 |
public final void setName(String name) | 改变线程名称 |
public final void setPriority(int priority) | 更改线程的优先级 |
public final void setDaemon(boolean on) | 将该线程标记为守护线程或用户线程 |
public final void join(long millisec) | 待该线程终止的时间最长为 millis 毫秒 |
public final void join(long millisec) | 等待该线程终止的时间最长为 millis 毫秒 |
public void interrupt() | 中断线程 |
public final boolean isAlive() | 线程是否处于活动状态 |
线程优先级
class ContomRunable implements Runnable{
@Override
public void run() {
System.out.println("start...");
}
}
public class RannbleTesk {
public static void main(String[] args) {
ContomRunable cr = new ContomRunable();
Thread td = new Thread(cr); // 获取线程对象
System.out.println(td.getPriority()); // 获取线程优先级
td.setPriority(Thread.MAX_PRIORITY); // 设置线程优先级
System.out.println(td.getPriority()); // 获取线程优先级
}
}
通过继承
Thread
类创建线程
示例一:
class ContomThead extends Thread{
public void run() {
System.out.println("start...");
}
}
public class TreadDemo {
public static void main(String[] args) {
ContomThead ct = new ContomThead();
ct.start();
}
}
示例二:
class ContomThead extends Thread {
public ContomThead(String threadName) {
super(threadName);
}
public void run() {
System.out.println("start...");
}
}
public class TreadDemo {
public static void main(String[] args) {
ContomThead ct = new ContomThead("线程一");
ct.start();
}
}
7.2 Runnable
接口
创建线程,通过实现
Runnable
接口
class ContomRunable implements Runnable{
@Override
public void run() {
System.out.println("start...");
}
}
public class RannbleTesk {
public static void main(String[] args) {
ContomRunable cr = new ContomRunable();
new Thread(cr).start();
}
}
7.3 线程同步
使用synchronized
关键字实现线程同步
方式一:同步方法,即
synchronized
关键字修饰的方法
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
public class Bank {
private int count =0;//账户余额
//存钱
public synchronized void addMoney(int money){
count +=money;
System.out.println(System.currentTimeMillis()+"存进:"+money);
}
//取钱
public synchronized void subMoney(int money){
if(count-money < 0){
System.out.println("余额不足");
return;
}
count -=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}
//查询
public void lookMoney(){
System.out.println("账户余额:"+count);
}
}
方式二:同步代码块
即有synchronized
关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用代码块同步关键代码即可
public class Bank {
private int count = 0;// 账户余额
// 存钱
public void addMoney(int money) {
synchronized (this) {
count += money;
}
System.out.println(System.currentTimeMillis() + "存进:" + money);
}
// 取钱
public void subMoney(int money) {
synchronized (this) {
if (count - money < 0) {
System.out.println("余额不足");
return;
}
count -= money;
}
System.out.println(+System.currentTimeMillis() + "取出:" + money);
}
// 查询
public void lookMoney() {
System.out.println("账户余额:" + count);
}
}
7.4 线程间通信
7.5 线程死锁
8. I/O 流
8.1 File
类
该类主要用于文件和目录的创建、文件的查找和文件的删除等,File
对象代表磁盘中实际存在的文件和目录
构造函数:创建FILE对象
一:通过将给定路径名字符串转换成抽象路径名来创建
File file = new File("E:\1.txt");
二:根据父路径名字符串和子路径名字符串创建
File file = new File("E:\","1.txt");
三:通过给定的父抽象路径名和子路径名字符串创建
File file1 = new File("E:\");
File file = new File(file1,"1.txt");
实例方法
方法名称 | 描述 |
---|---|
公共操作 | |
String getName() | 返回由此抽象路径名表示的文件或目录的名称 |
boolean exists() | 此抽象路径名表示的文件或目录是否存在 |
boolean delete() | 删除此抽象路径名表示的文件或目录(只能是空目录) |
String getParent() | 返回此抽象路径名的父路径名的路径名字符串,若无,则返回 null |
File getParentFile() | 返回此抽象路径名的父路径名的抽象路径名,若无,则返回 null |
String getPath() | 此抽象路径名转换为一个路径名字符串 |
boolean isAbsolute() | 此抽象路径名是否为绝对路径名 |
String getAbsolutePath() | 返回抽象路径名的绝对路径名字符串 |
目录操作 | |
boolean isDirectory() | 此抽象路径名表示的文件是否是一个目录 |
boolean mkdir() | 创建此抽象路径名指定的目录(单个目录) |
boolean mkdirs() | 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录(多级目录) |
String[] list() | 返回目录中的文件和目录的名称 |
File[] listFiles() | 返回目录中文件和目录的File类型实例 |
文件操作 | |
boolean isFile() | 此抽象路径名表示的文件是否是一个标准文件 |
boolean createNewFile() | 当文件不存在时创建文件,返回true,反之返回false |
boolean canRead() | 应用程序是否可以读取此抽象路径名表示的文件 |
boolean canWrite() | 应用程序是否可以修改此抽象路径名表示的文件 |
8.2 读写文件
输入流用于从源读取数据,输出流用于向目标写数据
8.3 字节输入流
创建输入流对象
使用字符串类型的文件名来创建一个输入流对象来读取文件:
InputStream f = new FileInputStream("C:/java/hello");
使用一个文件对象来创建一个输入流对象来读取文件:
File f = new File("C:/java/hello");
InputStream out = new FileInputStream(f);
实例方法
方法名称 | 描述 |
---|---|
void close() | 闭此文件输入流并释放与此流有关的所有系统资源 |
int read(int r) | 读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1 |
int read(byte[] r) | 读取r.length长度的字节。返回读取的字节数。如果是文件结尾则返回-1 |
8.4 字节输出流
创建输出流对象
如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件
使用字符串类型的文件名来创建:
OutputStream f = new FileOutputStream("C:/java/hello")
使用一个文件对象来创建:
File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f);
实例方法
方法名称 | 描述 |
---|---|
void close() | 关闭此文件输入流并释放与此流有关的所有系统资源 |
void write(int w) | 把指定的字节写到输出流中 |
void write(byte[] w) | 把指定数组中w.length长度的字节写到OutputStream中 |
8.5 字符输入流
创建写入对象
在给出 File 对象的情况下构造一个 FileWriter 对象:
File file = new File("E:\2.txt");
FileWriter fw = new FileWriter(file); // 写入对象,重置
FileWriter fw = new FileWriter(file,true); // 写入对象,追加
在给出文件名的情况下构造 FileWriter 对象:
FileWriter fw = new FileWriter("E:\2.txt"); // 写入对象,重置
FileWriter fw = new FileWriter("E:\2.txt",true); // 写入对象,追加
实例方法
方法名称 | 描述 |
---|---|
void write(int c) | 写入单个字符c |
void write(char [] c, int offset, int len) | 写入字符数组中开始为offset长度为len的某一部分 |
void write(String s, int offset, int len) | 写入字符串中开始为offset长度为len的某一部分 |
void flush() | 刷新流 |
void close() | 关闭流 |
8.6 字符输出流
创建读取对象
在给定从中读取数据的 File 的情况下创建:
File file = new File("E:\2.txt");
FileReader fr = new FileReader(file);
在给定从中读取数据的文件名的情况下创建:
FileReader fr = new FileReader("E:\2.txt");
实例方法
方法名称 | 描述 |
---|---|
int read() | 读取单个字符,返回一个int型变量代表读取到的字符 |
int read(char [] c, int offset, int len) | 读取字符到c数组,返回读取到字符的个数 |
void close() | 关闭流 |
9. 反/序列化
10. Java
反射
10.1 实现反射机制的类
Java
中反射机制的类都位于java.lang.reflect
包中:
-
Class
类:代表一个类 -
Constructor
类:代表类的构造方法 -
Method
类:代表类的方法 -
Field
类:代表类的成员变量(成员变量也称为类的属性)
10.2 Class
类型
Class是JVM中代表“类和接口“的类,包含了某个特定类的结构信息
方法列表
方法名称 | 描述 |
---|---|
Class.forName() | 静态方法,用户获取指定Class对象 |
ClassObj.newInstance() | 通过默认构造方法创建新的对象 |
ClassObj.getConstructor() | 获取指定的public修饰构造方法的Constructor对象 |
ClassObj.getMethod() | 获取指定的public修饰方法Method对象 |
ClassObj.getField() | 获取指定的public修饰成员变量Field对象 |
ClassObj.getDeclaredFields() | 获得类的所有属性(包括公共的,私有的) |
ClassObj.getFields() | 获得类的public 类型的属性 |
ClassObj.getDeclaredMethods() | 获得类的所有方法 |
ClassObj.getMethods() | 获得类的public类型的方法 |
ClassObj.getConstrutors() | 获得类的public类型的构造方法 |
获取
Class
对象的三种方式
通过Object
类型对象获取:
Object obj = new Customer();
Class cls = obj.getClass();
System.out.println(cls.getName());
通过对象的“静态”的class
属性:
Class cls = Customer.class;
System.out.println(cls.getName());
通过Class
类的静态方法:常用
Class cus = Class.forName("com.Customer");
System.out.println(cus.getName());
注意:在运行期间,一个类,只有一个Class
对象产生
10.3 Constructor
类型
方法列表
方法名称 | 描述 |
---|---|
con.newInstance() | 执行构造方法创建对象 |
con.setAccessible(true) | 暴力访问(忽略掉访问修饰符) |
获取构造方法
获取所有的构造方法:
Constructor[] conArray = ClassObj.getDeclaredConstructors();
获取所有公有构造方法:
Constructor[] conArray = ClassObj.getConstructors();
获取公有、无参的构造方法:
Constructor con = ClassObj.getConstructor(null);
获取共有,有参的构造方法:
Constructor con = ClassObj.getConstructor(new Class[]{String.class[,...]});
获取私有,无参的构造方法:
Constructor con = ClassObj.getDeclaredConstructor(null);
获取私有,有参的构造方法:
Constructor con = ClassObj.getDeclaredConstructor(new Class[]{String.class[,...]});
调用构造方法
调用共有,无参的构造方法:
con.newInstance(); / con.newInstance(null);
调用共有,有参的构造方法:值的顺序,类型与构造方法一致
con.newInstance(new Object[]{"李白",18[,...]});
调用私有,无参的构造方法:
con.setAccessible(true);
con.newInstance(); / con.newInstance(null);
调用私有,有参的构造方法:
con.setAccessible(true);
con.newInstance(new Object[]{"李白",18[,...]});
10.4 Method
类型
方法名称 | 描述 |
---|---|
method.setAccessible(true) | 暴力访问(忽略掉访问修饰符) |
获取方法
获取所有的成员方法,包括私有的(不包括继承的):
Method[] methodArray = ClassObj.getDeclaredMethods();
获取所有公共方法,包含了父类的方法也包含Object类:
Method[] methodArray = ClassObj.getMethods();
获取指定公共方法,包括私有的:
// 获取指定无参方法
Method method = ClassObj.getMethod("Show");
// 获取指定参数类型的方法
Method method = ClassObj.getMethod("Show", String.class);
获取指定公共方法:
// 获取指定无参方法
Method method = ClassObj.getMethod("Show");
// 获取指定参数类型的方法
Method method = ClassObj.getMethod("Show", String.class);
调用方法
Class ClassObj = Class.forName("com.Customer");
Object obj = ClassObj.getConstructor().newInstance();
调用公共,无参,无返回值方法:
Method method = ClassObj.getMethod("Show");
method.invoke(obj);
调用公共,有参,无返回值方法方法:
Method method = ClassObj.getMethod("Show",String.class);
method.invoke(obj,"李白");
调用公共,无参,有返回值方法方法:
Method method = ClassObj.getMethod("GetInt");
Object result = method.invoke(obj);
System.out.println((Integer)result);
调用私有,无参,无返回值方法:
Method method = ClassObj.getDeclaredMethod("Show");
method.setAccessible(true);
method.invoke(obj);
10.5 Field
类型
方法名称 | 描述 |
---|---|
field.setAccessible(true) | 暴力访问(忽略掉访问修饰符) |
获取字段
获取所有字段,包括:私有、受保护、默认、公有:
Field[] fields = ClassObj.getDeclaredFields();
获取公共字段:
Field[] fields = ClassObj.getFields();
获取某个字段,不限:私有、受保护、默认、公有:
Field field = ClassObj.getDeclaredField("id");
获取某个公共字段:
Field field = ClassObj.getField("id");
设置字段值
设置公共字段值:
Class ClassObj = Class.forName("com.Customer");
Field f = null;
try {
f = ClassObj.getField("name");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
Object obj = ClassObj.getConstructor().newInstance();
f.set(obj, "刘德华");
Customer customer = (Customer) obj;
System.out.println(customer.getName());
设置私有字段值:
Class ClassObj = Class.forName("com.Customer");
Field f = null;
try {
f = ClassObj.getDeclaredField("name");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
Object obj = ClassObj.getConstructor().newInstance();
f.setAccessible(true);
f.set(obj, "刘德华");
Customer customer = (Customer) obj;
System.out.println(customer.getName());
11. 函数式接口
11.1 常用函数
name | type | description |
---|---|---|
Consumer | Consumer |
接收T对象,不返回值 |
Predicate | Predicate |
接收T对象并返回boolean |
Function | Function<T,R> | 接收T对象,返回R对象 |
Supplier | Supplier |
提供T对象(例如工厂),不接收值 |
11.2 Predicate
package fun;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateSmp {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Filter(list, n -> n > 3);
}
public static void Filter(List<Integer> list, Predicate<Integer> predicate) {
for (Integer integer : list) {
if (predicate.test(integer))
System.out.println(integer);
}
}
}
12. Java
Stream
12.1 简单介绍
Stream
流式处理是建立在Lambda
基础上的多数据处理技术,可对集合进行迭代,去重,筛选,排序,聚合等
package fun;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class StreamSmp {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> num = list.stream()
.filter(x -> x % 2 == 0)
.sorted((a, b) -> b - a)
.findFirst();
System.out.println(num.get());
}
}
12.2 常用方法
方法名称 | 描述 |
---|---|
forEach | 循环遍历 |
map | 用于映射每个元素到对象的结果 |
filter | 用于通过设置的条件(Lambda 表达式)过滤元素 |
limit | 用于获取指定数量的流 |
sorted | 用于对流进行排序 |
distinct | 用于对于进行去重 |
Collectors | 将流转换为集合和聚合操作 |
示例一:mapToInt,filter,count
package fun;
import java.util.Arrays;
import java.util.List;
public class StreamSmp {
public static void main(String[] args) {
List<String> list = Arrays.asList("1", "2", "3", "4", "5");
long sum = list.stream()
.mapToInt(i -> Integer.parseInt(i))
.filter(i -> i > 3)
.count();
System.out.println(sum);
}
}
示例二:map,collect
package fun;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class PredicateSmp {
public static void main(String[] args) {
List<String> list = Arrays.asList("1", "2", "3", "4", "5");
List newlist = list.stream()
.map(i->i.toLowerCase(Locale.ROOT))
.collect(Collectors.toList());
System.out.println(newlist);
}
}
12.3 创建Stream流
基于数组创建
Integer[] list = {1,2,3};
Stream<Integer> stream = Stream.of(list);
stream.forEach(e-> System.out.println(e));
基于集合创建
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = list.stream();
stream.forEach(e-> System.out.println(e));