文章目录
基础类库
Random
-
创建伪随机数
-
伪随机数:给定一个初始的种子,产生的随机数序列是完全一样的
-
创建
Random
实例若不给定种子,使用系统当前时间戳作为种子- 每次运行时,种子不同,得到的伪随机数序列就不同
-
创建
Random
实例时指定一个种子,就会得到完全确定的随机数序列-
Random r = new Random(12345); for (int i = 0; i < 10; i++) { System.out.println(r.nextInt(100)); // 每次得到的序列完全一致 }
-
-
-
public int nextInt(int bound){}
- 随机生成不大于 bound 的随机正整数
- 范围:[0, bound)
/* 常用方法 */ Random r = new Random(); r.nextInt(); // 2071575453;每次都不一样 r.nextInt(10); // 5;生成一个[0, 10)之间的 int r.nextLong(); // 8811649292570369305;每次都不一样 r.nextFloat(); // 0.54335...;生成一个[0, 1)之间的 float r.nextDouble(); // 0.3716...;生成一个[0, 1)之间的 double
-
-
Math.random() 也可以生成随机数
- 范围 [0, 1);取不到 1
- 实际内部调用
Random
类- 所以也是伪随机数,但无法指定种子
- 返回指定范围 a ~ b 随机数公式
- (int)(a + Math.random()*(b - a + 1))
-
import java.util.Random; /** 生成随机数 */ public class Test{ public static void main(String[] args) { Random random = new Random(); int a = random.nextInt(100); // 数字在 0 ~ 100 之间,但取不到 100 System.out.println(a); } } 运行结果: 19 // 0 <= a < 100
SecureRandom
-
真随机数:创建安全的随机数的
-
真正的真随机数只能通过量子力学原理来获取
-
想要的是一个不可预测的安全的随机数
-
SecureRandom sr = new SecureRandom(); System.out.println(sr.nextInt(100));
-
-
SecureRandom
无法指定种子-
使用
RNG
(random number generator
)算法 -
JDK 的
SecureRandom
实际有多种不同的底层实现-
有的使用安全随机种子加上伪随机数算法来产生安全的随机数
-
有的使用真正的随机数生成器
-
实际使用优先获取高强度的安全随机数生成器,没有再使用普通等级的安全随机数生成器
-
public class Main { public static void main(String[] args) { SecureRandom sr = null; try { sr = SecureRandom.getInstanceStrong(); // 获取高强度安全随机数生成器 } catch (NoSuchAlgorithmException e) { sr = new SecureRandom(); // 获取普通的安全随机数生成器 } byte[] buffer = new byte[16]; sr.nextBytes(buffer); // 用安全随机数填充buffer System.out.println(Arrays.toString(buffer)); } }
-
-
-
SecureRandom
的安全性- 通过操作系统提供的安全的随机种子来生成随机数
- 种子是通过CPU的热噪声、读写磁盘的字节、网络流量等各种随机事件产生的熵
-
密码学中,安全的随机数非常重要
- 使用不安全的伪随机数,所有加密体系都将被攻破
- 必须使用
SecureRandom
来产生安全的随机数
-
需要使用安全随机数的时候,必须使用
SecureRandom
,绝不能使用Random
!
AutoCloseable
-
用于资源开发,实现资源自动关闭(释放资源)
-
实现该接口的类可以实现自动关闭资源
- 实现自动关闭功能还需要结合异常捕捉机制同时使用,没有对异常操作则无效
-
close()
方法在退出try-with-resources
块时自动调用- 该对象已在资源规范标头中声明了该对象
- 这种构造确保了及时释放,避免了资源耗尽异常和错误
-
即使不是所有的子类或实例都拥有可释放的资源,基类也有可能实现
AutoCloseable
- 对于必须完全通用运行的代码,或知道
AutoCloseable
实例需要释放资源时- 建议使用
try-with-resources
构造
- 建议使用
- 当使用
java.util.stream.Stream
等同时支持基于 I/O 和非基于 I/O 的形式时- 使用非 I/O 时通常不需要 try-with-resources 块
- 对于必须完全通用运行的代码,或知道
-
/** * 关闭此资源,放弃任何基础资源 * 此方法在由 try-with-resources 语句管理的对象上自动调用 * 接口方法被声明为抛出Exception ,强烈建议声明close方法的具体实现以抛出更具体的异常,或关闭操作不会失败,则根本不抛出异常 * 关闭操作可能失败的情况需要仔细注意。强烈建议在抛出异常之前放弃底层资源并在内部将资源标记为已关闭 * close方法不太可能被多次调用,因此可以确保及时释放资源。此外减少了资源包装或被另一个资源包装时可能出现的问题 * 强烈建议此接口的实现者不要使用close方法 throw InterruptedException * 此异常与线程的中断状态交互,如果InterruptedException被抑制,则很可能发生运行时错误行为 * 如果抑制异常会导致问题,则AutoCloseable.close方法不应抛出它 * 请注意,与java.io.Closeable的close方法不同,此close方法不需要是幂等的 * 多次调用此close方法可能会产生一些可见的副作用 * 与Closeable.close不同,如果多次调用则要求无效 * 但强烈建议此接口的实现者使他们的close方法具有幂等性 * * @throws Exception 如果无法关闭此资源 */ void close() throws Exception;
Runtime
-
操作系统涉及到 CPU管理、进程管理、内存管理等资源
JVM
进程实质上是对操作系统资源进行抢占- 通过操作系统提供的函数获取操作系统的资源信息
- 获取的资源信息存放在
Runtime
类 - 因此一个 JVM 进程只需要一个对象提供资源信息
-
表示运行状态
-
整个
JVM
中唯一与JVM
运行状态相关的类 -
默认提供一个
Runtime
类对象,由JVM
进行维护 -
在每一个JVM进程只允许提供一个
Runtime
类对象,所以该类构造方法默认私有化-
即
Runtime
类使用单例设计模式private static Runtime currentRuntime = new Runtime(); private Runtime() {} public static Runtime getRuntime() { return currentRuntime; }
-
通过类中的
availableProcessors()
方法可获取本机的 CPU 内核数public native int availableProcessors();
-
-
-
范例:获取
Runtime
类对象-
public class JavaAPIDemo { public static void main(String[] args) throws Exception { Runtime run = Runtime.getRuntime(); //获取实例化对象 System.out.println(run.availableProcessors()); //获取本机cpu内核数 } }
-
-
Runtime
类操作方法:-
public native long maxMemory();
- 获取最大可用内存空间
- 默认配置为本机系统的
4/1
-
public native long totalMemory();
-
获取可用内存空间
-
默认配置为本机系统的
64/1
-
public native long freeMemory();
- 获取空闲内存空间
-
public native void gc();
- 手动进行 GC 处理
- 虚拟机根据需要在单独的线程中自动执行此回收过程,即使没有显式调用 gc 方法
-
public void exit(int status)
- 终止当前正在运行的 Java 虚拟机;此方法永远不会正常返回
- 关闭顺序
- 所有注册的
shutdown hooks
(如果有)都以某种未指定的顺序启动,并允许同时运行直到它们完成 - 如果
finalization-on-exit
已启用,则所有未调用的终结器都会运行- 一旦完成,虚拟机就会
halts
- 一旦完成,虚拟机就会
- 所有注册的
- 虚拟机开始关闭序列后调用此方法,如果正在运行关闭挂钩,将无限期阻塞
- 如果已运行关闭挂钩并且已启用退出终止,会在状态非零时使用给定的状态代码暂停虚拟机;否则会无限期地阻塞
- 关闭顺序
status
:终止状态,通常非零状态码表示异常终止System.exit
方法实际调用此方法
- 终止当前正在运行的 Java 虚拟机;此方法永远不会正常返回
-
public void halt(int status)
- 强制终止当前运行的 Java 虚拟机;此方法永远不会正常返回
- 使用时应格外小心
- 与
exit
方法不同,如果finalization-on-exit
已启用- 此方法不会导致关闭挂钩启动并且不会运行未调用的终结器
- 如果已启动关闭序列,则此方法不会等待任何正在运行的关闭挂钩或终结器完成其工作
- 与
status
:终止状态,通常非零状态码表示异常终止- 如果已经调用
exit
方法,则此状态代码将覆盖传递给该方法的状态代码
- 如果已经调用
-
-
范例:观察内存状态
-
package demo03; public class Test { public static void main(String[] args) throws Exception { Runtime run = Runtime.getRuntime(); // 获取实例化对象 // 最大可用内存空间,默认配置为本机内存 1/4 System.out.println("【1】MAX_MEMORY:" + run.maxMemory()); // 可用内存空间,默认配置为本机 1/64 System.out.println("【1】TOTAL_MEMORY:" + run.totalMemory()); // 空闲内存空间 System.out.println("【1】FREE_MEMORY:" + run.freeMemory()); String str = ""; for (int x = 0; x < Integer.MAX_VALUE; x++) { str += x; // 产生大量的垃圾空间 } System.out.println("【2】MAX_MEMORY:" + run.maxMemory()); System.out.println("【2】TOTAL_MEMORY:" + run.totalMemory()); System.out.println("【2】FREE MEMORY;" + run.freeMemory()); run.gc(); // 手动GC处理 System.out.println("【3】MAX_MEMORY:" + run.maxMemory()); System.out.println("【3】TOTAL_MEMORY:" + run.totalMemory(); System.out.println("【3】FREE_MEMORY:" + run.freeMemory()); } }
-
GC
-
Garbage Collection:垃圾收集器
- 由系统自动调用的垃圾释放功能
- 使用
Runtime
类的gc()
手动调用public native void gc();
- 运行垃圾收集器
- 回收未使用的对象,使当前占用的内存可用于快速重用
- 方法调用返回时,虚拟机已尽最大努力回收所有丢弃的对象
System.gc()
方法实际调用此方法
System
-
System
类提供包括标准输入、标准输出和错误输出流- 访问外部定义的属性和环境变量
- 加载文件和库的方法
- 一种用于快速复制数组的一部分的实用方法
-
属性字段
-
private System() {} // 私有构造,不允许实例化 public final static InputStream in = null; // 标准输入流 public final static PrintStream out = null; // 标准输出流 public final static PrintStream err = null; // 错误输出流
-
-
常用方法
-
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
- 数组拷贝,可以拷贝各类型数组(Object)
- 指定源数组中的数组从指定位置开始复制到目标数组的指定位置。
- 从
src
引用的源数组 的srcPos
位置复制到dest
引用的目标数组destPos
位置
- 从
-
public static long currentTimeMillis()
- 获取当前数日期时间,返回从1970-1-01 00:00:00.000 至今毫秒数
- 一般用来进行操作耗时统计:结束、开始时间差
-
public static void gc()
- 垃圾回收,但并非重新定义的方法
- 而是调用了
Runtime
类中的gc()
操作- 等价于
Runtime getRuntim().gc();
- 等价于
-
public static void exit(int status)
、- 终止虚拟机
- 调用
Runtime
类exit
方法Runtime.getRuntime().exit(status);
-
public static Console console()
- 返回系统控制台(如果有),否则为 null
-
Cleaner
介绍
-
JDK1.9 之后提供的对象清理操作,对
fianlize()
方法替代C++
有两种特殊函数:构造函数、析构函数(对象手动回收)
-
Java 中垃圾空间由 GC 自动回收
-
基本不需要析构函数,因此没有提供此支持
-
但依然提供了给用户收尾的操作,在实例化对象回收前给予喘息机会
-
最初实现方法是
Object
类的finalize()
方法 -
finalize()
方法已不被建议使用- 最大特点是抛出
Throwable
异常 - JDK 1.9 开始,该方法不建议使用
- 最大特点是抛出
-
-
-
对象回收释放 JDK1.9 开始建议使用
AutoCloseable
- 或使用
java.lang.ref.Cleaner
类进行回收处理 Cleaner
也支持AutoCloseable
处理
- 或使用
finalize 和 Cleaner
finalize()
class Member {
public Member() {
System.out.println("【构造】");
}
@Override
protected void finalize() throws Throwable {
System.out.println("【回收】");
throw new Exception("抛出异常"); //即使抛出异常仍无效
}
}
public class Test {
public static void main(String[] args) throws Exception {
Member mem = new Member(); // 实例化
mem = null; // 指向空,成为垃圾
System.gc(); // 手动 gc
System.out.println("太阳照常升起,地球照样转动。");
}
}
/*
运行结果:
【构造】
太阳照常升起,地球照样转动。
【回收】
*/
Cleaner
-
新一代清除回收处理过程中,更多情况是考虑多线程使用
- 防止有可能造成的延迟处理,许多对象回收前的处理都是单独通过一个线程进行
import java.lang.ref.Cleaner;
class Member implements Runnable {
public Member() {
System.out.println("【构造】");
}
@Override
public void run() { // 执行清除的时候执行的是此操作
System.out.println("【回收】");
}
}
class MemberCleaning implements AutoCloseable { // 实现清除的处理
private static final Cleaner cleaner = Cleaner.create(); // 创建一个清除处理
/*
public static Cleaner create() { // create 方法实际实现
Cleaner cleaner = new Cleaner();
cleaner.impl.start(cleaner, null); // 通过 cleanerImpl 实现子类创建并启动线程
return cleaner;
}
*/
private Member member;
private Cleaner.Cleanable cleanable; //内部接口对象
public MemberCleaning() {
this.member = new Member(); // 创建新对象
this.cleanable = this.cleaner.register(this, this.member); // 注册使用的对象
}
@Override
public void close() throws Exception {
this.cleanable.clean(); // 注销可清理对象并调用清理操作。无论调用多少次,清洗操作最多被调用一次
// 即启动多线程操作,每个清除都在单独线程中执行
}
}
public class Test {
public static void main(String[] args) throws Exception {
try (MemberCleaning mc = new MemberCleaning()){
// 中间可以执行一些相关的代码
} catch(Exception ignored){/* 无需操作,自动关闭 */}
}
}
/*
运行结果:
【构造】
【回收】
*/
开发支持类库
UUID
生成无重复字符串的程序类
- 主要功能是根据时间戳实现自动的无重复字符串定义
- 并非完全不可能重复,几率非常小(几千万分之一)
- 一般获取
UUID
时往往获取随机生成的内容- 获取
UUID
对象public static UUID randomUUID()
- UUID 是使用加密强的伪随机数生成器生成的
UUID uid = UUID.randomUUID()
- 获取
- 根据字符串获取
UUID
内容public static UUID fromString(String name)
- 字符串长度不大于 36,否则抛出非法参数异常
- 对一些文件名自动命名处理的情况下,UUID类型非常好用
Optional
-
进行
null
的相关处理-
程序开发为防止空指向异常追加有
null
的验证 -
在引用接收的一端只能被动进行判断
- 即有可能接收 null 或其他任何可能传入的参数
-
Java 1.8 中提供了
Optional
类实现null
的处理
-
-
相关方法
-
返回 null 数据:
public static <T> Optional<T> empty()
-
获取数据:
public T get()
- 获取数据时引用对象不能为
null
- 获取数据时引用对象不能为
-
null
的时候返回其他数据:public T orElse(T other)
- 获取数据时若引用对象为
null
则获取other
自定义对象
- 获取数据时若引用对象为
-
保存数据但不允许为
null
:public static <T> Optional<T> of(T value)
- 若保存数据时存在
null
则抛出NullPointerException
异常
- 若保存数据时存在
-
保存数据允许为 null :
public static <T> Optional<T> ofNullable(T value)
-
-
所有引用数据类型操作处理中 null 都是很重要的问题
- JDK 1.8 之后提供的 Optional 类对 null 的处理很有帮助
定时调度
定时器主要操作是进行定时任务的处理
-
这种任务的处理只是实现一种间隔触发的操作,无法准时进行
-
JDK提供的最原始的操作,依靠系统时钟完成,实际开发若使用代码十分复杂
- 需要定时操作的 主体类 和 定时任务的控制
java.util.TimerTask
抽象类:实现定时任务处理- 实现了
Runnable
接口
- 实现了
java.util.Timer
类:进行任务的启动- 任务启动
schedule(TimerTask task, long delay)
- 延迟单位为 ms
- 间隔触发
scheduleAtFixedRate(TimerTask task, long delay, long period)
- task:要执行的任务
- delay:开始执行的时间
- period:执行的时间间隔
- 任务启动
- 需要定时操作的 主体类 和 定时任务的控制
-
import java.text.SimpleDateFormat; import java.util.Timer; import java.util.TimerTask; class MyTask extends TimerTask { // 任务主体 @Override public void run() { // 多线程的处理方法 System.out.println(Thread.currentThread().getName() + "当前时间: " + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(System.currentTimeMillis()));} } public class Test { public static void main(String[] args) throws Exception { Timer timer = new Timer(); timer.scheduleAtFixedRate(new MyTask(), 100, 1000); /* delay: 100 : 第一次执行的延迟 ,设为 0 则立即执行 period: 1000 : 每次执行的时间间隔, 设为 0 则报异常:IllegalArgumentException */ } }
Base64
-
加密 、解密
- 一般加密总伴随着解密,加密、解密都有一定的规则
-
JDK 1.8 开始提供
Base64
处理类-
有两个内部类进行加密、解密处理
-
Base64.Encoder
:进行加密才能处理public byte[] encode(byte[] src)
-
Base64.Decoder
:进行解密处理public byte[] decode(String src)
-
-
-
Base64
是公版加密操作,因此加密操作并不安全,可以使用盐值操作-
import java.util.Base64; public class Test { public static void main(String[] args){ String password = "废物"; // 要被加密的数据 String salt = "菜狗"; // 盐值干扰 // 使用Base64.Encoder 类进行加密;参数为字节数组,返回加密后的字节数组 // 被加密的数据由 源数据 和 盐值 共同组成 byte[] encode = Base64.getEncoder().encode((password + "{" + salt + "}").getBytes()); password = new String(encode); // 加密后的字符数组转为字符串 System.out.println(password); // 使用Base64.Decoder 类进行解密;传入字符串,返回解密后的字节数组 byte[] decode = Base64.getDecoder().decode(password); System.out.println(new String(decode)); } } 运行结果: 5bqf54mpe+iPnOeLl30= // 加密后的密码 废物{菜狗} // 解密后的密码
-
-
使用盐值加密效果仍不完善,可以使用多次加密
-
将盐值先加密,再放入数据进行加密
-
将数据加密一定次数,倒置后再进行加密
-
-
最好方法是使用多种加密程序,同时找到一些完全不可能解密的加密算法
-
使用这些方式进行加密则解密时同样需要自己编写方法
-
对加密过程反过来才可以实现解密
-
import java.util.Base64; /** * 使用工具类完成特定加密、解密方式 */ class BaseUtil{ private static final String SALT = "废物"; // 盐值;项目共享,不允许修改 private static final int count = 5; // 加密次数;加密解密时要保持一致,不允许修改 /** * 加密 * @param str 要加密的数据 * @return 返回加密后的数据 */ public static String encode(String str){ byte[] date = (str + "{" + SALT + "}").getBytes(); //盐值加密 for (int i = 0; i < count; i++) { date = Base64.getEncoder().encode(date); // 循环多次加密 } return new String(date); } /** * 解密 * @param str 要解密的数据 * @return 解密后的数据 */ public static String decode(String str){ byte[] date = str.getBytes(); for (int i = 0; i < count; i++) { date = Base64.getDecoder().decode(date); // 相同次数循环解密 } return new String(date).replaceAll("\\{.+\\}", ""); // 解密后去掉盐值 } } public class Test { public static void main(String[] args){ String password = BaseUtil.encode("菜狗"); System.out.println(password); //VkcxMGNtTnNiRFpXVkVKclZtMW9jMU42Um1wTmJVcHdaRWQ0VkdKcldscFVWVkYzVUZFOVBRPT0= System.out.println(BaseUtil.decode(password)); // 菜狗 } }
-