Object 类 1.概述: java.lang.Object类,是java的根类,也就是所有类的父类 2.构造方法: public Object(); 3.成员方法(总共11个): public String toString(); 默认返回的字符串格式为: 包名+类名+@+地址值 如果想返回不同格式的字符串,那么需要重写 public boolean equals(Object obj); 比较2个对象是否相等,默认比较的是地址值,如果想以不同的方式比较,需要重写
Date 日期类 1.概述: 表示日期对象,精确到毫秒值 2.构造方法: public Date(); 创建当前系统的日期对象 public Date(long mills); 创建以 标准基准时间为基准 指定偏移毫秒数 对应的时间对象 标准基准时间: 0时区: 1970-01-01 00:00:00 东八区:1970-01-01 08:00:00 3.成员方法: public long getTime(); 获取对应的毫秒值
DateFormat 日期格式化类 1.概述:DateFormat 是抽象类,无法直接创建对象,所以只能创建器子类对象 2.子类 SimpleDateFormat 类: 2.1 构造方法: public SimpleDateFormat(String partern); 创建一个日期格式化对象,指定格式化规则 常用规则: yyyy年MM月dd日 HH:mm:ss yyyy-MM-dd HH:mm:ss
2.2 成员方法: 格式化: 从Date类型 转换为 String类型 public String format(Date date); 解析: 从String类型 转换为 Date类型 public Date parse(String date);Calendar 日历类 1.概述: Calendar 表示日历类,也是一个抽象类,包含了很多的关于时间的信息 2.获取一个日历对象: public static Calendar getInstance(); 3.获取日历对象中的时间信息: public int get(int feild); field参数: Calendar类中的静态成员变量 格式: Calendar.xxxx 4.成员方法: 修改: public void set(int feild,int value); 增加: public void add(int feild,int value); 转换: public Date getTime();
System 类 1.概述: System 类主要提供的是关于系统相关的方法 2.成员方法: public static long currentTimeMillis(); 获取当前系统时间对应的毫秒值 public static void arraycopy(Object src,int srcPoc,Object dest,int destPoc,int length)
StringBuilder 可变字符串类 1.概述: StringBuilder 表示可变字符串 2.构造方法: public StringBuilder(); public StringBuilder(String str) 3.成员方法: public StringBuilder append(…); 拼接 public String toString(); public StringBuilder reverse();反转 public StringBuilder insert(int index,数据类型 变量名);
包装类 略 基本数据类型 对应 包装类 自动拆箱 自动装箱
*基本类型直接与””相连接即可;如:34+""
*String转换成对应的基本类型
public class Demo18WrapperParse { public static void main(String[] args) { int num = Integer.parseInt(“100”); } }
集合特点:
1.概述:集合可以存储多个引用数据类型的数据 2.集合的大小是不固定的 3.集合中的元素类型可以不一致,建议一致 4.集合中存储的是引用数据类型的数据 集合的体系: 单列集合: Collection集合: 单列集合的顶层接口,定义了所有单列集合共有的方法 List集合: 元素存取有序,元素有索引,元素可以重复 ArrayList Vector LinkedList Set集合:元素存取无序,元素无索引,元素不可以重复(元素唯一) HashSet LinkedHashSet TreeSet 双列集合: Map集合: 双列集合的顶层接口,定义了所有双列集合共有的方法 HashMap LinkedHashMap TreeMap Collection集合: 单列集合共有的方法 public boolean add(E e); public boolean remove(E e); public int size(); public boolean contains(Object obj); public void clear(); public boolean isEmpty(); public Iterator iterator(); 获取迭代器 遍历Collection集合: 获取迭代器:使用Collection集合中的 iterator()方法 遍历: 判断集合中是否有元素可以迭代: 使用迭代器Iterator的hashNext()方法 获取元素: 使用迭代器Iterator的 next()方法 泛型: 泛型: 代表一种未知的数据类型,一般是在定义类,接口,方法的时候指定泛型,然后在使用的时候确定泛型的具体数据类型 泛型类的定义 修饰符 class 类名<E>{ } 泛型类的使用:什么时候确定泛型的具体数据类型 ======> 创建该类对象的时候确定泛型的具体数据类型 泛型接口的定义 修饰符 interface 接口名<E>{ } 泛型接口的使用:什么时候确定泛型的具体数据类型 1.创建实现类的时候确定 实现类: public class 实现名 implements 接口名<具体数据类型>{ } 2.创建实现类的时候不确定,直到创建实现类对象的时候确定 实现类: public class 实现名<E> implements 接口名<E>{ } 泛型方法的定义: 修饰符 <E> 返回值类型 方法名(参数列表){ } 泛型方法的使用: 什么时候确定泛型的具体数据类型 =====>调用方法的时候确定 泛型的通配符: 作为方法的参数的时候,不能确定泛型的具体数据类型,这个时候就可以使用泛型通配符 ?来表示 1.基本使用: ? 2.高级使用: 上限: ? extends 类名 下限: ? super 类名List集合:
1.特点: 元素存取有序,元素有索引,元素可以重复 2.常用方法: 增删查改 public void add(int index,E element); 在指定位置添加元素 public E remove(int index); 删除指定位置上的元素,返回被删除的元素 public E get(int index); 获取指定位置上的元素 public E set(int index,Element);修改指定位置上的元素,返回被修改的元素 3.List集合的实现类: ArrayList:数组存储结构 查询快,增删慢,线程不安全 Vector:数组存储结构 查询快,增删慢,线程安全 LinkedList:链表存储结构 查询慢,增删快 特有方法: 跟头和尾有关的方法 addFirst(E element); addLast(E element); removeFirst(); removeLast(); getFirst(); getLast(); pop(E e); 弹出第一个元素(删除第一个元素) push(E e); 在首位添加一个元素 Set集合: 1.主要使用的是Colleciton集合中的方法 public boolean add(E e); public boolean remove(E e); public int size(); public boolean contains(Object obj); public void clear(); public boolean isEmpty(); public Iterator iterator(); 获取迭代器 2.特点:元素存取无序,元素无索引,元素唯一 3.实现类: HashSet:哈希表存储结构,由哈希表保证元素唯一 LinkedHashSet: 元素存取有序,哈希表+链表的存储结构,由链表保证元素存取有序,由哈希表保证元素唯一 TreeSet:可以对集合元素进行排序,二叉树的存储结构,由二叉树保证元素唯一,以及对元进行排序 4.HashSet集合保证元素唯一的原理: 1.首先存储元素,会调用元素的hashCode()方法,计算该元素的哈希值 2.判断该哈希值对应的位置上是否有相同哈希值的元素 3.如果该位置上没有相同哈希值的元素,那么就直接存储 4.如果该位置上有相同哈希值的元素,那么就产生了哈希冲突 5.如果产生了哈希冲突就会调用元素的equals()方法,来判断该元素与该哈希值位置上的所有元素进行一一比较: 如果该位置上的所有元素没有一个元素与该元素相等,那么就直接存储 如果该位置上有任意一个元素与该元素相等,那么就不存储 5.HashSet集合存储自定义类型的对象:需要重写hashCode()和equals()方法 因为Object类中的hashCode()方法是根据地址值计算哈希值, equals()方法默认比较的是地址值,所以需要重写这2个方法,让其根据 对象的所有属性计算哈希值以及比较对象是否相等 Collecitons工具类: public static <T> boolean addAll(Collection<? super T> col,T... element); public static void shuffle(List<?> list); public static <T> void sort(List<T> list); 默认规则排序 默认规则: 在集合元素所属的类中指定,怎么指定---元素所属的类实现Comparable接口,在compareTo()方法中指定默认规则 public static <T> void sort(List<T> list,Comparator<? super T> comparator); 指定规则排序 指定规则: Comparator接口对象中的compare()方法中指定 前减后 升序 后减前 降序Map<K,V>集合:
1.概述:双列集合的顶层父接口,定义了所有双列集合共有的方法 K:代表键的类型,V:代表值的类型 2.共有的方法: ----> 提示的时候,知道方法的功能,怎么调用 V put(K k,V v); 往集合中添加键值对元素,如果键存在,那么就会覆盖 添加\修改 V remove(K k);根据指定的键删除该键对应的键值对 V get(K k);根据键找值 boolean containsKey(K k);判断是否包含指定的键 boolean containsValue(V v);判断是否包含指定的值 int size();统计map集合键值对的个数 Set<K> keySet();获取map集合中所有的键 Colleciton<V> values();获取map集合中所有的值 Set<Map.Entry<K,V>> entrySet();获取所有的键值对对象 3.Map集合的特点: 3.1 Map集合是以键值对的形式存储元素 3.2 Map集合键的唯一,值可以重复,如果键重复了就会覆盖 3.3 Map集合根据键找值 4.Map集合的遍历 方式一:根据键找值的方式 1.使用keySet()方法获取所有键的集合 2.遍历所有键的集合,拿到每一个键 3.使用get()方法根据键找值 方式二:根据键值对对象的方式 1.使用entrySet()方法获取所有键值对对象的集合 2.遍历所有键值对对象的集合,拿到每一个键值对对象 3.使用Entry里面的getKey()和getValue()方法,获取键和值 总结: 集合体系图: 单列集合: 单个单个元素存储 Collection接口:是单列集合的顶层接口,定义了所有单列集合共有的方法 List接口: 元素存取有序,元素有索引,元素可以重复 ArrayList实现类:查询快,增删慢,线程不安全 Vector实现类:查询快,增删慢,线程安全 LinkedList实现类:查询慢,增删快 Set接口:元素存取无序,元素无索引,元素不可以重复 HashSet实现类: 元素存取无序,元素无索引,元素不可以重复 LinkedHashSet实现类:元素存取有序,元素无索引,元素不可以重复 由链表保证元素存取有序 TreeSet实现类: 元素存取无序,元素无索引,元素不可以重复,按照指定的规则进行排序 双列集合: 一对一对的存储 Map接口: HashMap实现类 LinkedHashMap实现类 TreeMap实现类 元素为单个单个,并且元素重复: ArrayList 元素为单个单个,并且元素不重复: HashSet 元素为一对一对: HashMap异常:
1.概述: 程序运行期间出现的不正常情况,导致程序终止运行 2.特点: 异常本身就是一个类,只要发生异常就会创建一个异常对象,该对象会封装异常的信息 3.如何在方法中抛出一个异常? 使用throw关键字,格式: throw 异常对象; 4.如何处理一个异常 4.1 使用throws关键字声明处理异常 仅仅只是提示调用者需要处理该异常 4.2 使用try...catch捕获处理异常 格式: try{ 可能会发生异常的代码 }catch(Exception e){ 处理异常的代码\打印一次的信息 }finally{ 一般正常情况永远都会执行,所以一般用来释放资源 } 进程:是正在进行的程序 1.是系统进行资源分配和调用的独立单位 2.每一个进程都有它自己的内存空间和系统资源 线程:是进程的单个顺序的控制流,是一条执行路径 1.单线程:一个进程如果只有一条执行路径,则称为单线程程序 2.多线程:一个进程如果有多条执行路线,则称为多线程程序 4.3 注意事项: 1.try不能单独使用 2.catch中的代码只有try中发生了异常才会执行,而finally中的代码正常情况永远都会执行 多线程: 1.多线程并发:多条线程同时请求执行,但是在一个时间段内只能交替执行 2.多线程并行:多条线程同时请求执行,在同一个时刻多条线程同时执行 3.java中多线程的调度: 抢占式调度 4.java程序就是一个进程,所以在java中只有多线程并发 5.java程序至少会有2条线程,一条主线程,一条垃圾回收线程线程的创建和启动:
1.线程的创建方式一:通过继承Thread类的方式 1.1 创建一个子类继承Thread类 1.2 重写run()方法,把多线程需要执行的任务放入run()方法中 1.3 创建该子类的对象调用start()方法来启动线程 2.线程的创建方式二: 通过Runnable接口的实现类的方式 2.1 创建一个实现类实现Runnable接口 2.2 重写run()方法,把多线程需要执行的任务放入run()方法中 2.3 创建Thread类的对象,并传入实现类的对象 2.4 使用Thread类的对象调用start()方法来启动线程 3.线程的创建方式三: 通过Runnable接口的匿名内部类的方式 3.1 直接创建Thread类的对象,传入Runnable接口的匿名内部类 3.2 匿名内部类中重写run()方法,把多线程需要执行的任务放入run()方法中 3.3 调用start()方法启动线程 4.线程的执行: 4.1 线程的调度:抢占式调度 4.2 线程的执行都会有一块独立的栈空间 5.Thread类的方法: Thread() Thread(String name) Thread(Runnable runnable) Thread(Runnable runnable,String name) public String getName(); public static Thread currentThread(); public static void sleep(long millis); public void run(); public void start(); 线程的安全: 线程安全问题: 多个线程同时操作同一资源,就有可能出现数据不安全的问题 解决线程安全问题:同步机制 同步代码块: 概述:对一段代码进行加锁 格式: synchronized(锁对象){ 代码... } 注意: 锁对象可以是任意类的对象 多个线程需要实现同步,那么必须保证这多个线程的锁对象一致 同步方法: 概述:对一个方法进行加锁 格式: 返回值类型前面加上 synchronized 注意: 静态同步方法: 锁对象是该静态方法所在的类的字节码文件对象 类名.class 非静态同步方法: this Lock锁: public void lock();加锁 public void unlock();释放锁 线程的状态: 新建---可运行---锁阻塞---无限等待---计时等待---死亡状态 新建: 线程刚创建,还没调用start()方法启动 可运行: 线程可能在运行,也可能不在运行 锁阻塞: 线程视图获取锁对象,但是没有获取到 无限等待: 使用了锁对象调用wait()方法,该线程就会进入无限等待状态,只能等另一个线程使用同一个锁对象调用了notify()或者notifyAll()方法进行唤醒 计时等待: 设定了等待的时间(使用Thread类的sleep()方法指定睡眠时间,使用wait(long mills)指定睡眠时间) 死亡状态: 线程已执行了run()方法,或者异常终止了 线程状态的切换: 计时等待: 通过Thread类的sleep()方法使得线程进入计时等待,时间到了,线程就继续往下执行 通过锁对象的wait(long mills)方法使得线程进入计时等待: 时间到了: 时间到了,获取到了锁对象,进入可运行状态 时间到了,没有获取到了锁对象,进入锁阻塞状态 时间没有到,被唤醒了: 获取到锁对象,进入可运行状态 没有获取到锁对象,进入锁阻塞状态 无限等待: 通过wait()方法进入无限等待,等待其他线程调用notify()或者notifyAll()方法唤醒 注意: 1.使用相同的锁对象调用wait()方法和notify()以及notifyAll()方法 2.线程的执行是抢占式执行 3.线程进入无限等待之后,被唤醒了,并且获取到了锁对象,那么就会从唤醒的位置继续往下执行...线程间的有效通信: 其实就是多个线程之间有规律的去执行
等待唤醒机制实现线程间的有效通信: 1.使用锁对象调用wait()方法让线程进入无线等待 2.使用锁对象调用notify()或者notifyAll()方法让线程进入唤醒状态 注意: 1.调用wait()和notfiy()以及notifyAll()方法的锁对象要一致 2.线程的调度是抢占式调度 3.当线程进入了无限等待,那么该线程就不会抢占锁对象,和cpu资源 4.线程如果从无限等待状态被唤醒了,那么当抢到锁对象,就会继续从进入无限等待的位置继续往下执行 线程池: 线程池的作用:让线程可以得到重复利用 创建线程池指定初始化线程: Executors工厂类: public static ExecutorService newFixedThreadPool(int nThreads); 提交任务: ExecutorService接口: submit(Runnable runnable);提交任务 线程池的关闭: ExecutorService接口: shutDown(); Lambda表达式: 使用前提: 有且仅有一个抽象方法的接口(函数式接口) 标准格式: (参数列表)->{代码...} 1.小括号中的内容和函数式接口中的抽象方法小括号中的内容一致 2.大括号中其实就是实现函数式接口抽象方法的方法体 省略格式: 1.小括号中参数的类型可以省略 2.如果小括号中的有且仅有一个参数,那么小括号也可以省略 3.如果大括号中有且仅有一条语句,那么大括号,return,以及分号都可以一起省略 三个线程之间的有效通信: A线程: 打印abcd B线程: 打印ABCD C线程: 打印1234 多个线程想要实现同步,多个线程必须加同一把锁 --->实现线程安全 实现有效通信: 让A,B,C线程交替执行 如果A线程在执行,那么BC线程就只能进入无线等待,然后A执行完了,就得唤醒所有等待线程 如果B线程在执行,那么AC线程就只能进入无线等待,然后B执行完了,就得唤醒所有等待线程 如果C线程在执行,那么AB线程就只能进入无线等待,然后C执行完了,就得唤醒所有等待线程 如果A线程执行完毕,那么必须让B线程抢到,即使AC抢到也得进入无限等待 B执行完之后,唤醒所有线程,必须让C线程抢到,即使AB抢到了也得进入无限等待 C执行完之后,唤醒所有线程,必须让A线程抢到,即使BC抢到了也得进入无限等待 A线程执行完毕,那么必须让B线程抢到,即使AC抢到也得进入无限等待IO的概述: 输出和输入是以内存为基准
I:Input 输入 从硬盘读写数据到内存中 O:Output 输出 从内存读写数据到硬盘中 IO的分类: 根据数据的流向分为:输入流和输出流。 - 输入流 :把数据从其他设备上读取到内存中的流。 字节输入流:以字节为单位,读取数据,顶层父类:InputStream 字符输入流:以字符为单位,读取数据,顶层父类:Reader - 输出流 :把数据从内存 中写出到其他设备上的流。 字节输出流:以字节为单位,写出数据,顶层父类:OutputStream 字符输出流:以字符为单位,写出数据,顶层父类:Writer 格局数据的类型分为:字节流和字符流。 - 字节流 :以字节为单位,读写数据的流。 字节输入流:以字节为单位,读取数据,顶层父类:InputStream 字节输出流:以字节为单位,写出数据,顶层父类:OutputStream - 字符流 :以字符为单位,读写数据的流。 字符输入流:以字符为单位,读取数据,顶层父类:Reader 字符输出流:以字符为单位,写出数据,顶层父类:Writer 结论: IO流中的字节流和字符流的顶层父类都是抽象类 字节流: 字节输出流: 写出数据 概述:java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。 成员方法: - public void close() :关闭此输出流并释放与此流相关联的任何系统资源。 - public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。 - public abstract void write(int b) :将指定的字节输出流。 一次写出一个字节数据 - public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。 - public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。 注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源。 由于OutputStream字节输出流是一个抽象类,不能直接创建对象,所以得创建器子类对象: FileOutputStream:OutputStream抽象类的子类 概述:类是文件输出流,用于将数据写出到文件。 构造方法: FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。 FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。 参数name: 代表路径 参数append: 如果指定为true,代表写出的数据是拼接到文件的末尾; 如果指定为false,代表写出的数据是覆盖文件中原有的数据 注意事项: 无论使用哪个构造方法创建字节输出流对象,假设指定的路径文件不存在,那么都会自动创建一个空文件字节流:
FileInputStream:字节输入流,从文件中读取字节数据到内存中 构造方法: 指定文件路径不存在,会报文件找不到异常 FileInputStream(String path) FileInputStream(File path) 成员方法: void close(); 关闭流,释放资源 int read();一次读取一个字节数据,返回的是读取到的字节数据,如果读取到了文件的末尾返回-1 int read(byte[] bys);一次读取一个字节数组长度的字节数据,把读取到的字节数据存储在字节数组中 返回的是读取到的有效字节个数,如果读取到了文件的末尾返回-1 FileOutputStream:字节输出流,从内存写出字节数据到文件中 构造方法: 指定文件路径不存在,会创建一个空文件 默认是覆盖,指定参数为true,就是拼接 FileOutputStream(String path) FileOutputStream(String path,boolean append); FileOutputStream(File path) FileOutputStream(File path,boolean append) 成员方法: void close(); 关闭流,释放资源 void write(int byte);一次写一个字节数据 void write(byte[] bytes);一次写一个字节数组长度的字节数据 void write(byte[] bytes,int off,int len);一次写一个指定范围的字节数组长度的字节数据 字符流: 字符输入流: FileReader:以字符为单位,读取数据 从文件中读取字符到内存中 构造方法: 如果指定的文件路径不存在,那么会报文件找不到异常 FileNotFoundException FileReader(String path) FileReader(File path) 成员方法: - public void close() :关闭此流并释放与此流相关联的任何系统资源。 - public int read(): 从输入流读取一个字符。 如果读取到文件的末尾返回-1 - public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。 如果已到达流的末尾,则返回 -1 字符输出流: FileWriter: 以字符为单位,写出数据, 从内存中写出字符到文件中 构造方法: 指定文件路径不存在,会创建一个空文件 默认是覆盖,指定参数为true,就是拼接 FileWriter(String path) FileWriter(String path,boolean append); FileWriter(File path) FileWriter(File path,boolean append) 成员方法: - public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。 - public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。 - public void write(int c) :写出一个字符。 - public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。 - public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。 - public void write(String str) :写出一个字符串。 应用: 拷贝文件 一次读写一个字节拷贝文件 一次读写一个字节数组拷贝文件 一次读写一个字符拷贝文件 一次读写一个字符数组拷贝文件 IO流核心思路: 1.创建输入流的对象,封装数据源文件路径 2.创建输出流的对象,封装目的地文件路径 3.定义一个变量用来存储读取到的数据 4.循环读取数据 5.写出数据 6.关闭流,释放资源 处理IO异常: jdk7以前 jdk7 jdk9 Properties类: 构造方法: Properties(); 成员方法: void load(InputStream inputStream);加载配置文件中的数据到Properties对象中 String getProperty(String key); Set<String> stringPropertyNames(); setProperty(String key,String value);缓冲流:
字节缓冲流: 特点读写数据高效 字节缓冲输入流:BufferedInputStream 字节缓冲输出流:BufferedOutputStream 字符缓冲流:特点读写数据高效,读取一行,根据系统写出换行 字符缓冲输入流:BufferedReader 字符缓冲输出流:BufferedWriter 特殊: String readLine(); 读取一行数据 void newLine();根据系统写出换行 转换流: 特点指定编码进行读写数据 InputStreamReader类: 指定编码读取数据 Reader的子类 构造方法 InputStreamReader(InputStream in);按照平台默认编码读取数据 InputStreamReader(InputStream in,String charsetnames);指定编码读取数据 OutputStreamWriter类: 指定编码写出数据 Writer的子类 构造方法 OutputStreamWriter(OutputStream os);按照平台默认编码写出数据 OutputStreamWriter(OutputStream os,String charsetnames);指定编码写出数据 序列化流: ObjectOutputStream 写出对象: writeObject(Object obj) 反序列化流: ObjectInputStream 读取对象: readObject(); 打印流:PrintStream 构造方法 PrintStream(String path); 成员方法: println(xxx); print(xxx);网络编程三要素:ip,端口号,协议
TCP通信程序:建立连接 在Java中,提供了两个类用于实现TCP通信程序: 1. 客户端:java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。 2. 服务端:java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接。 两端通信时步骤: 1. 服务端程序,需要事先启动,等待客户端的连接。 2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。 Socket类: 1.查看包:java.net 2.概述:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。 3.构造方法: Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。 参数:host 代表服务器的IP地址 port: 服务器端的端口号 如果服务器和客户端程序都在本机上,那么ip地址可以指定为127.0.0.1 4. 成员方法: - public InputStream getInputStream() : 返回此套接字的输入流。 - 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。 - 关闭生成的InputStream也将关闭相关的Socket。 - public OutputStream getOutputStream() : 返回此套接字的输出流。 - 如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。 - 关闭生成的OutputStream也将关闭相关的Socket。 - public void close() :关闭此套接字。 - 一旦一个socket被关闭,它不可再使用。 - 关闭此socket也将关闭相关的InputStream和OutputStream 。 - public void shutdownOutput() : 禁用此套接字的输出流。 - 任何先前写出的数据将被发送,随后终止输出流。 ServerSocket类: 1.查看包:java.net 2.查看类的解释说明:此类实现服务器套接字。 3.构造方法: ServerSocket(int port) 创建绑定到特定端口的服务器套接字。 参数:端口号 1024-65535之间 4.成员方法: Socket accept() 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。 案例1:TCP网络程序:客户端写出字符串数据给服务端 1.创建一个客户端类,一个服务端类 服务端: 1.创建ServerSocket对象,指定端口号 2.调用accept()方法等待请求,建立连接,返回Socket对象 3.通过建立连接返回的socket对象获取输入流 4.读取数据 5.关闭流,释放资源 客户端: 1.创建Socket对象,指定服务器的ip地址和端口号 2.通过Socket对象获得输出流对象 3.使用输出流写出数据 4.关闭流,释放资源 案例2:TCP网络程序:服务端回写字符串数据给客户端 服务器: 1.通过Socket对象获取输出流对象 2.写出数据 3.关闭流,释放资源 客户端: 1.通过Socket对象获取输入流对象 2.读取数据 3.关闭流,释放资源 案例3:模拟文件上传 模拟文件上传: 客户端: 1.创建Socket对象,指定需要连接的服务器的端口号8888 2.创建一个输入流对象,封装数据源文件路径 3.通过Socket对象,获取输出流对象,关联连接通道 4.定义字节数组变量,用来存储读取到的字节数据 5.循环读取数据 6.写出数据 7.释放资源 服务端: 1.创建ServerSocket对象,指定端口号 2.调用accept()方法,建立连接,返回socket对象 3.使用socket对象获取输入流对象 4.创建输出流对象,封装目的地文件路径 5.定义字节数组变量,用来存储读取到的字节数据 6.循环读取数据 7.写出数据 8.释放资源 优化: 1.客户端上传完文件,也就是服务器接收完文件之后,应该回写信息给客户端(上传成功) 2.优化服务器生成的文件名: 服务器生成的文件名是固定的 变化 3.服务器只能上传一个文件结束了 4.服务器代码是单线程,如果有一个客户端上传了一个字节数比较大的文件,那么其余的客户端就得等待 案例4:模拟(b/s结构)服务器 模拟浏览器访问服务器页面的服务器代码: 1.创建ServerSocket对象,指定端口号为8888 2.调用accept()方法,接收请求,建立连接,得到socket对象 3.通过socket对象获取输入流对象 4.获取到浏览器的请求信息,得到请求路径 5.创建一个输入流对象,封装index.html文件的路径 6.通过Socket对象获取输出流对象 7.创建字节数组变量,用来存储读取到的字节数据 8.循环读取数据 9.写出数据 10.释放资源 处理: 1.回写页面,需要先回写HTTP协议响应头,固定写法 2.回写页面中有图片,需要开启线程回写函数式接口
概述:有且仅有一个抽象方法的接口,可以适用于Lambda使用的接口 简而言之: 以后如果碰到一个接口是函数式接口,那么就可以使用Lambda表达式来表示该接口的对象 格式: 修饰符 interface 接口名称 { public abstract 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 } 注解标识函数式接口 函数式接口可以使用@FunctionalInterface注解来标识该接口是一个函数式接口, 如果该接口不是函数式接口,那么使用@FunctionalInterface注解标识就会报错 如果该接口是函数式接口,那么使用@FunctionalInterface注解标识就不会报错,当然你可以不使用该注解标识 自定义函数式接口 案例1: 请定义一个函数式接口Eatable,内含抽象eat方法,没有参数或返回值。 使用该接口作为方法的参数,并进而通过Lambda来使用它。 函数式编程:强调的是做什么,而不是以什么形式做,大白话就是,直接给解决方案 函数式编程的体现:Lambda表达式 函数: 一套解决方案 Lambda表达式标准格式: (形参列表)->{代码...} Lambda表达式省略格式: 1.小括号中的参数类型可以省略 2.如果小括号中有且仅有一个参数,那么小括号也可以省略 3.如果大括号中有且仅有一条语句,那么大括号,分号,return语句可以一起省略 Lambda表达式的使用场景: 如果一个接口是函数式接口,那么就可以使用Lambda表达式来表示该接口的对象 案例2: 请定义一个函数式接口 Sumable,内含抽象sum方法,可以将两个int数字相加返回int结果。 使用该接口作为方法的参数,并进而通过Lambda来使用它。 方法的引用 应用场景: 如果Lambda表达式指定的解决方案就是调用另一个方法,那么就可以使用方法引用直接把该方法引入过来,从而替换Lambda表达式 如果Lambda表达式指定的解决方案就是在另一个方法中已经实现了,那么就可以使用方法引用直接把该方法引入过来,从而替换Lambda表达式 注意: 能够使用Lambda表达式的地方,不一定可以使用方法引用来替换Lambda表达式 只要是函数式接口,那么就可以使用Lambda表达式表示,也可以使用方法引用表示 只有符合方法引用的应用场景的情况下,才会使用方法引用替换Lambda表达式,否则就使用Lambda表达式 方法引用: 使用双冒号 :: 可推导可省略 方法引用分类: 通过对象名引入成员方法: 对象名::方法名 通过类名引入静态方法: 类名::方法名 通过super引入父类的成员方法: super::方法名 通过this引入本类的成员方法: this::方法名 类的构造引用: 类名::new 数组的构造引用: 数组类型::new 通过对象名引入成员方法的应用场景:Lambda指定的解决方案是通过一个对象调用对象的成员方法 通过类名引入静态方法的应用场景: Lambda指定的解决方案是通过一个类名调用静态方法 通过super引入父类的成员方法的应用场景:Lambda指定的解决方案是通过super调用父类的成员方法 通过this引入本类的成员方法的应用场景:Lambda指定的解决方案是通过this调用本类的成员方法 类的构造引用 的应用场景:Lambda指定的解决方案是通过类的构造方法创建该类的对象 数组的构造引用 的应用场景:Lambda指定的解决方案是创建一个数组对象 常用函数式接口---应用 生产接口 演示方法引用写代码套路: 1.定义函数式接口 2.使用函数式接口作为方法的参数,调用抽象方法 3.调用有函数式接口参数的方法(传入Lambda表达式和方法引用) 演示常用函数式接口写代码套路: 1.使用常用函数式接口作为方法的参数,调用抽象方法 2.调用有常用函数式接口参数的方法(传入Lambda表达式和方法引用) 常用函数式接口:系统已经定义好了 Supplier<T>:生产接口 java.util.function.Supplier<T>接口仅包含一个无参的方法:T get() 使用生产接口的场景: 当需要获取一个对象的时候,就可以使用生产接口 消费接口 Consumer<T>消费接口: java.util.function.Consumer<T>接口则正好相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型参数决定。 抽象方法:accept Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。 默认方法:andThen 使用消费接口的场景: 当需要消费一个对象的时候,就可以使用消费接口 */ // 只要是函数式接口,那么就可以使用Lambda表达式表示,也可以使用方法引用表示Stream流:
概述:流式思想类似于工厂车间的“生产流水线”。 Stream流特点: 1.Stream流一定得搭建好模型,才能执行(也就是说一定要有终结的方法,才会执行) 终结方法:Stream流的方法的返回值类型不是Stream流 模型: 获取流-->操作流中的数据(延迟方法)--->得到结果(终结方法) ---->进行过滤筛选操作得到结果常见 模型: 获取流--->得到结果(终结方法) --->没意义 2.Stream流是单向的,不能重复使用 3.Stream流是有延迟性的,每一个操作延迟方法之后会得到一个新的流,除了终结的方法, 特点: 延迟方法想要执行,必须要调用终结方法 4.Stream流也是不能存储数据的 5.Stream流不会更改数据源 Stream流的使用步骤: 获取流--->调用延迟方法--->调用终结方法 作用: Stream流主要用于解决已有集合类库既有的弊端 获取流: 通过Collection集合获取 使用的是Collection集合中的 stream()方法 通过Map集合获取(其实通过map集合的所有键或者所有值,或者所有键值对对象获取) 通过数组集合获取 使用的是Stream流中的of(T... args); Stream流接口常用方法 - 终结方法:返回值类型不再是Stream接口自身类型的方法,终结方法包括count和forEach方法。 count方法: 统计流中元素的个数 long count(); forEach方法: 逐一处理 void forEach(Consumer<? super T> action); - 延迟方法:返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。) filter方法:将一个流转换成另一个子集流。方法签名: Stream<T> filter(Predicate<? super T> predicate); Predicate<? super T> 抽象方法: boolean test(T t); limit方法可以对流进行截取,只取用前n个 Stream<T> limit(long maxSize); skip方法跳过前几个元素,可以使用skip方法获取一个截取之后的新流: Stream<T> skip(long n); map方法: 流中的元素映射到另一个流中,可以使用map方法。方法签名: <R> Stream<R> map(Function<? super T, ? extends R> mapper); Function<? super T, ? extends R>:转换接口: R apply(T t) concat方法: 如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat: static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)常用的函数式接口:
Predicate<T>接口: 判断接口 1.应用场景:当我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate<T>接口。 2.抽象方法:test() boolean test(T t); 3.默认方法 and && or || negate ! Function<T,R>接口: 转换接口 从T类型的数据转换为R类型的数据 T,R类型可以一致也可以不一致 java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。 抽象方法:apply Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果 默认方法; andThen 生产接口: Supplier接口 T get();用来获取一个数据 Supplier接口的使用场景:当需要获取一个数据的时候,就可以使用该接口 消费接口: Consumer接口 void accept(T t);用来消费一个数据 Consumer接口的使用场景:当需要消费一个数据的时候,就可以使用该接口 默认方法: Consumer<T> andThen(Consumer<? super T> after); 源码: default Consumer<T> andThen(Consumer<? super T> after){ Objects.requireNonNull(after); return (T t)->{this.accept(t);after.accept(t);}; ====> one.accept(t); two.accept(t); } one.andThen(two).andThen(three).accept(t);====> one.accept(t); two.accept(t);three.accept(t);