JavaSE
2023-08-22 17:15:38 0 举报
AI智能生成
JavaSE学习笔记,应该算是比较详细的
作者其他创作
大纲/内容
区别
==和equals()的区别
1、==是运算符,equals() 是方法
2、基本数据类型判断值,引用类型两者均判断对象在内存中的地址,若equals()重写,则可以进行内存地址,长度,内容进行判断是否为同一个对象底层判断的先后顺序
3、==哪里都可以用,equals() 需要对象才可以调用
重写和重载的区别
1、重载是方法的扩展 重写是覆盖,存在于继承关系中
2、重载:方法名必须相同,参数列表必须不同,与返回值和访问修饰符无关
3、重写:方法名必须相同,参数列表,返回值必须相同,权限不可以小于父类的继承方法
自然排序和比较器的区别
1、当自然排序和比较器同时存在时,比较器的优先级比自然排序的高
2、使用自然排序会改变存储的对象类的结构,比较器不会
3、使用比较器需要额外创建一个类实现比较器接口,通过TreeSet的构造方法传递比较对象(可以匿名内部类==》lambda表达式)
4、当非自定义类的自然排序不符合需求时,可以传递比较器改变排序规则
ArrayList和LinkedList的区别
1、底层结构不同,ArrayList动态数组,扩1.5 LinkedList双向链表
2、ArrayL:ist查询比LinkedList快(前者索引,后者只能从头开始)
3、在不需要扩容的时候,末尾追加ArrayList比LinkedList快
4、中间插入和中间删除根据不同的情况下效率不同
5、ArrayList修改比LinkedList快
6、ArrayList容量有限,LinkedList理论上容量无限
wait() 和 sleep()的区别
1、wait() 来自Object类 sleep() 来自Thread 类
2、sleep() 不需要唤醒,会自动唤醒,wait() 要通过 notify() 或者 notifyAll() 唤醒,notify() 先阻塞先唤醒(像队列,先进先出) notifyAll() 先阻塞后唤醒(像栈,后进先出)
3、sleep() 不会释放资源 wait() 会释放资源
4、sleep() 任意位置都可以使用 wait() 必须在 synchronized 的同步区域中使用
TCP (传输控制协议)和UDP (用户数据报协议)
TCP (传输控制协议)和UDP (用户数据报协议)是两种常用的传输层协议,它们在数据传输时有一些显著的区别。
1连接导向 vs 非连接导向
TCP是一种连接导向的协议,即在发送数据前必须先与对方建立连接。连接过程包括三次握手(建立连接)、数据传输、四次挥手(断开连接)等步。UDP 则是一种非连接导向的协议,即发送数据时不需要建立连接,可以随时发送、随时接收。这也是 UDP 速度更快的主要原因之一。
2.可靠传输 vs不可靠传输
TCP 提供可靠的传输服务,即在数据传输时会进行校验、重传等操作,确保数据的正确性和完整性,如果数据传输出现丢失、迟、重复等问题,TCP 会尝试重新传输数据,UDp 则是一种不可靠传输协议,将数发送出去后并不关心它是否能够成功到达目的地,因此也不提供校和重传等机制。如果数据丢失或出错,UDP 不会进行任间处理,需要由应用程序自行处理。
3.流量控制 vs无流量控制
TCp 支持流量控制和相寒控制制,即在教据传输过程中会根据网终状本动本调整传输速度和质量。避免出现网终案等问题。UDP 则不支持这些控制机制。发送的教准包大小和频率完全由应用程序决定,因此可能会因为网络拥塞而造成数据丢失或延迟。
4.有序传输vs 无序传输
TCP 能够确保数据包按照发送顺字到达接收端,以确保数据的有序性。DP 则不保证数据包的有房性,多个数据包到达接收端后可能会按照任意顺字排列
综上述,TCP 和 UDP 都有各自的优缺点,在不同的场景中洗合适的协议可以更好地满足需求,例,TCP 适用于对数准性要求高、需要保证数据传输顺字的场景(红HTTP、FTP 等),而 UDP 适用于对数据传输实时性要求高、允许数据丢失或不按顺序到达的场景(如视频直播、实时游戏等)。
1连接导向 vs 非连接导向
TCP是一种连接导向的协议,即在发送数据前必须先与对方建立连接。连接过程包括三次握手(建立连接)、数据传输、四次挥手(断开连接)等步。UDP 则是一种非连接导向的协议,即发送数据时不需要建立连接,可以随时发送、随时接收。这也是 UDP 速度更快的主要原因之一。
2.可靠传输 vs不可靠传输
TCP 提供可靠的传输服务,即在数据传输时会进行校验、重传等操作,确保数据的正确性和完整性,如果数据传输出现丢失、迟、重复等问题,TCP 会尝试重新传输数据,UDp 则是一种不可靠传输协议,将数发送出去后并不关心它是否能够成功到达目的地,因此也不提供校和重传等机制。如果数据丢失或出错,UDP 不会进行任间处理,需要由应用程序自行处理。
3.流量控制 vs无流量控制
TCp 支持流量控制和相寒控制制,即在教据传输过程中会根据网终状本动本调整传输速度和质量。避免出现网终案等问题。UDP 则不支持这些控制机制。发送的教准包大小和频率完全由应用程序决定,因此可能会因为网络拥塞而造成数据丢失或延迟。
4.有序传输vs 无序传输
TCP 能够确保数据包按照发送顺字到达接收端,以确保数据的有序性。DP 则不保证数据包的有房性,多个数据包到达接收端后可能会按照任意顺字排列
综上述,TCP 和 UDP 都有各自的优缺点,在不同的场景中洗合适的协议可以更好地满足需求,例,TCP 适用于对数准性要求高、需要保证数据传输顺字的场景(红HTTP、FTP 等),而 UDP 适用于对数据传输实时性要求高、允许数据丢失或不按顺序到达的场景(如视频直播、实时游戏等)。
IO流
分类
方向
输入流
程序从文件内读取数据
输出流
程序向文件内输入数据
读写单位
字节流
字节为单位,可以传递字节数组
字符流
字符为单位,可以传递字符串/字符数组
功能
基础流(节点流)直接与磁盘交互
包装流(处理流)在节点流的基础上,通过缓冲区进行读写操作
字节流
FileInputStream
FileOutputStream
字符流
FileReader
FileWriter
带缓冲区
Buffered
+InputStream
+OutputStream
+Reader
.newLine() 换行
+Writer
.readLine() 读取一行
特点
默认生成一个 8192 字节的缓冲区
可以指定缓冲区大小
转换流
InputStreamReader isr = new InputStreamReader(new FileInputStream("path"));
(同上,换成输出流即可)
对象流
序列化(写)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("path"));
反序列化流(读)
ObjectInputStream oos = new ObjectInputStream(new FileInputStream("path"));
特点
对象类必须实现 Serializable 接口,(序列号UUID)
不改变对象类的内部结构,可以没有序列号
不固定序列号改变对象类结构
可以将方法设置为是有静态最终方法/属性
可以给私有化属性加上transient
随机访问流
RandomAccessFile("Path","读写权限rw")
读(赋权限 r 即可)
写(赋权限 rw)
特点
1、拥有偏移量
2、只有一个类,由同一个类创建不同的对象进行读取和写入操作
3、每次实例化对象偏移量为0,不会清空原文件内容,在偏移量开始地方进行覆盖写入或者读取操作
内存流
ByteArrayInputStream
内存 => 程序
ByteArrayOutputStream
程序 => 内存
bos.reset() 清空
特点
相对于其他流效率更高
操作的数量少
只适用于操作临时数据
获取数据方式
输出流对象.toByteArray() 从内存中获取输出流输出的数据
bos.toString() 直接打印输出流对象
使用输入流获取相同字节数组对象的数据并打印
打印流
PrintStream
PrintWriter
特点
只可操作流的目的地,不可操作数据流
有特有的写出方式,可实现数据的原样写出
特有的方法,实现自动刷新,自动换行,打印一次数据 = 写出+ 换行 + 刷新
只有输出流,没有输入流
Properties
1、要求key和value都是String
2、通常用于配置文件的读取
prop.load 获取配置文件内的信息(键值对,都为String类型)
prop.store(字符流,"文件内的标题")
多线程
进程
程序执行的基本单位,一个程序的执行由一个或多个进程组合而成
线程
CPU调度的基本单位,一个进程的执行由一个或多个线程组合而成
多线程的创建方式
1、自定义线程类 MyThread 继承 Thread 类,重写 run()
在 run() 中添加线程执行任务,然后在其他执行的线程中
实例化 MyThread 类对象,通过对象调用 start()开启线程
在 run() 中添加线程执行任务,然后在其他执行的线程中
实例化 MyThread 类对象,通过对象调用 start()开启线程
2、自定义任务类 Task 实现 Runnable 接口,重写 run()
在 run() 中添加线程执行任务,然后在其他执行的线程中
实例化 Task 类对象,再实例化 Thread 类对象,并把 Task 对象
当做构造方法的参数进行传递,通过 Thread 类对象调用 start() 开启线程
在 run() 中添加线程执行任务,然后在其他执行的线程中
实例化 Task 类对象,再实例化 Thread 类对象,并把 Task 对象
当做构造方法的参数进行传递,通过 Thread 类对象调用 start() 开启线程
3、实现Callable 接口,重写call()方法,并创建FutureTask<>进行管理其返回的对象,再将该对象当做参数传递进线程对象的构造方法中,并开启线程
Runnable接口和Callable接口的区别
Callable接口中call方法有返回值,Runnable接口中run方法没有返回值
Callable接口中call方法有声明异常,Runnable接口中run方法没有异常
4、线程池
Thread.currentThread() 获取当前线程
生命周期
线程安全
多条线程异步操作临界资源,导致数据异常
解决问题
1、synchronized:同步锁
1、同步代码块
把需要从异步变成同步的代码存放再代码块中,添加同步锁和同步监视器
要求多条线程访问同步代码块时,同步监视器的对象都为同一个对象
当有一条线程进入同步代码块时,其他线程在执行到同步代码块时会等待进入同步代码块的
线程执行完才会继续进入同步代码块,一次只会有一条线程进入。
把需要从异步变成同步的代码存放再代码块中,添加同步锁和同步监视器
要求多条线程访问同步代码块时,同步监视器的对象都为同一个对象
当有一条线程进入同步代码块时,其他线程在执行到同步代码块时会等待进入同步代码块的
线程执行完才会继续进入同步代码块,一次只会有一条线程进入。
2 同步方法
synchronized 修饰的方法为同步方法,同步监视器为方法本身
多条线程访问同步方法时,要求访问是同一个方法
当有线程调用同步方法时,其他线程则等待方法调用结束才能继续调用。
synchronized 修饰的方法为同步方法,同步监视器为方法本身
多条线程访问同步方法时,要求访问是同一个方法
当有线程调用同步方法时,其他线程则等待方法调用结束才能继续调用。
2、Lock接口,创建实现类 ReentrantLock
lock.lock() 上锁
lock.unlock() 解锁
子主题
线程安全的集合
StringBuffer
Vector<>[基本不用了]
Stack<>
CopyOnWriteArrayList<> 读写并发的动态数组集合
CopyOnWriteArraySet<> 在addIfAbsent()添加元素时,会遍历数组,底层还是 CopyOnWriteArrayList 实现的
ConcurrentHashMap 初始容量默认为16段,分段锁设计,使用方法和 HashMap 无异
就是将Hash表分为16段,锁加在每一个段上,而不是 Hash 表上
Queue 队列
ConcurrentLinkedQueue 可读可写的队列,高并发下性能最好的队列
无锁
V:要更新的变量
E:预期值
N:新值
只有当V==E时,V=N;否则表示已被更新过,则取消当前操作
BlockingQueue 阻塞的队列
增加了两个线程状态为无限期等待的方法
可用于解决生产者、消费者问题
ArrayBlockingQueue
数组结构实现,有界队列
手工固定上限
LinkedBlockingQueue
链表结构实现,无界队列
默认上限 Integer.MAX_VALUE
使用方法和ArrayBlockingQueue相同
wait() 和 sleep()的区别
1、wait() 来自Object类 sleep() 来自Thread 类
2、sleep() 不需要唤醒,会自动唤醒,wait() 要通过 notify() 或者 notifyAll() 唤醒,notify() 先阻塞先唤醒(像队列,先进先出) notifyAll() 先阻塞后唤醒(像栈,后进先出)
3、sleep() 不会释放资源 wait() 会释放资源
4、sleep() 任意位置都可以使用 wait() 必须在 synchronized 的同步区域中使用
线程池
用于维护一个队列,队列中保存着处于等待(空闲)状态的线程。不用每次创建新的线程
常用API
Executor 线程池的顶级接口
ExecutorService 线程池接口,可通过 sumbit(Runnable task) 提交任务代码
Executors工厂类 通过此类可以获得一个线程池
newFixedThreadPoll(int nThreads) 获取固定数量的线程池
参数: 指定线程池中线程的数量
newCachedThreadPool() 获得动态数量的线程池
若不够,则创建新的,无上限
newSingleThreadExecutor() 创建单个线程的线程池
只有一个线程
newScheduledThreadPool() 创建固定大小的线程池
可以延迟或定时执行任务
反射
反射机制
能有在运行状态中动态获取类对象的属性和调用类对象的方法
获取反射对象方法
1、通过完整的类路径获取反射对象 Class.forName("").var
2、通过类名获取 类名.class.var
3、通过实例对象调用 实例对象名.getClass().var
通过反射机制操作实例对象的私有属性
1、获取反射对象
2、通过反射对象获取属性对象 反射对象.getField("属性名")
3、打开访问权限 id.setAccessible(true)
4、修改指定实例对象的属性 id.set(指定的实例对象的属性, 修改后的属性值)
通过反射机制操作实例对象的私有方法
1、获取反射对象
不同的获取方法对象
2、通过反射对象获取方法对象 反射对象.getMethod("方法名")
2、通过反色或对象获取方法对象 需要传递方法名和参数列表类型的反射对象
3、打开访问权限 method.setAccessible(true)
4、调用方法 传递指定对象
通过反射机制操作实例对象的构造方法
1、获取反射对象
构造方法
非私有化
调用无参构造方法实例化对象
私有化
通过反射对象获取构造方法的操作对象
3、打开访问权限
4、通过构造方法的操作对象创建实例对象
案例 toString() 的封装
1、StringBuilder/StringBUfffer 为toString的返回值为字符串类型做准备,进行字符拼接
2、获取反射对象,反射对象为当前调用的类对象,所以直接用 this 即可==>[运行时 特点]
3、获取反射对象所有的成员变量 使用getDe
注解
元数据,一种代码级别的说明,能够增强代码的作用性
@Override:校验方法是否为重写的方法
@Test:单元测试
@FunctionalInterface:校验接口是否为函数式接口
@Test:单元测试
@FunctionalInterface:校验接口是否为函数式接口
元注解:修饰注解的注解
@Retention:修饰注解保留在什么状态中
RetentionPolicy.SOURCE 指定被修饰的注解只保留在源代码中
RetentionPolicy.CLASS 指定被修饰的注解只保留在字节码文件中
RetentionPolicy.RUNTIME 指定被修饰的注解只保留在运行状态中
RetentionPolicy.SOURCE 指定被修饰的注解只保留在源代码中
RetentionPolicy.CLASS 指定被修饰的注解只保留在字节码文件中
RetentionPolicy.RUNTIME 指定被修饰的注解只保留在运行状态中
@Target:修饰的注解能作用在哪些代码上
ElementType.TYPE 指定被修饰的注解只能作用于类、接口、枚举、注解
ElementType.FIELD 指定被修饰的注解只能作用于全局属性
ElementType.METHOD 指定被修饰的注解只能作用于方法
ElementType.PARAMETER 指定被修饰的注解只能作用于形参
ElementType.CONSTRUCTOR 指定被修饰的注解只能作用于构造器
ElementType.LOCAL_VARIABLE 指定被修饰的注解只能作用于方法体中定义的局部变量
ElementType.ANNOTATION_TYPE 指定被修饰的注解只能作用于注解
ElementType.TYPE_PARAMETER 指定被修饰的注解只能作用于泛型
ElementType.TYPE_USE 指定被修饰的注解不能作用于返回值为 void 的方法
ElementType.TYPE 指定被修饰的注解只能作用于类、接口、枚举、注解
ElementType.FIELD 指定被修饰的注解只能作用于全局属性
ElementType.METHOD 指定被修饰的注解只能作用于方法
ElementType.PARAMETER 指定被修饰的注解只能作用于形参
ElementType.CONSTRUCTOR 指定被修饰的注解只能作用于构造器
ElementType.LOCAL_VARIABLE 指定被修饰的注解只能作用于方法体中定义的局部变量
ElementType.ANNOTATION_TYPE 指定被修饰的注解只能作用于注解
ElementType.TYPE_PARAMETER 指定被修饰的注解只能作用于泛型
ElementType.TYPE_USE 指定被修饰的注解不能作用于返回值为 void 的方法
例子
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
//元素类 元素名
String key();
int value();
//元素默认为1
//int value() default 1;
}
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
//元素类 元素名
String key();
int value();
//元素默认为1
//int value() default 1;
}
@Target({ElementType.TYPE_USE,ElementType.METHOD})
public @interface MyAnnotation1 {
}
public @interface MyAnnotation1 {
}
当@target中传递的是RUNTIME
static{
try {
//1.获取当前类对象的方法对象
Method init = Demo01.class.getDeclaredMethod("init", String.class, int.class);
//2.打开访问权限
init.setAccessible(true);
//3.通过方法对象获取注解对象
MyAnnotation2 annotation = init.getAnnotation(MyAnnotation2.class);
//4.根据注解对象获取方法上传递的元素值
String key = annotation.key();
int value = annotation.value();
//5.创建当前类的实例对象
Demo01 demo01 = Demo01.class.newInstance();
//6.调用初始化方法
init.invoke(demo01,key,value);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@MyAnnotation2(key="zs",value=18)
public void init(String name,int age){
System.out.println("name:"+name);
System.out.println("age:"+age);
}
public static void main(String[] args) {
}
try {
//1.获取当前类对象的方法对象
Method init = Demo01.class.getDeclaredMethod("init", String.class, int.class);
//2.打开访问权限
init.setAccessible(true);
//3.通过方法对象获取注解对象
MyAnnotation2 annotation = init.getAnnotation(MyAnnotation2.class);
//4.根据注解对象获取方法上传递的元素值
String key = annotation.key();
int value = annotation.value();
//5.创建当前类的实例对象
Demo01 demo01 = Demo01.class.newInstance();
//6.调用初始化方法
init.invoke(demo01,key,value);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@MyAnnotation2(key="zs",value=18)
public void init(String name,int age){
System.out.println("name:"+name);
System.out.println("age:"+age);
}
public static void main(String[] args) {
}
枚举
自定义枚举
public enum MyEnum {
//芭比娃娃
BARBIE_MOPPET,
//哪吒娃娃
NEZHA_MOPPET,
//葫芦娃
CALABASH_MOPPET
}
//芭比娃娃
BARBIE_MOPPET,
//哪吒娃娃
NEZHA_MOPPET,
//葫芦娃
CALABASH_MOPPET
}
设计模式
记忆口诀:
单元见公象
代氏乔装外祖享
壮观盅碟备街坊
命责莫测
单元见公象
代氏乔装外祖享
壮观盅碟备街坊
命责莫测
设计模式:一套由程序员长期积累总结的经验规划出来的设计思想
1.创建型(5):只关注对象的创建,用于解耦
单例模式、原型模式、建造者模式、工厂方法模式、抽象工厂模式
2.结构型(7):只关注对象的结构,让类与对象结合形成更强大的结构
代理模式、适配器模式、桥接模式、装饰者模式【IO流中的包装流】、外观模式、组合模式、享元模式
3.行为型(11):只关注对象的行为,关注对象与类之间的交互和职责的划分
状态模式、观察者模式、中介者模式、迭代器模式、备忘录模式、解析器模式、访问模式
命令模式、责任链模式、模板模式、策略模式
1.创建型(5):只关注对象的创建,用于解耦
单例模式、原型模式、建造者模式、工厂方法模式、抽象工厂模式
2.结构型(7):只关注对象的结构,让类与对象结合形成更强大的结构
代理模式、适配器模式、桥接模式、装饰者模式【IO流中的包装流】、外观模式、组合模式、享元模式
3.行为型(11):只关注对象的行为,关注对象与类之间的交互和职责的划分
状态模式、观察者模式、中介者模式、迭代器模式、备忘录模式、解析器模式、访问模式
命令模式、责任链模式、模板模式、策略模式
jdk1.8特性
lambda表达式
特殊的匿名内部类,允许我们把函数当做是方法的参数进行传递
/*
() 代表的是方法的参数列表
-> 指向方法体
{} 方法体
当方法体中只存在一行代码时,可以省略大括号
*/
/*method(()->{
System.out.println("lambda");
});*/
//接口必须为函数式接口
() 代表的是方法的参数列表
-> 指向方法体
{} 方法体
当方法体中只存在一行代码时,可以省略大括号
*/
/*method(()->{
System.out.println("lambda");
});*/
//接口必须为函数式接口
//当参数只有一个的时候,可以省略()
//method((item)-> System.out.println(item));
//item 为参数名,参数不能有数据类型
//method((item)-> System.out.println(item));
//item 为参数名,参数不能有数据类型
stream流
数据渠道(高级迭代器),用于操作数据源所生成的元素序列,可以实现对集合的复杂操作。
只改变打印结果,不改变数据源
只改变打印结果,不改变数据源
//获取流的方式
Stream<User> stream = list.parallelStream();
//多线程方式进行遍历
//stream.forEach(item -> System.out.println(item));
Stream<User> stream = list.parallelStream();
//多线程方式进行遍历
//stream.forEach(item -> System.out.println(item));
常用方法
.filter()过滤
.skip(int num) 跳过 num 条数据
.limit(int num) 提取前 num 条数据
.sorted( null / compator比较器 ) 排序
末尾操作
.forEach( System.out::println ) 遍历
若排序,则按照排序后的来取第一个/最后一个,否则按照源数据的存储顺序进行操作
.max 获取最后一个对象
.min 获取第一个对象
拓展完整方法+eg
创建Stream流
- 通过Collection对象的stream()或parallelStream()方法。
- 通过Arrays类的stream()方法。
- 通过Stream接口的of()、iterate()、generate()方法。
- 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
- 通过Arrays类的stream()方法。
- 通过Stream接口的of()、iterate()、generate()方法。
- 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
public class Demo5 {
public static void main(String[] args) {
//(1)Collection对象中的stream()和parallelStream()方法
ArrayList<String> arrayList=new ArrayList<>();
arrayList.add("apple");
arrayList.add("huawei");
arrayList.add("xiaomi");
}}
public static void main(String[] args) {
//(1)Collection对象中的stream()和parallelStream()方法
ArrayList<String> arrayList=new ArrayList<>();
arrayList.add("apple");
arrayList.add("huawei");
arrayList.add("xiaomi");
}}
Stream<String> stream = arrayList.parallelStream();
// 遍历-----多线程获取打印
// stream.forEach(s->System.out.println(s));
stream.forEach(System.out::println);
// 遍历-----多线程获取打印
// stream.forEach(s->System.out.println(s));
stream.forEach(System.out::println);
//(2)Arrays工具类的stream方法
String[] arr= {"aaa","bbb","ccc"};
Stream<String> stream2=Arrays.stream(arr);
stream2.forEach(System.out::println);
String[] arr= {"aaa","bbb","ccc"};
Stream<String> stream2=Arrays.stream(arr);
stream2.forEach(System.out::println);
//(3)Stream接口中的of iterate 、generate 方法
System.out.println("-----of------");
Stream<Integer> stream3 = Stream.of(10,20,30,40,50);
stream3.forEach(System.out::println);
//迭代流
System.out.println("-----迭代流------");
Stream<Integer> iterate = Stream.iterate(0, x->x+2);
iterate.limit(5).forEach(System.out::println);
//生成流
System.out.println("--------生成流----------");
Stream<Integer> generate = Stream.generate(()->new Random().nextInt(100));
generate.limit(10).forEach(System.out::println);
System.out.println("-----of------");
Stream<Integer> stream3 = Stream.of(10,20,30,40,50);
stream3.forEach(System.out::println);
//迭代流
System.out.println("-----迭代流------");
Stream<Integer> iterate = Stream.iterate(0, x->x+2);
iterate.limit(5).forEach(System.out::println);
//生成流
System.out.println("--------生成流----------");
Stream<Integer> generate = Stream.generate(()->new Random().nextInt(100));
generate.limit(10).forEach(System.out::println);
//(4)IntStream,LongStream,DoubleStream 的of 、range、rangeClosed
IntStream stream4 = IntStream.of(100,200,300);
stream4.forEach(System.out::println);
IntStream range = IntStream.rangeClosed(0, 50);
range.forEach(System.out::println);
IntStream stream4 = IntStream.of(100,200,300);
stream4.forEach(System.out::println);
IntStream range = IntStream.rangeClosed(0, 50);
range.forEach(System.out::println);
常见中间操作:
- filter、limit、skip、distinct、sorted
- map
- parallel
- filter、limit、skip、distinct、sorted
- map
- parallel
public class Demo6 {
public static void main(String[] args) {
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
//list.add(new Employee("小刘", 25000));
//中间操作1
//filter过滤、limit 限制、skip 跳过、distinct 去掉重复、sorted排序
}
}
public static void main(String[] args) {
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
//list.add(new Employee("小刘", 25000));
//中间操作1
//filter过滤、limit 限制、skip 跳过、distinct 去掉重复、sorted排序
}
}
//(1) filter过滤
System.out.println("------filter-------");
list.stream()
.filter(e->e.getMoney()>15000)
.forEach(System.out::println);
System.out.println("------filter-------");
list.stream()
.filter(e->e.getMoney()>15000)
.forEach(System.out::println);
//(2) limit限制
System.out.println("----limit------");
list.stream()
.limit(2)
.forEach(System.out::println);
System.out.println("----limit------");
list.stream()
.limit(2)
.forEach(System.out::println);
//(3) skip跳过
System.out.println("-----skip------");
list.stream()
.skip(2)
.forEach(System.out::println);
System.out.println("-----skip------");
list.stream()
.skip(2)
.forEach(System.out::println);
System.out.println("------distinct--------");
//(4) distinct去重复
list.stream()
.distinct()
.forEach(System.out::println);
//(4) distinct去重复
list.stream()
.distinct()
.forEach(System.out::println);
System.out.println("---------sorted---------");
//(5) sorted排序
list.stream()
.sorted((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()))
.forEach(System.out::println);
//(5) sorted排序
list.stream()
.sorted((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()))
.forEach(System.out::println);
//中间操作2 map
System.out.println("---------map--------");
list.stream()
.map(e->e.getName())
.forEach(System.out::println);
System.out.println("---------map--------");
list.stream()
.map(e->e.getName())
.forEach(System.out::println);
//中间操作3 parallel 采用多线程 效率高
System.out.println("---------map--------");
list.parallelStream()
.forEach(System.out::println);
System.out.println("---------map--------");
list.parallelStream()
.forEach(System.out::println);
终止操作
常见终止操作:
- forEach、min、max、count
- reduce、collect
- forEach、min、max、count
- reduce、collect
public class Demo8 {
public static void main(String[] args) {
ArrayList<Employee> list = new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
}}}
public static void main(String[] args) {
ArrayList<Employee> list = new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
}}}
//1 终止操作 foreach
list.stream()
.filter(e->{
System.out.println("过滤了....");
return e.getMoney()>15000;
})
.forEach(System.out::println);
list.stream()
.filter(e->{
System.out.println("过滤了....");
return e.getMoney()>15000;
})
.forEach(System.out::println);
//2 终止操作 min max count
System.out.println("-----min-----");
Optional<Employee> min = list.stream()
.min((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()));
System.out.println(min.get());
System.out.println("-----max-----");
Optional<Employee> max = list.stream()
.max((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()));
System.out.println(max.get());
System.out.println("-----count-----");
long count = list.stream().count();
System.out.println("员工个数:"+count);
System.out.println("-----min-----");
Optional<Employee> min = list.stream()
.min((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()));
System.out.println(min.get());
System.out.println("-----max-----");
Optional<Employee> max = list.stream()
.max((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()));
System.out.println(max.get());
System.out.println("-----count-----");
long count = list.stream().count();
System.out.println("员工个数:"+count);
//3 终止操作 reduce 规约
//计算所有员工的工资和
System.out.println("--------reduce---------");
Optional<Double> sum = list.stream()
.map(e->e.getMoney())
.reduce((x,y)->x+y);
System.out.println(sum.get());
//计算所有员工的工资和
System.out.println("--------reduce---------");
Optional<Double> sum = list.stream()
.map(e->e.getMoney())
.reduce((x,y)->x+y);
System.out.println(sum.get());
//4 终止方法 collect收集
//获取所有的员工姓名,封装成一个list集合
System.out.println("------collect------");
List<String> names = list.stream()
.map(e->e.getName())
.collect(Collectors.toList());
for (String string : names) {
System.out.println(string);
//获取所有的员工姓名,封装成一个list集合
System.out.println("------collect------");
List<String> names = list.stream()
.map(e->e.getName())
.collect(Collectors.toList());
for (String string : names) {
System.out.println(string);
串行流和并行流
- 串行流使用单线程。
- 并行流使用多线程,效率更高。
- 并行流使用多线程,效率更高。
public class Demo7 {
public static void main(String[] args) {
//串行流和并行流的区别
ArrayList<String> list=new ArrayList<>();
for(int i=0;i<5000000;i++) {
list.add(UUID.randomUUID().toString());
}
//串行:10秒 并行:7秒
long start=System.currentTimeMillis();
long count=list.Stream().sorted().count();
//long count=list.parallelStream().sorted().count();
System.out.println(count);
long end=System.currentTimeMillis();
System.out.println("用时:"+(end-start));
}
}
public static void main(String[] args) {
//串行流和并行流的区别
ArrayList<String> list=new ArrayList<>();
for(int i=0;i<5000000;i++) {
list.add(UUID.randomUUID().toString());
}
//串行:10秒 并行:7秒
long start=System.currentTimeMillis();
long count=list.Stream().sorted().count();
//long count=list.parallelStream().sorted().count();
System.out.println(count);
long end=System.currentTimeMillis();
System.out.println("用时:"+(end-start));
}
}
新时间API
之前遇见的时间API有线程安全问题,以及一些设计的格式复杂
本地化日期时间 API:
- LocalDate
- LocalTime
- LocalDateTime
Instant:时间戳。
ZoneId:时区。
Date、Instant、LocalDateTime的转换。
DateTimeFormatter:格式化类。
- LocalDate
- LocalTime
- LocalDateTime
Instant:时间戳。
ZoneId:时区。
Date、Instant、LocalDateTime的转换。
DateTimeFormatter:格式化类。
LocalDateTime类
表示本地日期时间,没有时区信息
//1创建本地时间
LocalDateTime localDateTime=LocalDateTime.now();
//LocalDateTime localDateTime2=LocalDateTime.of(year, month, dayOfMonth, hour, minute)
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
//2添加两天
LocalDateTime localDateTime2 = localDateTime.plusDays(2);
System.out.println(localDateTime2);
//3减少一个月
LocalDateTime localDateTime3 = localDateTime.minusMonths(1);
System.out.println(localDateTime3);
LocalDateTime localDateTime=LocalDateTime.now();
//LocalDateTime localDateTime2=LocalDateTime.of(year, month, dayOfMonth, hour, minute)
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
//2添加两天
LocalDateTime localDateTime2 = localDateTime.plusDays(2);
System.out.println(localDateTime2);
//3减少一个月
LocalDateTime localDateTime3 = localDateTime.minusMonths(1);
System.out.println(localDateTime3);
Instant、ZoneId类
Instant 表示瞬间,和Date 类似
//1 创建Instant:时间戳
Instant instant=Instant.now();
System.out.println(instant.toString());
System.out.println(instant.toEpochMilli());
System.out.println(System.currentTimeMillis());
//2 添加减少时间
Instant instant2 = instant.plusSeconds(10);
System.out.println(Duration.between(instant, instant2).toMillis());
Instant instant=Instant.now();
System.out.println(instant.toString());
System.out.println(instant.toEpochMilli());
System.out.println(System.currentTimeMillis());
//2 添加减少时间
Instant instant2 = instant.plusSeconds(10);
System.out.println(Duration.between(instant, instant2).toMillis());
ZoneId 表示时区信息
//3 ZoneId
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String string : availableZoneIds) {
System.out.println(string);
}
System.out.println(ZoneId.systemDefault().toString());
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String string : availableZoneIds) {
System.out.println(string);
}
System.out.println(ZoneId.systemDefault().toString());
Date、Instant、LocalDateTime的转换。
//1 Date --->Instant--->LocalDateTime
System.out.println("-------------Date --->Instant---->LocalDateTime-----------");
Date date=new Date();
Instant instant3 = date.toInstant();
System.out.println(instant3);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant3, ZoneId.systemDefault());
System.out.println(localDateTime);
//2 LocalDateTime --->Instant--->Date
System.out.println("-------------LocalDateTime --->Instant---->Date-----------");
Instant instant4 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
System.out.println(instant4);
Date from = Date.from(instant4);
System.out.println(from);
System.out.println("-------------Date --->Instant---->LocalDateTime-----------");
Date date=new Date();
Instant instant3 = date.toInstant();
System.out.println(instant3);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant3, ZoneId.systemDefault());
System.out.println(localDateTime);
//2 LocalDateTime --->Instant--->Date
System.out.println("-------------LocalDateTime --->Instant---->Date-----------");
Instant instant4 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
System.out.println(instant4);
Date from = Date.from(instant4);
System.out.println(from);
DateTimeFormatter类
DateTimeFormatter 是时间格式化类
//创建DateTimeFormatter
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//1 把时间格式化成字符串
String format = dtf.format(LocalDateTime.now());
System.out.println(format);
//2 把字符串解析成时间
LocalDateTime localDateTime = LocalDateTime.parse("2020/03/10 10:20:35", dtf);
System.out.println(localDateTime);
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//1 把时间格式化成字符串
String format = dtf.format(LocalDateTime.now());
System.out.println(format);
//2 把字符串解析成时间
LocalDateTime localDateTime = LocalDateTime.parse("2020/03/10 10:20:35", dtf);
System.out.println(localDateTime);
JSON格式
数据格式,本质上字符串
{属性名:属性值,属性名:属性值}
{属性名:属性值,属性名:属性值}
//JSON格式的数据 -- 前端发送的数据
//实例化 JSONObject 对象,通过构造方法传递 JSON 格式的数据
//根据属性名获取属性值
解析(JSON=》对象)
解析复杂结构的 JSON 格式数据
String json = "{id:1,name:'ls',score:{chinaScore:95.5,mathScore:96.0,engScore:66.5}}";
//1.创建 JSONObject 对象,通过构造方法传递 json 格式字符串
JSONObject jsonObject = new JSONObject(json);
//2.根据属性名获取属性值
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
//3.根据对象名获取对象
JSONObject object = jsonObject.getJSONObject("score");
double chinaScore = object.getDouble("chinaScore");
double mathScore = object.getDouble("mathScore");
double engScore = object.getDouble("engScore");
Student student = new Student(id, name, new Score(chinaScore, mathScore, engScore));
System.out.println(student);
//1.创建 JSONObject 对象,通过构造方法传递 json 格式字符串
JSONObject jsonObject = new JSONObject(json);
//2.根据属性名获取属性值
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
//3.根据对象名获取对象
JSONObject object = jsonObject.getJSONObject("score");
double chinaScore = object.getDouble("chinaScore");
double mathScore = object.getDouble("mathScore");
double engScore = object.getDouble("engScore");
Student student = new Student(id, name, new Score(chinaScore, mathScore, engScore));
System.out.println(student);
String json = "[{id:1,name:'zs'},{id:2,name:'ls'},{id:3,name:'ww'}]";
ArrayList<User> list = new ArrayList<>();
//1.创建 JSONArray 对象,通过构造方法传递 json 格式的字符串
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
//根据索引获取 JSONObject 的对象
JSONObject obj = jsonArray.getJSONObject(i);
int id = obj.getInt("id");
String name = obj.getString("name");
User user = new User(id,name);
list.add(user);
}
list.forEach(item -> System.out.println(item));
ArrayList<User> list = new ArrayList<>();
//1.创建 JSONArray 对象,通过构造方法传递 json 格式的字符串
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
//根据索引获取 JSONObject 的对象
JSONObject obj = jsonArray.getJSONObject(i);
int id = obj.getInt("id");
String name = obj.getString("name");
User user = new User(id,name);
list.add(user);
}
list.forEach(item -> System.out.println(item));
String json = "[{id:1,name:'zs',score:{chinaScore:95.5,mathScore:96.0,engScore:66.5}}," +
"{id:2,name:'ls',score:{chinaScore:95.5,mathScore:9.0,engScore:6.5}}," +
"{id:3,name:'ww',score:{chinaScore:9.5,mathScore:96.0,engScore:66.5}}]";
ArrayList<Student> students = new ArrayList<>();
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
JSONObject score = jsonObject.getJSONObject("score");
Double chinaScore = score.getDouble("chinaScore");
Double mathScore = score.getDouble("mathScore");
Double engScore = score.getDouble("engScore");
students.add(new Student(id,name,new Score(chinaScore,mathScore,engScore)));
}
students.forEach(item -> System.out.println(item));
"{id:2,name:'ls',score:{chinaScore:95.5,mathScore:9.0,engScore:6.5}}," +
"{id:3,name:'ww',score:{chinaScore:9.5,mathScore:96.0,engScore:66.5}}]";
ArrayList<Student> students = new ArrayList<>();
JSONArray jsonArray = new JSONArray(json);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
JSONObject score = jsonObject.getJSONObject("score");
Double chinaScore = score.getDouble("chinaScore");
Double mathScore = score.getDouble("mathScore");
Double engScore = score.getDouble("engScore");
students.add(new Student(id,name,new Score(chinaScore,mathScore,engScore)));
}
students.forEach(item -> System.out.println(item));
转换(对象=》JSON)
//简单格式的对象
User user = new User(1, "zs");
JSONObject obj1 = new JSONObject(user);
System.out.println(obj1);
//复杂格式的对象
Student student = new Student(1, "ls", new Score(96, 75, 84.5));
JSONObject obj2 = new JSONObject(student);
System.out.println(obj2);
//集合
ArrayList<User> list = new ArrayList<>();
Collections.addAll(list,new User(1,"zs"),new User(1,"ls"));
JSONArray obj3 = new JSONArray(list);
System.out.println(obj3);
User user = new User(1, "zs");
JSONObject obj1 = new JSONObject(user);
System.out.println(obj1);
//复杂格式的对象
Student student = new Student(1, "ls", new Score(96, 75, 84.5));
JSONObject obj2 = new JSONObject(student);
System.out.println(obj2);
//集合
ArrayList<User> list = new ArrayList<>();
Collections.addAll(list,new User(1,"zs"),new User(1,"ls"));
JSONArray obj3 = new JSONArray(list);
System.out.println(obj3);
jar包
json-lib.jar
fastjson-1.1.22.jar
网络编程
常见的计算机网络
- 互联网:(Internet)点与点相连。
- 万维网:(WWW – World Wide Web)端与端相连。
- 物联网:( IoT - Internet of things) 物与物相连。
- 网络编程:让计算机与计算机之间建立连接、进行通信。
- 万维网:(WWW – World Wide Web)端与端相连。
- 物联网:( IoT - Internet of things) 物与物相连。
- 网络编程:让计算机与计算机之间建立连接、进行通信。
网络模型
OSI(Open System Interconnect),即开放式系统互联。
- 是ISO组织在1985年研究的网络互联模型。
- 该体系结构标准定义了网络互联的七层框架([物理层]()、[数据链路层]()、[网络层]()、[传输层]()、[会话层]()、[表示层]()和[应用层]())。
- 该体系结构标准定义了网络互联的七层框架([物理层]()、[数据链路层]()、[网络层]()、[传输层]()、[会话层]()、[表示层]()和[应用层]())。
每层功能:
- 第七层:应用层负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)。
- 第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
- 第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)。
- 第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)。
- 第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)。
- 第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)。
- 第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
- 第七层:应用层负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)。
- 第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
- 第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)。
- 第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)。
- 第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)。
- 第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)。
- 第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
TCP/IP模型
- TCP/IP模型是因特网使用的参考模型,基于TCP/IP的参考模型将协议分成四个层次。
- 该模型中最重要的两个协议是TCP和IP协议。
- 该模型中最重要的两个协议是TCP和IP协议。
每层功能:
- 第四层:应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
- 第三层:传输层负责传送文本数据,主要协议是TCP、UDP协议。
- 第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
- 第一层:接口层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等。
- 第四层:应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
- 第三层:传输层负责传送文本数据,主要协议是TCP、UDP协议。
- 第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
- 第一层:接口层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等。
常见协议
TCP---Transmission Control Protocol 传输控制协议
是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。
建立连接的过程需要三次握手,
断开连接的过程需要四次挥手
是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。
建立连接的过程需要三次握手,
断开连接的过程需要四次挥手
连接---三次握手
客户端给服务器发送一个SYN段(在 TCP 标头中 SYN 位字段为 1 的 TCP/IP 数据包), 该段中也包含客户端的初始序列号(Sequence number = J)。
服务器返回客户端 SYN +ACK 段(在 TCP 标头中SYN和ACK位字段都为 1 的 TCP/IP 数据包), 该段中包含服务器的初始序列号(Sequence number = K);同时使 Acknowledgment number = J + 1来表示确认已收到客户端的 SYN段(Sequence number = J)。
客户端给服务器响应一个ACK段(在 TCP 标头中 ACK 位字段为 1 的 TCP/IP 数据包), 该段中使 Acknowledgment number = K + 1来表示确认已收到服务器的 SYN段(Sequence number = K)。
断开---四次挥手
四次挥手(Four-way handshake 是CP/P协议中用于关闭一个已经建立的连接的过程。它由四个步骤组成,每个步都需要由一方发起并等待对方的确认:
1.主动关闭方 (Client) 发送一个FIN分节,表示不再向被动关闭方发送数据。
2.被动关闭方(Server) 接收到FIN分节后,发送一个ACK分节,表示已经接收到关闭请求。
3.被动关闭方发送一个FIN分节,表示自己也不再向主动关闭方发送数据。
4.主动关闭方接收到FIN分节后,发送一个ACK分节,表示已经接收到关闭请求.四次挥手的目的是让客户端和服务器在终止通信时彼此确认彼此已经停止发送数。由于TCPP协议是面向连接的协议,因此在关闭连接之前,需要先完或数据的传输以保证数据的完整性。
以下是四次挥手的详细过程
1,主动关闭方发送FIN分节,表示不再向被动关闭方发送数据,进入FIN WAIT 1状态2.被动关闭方接收到FIN分节后,发送ACK分节作为确认,进入CLOSE WAIT状态。3.被动关闭方发送FIN分节,表示自己也不再向主动关闭方发送数据,进入LAST_ACK状态。4.主动关闭方接收到FIN分节后,发送ACK分节作为确认,进入TIME WAT状态,此主动关闭方等待2倍的MSL时间(最长报文段生存时间),以确保对方收到了确认分节在等待期间,如果对方没有回复,则主动关闭方可以直接关闭连接并释放资源,如果对方回复了ACK分节,则主动关闭方也进行相同的操作。5.被动关闭方等待2倍的MSL时间后,关闭连接并释放资源。
需要注意的是,四次挥手中每一步的ACK分节都是必须的。因为1CPP协议是面向可靠传输的,每一次数据包的发送和接收都有可能导致传输借误或丢失,只有在确认方接收到对方的分节时,才能保证数据的完整性和可靠性。
1.主动关闭方 (Client) 发送一个FIN分节,表示不再向被动关闭方发送数据。
2.被动关闭方(Server) 接收到FIN分节后,发送一个ACK分节,表示已经接收到关闭请求。
3.被动关闭方发送一个FIN分节,表示自己也不再向主动关闭方发送数据。
4.主动关闭方接收到FIN分节后,发送一个ACK分节,表示已经接收到关闭请求.四次挥手的目的是让客户端和服务器在终止通信时彼此确认彼此已经停止发送数。由于TCPP协议是面向连接的协议,因此在关闭连接之前,需要先完或数据的传输以保证数据的完整性。
以下是四次挥手的详细过程
1,主动关闭方发送FIN分节,表示不再向被动关闭方发送数据,进入FIN WAIT 1状态2.被动关闭方接收到FIN分节后,发送ACK分节作为确认,进入CLOSE WAIT状态。3.被动关闭方发送FIN分节,表示自己也不再向主动关闭方发送数据,进入LAST_ACK状态。4.主动关闭方接收到FIN分节后,发送ACK分节作为确认,进入TIME WAT状态,此主动关闭方等待2倍的MSL时间(最长报文段生存时间),以确保对方收到了确认分节在等待期间,如果对方没有回复,则主动关闭方可以直接关闭连接并释放资源,如果对方回复了ACK分节,则主动关闭方也进行相同的操作。5.被动关闭方等待2倍的MSL时间后,关闭连接并释放资源。
需要注意的是,四次挥手中每一步的ACK分节都是必须的。因为1CPP协议是面向可靠传输的,每一次数据包的发送和接收都有可能导致传输借误或丢失,只有在确认方接收到对方的分节时,才能保证数据的完整性和可靠性。
在断开连接之前客户端和服务器都处于ESTABLISHED状态,双方都可以主动断开连接,以客户端主动断开连接为优。
第一次挥手:客户端打算断开连接,向服务器发送FIN报文(FIN标记位被设置为1,1表示为FIN,0表示不是),FIN报文中会指定一个序列号,之后客户端进入FIN_WAIT_1状态。
也就是客户端发出连接释放报文段(FIN报文),指定序列号seq = u,主动关闭TCP连接,等待服务器的确认。
第二次挥手:服务器收到连接释放报文段(FIN报文)后,就向客户端发送ACK应答报文,以客户端的FIN报文的序列号 seq+1 作为ACK应答报文段的确认序列号ack = seq+1 = u + 1。
接着服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态(下面会说什么是半关闭状态),客户端到服务器的连接释放。客户端收到来自服务器的ACK应答报文段后,进入FIN_WAIT_2状态。
第三次握手:服务器也打算断开连接,向客户端发送连接释放(FIN)报文段,之后服务器进入LASK_ACK(最后确认)状态,等待客户端的确认。
服务器的连接释放(FIN)报文段的FIN=1,ACK=1,序列号seq=m,确认序列号ack=u+1。
第四次握手:客户端收到来自服务器的连接释放(FIN)报文段后,会向服务器发送一个ACK应答报文段,以连接释放(FIN)报文段的确认序号 ack 作为ACK应答报文段的序列号 seq,以连接释放(FIN)报文段的序列号 seq+1作为确认序号ack。
之后客户端进入TIME_WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态,到此服务器的连接已经完成关闭。
客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后,客户端才进入CLOSE状态。
第一次挥手:客户端打算断开连接,向服务器发送FIN报文(FIN标记位被设置为1,1表示为FIN,0表示不是),FIN报文中会指定一个序列号,之后客户端进入FIN_WAIT_1状态。
也就是客户端发出连接释放报文段(FIN报文),指定序列号seq = u,主动关闭TCP连接,等待服务器的确认。
第二次挥手:服务器收到连接释放报文段(FIN报文)后,就向客户端发送ACK应答报文,以客户端的FIN报文的序列号 seq+1 作为ACK应答报文段的确认序列号ack = seq+1 = u + 1。
接着服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态(下面会说什么是半关闭状态),客户端到服务器的连接释放。客户端收到来自服务器的ACK应答报文段后,进入FIN_WAIT_2状态。
第三次握手:服务器也打算断开连接,向客户端发送连接释放(FIN)报文段,之后服务器进入LASK_ACK(最后确认)状态,等待客户端的确认。
服务器的连接释放(FIN)报文段的FIN=1,ACK=1,序列号seq=m,确认序列号ack=u+1。
第四次握手:客户端收到来自服务器的连接释放(FIN)报文段后,会向服务器发送一个ACK应答报文段,以连接释放(FIN)报文段的确认序号 ack 作为ACK应答报文段的序列号 seq,以连接释放(FIN)报文段的序列号 seq+1作为确认序号ack。
之后客户端进入TIME_WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态,到此服务器的连接已经完成关闭。
客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后,客户端才进入CLOSE状态。
UDP---User Datagram Protocol 用户数据报协议
是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,基于管道,包,每个包的大小64KB。
是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,基于管道,包,每个包的大小64KB。
IP---Internet Protocol Address 互联网协议地址/网际协议地址
分配给互联网设备的数字标签(唯一标识)
分配给互联网设备的数字标签(唯一标识)
IP地址版本:
- IPV4:4字节32位整数,并分成4段8位的二进制数,每8位之间用圆点隔开,每8位整数可以转换为一个0~255的十进制整数。
格式:D.D.D.D 例如:255.255.255.255
- IPV6:16字节128位整数,并分成8段十六进制数,每16位之间用圆点隔开,每16位整数可以转换为一个0~65535的十进制数。
格式:X.X.X.X.X.X.X.X 例如:FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
格式:D.D.D.D 例如:255.255.255.255
- IPV6:16字节128位整数,并分成8段十六进制数,每16位之间用圆点隔开,每16位整数可以转换为一个0~65535的十进制数。
格式:X.X.X.X.X.X.X.X 例如:FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
IP地址分类:
- A类:政府机构,1.0.0.1 ~ 126.255.255.254
- B类:中型企业,128.0.0.1 ~ 191.255.255.254
- C类:个人用户,192.0.0.1 ~ 223.255.255.254
- D类:用于组播,224.0.0.1 ~ 239.255.255.254
- E类:用于实验,240.0.0.1 ~ 255.255.255.254
- 回环地址:127.0.0.1,指本机,一般用于测试使用。
- B类:中型企业,128.0.0.1 ~ 191.255.255.254
- C类:个人用户,192.0.0.1 ~ 223.255.255.254
- D类:用于组播,224.0.0.1 ~ 239.255.255.254
- E类:用于实验,240.0.0.1 ~ 255.255.255.254
- 回环地址:127.0.0.1,指本机,一般用于测试使用。
查看IP命令:ipconfig
测试IP命令:ping D.D.D.D
测试IP命令:ping D.D.D.D
端口号---在通信实体上进行网络通讯的程序的唯一标识
端口分类:
- 公认端口:0~1023
- 注册端口:1024~49151
- 动态或私有端口:49152~65535
- 注册端口:1024~49151
- 动态或私有端口:49152~65535
常用端口:
- MySql:3306
- Oracle:1521
- Tomcat:8080
- SMTP:25
- Web服务器:80
- FTP服务器:21
- Oracle:1521
- Tomcat:8080
- SMTP:25
- Web服务器:80
- FTP服务器:21
基于 TCP 的网络编程
- Socket(套接字)是网络中的一个通信节点。
- 分为客户端Socket与服务器ServerSocket。
- 通信要求:IP地址 + 端口号。
- 分为客户端Socket与服务器ServerSocket。
- 通信要求:IP地址 + 端口号。
> 开发步骤:
>
> - 建立通信连接(会话):
> - 创建ServerSocket,指定端口号。
> - 调用accept等待客户端接入。
> - 客户端请求服务器:
> - 创建Socket,指定服务器IP + 端口号。
> - 使用输出流,发送请求数据给服务器。
> - 使用输入流,接收响应数据到客户端(等待)
> - 服务器响应客户端。
> - 使用输入流,接收请求数据到服务器(等待)。
> - 使用输出流,发送响应数据给客户端。
>
> - 建立通信连接(会话):
> - 创建ServerSocket,指定端口号。
> - 调用accept等待客户端接入。
> - 客户端请求服务器:
> - 创建Socket,指定服务器IP + 端口号。
> - 使用输出流,发送请求数据给服务器。
> - 使用输入流,接收响应数据到客户端(等待)
> - 服务器响应客户端。
> - 使用输入流,接收请求数据到服务器(等待)。
> - 使用输出流,发送响应数据给客户端。
环境搭建
JDK1.8
特性
JDK(Java开发工具包)【类库,编译器,调试工具】>JRE(Java运行环境)【解释器】>JVM(Java虚拟机)
dos命令窗口使用
进行校验
javac xxx
java xxx.java
编译运行
先编译后解释.
环境变量
JAVA_HOME属性
Path属性
IDEA使用
如何创建java项目
快捷键
基础语法
第一个Java程序
执行机制
先编译后运行
代码格式
类
全局变量
main()
方法
内部类
注释
// 单行注释
/**/ 多行注释
/** */ 文本注释
标识符
由字母,数字,下划线,$ 组合而成
命名规则
驼峰命名法(见名知意)
数据类型
基本数据类型(8个)
整型
byte
short
int
long
浮点型
float
double
布尔型
boolean
字符型
char
引用型(String等)
引用对象
内存地址
引用字符串
字符串常量池
转义字符
\n 换行
\t 水平制表符
运算符
一元运算符
前置++/--
后置++/--
三元运算符
关系表达式?值1:值2
逻辑运算符
& 逻辑与
&& 短路与
| 逻辑或
|| 短路或
^ 异或
! 非/取反
算术运算符
+ 加
- 减
* 乘
/ 除
% 取余
赋值运算符
+= 加等
-= 减等
*= 乘等
/= 除等
%= 取余等
关系运算符
== 等等
!= 不等
>= 大于等
<= 小于等
> 大于
< 小于
分支语句
选择分支
if(){}else if(){}else(){}
switch(判断依据对象){ case x: break; default: break;}
循环
for i
可以操作数据
循环次数可以确定时,建议使用
循环次数不确定
foreach
只可以遍历
while
先判断在运行
do while
至少运行一次,先运行后判断
循环标识符
continue
break
break 标号:
java初阶
方法
代码规格
重载
方法的扩展-----发生在同一个类当中
1、方法名相同
2、参数列表不同(顺序、个数、类型)
3、与返回值类型,访问修饰符无关
重写
方法的覆盖------只能发生在继承关系中的子类
1、方法名、参数列表、返回值类型相同
2、访问权限不能比父类小
3、私有方法不能被重写
数组
特点
1、定义后,长度固定不变
2、只能存放相同数据类型的数据
3、每个数组都拥有索引(下标),从0开始,最大长度为长度-1
遍历方式
for i
foreach
无法改变数组中的元素
存储规则
只可存同一种属性的数据
需要手动初始化数组长度
中间插入、删除效率较低
排序算法(10种)
冒泡排序
相邻两个数的比较,进行换位排序
选择排序
记录最小值/最大值下标,完成一轮比较后进行换位排序
插入排序
记录最小值/最大值的值,完成一轮比较后进行换位排序
快速排序、堆排序、希尔排序、归并排序、桶排序、计数排序、基数排序
内存分析
栈
局部变量
栈帧(main方法内的)
堆
实例对象(new)
字符串常量池
方法区
运行时常量池
字节码文件(.class)
静态资源
常用类
内部类
定义
在一个类的内部在定义一个完整的类
分类
成员内部类
在类的内部定义,与实例变量、实例方法同级别的类
外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象
当外部类、内部类存在重名属性时,会优先访问内部类属性,打印外部类的属性,内部类属性和外部类的属性名相同Outer.this
成员内部类不能定义静态成员
静态内部类
不依赖外部类对象,可以直接创建或通过类名访问,可声明静态成员
只能直接访问外部类的静态成员(实例成员需实例化外部类对象)
局部内部类
定义在外部类方法中,作用范围和创建对象范围仅限于当前方法
局部内部类访问外部类当前方法中的局部变量时。因无法保障变量的生命周期与自身相同
限制类的使用范围
匿名内部类
没有类名的局部内部类(一切特征都与局部内部类相同)
必须继承一个父类或者实现一个接口
定义类、实现类、创建对象的语法合并,只能创建一个该类的对象
优点: 减少代码量
缺点:可读性较差
特点
编译之后可生成独立的字节码文件
内部类可直接访问外部类的私有成员,而不破坏封装
可为外部类提供必要的内部功能组件
Object 类
- 超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
- 任何类,如没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承。
- Object类中所定义的方法,是所有对象都具备的方法。
- Object类型可以存储任何对象。
- 作为参数,可接受任何对象。
- 作为返回值,可返回任何对象。
- 任何类,如没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承。
- Object类中所定义的方法,是所有对象都具备的方法。
- Object类型可以存储任何对象。
- 作为参数,可接受任何对象。
- 作为返回值,可返回任何对象。
常用方法
getClass()
- 返回引用中存储的实际对象类型。
- 应用:通常用于判断两个引用中实际存储对象类型是否一致。
- 应用:通常用于判断两个引用中实际存储对象类型是否一致。
hashCode()
- 返回该对象的十进制的哈希码值。
- 哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
- 哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码。
- 哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
- 哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码。
toString()
- 返回该对象的字符串表示(表现形式)。
- 可以根据程序需求覆盖该方法,如:展示对象各个属性值。
- 可以根据程序需求覆盖该方法,如:展示对象各个属性值。
equals()
- 默认实现为(this == obj),比较两个对象地址是否相同。
- 可进行覆盖,比较两个对象的内容是否相同。
**equals重写步骤:**
- 比较两个引用是否指向同一个对象。
- 判断obj是否为null。
- 判断两个引用指向的实际对象类型是否一致。
- 强制类型转换。
- 依次比较各个属性值是否相同。
- 比较两个引用是否指向同一个对象。
- 判断obj是否为null。
- 判断两个引用指向的实际对象类型是否一致。
- 强制类型转换。
- 依次比较各个属性值是否相同。
finalize()
- 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
- 垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
- 手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
- 垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
- 手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。
包装类
基本数据类型==>引用型(8个)
装箱/拆箱
- 八种包装类提供不同类型间的转换方式。
- Number父类中提供的6个共性方法。
- parseXXX()静态方法(除了Character)。
- valueOf()静态方法。
- 注意:需保证类型兼容,否则抛出NumberFormatException异常。
- JDK 5.0之后,自动装箱、拆箱。基本数据类型和包装类自动转换。
- Number父类中提供的6个共性方法。
- parseXXX()静态方法(除了Character)。
- valueOf()静态方法。
- 注意:需保证类型兼容,否则抛出NumberFormatException异常。
- JDK 5.0之后,自动装箱、拆箱。基本数据类型和包装类自动转换。
整数缓冲区
- Java预先创建了256个常用的整数包装类型对象。
- 在实际应用当中,对已创建的对象进行复用。
- 在实际应用当中,对已创建的对象进行复用。
String类
- Java程序中的所有字符串文本(例如“abc”)都是此类的实例。
- 字符串字面值是常量,创建之后不可改变。
- 常用创建方式:
- String str1 = “Hello”;
- String str2 = new String(“World”);
- 字符串字面值是常量,创建之后不可改变。
- 常用创建方式:
- String str1 = “Hello”;
- String str2 = new String(“World”);
可变字符串
概念:可在内存中创建可变的缓冲空间,存储频繁改变的字符串
Java中提供了两个可变字符串类:
- StringBuilder:可变长字符串,JDK5.0提供,运行效率快、线程不安全。
- StringBuffer:可变长字符串,JDK1.0提供,运行效率慢、线程安全。
- 这两个类中方法和属性完全一致。
- StringBuilder:可变长字符串,JDK5.0提供,运行效率快、线程不安全。
- StringBuffer:可变长字符串,JDK1.0提供,运行效率慢、线程安全。
- 这两个类中方法和属性完全一致。
BigDeicmal
- 位置:java.math包中。
- 作用:精确计算浮点数。
- 创建方式:BigDecimal bd=new BigDecimal(“1.0”)。
- 作用:精确计算浮点数。
- 创建方式:BigDecimal bd=new BigDecimal(“1.0”)。
- 除法:divide(BigDecimal bd,int scal,RoundingMode mode)。
- 参数scale :指定精确到小数点后几位。
- 参数mode :
- 指定小数部分的取舍模式,通常采用四舍五入的模式。
- 取值为BigDecimal.ROUND_HALF_UP。
- 参数scale :指定精确到小数点后几位。
- 参数mode :
- 指定小数部分的取舍模式,通常采用四舍五入的模式。
- 取值为BigDecimal.ROUND_HALF_UP。
Date
- Date表示特定的瞬间,精确到毫秒。
- Date类中的大部分方法都已经被Calendar类中的方法所取代。
- 时间单位
- 1秒=1000毫秒
- 1毫秒=1000微秒
- 1微秒=1000纳秒
- Date类中的大部分方法都已经被Calendar类中的方法所取代。
- 时间单位
- 1秒=1000毫秒
- 1毫秒=1000微秒
- 1微秒=1000纳秒
Calendar
- Calendar提供了获取或设置各种日历字段的方法。
- protected Calendar() 构造方法为protected修饰,无法直接创建该对象。
- protected Calendar() 构造方法为protected修饰,无法直接创建该对象。
SimpleDateFormat
- SimpleDateFormat是以与语言环境有关的方式来格式化和解析日期的类。
- 进行格式化(日期 -> 文本)、解析(文本 -> 日期)。
- 进行格式化(日期 -> 文本)、解析(文本 -> 日期)。
System
System系统类,主要用于获取系统的属性数据和其他操作。
特殊字符
访问修饰符(从大到小)
public 公有的
protected 受保护的
default 默认
private 私有的
static 静态的
静态属性
通过类名直接调用
静态属性只有一份,多个对象调用同一份属性
静态方法
静态方法只能调用静态方法,通过类名直接调用
方法为工具方法,则会设置为静态方法
当方法中调用到类对象的属性则不能成为静态方法
静态方法只能调用静态属性,不可调用非静态属性
静态构造代码块
当调用构造方法创建对象或者调用静态属性或者调用静态方法都会先执行静态构造代码块
有且只执行一次
static 不能修饰构造方法
构造代码块
调用构造方法创建对象时,会优先于构造方法先执行
静态构造代码块 > 构造代码块 > 构造方法
静态构造代码块跟静态属性的优先级别一致,先加载先执行
final (最终的)
1、final 修饰的变量为常量,手动初始化。
2、final修饰的方法为最终方法,不能被子类重写,可以被重载。 不可修饰构造方法,不可修饰构造代码块
3、final修饰类,不可被继承
注:常量通常都会使用大写字母,用下划线拼接多个单词,与static一起使用为静态常量,一般当做是状态值使用。
this 当前类对象
this() 当前类对象的无参构造方法
在构造方法中
必须在第一行 && 不可与super同时用
this.属性名
super 当前类对象的父类
super() 当前类对象的无参构造方法
在构造方法中
必须在第一行 && 不可与this同时用
super.属性名
super.方法名()
面向对象
三大特征
封装
private 私有化属性
提供对应的set/get方法
继承
定义
多个类存在相同属性或方法
把相同的属性或者方法抽取到一个父类
其他类(子类)通过extends 继承父类,子类就存在父类的属性和方法
特点
1、子类能继承父类的所有属性和方法(除私有化)
2、类与类之间只能单继承,允许多层继承
3、子类不能继承父类的构造方法
4、每个子类的构造方法中默认存在super() ---初始化父类的属性
super 当前类对象的父类
super.属性名
super.方法名()
super() ...无参构造方法
super(参数列表) ...有参构造方法
注:在子类的构造方法中,this和super无法同时间调用构造方法,因为使用super调用父类的构造方法与this一样都必须在构造方法第一行
多态
对象行为的多种表现形态
同一个对象行为具有不同的实现形态或者是不同的形态
同一个方法,使用不同实例对象执行不同的操作
注意:上下转型,精度丢失,以及转型的可行性
向下转型
子类类名 对象名 =(子类类名)父类对象名
默认小转大
父类类名 对象名 = new 子类构造方法
多态中成员变量的访问特点
编译看左边,运行看左边。
对象类
普通类
构造方法
无参
有参
参数列表
特征
this
创建对象步骤
创建对象类(抽象)
属性(特征)
方法(行为)
创建对象(实例化对象)
数据类型 对象名 = new 类名()
对象名.属性
对象名.方法()
抽象类(abstract)
定义
模板
abstract
特点
1、abstract 修饰的方法为抽象方法,不存在方法体,必须在抽象类中
2、abstract 修饰的类为抽象类,存在抽象方法和普通方法
3、抽象类不能被实例化,但是存在构造方法,给子类调用初始化父类属性
4、抽象类可以没有任何抽象方法,唯一的作用就是不能被实例化
5、普通子类继承抽象父类,必须重写实现抽象方法;若继承类为抽象子类,可不重写父类抽象方法
子类继承extends
接口类(interface)
定义
功能的扩展
interface
特点
1、接口只能被类实现implements,在extends后面,不可被类继承
2、接口可以被类多个实现
3、接口不可实现接口,但可以继承,并且可以多继承
4、接口无构造方法,也不可实例化
5、属性默认公开静态常量
6、JDK1.8后,允许存在 static,default ,存在方法体
类实现接口implements
异常
错误(Error)
异常(Exception)
受检异常CheckedException(检查时异常)
编写时需要对其异常处理
非受检异常RuntimeException(运行时异常)
编译时不会报错,运行时才回报错
异常处理
try...catch...
1、正常请求
2、出现异常并处理
3、异常类型不匹配
try...catch...finally
1、finally块是否发生异常都执行,释放资源等
2、finally块不执行的唯一情况,退出java虚拟机
多重catch
1、子类异常在前,父类异常在后
2、发生异常时按顺序逐个匹配
3、只执行第一个与异常类型匹配的catch语句
4、finally根据需要可写或不写
try...finally
1、try...finally...不能捕获异常,仅仅用来当发生异常时,用来释放资源
2、一般用在底层代码,只释放资源不做异常处理,把异常向上抛出
声明异常 throws
其他
抛出异常
抛出异常 throw
自定义异常
1、需继承Exception或Exception的子类,代表特定问题
2、异常类型名称望文生义,可在发生特定问题时抛出对应的异常
集合
对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
集合和数组的区别
1、数组长度固定,集合长度不固定
2、数组可以存储基本类型和引用类型,集合只能存储引用类型
Collection
特点:代表一组任意类型的对象,无序、无下标。
遍历同时不能使用集合删除方法,否则出现并发修改异常,可使用迭代器的删除方法。]()
Iterator 迭代器
hasNext()
next()
remove()
Collections(工具类)
reverse() 反转
shuffle() 随机打乱顺序
sort() 升序排序
binarySearch() 二分查找
子接口
List
特点:有下标,元素可重复,extends Collection接口
ArrayList
1、数组结构实现
2、查询快,增删慢
3、线程不安全
ArrayList和LinkedList区别
1、ArrayList 存储结构是数组,查找、遍历效率高
2、LinkedList 存储结构是双向链表,删除、添加效率高
LinkedList
1、链表结构实现
2、增删快,查询慢
3、线程不安全
Vector
1、数组结构实现
2、查询快、增删慢
3、线程安全、运行效率比ArrayList较慢
stack 栈
1、后进先出,用完即删
Set
特点:无下标,元素不能重复【foreach循环遍历】
HashSet
底层 HashMap
1、基于HashCode实现元素不重复
2、当存入元素的哈希码相同时,会调用==或equals()进行确认,true不存,false存入
LinkedHashSet
链表实现的HashSet
TreeSet
底层 TreeMap,红黑树
元素必须实现Comparable接口,compareTo() 返回值为0,认为是重复元素
1、基于排列顺序实现元素不重复
2、实现SortedSet接口,对集合元素自动排序
3、元素对象的类型必须实现Comparable接口,指定排序规则(自然排序)
4、通过CompareTo() 确定是否为重复元素
自定义排序规则
【自然排序】实现Comparable接口,重写compare方法
【比较器】直接Comparator,重写compare(o1,o2)
Queue 队列
底层 双向链表
特点:
1、先进先出
2、用完即删
queue.poll() 获取列头
Stack 栈
底层 动态数组
特点:
1、后进先出
2、用完即删
stack.pop()
Map
key-value: 键不可重复,值可以重复
HashMap
1、线程不安全,运行效率快
2、允许用null作为key或value
3、存储结构: 哈希表
TreeMap
1、实现了SortedMap接口,可以对key自动排序
2、key必须实现Comparable或传递比较器对象
泛型
优点:
1、提高代码的重用性
2、防止类型转换异常,提高代码的安全性
特点
1、编译时即可检查,而非运行时抛出异常
2、访问时,不必类型转换(拆箱)
3、不同泛型之间引用不能相互赋值,泛型不存在多态
Hashtable
1、线程安全,运行效率慢
2、不允许null作为key或value
0 条评论
下一页