javaSE
1. JAVA简述
Java平台由Java虚拟机(Java Virtual Machine)和Java 应用编程接口(Application Programming Interface、简称API)构成。Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。Java应用编程接口已经从1.1x版发展到1.2版。常用的Java平台基于Java1.8。
JRE:只需要运行JAVA程序
JDK:用于开发,我用的版本:JDK8
SE主要用于桌面开发,其中一部分核心的是EE也要学的共同
的基础部分,所以我们叫SE为基础版,是企业级开发的基础
JAVA语言的特性:跨平台性
JDK8安装
oracle下载jdk8u311
下一步下一步安装即可(路径不要有中文)
安装完成后只有进入到这个文件夹才能执行javac.exe等,所以要配置环境变量(在任何目录都可以执行)
配置环境变量
新建一个JAVA_HOME变量,值是bin所在文件夹
在path里建一个bin里文件的路径
可以下载多个版本jdk,环境变量配置谁就用哪个版本的jdk
2. Windows常用cmd命令
cmd打开命令行窗口
d:,回车进入d盘(可以不加cd )
dir 显示当前
md 创建文件目录
1
2echo str>1.txt
创建文件1.txt 并将str写入该文件cd filename 进入目录
cd.. 返回上一级目录
cd filename 返回指定目录
cd\ 返回到根目录
del 1.txt 删除1.txt这个文件
del *.txt 删除所有txt后缀的文件
del 文件目录名字(删除该目录下所有文件,目录不删)
rd 文件目录名 (删除目录,目录需为空才能删除)
执行完上一条命令后,按↑即可快速再次执行该命令
3. HelloWorld
- 新建一个.java文件(用记事本打开)
- java代码编写.java文件;javac命令编译java文件成为字节码.class文件;java命令运行字节码文件
文档注释
1
2
3
4
5
6
7
8/**
bbbbb
*/
/**
解释说明此function
*/
funion
注释内容可以被JDK提供的工具javadoc解析,生成一套网页文件的说明文档1
2javadoc -d 文件名 -author -version filename.java
//完成后可以在文件名的文件夹中找到index.html文档
4. JAVA基本语法
4.1 关键字和保留字
保留字:go to const,以后可能会用,但现在不用。不要用作标识符
4.2 标识符
命名规则:
- 由26个英文字母大小写,0-9,_或$组成
- 数字不可以开头
- 不能使用关键字和保留字,但能包含关键字和保留字
- 不能包含空格
- Java中严格区分大小写,长度无限制
命名规范:
- 包名:多单词组成时所有字母都小写xxxyyyzzz
- 类名,接口名:多单词组成时,所有单词首字母大写XxxYyyZzz
- 变量名,方法名:第一个单词字母小写,第二个开始首字母大写xxxYyyZzz
- 常量名:所有字母都大写,多单词用下划线连接XXX_YYY_ZZZ
4.3 数据类型和运算符
4.3.1 整型
1 | class VariableTest |
java默认整型常量为int,声明long型常量须后加‘l’或者‘L’
byte:1字节
short:2字节
int:4字节
long:8字节
Byte或者B是字节,bit是二进制位
4.3.2 浮点型
1 | float f1 = 12.3f; |
4.3.3 字符类型
1 | //char 字符 = 两个字节2byte = 16bit |
1 | "\n" 转义换行 |
4.3.4 基本数据类型运算的规则
- 自动类型提升
1 | byte b1 = 2; |
byte char short–>int–>long–>float–>double
前三者运算应用int型接收,即使是byte+byte
整型常量默认为int,浮点类型默认为float
1 | short s1 = 10; |
类似 += *= 这种是不会改变变量类型的(推荐使用)
- 强制类型转换
1 | double d1 = 12.9; |
//除法运算 int num1 = 12; int num2 = 5; int result = num1/num2//result = 2 double result1 = num1/num2//result1 = 2.0 double result2 = num1 / (num2 + 0.0)//result2 = 2.4 double result3 = (double)num1 / num2;//result3 = 2.4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 逻辑运算符
![image-20230707134724813](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307071347919.png)
短路与的判断方式是:
从左到右依次判断,直到出现false为止将不再判断,直接得到结果为false(短路遇false就停)
逻辑或和短路或的区别 逻辑或的判断方式是:
从左到右依次判断,直到结尾
### 4.3.5 String
~~~java
class StringTest{
public static void main(String[] args){
String s1 = "Hello World";
String s2 = "";//空串
int number = 1001;
String s3 = s1 + number;//字符串和其他类型的+均为连接,结果任然是字符串
System.out.printl(s1);
}
}
两种创建String的方法
//一是new型:String s = new String("abc");
//另一种是双引号型:String s = "abc";(相同内容的会共享内存空间)
1 | //String的常见操作 |
4.3.6 进制
1 | int num1 = 0b110;//二进制 |
正数三码合一
负数
补码再求一个补码就得到源码
计算机底层都以补码的形式存储数据,运算的时候,都是以补码进行运算的。
4.3.7 位运算符
位运算符操作的都是整型的数据
在一定范围内:<< 每向左移一位,相当于*2,>>每向右移一位,相当于/2
左移a
右移
无符号右移
4.3.8 三元运算符
1 | (m > n)?m : n //真执行m,假执行n |
4.4 程序流程控制
4.4.1 if-else
1 | if() |
4.4.2 switch-case
1 | //表达式只能是6种类型之一:byte short char int String 枚举 |
break在switch中是可选的,第一次根据case进来,一直往下执行,直到遇到break或者末尾才跳出switch语句结构
4.4.3 循环
1 | //break;跳出循环结构 |
带标签的循环
1 | label:for(int i=1;i<=4;++i) |
foreach循环(增强for循环)内部是迭代器实现只能用于遍历集合或者数组
1 | int[] arr = new int[]{1,2,3,4} |
5. 数组
5.1 数组的初始化
1 | //静态初始化 |
5.2 元素索引
1 | //索引角标从0开始,到-1结束 |
5.3 获取数组长度
1 | //数组有一个length的属性 |
5.4 数组内存解析
new的东西都在堆区,数组名是在栈区,指向了堆区的地址。当堆区的东西没有索引指向它的时候,内存就会被释放掉。
5.5 多维数组
1 | int[][] arr = new int[4][];//动态初始化二维数组,且每行长度是不固定 |
5.6 Arrays工具类
1 | Arrays.fill()//填值 |
1 | int[] arr = new int[]{1, 2, 3}; |
6. 面向对象
6.1 内存分配
6.2 类成员
成员变量:类{}里面的,可以先不赋初值。
局部变量:函数方法里面的,必须有初值。
6.3 匿名对象
1 | new phone().sendEmail();//创建一个对象,但没有显示的赋给一个对象名,调用完方法就无法使用了。 |
6.4 方法
6.4.1 方法的重载
重载:一些重名的方法
同一个类,相同的方法名;
参数列表不同,参数个数不同,参数类型不同;
6.4.2 可变个数的形参
1 | public void show(int num,String...strs){//传入任意个数的String类型参数(可以为0个),可变类型形参只能有一个,且只能在参数列表末尾。 |
6.5 变量赋值
基本数据类型:值传递
引用数据类型:地址传递
6.6 封装性
类属性私有化(private),提供公共的属性(public)来获取或者设置该属性。
类只能用缺省和public修饰
6.7 构造器
一个类中多个构造器构成重载;
构造方法没有返回类型,但是有返回值,返回的就是一个对象,可以有访问权限修饰符,但是不能有static final之类的修饰符
- 空参构造器
- 子类继承时,默认调用super()空参
- 便于反射时创建运行时类对象
6.8 UML类图
6.9 this
this即是当前对象,可以调用当前类的属性和方法。
6.10 package和import
package
import
6.11 继承
- extends
- 一个类可以被多个类继承,一个类只能有一个父类(单继承性)
- 光标放到类名,CTRL+T 可以看到继承结构
1 | class A extends B{ |
6.11.1 方法的重写
子类继承父类,对同名同参的方法,进行覆盖操作;
不能重写父类的private方法
1 | //表明以下方法是重写 |
6.11.2 super
显式的调用父类的方法
super.属性
super.方法
1 | //在构造器中,以下两种只能二选一(因为他们都必须在构造器的首行) |
6.12 多态
对象的多态性
1
2
3
4
5
6
7
8
9
10
11//父类的引用指向子类的对象
Person p = new Man();
//也叫虚拟方法调用
p.method();//调用的是子类的方法(有重写的情况下)
p.参数;//只能调用Person类的属性
//虽然参数类型是Person,但可以传入其子类对象Man,调用的当然也是子类的方法,
public void func(Person p){
p.method();
}- 多态和重载的区别
多态是运行时行为
instanceof
1
2
3a instanceof A//判断实列对象a是否是类A的一个实列,是返回true,不是返回false
A可以是父类,也可以是间接父类,都会返回true
6.13 Object类
6.13.1 equal和==
比如说比较String,就要用equals(),==比较的是地址,不同的String肯定不会相等,而equals是重写过的,比较的是字符串的每一个字符是否都相等。
6.13.2 toString()
1 | System.out.println(object); |
执行过程中调用对象内部的toString方法
6.14 单元测试
就相当于写了一个Public void无参函数,可以单独执行这个函数,从而测试这个函数体类的相关代码。
6.15 包装类(Wrapper)
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
基本数据类型、包装类、和string之间的转换
新特性,自动装箱与自动拆箱(只适用于基本数据类型和包装类)
6.16 static
1 | //静态变量(也叫类变量)随着类的加载而加载 |
6.17 代码块
1 | class mmm{ |
- 静态代码块
内部可以有输出语句
随着类的加载而执行,而且只执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
- 非静态代码块
内部可以有输出语句
随着对象的创建而执行
每创建一个对象,就执行一次非静态代码块
作用:可以在创建对象时,对对象的属性等选行初始化
如果一个类中定义了多个非静态代码块,则按昭声明的先后顺序执行
非楼态代码块內可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
要理解清楚静态的只有类,还没有对象
6.18 final
- final可以用来修饰的结构:类、方法、变量
- final 用来修饰一个类:此类不能被其他类所继承
比如: String、System类、StringBuffer类 - final 用来修饰方法,表明此方法不可以被重写
比如Object类中getClass() - final 用来修饰变量,此时的“变量“就称为是一个常量
- final修饰属性,可以考虑赋值的位置有,显式初始化、代码块中初始化、构造器中初始化
- final修饰局部变量
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋值一个实参,就只能在方法体内使用此形参,但不能对其重新赋值
6.19 匿名类
1 | abstract class Person{ |
6.20 抽象类
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能共享特征。有时将一个父类设计得非常抽象,以至手它没有具体的实例,这样的类叫做抽象类。
1 | abstract class name{ |
abstract只能修饰类和方法
- abstract修饰类:抽象类
此类不能实例化
抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
- abstract俊饰方法:抽象方法
抽象方法只有方法的声明,没有方法体
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则子类也是一个抽象类,需要使用abstract修饰
6.21 接口
接口使用interface来定义
java中,接口和类是并列的两个结构
如何定义接口:定义接口中的成员
- JDK7及以前:只能定义全局常量和抽象方法
- 全局常量:
public static final
修饰的。但是书写时,可以省略不写 - 抽象方法:
public abstract
修饰
- 全局常量:
- JDK7及以前:只能定义全局常量和抽象方法
JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
接口中不能定义构造器的!意味着接口不可以实例化
java开发中,接口通过让类去实现(implements)的方式来使用,如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化,如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
java类可以实現多个接口 —>弥补了java单继承性的局限性
class AA extends BB implements CC, DD,EE
接口与接口之间可以继承,而且可以多继承,接口的县体使用,体现多态性
JDK8新特性:除了定义全局常量和抽象方法外,还可以定义静态方法和默认方法
- 接口中定义的静态方法,只能通过接口名来调用,其实现类的对象不能调用
- 而实现类的对象可以调用接口中的默认方法
1 | public interface ClothFactory { |
6.22 内部类
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
内部类的分类,成员内部类(静忘,非静态) VS 局部内部类(方法内,代码块内、构造器内)
- 成员内部类(作为类的属性成员)
- 局部内部类(方法内或者代码块内)
1 | public class Test { |
7. 设计模式
7.1 单例设计模式
1 | //饿汉式 |
饿汉式:1. 对象加载时间过长
2. 线程安全的
懒汉式:1. 延迟对象的创建
2.可能存在线程不安全的情况
7.2 模板方法的设计模式
抽象类的应用:模板方法的设计模式
1 | abstract class BankTemplateMethod{ |
7.3 代理模式
接口的应用:代理模式
1 | //实现网络访问的接口 |
- 静态代理
1 | public class StaticProxyTest { |
7.4 工厂模式
7.4.1 简单工厂
- 设计
- 使用
7.4.2 工厂方法
7.4.3 抽象工厂
8. 异常处理
8.1 概述
Throwable异常分类:
Exception:编译时异常&&运行时异常(RuntimeException)
8.2 异常处理机制
- try-catch-finally 注意:try-catch-finally 以下的代码会照样执行而try中发生异常之后的代码不执行
1 | try{ |
1 | e.getMessage();//返回一个错误信息的字符串 |
- throws
1 | //该方法可能会抛两个异常 |
子类重写父类方法时,抛出的异常应该比父类的异常同级或者是其子类,这样在某些多态条件下才能catch住这个给异常
8.3 生成异常
1 | //生成一个异常,同样可以用catch和throw方式进行处理 |
8.4 自定义异常类
一般继承两个异常 Exception(编译时就要考虑的异常)和RuntimeException(运行时异常)
9. 多线程
1 | Java.lang.Thread //多线程类 |
9.1 多线程的创建
- Tread类方法
设置优先级
1
myThread.setPriority(Thread.MAX_PRIORITY)
线程创建方法一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35public class MyThread extends Thread {
public MyThread(){}
//带参构造器,可以设置线程名字
public MyThread(String name){
super(name);
}
//run()里写的是我们这个线程需要执行的语句
public void run() {
super.run();
for (int i = 0; i < 100; i++) {
System.out.println(i);
if(i%20==0){
Thread.yield();//释放当前进程的执行权(当然下一刻又可能重新分配给他)
try {
sleep(1000);//当前进程阻塞1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class Start {
//主线程
public static void main(String[] args) {
MyThread myThread = new MyThread(); myThread.setPriority(Thread.MAX_PRIORITY);//线程开始之前可以设置优先级
myThread.start();//启动myThread线程;并调用当前线程的run方法;一个线程只能start一次
myThread.run();//不是多线程,只是执行这个方法
//如果这里再写其他输出语句,此时是主线程,就会和上面的myThread交替输出(并行)
}
}创建线程方法二:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public class ImplementRunnable {
public static void main(String[] args) {
//多个线程可以共用这个对象,适合多个线程有共享数据的情况
ImThread imThread = new ImThread();
Thread thread_1 = new Thread(imThread);
thread_1.setName("thread_1");
thread_1.start();
Thread thread_2 = new Thread(imThread);
thread_2.setName("thread_2");
thread_2.start();
}
}
class ImThread implements Runnable {
//一般来说只造一个对象,所以声明一个private类型的属性就行
private int data;//共享数据
public void run() {
for (int i = 0; i < 100; i++) {
//方便查看线程交错执行的情况,每次该线程阻塞100ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 输出 " + i);
}
}
}两者不同:
创建线程方法三:==可以抛异常,且有返回值,支持泛型==
实现Callable接口
创建线程方法四:线程池
9.2 生命周期
9.3 线程同步
方法一:同步代码块
继承Thread类的实现中,同步监视器可用 ==类名.class==
实现Runnable接口,同步监视器可用==this== 因为一般只new一个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class ImThread implements Runnable {
private int ticket = 100;
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "卖票 票号为: " + ticket);
ticket--;
} else {
break;
}
}
}
}
}方法二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,不妨将此方法声明为同步方法
==注意:==run()方法不能用synchronized修饰
实现runnable的使用,用同步方法
1
2
3
4//把操作临界区的方法设置为synchronized的,监视器默认为this(所以对于实现Thread的方式来说是不安全的,他一般会造几个对象,this就不唯一了)
public void synchronized fun(){
}实现Thread的方式
1
2
3
4//方法设置为静态,监视器为当前类(类名.class)
public static void synchronized fun(){
}
方法三:同步锁
JDK5.0开始,更强大的线程同步机制
1
2
3
4
5
6
7
8
9ReentrantLock lock = new ReentrantLock();
try{
lock.lock();
/**
临界区
*/
}finally{
lock.unlock();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Window implements Runnable {
private int ticket = 100;
//设置一个同步锁,true表示先来的进程会优先得到临界资源
private ReentrantLock lock = new ReentrantLock(true);
public void run() {
while (true) {
//临界代码用try/finally包围
try {
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "买票,票号为: " + ticket);
ticket--;
} else {
break;
}
} finally {
lock.unlock();
}
}
}
}
例题 一个账户两个储户:两个储户分别向这个账户存3000,每次存1000,存3次。
1 | public class Test { |
9.4 死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
9.5 线程通信
1 | wait();//执行该代码的线程进入阻塞状态 并释放锁 |
==只能用在同步代码块和同步方法(lock不能用这个进行通信),因为这三个方法的调用对象只能是同步监视器对象,lock没有同步监视器==
1 | class ImRunnable implements Runnable { |
10. String类
10.0 编码
最早的美国ASCII编码一个字节就能表示数字,字母等。首位没用,就用了后7位来表示
后来计算机技术传入其它国家,有新的编码方式GBK等;它是向下兼容的
仍用一个字节表示原来的ASCII字符,其它的如,汉字就用两个字节表示,字节首个二进制0代表一个字节表示,1代表2个字节表示
ANSI:平台默认编码。英文操作系统中是ISO-8859-1,中文系统是GBK
Unicode只是定义了一个庞大的,全球通用的字符集,并为每个字符确定了唯一确定的编号,具体存为什么样的字符流,取决于字符编码方案,推荐的Unicode编码为UTF-8,UTF-16(即每次传输8,16个二进制位)
如上图,同样用首位来确定几位编码,汉字用了3个字节
10.1 String
字符串的不可变性
1 | //字面量的定义方式,此时字符串值声明在字符串常量池中 |
1 | //字符串转换为字符数组 |
10.2 StringBuffer
默认容量是初始容量+16,超过之后会在底层重新new一个字符数组
1 | //指定容量的buffer |
10.3 StringBuilder
同StringBuffer,效率更高,但不是线程安全的;
10.4 Java比较器
- comparable
1 | compareable接口; |
- comparator
1 | //定制排序 |
10.4 正则表达式
- 主要类及其使用方法
1 | String s = "砸金花1998和时间256莎莎看哈萨克156874啥叫和."; |
1 | //调用Pattern类的静态方法判断字符串s是否整体匹配成功 |
正则转义符
1
String reg = "\\.";//匹配一个字符'.' ,两个\\表示转义
字符匹配(大写表示取反)
👆都是要加[]的
\\s匹配任何空白字符(空格,制表符)
\\S匹配任何非空白字符
大小写问题
1
2
3
4
5
6(?i)abc //abc不区分大小写
a(?i)bc //bc不区分大小写
a((?i)b)c //b不区分大小写
//创建模式时参数Pattern.CASE_INSENSITIVE不区分大小写
Pattern pattern = Pattern.compile(reg,Pattern.CASE_INSENSITIVE);选择匹配符
限定符
1
String regStr = "a{2,3}" //表示匹配aa 或者aaa 贪婪匹配,优先匹配多的即aaa
定位符
指定在原字符串的那个位置进行匹配
分组
1
2String reg = "(\\d\\d)(\\d\\d)"; //分组0,1,2
String reg = "(?<g1>\\d\\d)(?<g2>\\d\\d)"; //分组命名非捕获分组
就是加了括号,但表示的不是分组,不能用group(1)这样去获取
非贪婪匹配
默认贪婪匹配。后面加个?表示非贪婪匹配,即尽量匹配少的
反向引用
内部反向引用:正则表达式内使用的。
例:
1
2
3
4
5
6
7
8
9
10
11//反向引用案例:结巴去重
String s = "我我我...要要..学学学....java";
//反向引用,能匹配到 我我我 ... 要要 .. 学学学 ....
String reg = "(.)\\1+";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(s);
//在外面把匹配到的替换成 反向引用的那个(外部反向引用)
String s1 = matcher.replaceAll("$1");
//去除.
System.out.println(s1.replaceAll("\\.", ""));
11. 枚举类
1 | //自定义枚举类 |
12 注解
Annotation
框架 = 注解 + 反射+ 设计模式
- JDK内置的三个注解
1 |
|
自定义注解
框架的时候再学(根据反射来实现对应注解的功能)
1
2
3public 注解名{
//定义内容
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public class AnnotationTest {
//注解可以显示赋值,如果没有默认值,则必须赋值
public void test1(){
}
//只有一个参数可以省略参数名
public void test2(){
}
//没有参数
public void test3(){
}
}
MyAnnotation1{
//注解的参数:参数类型+参数名+()
String name() default "";
int age();
int id() default -1;//-1代表不存在
String[] schools() default {"武汉理工大学","南京师范大学"};
}
MyAnnotation2{
String value();//只有一个参数名字约定用value
}元注解
即修饰注解的注解
1
2
3用于描述注解的使用范围,修饰的是类,方法,还是其它;
用于描述注解的生命周期,即什么时候有效;
SOURCE<CLASS<RUNTIME 源代码时<编译成类时<运行时
13. 集合
无论是Collection还是Map的对象一定要重写equals()方法 {无论是否可重复,删除的时候一定会调用equals方法}
//向上转型,Collection list只能使用自己的方法,不能使用ArrayList的方法 Collection list = new ArrayList();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- ![image-20220509103112231](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307101725981.png)
## 13.1 Collection
![Collection](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307101724602.png)
~~~java
//Collection常用方法
Collection list = new ArrayList();
++++++++++++++++++++
list.add(Object);//添加元素
//判断是否包含元素 contains调用的是equal方法
boolean contains = list.contains(1);//True
list.containsAll(list1);//判断list1中的所有元素是不是都被包含
list.remove(1);//移除
list.removeAll(list1);//移除所有元素
list.retainAll(list1);//返回两个集合交集中的部分
Object[] arr = list.toArray();//集合转换为数组集合的遍历
1 | //集合的遍历 |
13.1.1 List
有序,支持索引
List方法(有序,可重复)
1
2
3
4//arr类型不能为基本数据类型
//数组转List集合(这样构建的list是定长的)
Arrays.asList(Integer[] arr)
Arrays.asList(1,2,3)
13.1.1.1 ArrayList
线程不安全,效率高
扩容机制
ArraysList底层是数组实现的。jdk7 new ArrayList()底层创建了长度是10的数组,jdk8初始化长度为0,首次add时才创建了长度为10的数组。容量不够时都是扩容为原来的1.5倍。
1
2//指定初始数组的容量,避免频繁扩容
ArrayList new ArrayList(int capacity);可以使用Collections工具类转变为线程安全的
13.1.1.2 LinkList
底层使用双向链表进行存储
实现了Queue接口
13.1.1.3 Vector
线程安全
Vector();底层创建长度为10的数组,默认扩容为原来数组长度的两倍
一般用ArrayList代替了
13.1.2 Set
重写equals()和hashCode()
无序性体现在底层是按hash值存储,所以无序
要重写hashCode用它自动生成那个就行,就保证了一致性
操作就是Collection的操作
13.1.2.1 HashSet
13.1.2.2 LinkHashSet
13.1.2.3 TreeSet
重写比较器
会把添加的元素按大小排列
1 | TreeSet set = new TreeSet(com);//TreeSet传入我们定制的比较器com |
13.1.3 Queue
13.1.3.1Queue
只能在队头进行操作,队尾进队
1 | Queue<Integer> q1 = new LinkedList<>(); |
可以存入null元素
13.1.3.2 Deque
1 | Deque<Integer> q3 = new LinkedList<>(); |
双端队列,在两头进行操作,尽量不要添加null元素
可以当作堆栈来使用,不用stack了
13.1.3.2 PriorityQueue
1 | PriorityQueue<Integer> q2 = new PriorityQueue<>(Comparator); |
优先级队列种的元素根据自然顺序进行排序,或者通过在队列构建时提供的Comparator进行排序,当然这取决于使用哪种构造函数。优先级队列不允许空(null)元素
PriorityQueue是一个无界优先级队列是基于优先级堆的
优先级队列的队头元素是最小的元素,如果有多个元素并列最小,那么队头是它们其中之一
13.1.3.3 BlockingQueue
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:
- 在队列为空时,获取元素的线程会等待队列变为非空。
- 当队列满时,存储元素的线程会等待队列可用。
13.2 Map
1 | //返回的泛型是一个map的Entry,这个Entry也是泛型 |
13.2.1 HashMap
- linkhashmap
HashMap和双向链表合二为一即是LinkedHashMap。所谓LinkedHashMap,其落脚点在HashMap,因此更准确地说,它是一个将所有Entry节点链入一个双向链表的HashMap。由于LinkedHashMap是HashMap的子类,所以LinkedHashMap自然会拥有HashMap的所有特性。比如,LinkedHashMap的元素存取过程基本与HashMap基本类似,只是在细节实现上稍有不同。当然,这是由LinkedHashMap本身的特性所决定的,因为它额外维护了一个双向链表用于保持迭代顺序。此外,LinkedHashMap可以很好的支持LRU算法。
13.2.2 TreeMap
- 按照key进行排序,所以key必须是同一类型的对象
//返回大于等于指定key的key或Entry Integer key = map.ceilingKey(2); Map.Entry<Integer, String> entry = map.ceilingEntry(2); //返回小于等于指定key的key或Entry Integer key1 = map.floorKey(5); Map.Entry<Integer, String> entry1 = map.floorEntry(5); //返回逆序的set或map NavigableSet<Integer> set = map.descendingKeySet(); NavigableMap<Integer, String> map1 = map.descendingMap(); //返回集合中含有最小的Key的元素或Entry,最大是last Integer key2 = map.firstKey(); Map.Entry<Integer, String> entry2 = map.firstEntry();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
### 13.2.3 HashTable
和HashMap差不多,一般不用。线程安全,效率低
properties:常用来处理配置文件
![image-20220812144917531](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307102309084.png) 配置文件
![image-20220812145013415](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307102309843.png)
~~~Java
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("./src/properties.properties");
properties.load(fileInputStream);
String user = properties.getProperty("user");
String mm = properties.getProperty("密码");
System.out.println(user);
System.out.println(mm);
}
13.3 Collections工具类
用来操作List Set Map
13.4 相互转换
数组转集合
- 遍历数组,将元素保存到集合中
1
2
3
4
5
6int[] arr = {1,2,3};
List<Integer> list = new ArrayList<Integer>();
for(int n:arr){
list.add(n);
}
System.out.println(list);使用asList()方法
注意:1)如果传入的参数是一个数组,那么这个数组一定要是引用类型才能将其转换为List集合,当传入基本数据类型数组时则会将这个数组对象当成一个引用类型对象存进List集合。
1
2
3Integer[] arr = {1,2,3};
List list = Arrays.asList(arr);
System.out.println(list); 注意:2)使用这种转换的方法,直接添加元素会报错,需要重新new一个list
1
2
3
4
5
6
7Integer[] arr = {1,2,3};
List<Integer> list = Arrays.asList(arr);
//使用这种转换的方法,直接添加元素会报错,需要重新new一个list
list.add(4);
ArrayList<Integer> list1 = new ArrayList<>(list);
list1.add(4);
list1.forEach(System.out::println);- 采用流的方式
1
2
3int[] arr = {1,2,3};
List<Integer> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
System.out.println(list);集合转数组
- 传入一个类型和大小完全相同的数组进行转换
1
2
3
4
5
6
7
8
9List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(30);
Integer[] arr = new Integer[list.size()];
list.toArray(arr);
for(int i:arr){
System.out.println(i);
}
14. 泛型
https://blog.csdn.net/weixin_45395059/article/details/126006369
静态方法不能用泛型
异常类不能用泛型
//T[] arr = new T[10];编译是不通过的 T[] arr =(T[]) new Object[10];
1
2
3
4
5
6
7
![image-20220513152638559](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307111249521.png)
~~~java
Collection<String> list = new ArrayList<String>();//java8后面的<String可以省略>
14.1 自定义泛型结构
- 泛型类
1 | class A<T>{ |
泛型方法
不仅类可以声明泛型,类中的方法也可以声明仅用于自身的泛型,这种方法叫做泛型方法
泛型方法可以声明为静态的
1 | class A<T> |
14.2 通配符
?
1 | public static void main(String[] args) { |
有限制条件的通配符
1 | <? extends P>//?是P类及其子类 上界通配符 |
15.网络编程
1. IP地址
- 本地回环地址
“本地回环地址127.0.0.1,通常被称为本地回环地址(Loopback Address),不属于任何一个有类别地址类。它代表设备的本地虚拟接口,所以默认被看作是永远不会宕掉的接口。”
1 | //获取本地IP地址对象 |
1 | //通过域名或者IP获取一个Ip地址的对象 |
2. 端口号
3. TCP
TCP或UDP的网络编程都叫socket编程
客户端向服务器端发送文件
流程
1.打开服务器端,会阻塞在read方法里(read()和readLine()都会读取对端发送过来的数据,如果无数据可读,就会阻塞直到有数据可读。或者到达流的末尾,这个时候分别返回-1和null。)
2.打开客户端,把文件写道socket里去,写完往下执行流会关闭
3.那么服务端的read操作也会完成
1 |
|
客户端服务端进行交互
1.打开服务端,一直read等待数据
2.写数据,写完关闭 socket.shutdownOutput();对面read就会停止
3.此时客户端阻塞在read,服务端就行写数据,写完向下执行流关闭
4.客户端read就会停止,向下执行,关闭流
1 |
|
4. UDP
代码略,这里稍微理解就行。
package(数据包(报))的形式发送,不用建立连接,不确保接收,速度更快。
5. URL编程
统一资源定位符
1 | URL url = new URL("url"); |
16. 反射
1. 概述
反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能操作任何对象的内部属性及方法
反射被视为动态语言的关键
2. Class
获取Class实例的方法(获取运行时类)
Class<Person> clazz = Person.class;
1
2
3
4
- ~~~Java
Person person = new Person();
Class<? extends Person> aClass = person.getClass();//注意要写全类名 Class<?> aClass1 = Class.forName("com.atzrh.java.Person");
clazz == aClass == aClass1 == aClass21
2
3
4
- ~~~Java
ClassLoader classLoader = 类名.class.getClassLoader();
Class<?> aClass2 = classLoader.loadClass("com.atzrh.java.Person");
哪些类型可以有class对象:
3. 类加载器
Class Loader
加载配置文件时通过类加载器获取输入流
1 | public static void main(String[] args) throws Exception { |
4. 创建运行时类对象
1 | //获取Class实例 |
5. 获取运行时类内部结构
- 获取类的属性,以及属性的权限修饰符、类型、变量名
- 获取类的方法,以及方法的权限修饰符、注解、返回值类型、方法名(参数信息)、异常
- 获取运行时类的构造器
- 获取运行时类的父类
- 获取运行时类实现的接口、所在包、注解
6. 调用运行时类的结构
调用指定的属性并可以设定值
1
2
3
4
5
6
7
8
9
10
11
12
13//获取运行时类
Class<?> aClass = Class.forName("com.atzrh.java.Person");
//创建运行时类对象
Person person = (Person) aClass.newInstance();
//获取指定的属性
Filed name = aClass.getDeclaredField("name");
//保证当前属性可访问,才能有如下操作
name.setAccessible(true);
//Set方法
name.set(person,"Tom");
//Get方法
name.get(person);调用方法
1
2
3
4
5
6
7
8
9
10
11//获取运行时类
Class<?> aClass = Class.forName("com.atzrh.java.Person");
//创建运行时类对象
Person person = (Person) aClass.newInstance();
//通过方法名和形参列表获取某个指定方法
Method show = aClass.getDeclaredMethod("show",String.class);
//保证方法可访问
show.setAccessible(true);
//传入通过对象和参数调用方法,没有返回值返回null
Object returnValue = show.invoke(person,"CHN");
//静态方法调用不用传对象调用指定构造器
1
2
3
4
5
6//获取对应参数列表的构造器
Constructor constructor = aClass.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
//创建运行时类对象
Person person = (Person) constructor.newInstance("Tom");
7. 反射应用:动态代理
代理模式和接口是密不可分的
代理设计模式:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理
前面第7章的代理是静态代理,代理类和目标对象在编译期间就确定了下来
动态代理举例:
1 | public class ProxyTest { |
17. IO
1. Scanner
1 | import java.util.Scanner; |
2. 格式化输出
1 | String str="Java"; |
3. File类
- Test单元测试里当前目录指的是当前Module下的目录
- main方法里当前目录指的是当前工程
- File类对象构造方法
1 |
|
- 以下全是File类对象的方法
先获得一个File对象,然后去创建它
1
2
3
4
5
6File file = new File("./test.txt");
if (!file.exists()){
file.createNewFile();
}else {
file.delete();
}
1 | boolean delete();//删除文件或者空的文件目录 |
4. IO流
1.IO
- 字节流 字符流
输入流 输出流(都是相对于内存来说的,读:把文件读到内存 写:从内存写到文件)
Reader:读文件 Writer:写文件
Input:读文件 Output:写文件
节点(文件)流 处理流
- (下图 上面是抽象基类,访问文件这一行属于节点流,可直接作用于文件,下面的都属于处理流,要作用于节点流才能处理文件)
FileReader&&FileWriter
读数据完整流程
读数据(读到内存),文件要存在,不然会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//把fr定义在{}里的话,下面finally{}就没有了
FileReader fr = null;
try {
//1.实例化File类对象,指明要操作的文件
File file1 = new File("./IO/hello.txt");
//2.提供具体的流
fr = new FileReader(file1);
//3.读入数据,read()返回的是每次读入字符的字符码,文件末尾就是-1
int data = fr.read();
while (data != -1) {
System.out.println((char) data);
data = fr.read();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//4.关闭流
if (fr!=null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}- read(char[]),每次可读入多个
1
2
3
4
5
6
7
8
9
10//创建一个5的char型数组,相当于每次可最多读取5个字符
char[] cbuf = new char[5];
int len;
//read返回的是每次读入字符的数量(最后一次可能不为5),读完返-1
while((len = fr.read(cbuf)!=-1){
//因为可能数组存不满,所以要用len,不能用cbuf.length
for(int i = 0;i<len;++i){
System.out.print(cbuf[i]);
}
}写数据完整流程
写到文件,File指向的文件不存在则会创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20FileWriter fw = null;
try {
//1. 提供file类的对象,指明写出到的文件
File file1 = new File("./IO/hello1.txt");
//2. 提供FileWriter的对象,用于数据的写出(可指定方式:覆盖or追加)
fw = new FileWriter(file1,true);
//3. 写出数据(若file1对应文件不存在则自动创建)
fw.write("\nhello1");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 关闭资源流
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}为了使代码逻辑清晰,以下代码均throws异常(实际开发中应该如上)
- 使用输入输出流进行文件复制操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//1. 构造File类对象,指明要操作的文件
File file1 = new File("./src/text/hello1.txt");
File file2 = new File("./src/text/hello2.txt");
//2. 创建输入输出流
FileReader fr = new FileReader(file1);
FileWriter fw = new FileWriter(file2);
//3. 文件读取,写入
char[] cbuf = new char[5];
int len;
while ((len = fr.read(cbuf)) != -1) {
//每次写入cbuf的0-len长度的字符
fw.write(cbuf, 0, len);
}
//4.流资源关闭
fr.close();
fw.close();FileInputStream&&FileOutputStream
1
2
3
4
5//操作基本都一样
//2. 创建输入输出流,使用字节流
FileReader fr = new FileInputStream(file1);
//3. 文件读取的时候使用字节数组
byte[] cbuf = new byte[5];当使用字节流去处理文字时,使用字节数组
1
byte[] cbuf = new byte[5];
而在UTF-8里,英文数字都是一个byte存储,汉字是3个byte
而你是每5个byte的去读,当你每读5个就通过控制台输出的话,汉字的3个byte可能就不在每批的那5个里,所以极可能乱码
字符流处理:文本文件(.txt .java .c .cpp)
字节流处理:非文本文件(.jpg .doc…….)
缓冲流
处理流的一种,要作用于节点流
实际工程中,通常使用缓冲流,因为它的速度更快
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//1. 构造File类对象,指明要操作的文件
File file1 = new File("./src/text/hello1.txt");
File file2 = new File("./src/text/hello2.txt");
//2.1. 创建输入输出流(字节流)
FileReader fr = new FileReader(file1);
FileWriter fw = new FileWriter(file2);
//2.2. 创建缓冲流(对应的字节缓冲流)
BufferedReader bufferedReader = new BufferedReader(fr);
BufferedWriter bufferedWriter = new BufferedWriter(fw);
//3. 文件传输的细节
char[] cbuf = new char[5];
int len;
while ((len = bufferedReader.read(cbuf)) != -1) {
//每次写入cbuf的0-len长度的字符
//在缓冲流的输出流中,有一个缓冲。输出达到缓冲区域上限时,就会输出出去(bufferedWriter.flush()可主动刷新缓冲)
bufferedWriter.write(cbuf, 0, len);
}
//4.流资源关闭,外层处理流关闭内层节点流会自动关闭
bufferedReader.close();
bufferedWriter.close();1
2
3
4
5
6
7//可以不造File对象,直接把文件路径传入节点流
BufferedReader bufferedReader = new BufferedReader(new FileReader("./src/text/hello1.txt"));
//缓冲流每次可以读一行
String data;
while ((data=bufferedReader.readLine())!=null){
System.out.println(data);
}转换流
实现字节流—->字符流
InputStreamReader
字节的读流—>字符的读流
1
2
3
4
5
6
7
8
9
10//1.字节输入(读)流
FileInputStream fileInputStream = new FileInputStream("./text/hello1.txt");
//2. 转换为字符输入(读)流
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
//3.按照字符流的方式读数据
char[] cbuf = new char[10];
int len;
while ((len=inputStreamReader.read(cbuf))!=-1){
//
}OutputStreamWriter
字节的写流—>字符的写流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//常用来更改编码格式
//1.字节输入输出流
FileInputStream fileInputStream = new FileInputStream("./src/text/hello1.txt");
FileOutputStream fileOutputStream = new FileOutputStream("./src/text/hello2.txt");
//2. 转换为字符输入输出流
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
//3.按照字符流的方式读写数据
char[] cbuf = new char[10];
int len;
while ((len=inputStreamReader.read(cbuf))!=-1){
outputStreamWriter.write(cbuf, 0, len);
}
inputStreamReader.close();
outputStreamWriter.close();标准输入输出流
标准:键盘输入,控制台输出
可调用System类的输入输出方法修改输入输出位置
1
2System.in//返回的是一个字节输入流(从键盘读入)
System.out//返回的是一个字节输出流(写出到控制台)打印流
两个都是输出流
PrintStream
PrintWriter
数据流
方便保存Java的基本数据类型和String
- DataOutputStream
1
2
3
4
5
6DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("./src/text/hello1.txt"));
String time = new Date().toString();
//写入String用writeUTF
dataOutputStream.writeUTF(time);
dataOutputStream.flush();//刷新,立马写入文件(默认达到缓冲区上限才写,其它流同理)
dataOutputStream.close();- DataInputStream
1
2
3
4DataInputStream dataInputStream = new DataInputStream(new FileInputStream("./src/text/hello1.txt"));
//如果写入多个数据,读的时候顺序要和写入顺序一样
System.out.println(dataInputStream.readUTF());
dataInputStream.close();对象流
ObjectInputStream :读取 反序列化
ObjectOutputStream:保存 序列化
弥补7,除了基本数据类型还可以操作对象
- 自定义类Person满足以下要求才能序列化
关于上图补充:被以上两个关键字修饰的成员变量,其实可以序列化,但是值保存不了,即反序列化的时候读取的是默认值(String为null,int为0等等)
1
2
3//标识接口,没有任何需要实现的抽象方法
public interface Serializable {
}
RandomAccessFile
不同于上述都是继承于4个抽象基类,他直接继承于Object类,同时实现了DataInput和DataOutput接口。它根据构造器的参数去指定这个流是实现输入还是输出的功能
代码逻辑一样:
作为输出流(写文件)时:
通过seek()调整写入时的指针位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69public class BreakPTrans {
public static boolean copy(String src, String des) {
boolean copySuccess = false;
RandomAccessFile r = null;
RandomAccessFile w = null;
File seekFile = new File("./BreakPointDL/src/file/seek.txt");
FileReader FileReader = null;
FileWriter FileWriter = null;
//记录每次读的位置
long seek = 0;
try {
//如果记录seek的文件存在,则要更新seek
if (seekFile.exists()) {
FileReader = new FileReader(seekFile);
StringBuilder stringBuilder = new StringBuilder();
int data;
while ((data = FileReader.read()) != -1) {
stringBuilder.append((char) data);
}
seek = Long.parseLong(new String(stringBuilder));
}
FileWriter = new FileWriter(seekFile);
r = new RandomAccessFile(src, "r");
r.seek(seek);
w = new RandomAccessFile(des, "rw");
//指针指向末尾,实现追加操作
w.seek(w.length());
int data;
while ((data = r.read()) != -1) {
w.write((char) data);
System.out.println("one byte has been written");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
copySuccess = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (FileWriter != null && r != null) {
//把退出时指针位置记录到文件
FileWriter.write(String.valueOf(r.getFilePointer()));
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (r != null) {
r.close();
}
if (w != null) {
w.close();
}
if (FileReader != null) {
FileReader.close();
}
if (FileWriter != null) {
FileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return copySuccess;
}
}
2.NIO
pass
18. 时间
随机数
1 | double value = Math.random();//随机生成一个[0.0,1.0)的随机数,double类型 |
19.2.1 System类
- 此方法适合于计算时间差
1 | //获取当前时间(距离时间戳1970年..)的毫秒数 |
19.2.2 Date类
- Java.util.Date
1 | Date date1 = new Date();//创建对应当前时间的Date对象 |
Java.sql.Date
是Java.util.Date的子类
1 | Date date2 = new Date(41524512L);//只有时间戳的这个构造方法 |
可以通过获取时间戳的方式进行两种Date的转换
19.2.3 SimpleDateFormat类
java.text.SimpleDateFormat
Date类的API不利于国际化,大部分已被废弃
SimpleDateFormat可以对Date类进行格式化解析
1 | //默认构造器pattern = "22-7-12 下午5:01" |
格式化:日期->字符串
1
2
3
4Date date = new Date();
long ms = System.currentTimeMillis();
//可以传Date,时间戳
String s = simpleDateFormat.format(ms);解析:字符串->日期
1
2
3String str = "22-7-12 下午5:01";
Date date1 = simpleDateFormat.parse(str);
System.out.println(date1);
19.2.4 Calendar类
Calendar是一个抽象基类,主用于完成日期字段之间相互操作的功能
创建实例
1
2//抽象类,调用静态方法得到实例
Calendar calendar = Calendar.getInstance();get set 方法
1
2
3
4//获取当前时间是本月的第几天
int day = calendar.get(Calendar.DAY_OF_MONTH);
//直接设置calendar为本月的第20天
calendar.set(Calendar.DAY_OF_MONTH, 20);add方法
1
2//本月第几天加3天,也可以加负数,表示减
calendar.add(Calendar.DAY_OF_MONTH, 3);和Date的相互转换
1
2
3
4
5
6
7//getTime()
//Calendar->Date
Date date = calendar.getTime();
//setTime()
//Date->Calendar
calendar.setTime(new Date());
19.2.4 JDK8的时间API
- LocalDateTime
构造方法
1
2
3
4//当前时间.now()
LocalDate date = LocalDate.now();//2022-07-14
LocalTime time = LocalTime.now();//14:15:24.020
LocalDateTime dateTime = LocalDateTime.now();//2022-07-14T14:15:24.0201
2//自定义时间.of()有多种构造器供使用
LocalDateTime dateTime1 = LocalDateTime.of(2020,7,14,14,54);get操作
1
2int dayOfMonth = dateTime.getDayOfMonth();
DayOfWeek dayOfWeek = dateTime.getDayOfWeek();with操作,设置日期
1
LocalDateTime dateTime2 = dateTime.withDayOfMonth(25);
日期加减
1
2LocalDateTime dateTime3 = dateTime.plusDays(3);//加
LocalDateTime dateTime4 = dateTime.minusDays(3);//减
Instant
DateTimeFormatter
创建对象
1
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
//将String转换为LocalDateTime的对象 String dateTimeStr= "2016-10-25 12:00:00"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); //把Str按照formatter进行转换 LocalDateTime localDateTime=LocalDateTime.parse(dateTimeStr,formatter); //将LocalDateTime的对象转换为String String format = localDateTime.format(formatter);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 19. Java8
## 1. 函数式接口
### 1. Lambda
本质:作为接口的实例(它是一个对象)。依赖函数式接口(该接口只能有一个抽象方法)
匿名实现类的对象可以替换为Lambda表达式
- ->左边:Lambda形参列表(就是接口中抽象方法的形参列表)
1. 形参的参数类型可以省略(类型推断)
2. 若只有一个参数,小括号也可以省略
- ->右边:Lambda体(就是重写的抽象方法的方法体)
1. Lambda体应用{}包裹
2. 如果该方法只有一条执行语句,可省略{},如果该条是return语句,return也可以省略
### 2. Functional
函数式接口(只有一个抽象方法的接口)
可通过注解 @FunctionalInterface 修饰
可通过Lambda表达式来创建函数式接口的对象
![image-20220815104432429](https://nnu-zrh.oss-cn-hangzhou.aliyuncs.com/202307131522484.png)
### 3. 方法引用
Method Reference
本质上就是Lambda表达式
- 对象::实例方法
~~~Java
Consumer<String> con1 = str-> System.out.println(str);
con1.accept("北京");
//Consumer中的void accept(T t)
//System.out对象中的void println(T t)
Consumer<String> con2 = System.out::println;
con2.accept("南京");
类::静态方法
1
2
3
4
5Comparator<Integer> com1 = (o1,o2)->o1.compareTo(o2);
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
Comparator<Integer> com2 = Integer::compareTo;类::实例·方法
1
2
3
4
5BiPredicate<String,String> pre1 = (s1,s2)->s1.equals(s2);
//BiPredicate中的Boolean test(T t1,T t2)
//String中的Boolean t1.equals()
BiPredicate<String,String> pre2 = String::equals;
4. 构造器引用
1 | //原始写法 |
2. StreamAPI
使用StreamAPI对集合数据进行操作,就类似于SQL进行的数据库查询
1. 创建Stream
通过集合
1
2
3
4
5List<Integer> list;
//返回一个顺序流
Stream<Integer> stream1 = list.stream();
//返回一个并行流
Stream<Integer> stream2 = list.parallelStream();通过数组
1
2
3
4int[] arr = new int[]{1,2,3};
IntStream stream1 = Arrays.stream(arr);
Stream<Person> stream2 = Arrays.stream(Person数组);Stream.of()
1
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
无限流
1
2//从0开始,每次加2,截取前10个,对每个元素进行输出操作
Stream.iterate(0, t->t+2).limit(10).forEach(System.out::println);
2. 中间操作
流就和iterator一样,进行了中间操作,然后进行了结尾操作(例如:forEach(System.out::println))。就不能再操作这个流了,它已经结束了
经过 中间操作得到的还是一个Stream
筛选与切片
1
2
3
4
5
6
7
8
9
10
11
12
13
14int[] arr = {1,2,3,4,4,6,7,8,9};
//过滤流:筛选输出arr中的偶数
IntStream stream = Arrays.stream(arr);
stream.filter(e->e%2==0).forEach(e-> System.out.print(e+" "));
System.out.println("------------------");
//截断流:只要前两个元素
Arrays.stream(arr).limit(2).forEach(System.out::println);
System.out.println("------------------");
//跳过前2个元素
Arrays.stream(arr).skip(2).forEach(System.out::println);
System.out.println("------------------");
//筛选:去除重复元素:依据hashcode和equals方法
Arrays.stream(arr).distinct().forEach(System.out::println);
System.out.println("------------------");映射
1
2
3
4
5
6
7
8List<String> list = Arrays.asList("aa", "bbc", "cc", "dd11");
//将流中的每一个元素都映射成另一个元素(大写)
list.stream().map(String::toUpperCase).forEach(System.out::println);
//.flatMap
//如果map把每个元素映射成了一个Stream,那么list.stream().map(映射成Stream)返回
//的就是stream构成的stream,而.flatMap会把各个stream拆包还是返回像上面的由元素构成的stream排序
1
2
3
4List<Person> list = Arrays.asList(new Person(52,"Tom"), new Person(18,"Jack"), new Person(24,"Jerry"), new Person(30,"Smith"));
//按年龄进行排序
list.stream().sorted((p1,p2)->-(p1.getAge()-p2.getAge())).forEach(System.out::println);
3. 终止操作
匹配与查找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//检查是否匹配所有元素
//是否所有人年龄都大于18
boolean allMatch = list.stream().allMatch(p -> p.getAge() > 18);
//检查是否至少匹配一个
//是否至少一个人年龄大于18
boolean anyMatch = list.stream().anyMatch(p -> p.getAge() > 18);
//findFirst 返回流中第一个元素,放在Optional容器
Optional<Person> first = list.stream().findFirst();
Person person = first.get();
//count 流中元素个数
//max
//min
//forEach 内部迭代规约
1
2//映射成age流,再对流中元素求和
Optional<Integer> sum = list.stream().map(Person::getAge).reduce(Integer::sum);收集
1
2//映射成为大写后收集成一个list或者set等
List<String> list1 = list.stream().map(String::toUpperCase).collect(Collectors.toList());.collect之后可以用Collectors工具类进行一系列操作
1
2
3
4
5
6
7
81.转换为集合;
List<String> custListResult = list.stream().collect(Collectors.toCollection(LinkedList::new));//转换为特定的集合LinkList
2.转换为map;
Map<String, Integer> mapResult = list.stream().collect(Collectors.toMap(Function.identity(), String::length));//Function.identity()就是x->x即流中元素本身
3.连接元素;
String joinResult = list.stream().collect(Collectors.joining());
3. Option类
避免空指针问题
20. Java9以后
1. java9
模块化系统
1
//创建一个module.info文件来导入需要的模块
REPL工具
像python一样在命令行就能交互式的编程环境
命令行输入jshell打开该交互工具
接口
新增可以定义私有方法
砖石操作符
在8中,使用匿名对象时,后面不能省略
try结构
java8之前,括号里不能写
java8:
java9:
String
底层时char型数组存储,每个字符两个字节
java9:底层为字节型数组存储,拉丁一个字节,汉字两个字节
集合工厂
快速创建只读集合
1
2Set.of();
List.of();流转换
StreamAPI
增强版
optional
optional容器也可以转换为流
Nashorn引擎
可以在JVM上运行JavaScript程序
2. Java10
局部变量类型推断
1
2
3
4
5var num = 10;
var list = new ArrayList<Integer>();
for(var num : list){
}
3. java11
Epsilon
ZGC
字符串新方法
A. Eclipse
创建一个工程:
- 在Package Explorer里新建一个Java project
- 在src目录下新建一个包(包名:com.at作者名.包名)
- 在包里新建一个class
Perspective(透视图,选择Java EE或者Java SE等)
Quick Access(快速搜索一些工具)
window->preferences->General->workspace->默认编码改成UTF-8
写个main,alt+/ 一下会出来选择
syso + 回车 标准输出
导入Javaproject
比如给你发了一个文件过来,你是不能直接改名的,导入到工作空间后修改才有效
file->import->
把勾打上,就在此空间复制了一份,原来的就可以删除了,不然链接的还是原来的文件
关联Java源文件后,按住CTRL就可以查看Java的比如String的源代码,左边outline可以看到他的结构
作者信息 package和method设置后 /**回车 即可显示
快捷键:Ctrl+shift+/ 多行注释选中代码
Ctrl+shift+\ 取消多行注释
Ctrl+/注释取消注释
Ctrl+d 删除光标所在行代码
alt+up/down 移动光标所在行代码
ctrl+alt+down 向下复制所选区域的代码
alt+shift+s 选择generate getters and setters(生成获得和设置类属性的方法)以及重写,设置构造器等,不用手写。
代码自动补全:window->preference->java->editor->content Assist
把Auto activation trigger for Java 后面的改为.qwer….键盘上的所有键
debug模式:
双击行左侧设置断点;
(右上角切换Javaee透视图和debug透视图)
(左边两个:直接到下一个断点;中止debug
右边四个:进入方法内部;进入下一语句;跳出方法内部;返回方法首行)
B. 易错易混
Test
1 | //创建一个数组大小为n,数组的元素是存放double[]型数组的List |