内容有点长,建议收藏方便下次看
目录
4.String和StringBuilder拼接字符串性能对比
8.使用SimpleDateFormat解析字符串形式的日期时间
5.从JDK7开始提供了更简单的资源释放方案:try-with-resource
集合体系概述
1.集合体系结构
-
Collection(单列集合)
COllection是单列集合的代表,集合中的每个元素只有一个值
-
LIst
添加的元素有序、可重复、有索引
-
ArrayList
添加的元素有序、可重复、有索引
-
LinkedList
添加的元素有序、可重复、有索引
-
-
Set
添加的元素无序、不重复、无索引
-
HashSet
添加的元素无序、不重复、无索引
-
LinkedHashSet
添加的元素有序、不重复、无索引
-
-
TreeSet
添加的元素按照大小默认升序排序、不重复、无索引
-
-
-
Map(双列集合)
Map是双列集合的代表,集合中每个元素都是一个键值对,由一个键和一个值共同组成
-
HashMap
-
LinkedHashMap
-
-
TreeMap
-
Collection单列集合
1.Collection常用方法
Collection是单列集合的祖宗接口,里面定义的方法能够被所有单列集合集成使用。
返回值类型 | 方法名和参数列表 | 说明 |
---|---|---|
boolean | add(E e) | 将指定元素添加到集合中 |
int | size() | 返回集合中元素的个数 |
boolean | remove(Object o) | 从集合中删除指定元素 |
boolean | contins(Object o) | 判断集合中是否存在指定的元素 |
void | clear() | 删除集合中所有的元素(清空集合) |
boolean | isEmpty() | 判断集合是否为空 |
Object[] | toArray() | 将集合中所有的元素添加到一个Object类型的数组中 |
default<T> T[] | toArray(IntFunction<T>generator) | 将集合中所有的元素添加到一个指定类型的数组中 |
2.遍历方式
-
迭代器
-
迭代器是用来遍历数组的专用方式(数组中没有迭代器),在Java中用 Iterator 接口来表示迭代器。
-
获得Collection集合的迭代器对象
返回值类型 方法名和参数列表 说明 Iterator<E> iterator() 返回Collection集合的迭代器对象 -
Iterator接口中提供的遍历相关的方法
返回值类型 方法名和参数列表 说明 boolean hasNext() 判断集合中是还有下一个元素 E next() 获取当前位置的元素,并将迭代器对象指向下一个元素 -
使用while循环遍历集合
Iterator<String> it = c.iterator(); while (it.hasNext()) { String emelent = it.next(); System.out.println(emelent); }
-
it.next每次执行先找到下一个索引的元素,然后取出当前索引的元素赋值给element
-
-
-
增强for循环
增强for是一种可以直接遍历到容器每一个数据的语法形式,既可以遍历数组,也可以遍历集合。
-
增强for循环的语法形式
for(集合中元素的数据类型 变量名 :数组或者集合){
System.out.println(变量名);
}
增强for循环遍历集合,本质上就是迭代器遍历集合的简化写法。
-
-
Lambda表达式
-
Lambda表达式遍历的匿名内部类形式
需要借助于 forEach 方法来实现
方法签名 说明 default void for Each(Consumer <? super T>) action 结合Consumer类型的对象遍历集合 -
将匿名内部类形式改造成Lambda表达式写法
-
3.List系列集合的独有功能
-
Collection集合体系
-
Set系列集合没有索引,所以Set集合中的全部方法都是继承自Collection接口的,几乎没有独有方法。
-
而List系列集合是支持索引的,所以List系列集合中定义了一系列跟索引操作相关的办法。
-
-
List系列集合的独有方法
-
List系列集合有索引,所以Lsit接口中又定义了一组和索引操作相关的方法:
返回值类型 方法名和参数列表 说明 void add(int index,E element) 在指定索引位置插入元素 E remove(int index) 删除指定索引出的元素,返回被删除的元素 E set(int index ,E element) 修改指定索引处的元素,返回修改前的元素 E get(int index) 返回指定所引出的元素 List<E> subList(int formlndex, int tolndex) 返回指定索引区间内元素组成的子集合(包前不包后) List系列集合支持索引,并提供了根据索引作数据类型的方法,所以,List集合还可以使用索引进行遍历
-
Stream流
1.认识Stream流
-
Stream流
Stream流是从JDK8开始提供的一套新的API,位于java.util.stream包下,用来操作集合或数组中的数据。
-
使用Stream流的优势
-
Stream流大量结合了Lambda表达式的语法风格,代码更简洁,书写更简单
-
在大数据量下,使用Stream流的性能相对比较高
-
Stream流本身不存储任何数据,也不会修改原始集合中的数据
-
在使用Stream流处理数据的时候,关注的是每一步做什么,而不是具体怎么做
-
2.Stream流的常用方法
-
Stream流的工作流程
-
Stream流怎么学?
-
怎样从数据源创建出Stream流实例(获取Stream流)
-
获取单列集合的Stream流
Collection接口提供的方法 说明 default Stream<E> stream() 获取单列集合的Stream -
获取数组的Stream
Arrays工具类提供的静态方法 说明 public static <T>Stream<T> stream(T[] array) 获取数组的Stream流对象 Stream接口提供的静态方法 说明 public static <T> Stream<T> of (T … values) 获取数组的Stream流对象
-
-
Stream流有哪些中间方法
中间方法是用来处理Stream流中数据的,这些操作都是惰性执行的,只有调用了终结操作才会真正的执行。
Stream接口提供的常用中间方法 操作 Stream<T> filter(Predicate<? super T> predicate) 对流中的数据进行过滤 Stream<T>sorted() 对元素进行升序排序 Stream<T>sorted(Comparator<? super T> comparator) 按照指定规则排序 Stream<T>limit(long maxSize) 获取前几个元素 Stream<T> skip(long n) 跳过前几个元素 Stream<T> distinct() 去除流中重复的元素 <R>Stream<R> map(Function<? super T, ? extends R> mapper) 对元素进行加工,返回对应的新流 -
Stream流有哪些终结方法
一旦调用了终结方法,当前这条流的执行就结束了,不能再继续操作了。
-
遍历统计大类
Stream接口提供的常用遍历统计类终结方法 操作 void forEach(Consumer<? super T> action) 对流中运算后的元素执行遍历操作 long count(); 统计流运算后剩余元素的个数 Optional<T>max(Comparator<? super T> comparator) 获取流运算后剩余元素中的最大元素 Optional<T>min(Comparator<? super T>comparator) 获取流运算后剩余元素中的最小元素 Optional<T>reduce(BinaryOperator<T>accumulator) 将流中的多个数据转换成单个值 Optional<T>findFirst(); 获取流中的第一个元素 -
Stream流常用的终结方法—Optional对象
Optional对象中封装了流操作后的结果,如果流操作后没有结果,Optional中封装的是null
OPtional类提供的获取结果的常用方法 操作 public T get() 如果结果不为空,返回结果,否则抛出No value present异常 public T orElse(T other) 如果结果不为空,返回结果,否则返回other public void ifPresent(Consumer<? super T>action) 如果结果不为空,对结果执行action操作,否则什么都不做 public void ifPresentOrElse(Cibsumer<? super T> action, Runnable emptyAction) 如果结果不为空,对结果执行action操作,否则执行emptyAction操作 -
收集结果大类
目的是将Stream流处理后的结果数据收集到集合或者数组中。
Stream流:方便操作集合/数组的手段; 新的集合/数组:操作数据的目的
Stream接口提供的常用结果收集类终结方法 操作 <A> A[] toArray(IntFunciton<A[]> generator) 把流处理后的结果收集到一个指定的数组中 <R,A>R collect(Collector<? super T,A,R> collector) 把流处理后的结果收集到一个指定的集合中 怎样得到一个Collection对象?
Collectors工具类中提供了获取Collector对象的方法 操作 public static <T> Collector <T , ? , List<T>> toList() 把流处理后的结果收集到一个List集合中 public static <T> Collector <T , ? , Set<T>> toSet() 把流处理后的结果收集到一个Set集合中
-
-
枚举
枚举也叫枚举类,是Java中的一种特殊类型,用来在程序中罗列所有可能出现的对象。
例如:一年有四季,一年有12个月,一周有七天,交通信号灯有红绿黄三种颜色,这些都可以用枚举来表示。
1.定义枚举的语法格式
修饰符 enum 枚举类名{
罗列枚举类实例的名称,用英文逗号隔开,分号结尾
}
2.反编译后枚举的特征
public enum Season{
SPRING,SUMMER,AUTUMN,WINTER;
}
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season>{
public static final Season SPRING;
public static final Season SUMMER;
public static final Season AUTUMN;
public static final Season WINTER;
public static Season[] values();
public static Season valueOf(java.lang.String);
static{};
}
-
枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
-
枚举类的构造方法都是私有的(默认的无参数构造方法也是私有的),因此,灭聚类对外不能创建对象。
-
枚举都是最终类,不可以被继承
3.在枚举中的其他成分
-
枚举本质上是一个被final修饰的类,因此,类中有的成员枚举中也有。
-
由于枚举类的第一行只能罗列枚举常量值,因此,其他成员只能从第二行开始定义。
public enum Season{ SPRING("春天"),SUMMER();AUTUMN,WINTER; private String desc; Season(){ } Season(String desc){ this.desc = desc; } public String getDesc(){ return desc; } }
Compiled from "Season.java"
public final class Season extends java.Lang.Enum<Season>{
public static final Season SPRING;
public static final Season SUMMER;
public static final Season AUTUMN;
public static final Season WINTER;
public static Season[] values();
public static Season valueOf(java.lang.String);
static {};
}
包装类
1.包装类
-
包装类是四大类八种基本数据类型所对应的引用数据类型
-
集合的泛型不支持基本数据类型,只支持引用数据类型
基本数据类型 | 对应的包装类(引用数据类型) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
-
所有包装类中都提供了一个静态方法:valueOf,可以将基本数据类型的数据转换成对应的包装类
-
自动装箱:基本数据类型可以自动转换成包装类型
-
自动拆箱:包装类型可以自动转换成基本数据类型
2.包装类的常用操作
-
把字符串类型的数值转换成数值本身对应的数据类型。
Integer类提供的方法 作用 public static int parseInt (String s) throws NumberFormatException 将字符串形式的整数转换为int类型 public static Integer valueOf (String s) throws NumberFormatException 将字符串形式的整数转换为Integer类型 Double类提供的方法 作用 public static double parseDouble (String s) throws NumberFormatException 将字符串形式的小数转换为double类型 public static DoublevalueOf (String s) throws NumberFormatException 将字符串形式的小数转换为Double类型 -
如果要转换的数字字符串不是真是的结果类型,会报错:NumberFormatException;
StringBuilder
1.StringBuilder
-
StringBuilder是字符串构建者的有意思,在Java中用来创建可变的字符串对象;
-
StringBuilder的对象里的内容可以根据业务需求随时修改,不会每次都产生新的对象。
-
好处:在频繁修改字符串的场景下,StringBuilder比String效率更高,代码也更简洁。
2.StringBuilder的构造方法
构造方法 | 作用 |
---|---|
public StringBuilder() | 创建一个空的可变字符串对象,不包含任何内容 |
public StringBuilder(String str) | 创建一个制定初始内容是str的可变字符串对象 |
3.StringBuilder的常用方法
方法签名 | 说明 |
---|---|
public StringBuilder append (Object obj) | 将obj转换成字符串添加到字符串末尾,StringBuilder对象本身 |
public StringBuilder reverse () | 将字符串中的内容反转,并返回StringBuilder对象本身 |
public int length () | 返回StringBuilder对象中字符的个数 |
public String toString () | 将StringBuilder对象转换为String类型的对象 |
-
append方法和reverse方法返回的都是this对象本身,因此,支持链式编程,调用后接着调用方法
4.String和StringBuilder拼接字符串性能对比
String的性能:
StringBuilder的性能:
-
在频繁的拼接、修改字符串的场景下,建议使用StringBuilder,效率更高
-
如果只是少量的字符串处理,或者只是定义字符串的场景下,还建议使用String
BigDecimal
1.BigDecimal
-
BigDecimal是一个不可变的,能表示任意精度小数的类,主要用来解决Java中小数运算精度失真问题。
2.创建BigDecimal对象
构造方法 | 作用 |
---|---|
public BigDecimal (double val) | 将double类型的小数转换成BigDecimal对象 |
public BigDecimal (String val) | 将字符串表示的小数转换成BigDecimal对象 |
-
推荐方法
方法签名 说明 public static BigDecimal valueOf (double val) 将double类型的小数转换成BigDecimal对象
3.BigDecimal中常用的API
方法签名 | 说明 |
---|---|
public BigDecimal add (BigDecimal augend) | 加法 |
public BigDecimal subtract (BigDecimal subtrahend) | 减法 |
public BigDecimal multiply (BigDecimal multiplicand) | 乘法 |
public BigDecimal divide (BigDecimal divisor) | 除法 |
public BigDecimal divide (BigDecimal divisor,int scale, RoundingMode roundingMode) | 除法、可以控制精确保留几位小数 |
public double doubleValue () | 将BigDecimal对象转换回double类型 |
4.RoundingMode的舍入模式
RoundingMode中的方法 | 说明 |
---|---|
HALF_EVEN | 整数位若是奇数则四舍五入,若是偶数则五舍六入 |
DOWN | 去掉小数部分取整,也就是正数取左边,负数取右边,相当于向原点靠近的方向取整 |
HALF_UP | 四舍五入,负数原理同上 |
HALF_DOWN | 五舍六入,负数先取绝对值再五舍六入再负数 |
CEILING | 取右边最近的整数 |
FLOOR | 取左边最近的正数 |
System
1.System
-
System也是Java中的一个工具类,是系统的意思,代表运行当前程序的系统环境。
2.System类提供的常用方法
方法签名 | 说明 |
---|---|
public static void exit (int status) | 退出当前运行程序的JVM虚拟机 |
public static native void arraycopy (Object src, int srcPos, Object dest, int destPos , int length); | 将一个数组中的元素复制到另一个数组中 |
public static native long currentTimeMillis () | 获取当前系统的时间毫秒值 |
-
exit:(非零状态代码表示异常终止。)
-
arraycopy:(要复制的原数组,从元素索引哪个位置开始复制,目标数组,将原数组的数据放到目标数组的哪个位置,要复制几个元素)
3.时间毫秒值
-
指的是从1970年01月01日 00:00:00走到此刻的总秒数,通常是一个很大的数字;1s=1000ms。
4.获取时间毫秒的作用
-
统计一段程序的执行耗时。
public class Test{ public static void main(String[] args){ long begin = System.currentTimeMillis(); String s = ""; for(int i = 0; i<10000; i++){ s += "我爱你"; } long end = System.currentTimeMillis(); System.out.println("程序执行耗时:" + (end - begin)/ 1000.0 +"秒"); } }
JDK8之前传统的日期、时间
1.Date
-
Date是从JDK1.0版本就开始提供的用来表示日期时间的类。
2.Date类的构造方法
构造方法 | 作用 |
---|---|
public Date () | 创建一个代表此刻时间的Date对象 |
public Date (long date) | 创建一个代表指定毫秒值时刻的Date对象 |
3.Date类的常用方法
方法签名 | 作用 |
---|---|
public long getTime () | 获取Date对象对应的时间毫秒值 |
public void setTime (long time) | 修改Date对象记录的时间为指定毫秒值时刻对应的时间 |
4.SimpleDateFormat
-
SimpleDateFormat是DateFormat类的子类,是一个简单日期格式化类允许我们按照指定的格式处理日期时间数据。
5.日期时间格式在程序中的表达方式
6.使用SimpleDateFormat格式化日期
SimpleDateFormat的构造方法 | 作用 |
---|---|
public SimpleDateFormat () | 使用默认格式构造一个SimpleDateFormat对象,通常不用 |
public SimpleDateFormat (String pattern) | 使用指定格式构造一个SimpleDateFormat对象 |
7.格式化相关方法
方法签名 | 作用 |
---|---|
public final String format (Date date) | 将Datge对象格式化成字符串 |
public final String format (Object obj) | 将时间毫秒值格式化成字符串 |
8.使用SimpleDateFormat解析字符串形式的日期时间
-
解析相关的方法
DateFormat类提供的方法签名 | 作用 |
---|---|
public Date parse (String source) throws ParseException | 将字符串时间解析成日期时间对象 |
JDK8开始新增的日期、时间
1.为什么JDK8要新增日期时间API
2.LocalDate
-
JDK8开始提供的代表日期的类,其对象中包含了年、月、日、星期等数据。
-
获取LocalDate的对象
-
LocalDate中只有一个私有的有参数构造方法,因此不能直接通过构造方法创建对象。
-
-
可以使用一下静态方法获取LocalDate的对象:
静态方法签名 作用 public static LocalDate now () 获取系统当前时刻对应对的日期对象 public static LocalDate of (int year, int month, int dayOfMonth) 获取指定年月日时间对应的日期对象
-
LocalDate的常用API
获取信息相关的方法签名 | 说明 |
---|---|
public int getYear () | 获取日期中的年 |
public int getMonthValue () | 获取日期中的月,1-12 |
public int getDayOfMonth () | 获取日期中的日:一个月的第几天 |
public int getDayOfYear () | 获取日期是一年的第几天 |
public DayOfWeek getDayOfWeek () :返回值是枚举 | 获取日期是一周的第几天:1d.getDayOfWeek().getValue() |
修改相关的方法签名 | 说明 |
---|---|
public LocalDate withYear (int year) | 修改日期中的年,并返回新的日期对象 |
public LocalDate withMonth (int month) | 修改日期中的月,并返回新的日期对象 |
public LocalDate withDayOfMonth (int dayOfMonth) | 修改日期中的日,并返回新的日期对象 |
public LocalDate withDayOfYear (int dayOfYear) | 修改日期中的一年的第几天,并返回新的日期对象 |
加减、判断信息相关的方法名 | 说明 |
---|---|
plusYears、plusMonths、plusDays、plusWeeks | 把年、月、日、周信息增加多少,返回新的日期对象 |
minusYears、minusMohths、minusDays、minusWeeks | 把年、月、日、周信息减少多少,返回新的日期对象 |
isEqual、isBefore、isAfter | 比较两个日期是否相等、是否在前、是否在后,返回boolean值 |
3.LocalDateTime
-
JDK8开始提供的代表本地日期的类,其对象中包含了年、月、日、星期、时、分、秒、纳秒等数据。
-
获取LocalDateTime的对象
-
LocalDateTime中只有一个私有的有参数构造方法,因此不能直接通过构造方法创建对象。
-
-
可以使用以下静态方法获取LocalDateTime的对象:
静态方法签名 作用 public static LocalDateTime now () 获取系统当前时刻对应的日期时间的对象 public static LocalDateTime of (int year, Month month, int dayOfMonth, int hour , int minute , int second) 获取指定年月日时分秒对应对的日期时间对象
-
LocalDateTime的常用API
方法名 | 说明 |
---|---|
getYear、 getMonthValue、 getDayOfMonth、 getDayOfYear、 getDayOfWeek、 getMinute、 getSecond、 getNano | 获取年月日、时分秒、纳秒等 |
withYear、 withMonth、 withDayOfMonth、 withDayOfYear、 withHour、 withMinute、withSecond、 withNano | 修改某个信息,返回信息日期时间对象 |
plusYears、 plusMonths、 plusDays、 plusWeeks、 plhusHours、 plusMinutes、 plusSeconds、 plusNanos | 把某个信息加多少,返回新日期时间对象 |
minsYears、 minusMonths、 minusDays、 minusWeeks、 minusHours、 minusMinutes、 minusSecond、 minusNanos | 把某个信息减多少,返回新日期时间对象 |
isEqual、 isBefore、 isAfter | 比较两个时间是否相等、是否 在前、是否在后 |
4.DateTimeFormatter
-
DJK8开始提供的时间日期格式化器,用于JDK8新增时间的格式化和解析
-
获取DateTimeFormatter的对象
静态方法签名 | 作用 |
---|---|
public static DateTimeFormatter ofPattern (String pattern) | 获取指定日期时间格式的格式化器对象 |
-
DateTimeFormatter提供的格式化方法
方法签名 | 作用 |
---|---|
public String format (日期时间对象) | 使用格式化器对象格式化日期时间对象 |
-
LocalDate、LocalDateTime提供的格式化方法
方法签名 | 作用 |
---|---|
public String format (DateTimeFormmatter formatter) | 使用格式化器对象格式化日期时间对象 |
-
LocalDate提供的解析方法
方法签名 | 作用 |
---|---|
public static LocalDate parse (CharSequnence text, DateTimeFormatter formatter) | 使用格式化器对象解析字符串格式的日期为LocalDate对象 |
-
LocalDateTime提供的解析方法
方法签名 | 作用 |
---|---|
public static LocalDateTime parse (CharSequnce text, DateTimeFormatter formatter) | 使用格式化器对象解析字符串格式的日期时间为LocalDateTime对象 |
泛型
1.认识泛型
-
泛型
-
泛型是一种编程机制,允许在定义类、接口、方法的同时指定一个或多个类型参数(如:<E>),则相应的类、接口、方法分别被称为泛型类、反应接口、泛型方法,它们统称为泛型。
-
-
泛型的作用
-
在编译阶段约束类、接口、方法能操作的具体类型,并自动进行类型检查,这样可以避免强制类型转换及其可能出现的异常。
-
-
泛型的注意事项
-
泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这种现象就是泛型擦除。
-
泛型不支持基本数据类型,只能支持引用类型。
-
2.自定义泛型类
-
定义类的同时在类名后面制定了一个或多个类型参数的类就是泛型类。
-
定义泛型类的格式:
可见性修饰符 class 类名<类型参数,类型参数>{
}
-
类型参数可以是任意大写字母,常见的有E、T、K、V;分别代表:Element、Type、Key、Value。
-
作用:在编译阶段指定类中能操作的数据的类型。
3.自定义泛型接口
-
定义接口的同时在接口名后面指定了一个或多个类型参数的接口就是泛型接口。
-
定义接口的格式:
可见修饰符 interface 接口名<类型参数,类型参数>{
}
-
作用:让实现类在实现接口的时候指定实现类中能操作的数据的类型。
4.自定义泛型方法
-
定义方法的同时在返回值类型前面指定了一个或多个类型参数的方法就是泛型方法。
-
定义泛型方法的格式:
修饰符<数据类型,数据类型>返回值类型 方法名称 (形参列表){
}
-
方法的返回值类型、参数列表、方法内部一切使用类型的地方都可以使用类型参数。
-
作用:在方法的形参列表中使用类型参数,方法可以接收一切类型作为参数,使方法更具通用性。
5.泛型通配符、泛型上下限
-
泛型通配符:?
-
?可以使用泛型时代表一切类型。
-
E T K V等大写字母是在定义泛型时代表一切类型的。
-
-
泛型下限
泛型上下限 语法 说明 泛型上限 ?extends Number ?代表的类型必须是Number或者Number的子类(最多是Number) 泛型下限 ? super Number ?代表的类型必须是Number或者Number的父类(最少是Number) 注:List<?>代表List集合中可以存放一切类型,等价于List<? extends Object>
Map集合
1.认识Map集合
-
集合体系结构
-
Collection:单列集合,集合中的每个元素只有一个值
-
Map:双列集合,集合中的每个元素都是一个键值对,由一个键和一个值共同组成
-
-
认识Map集合
-
Map是双列集合的代表,集合中的每个元素都是一个键值对,由一个键和一个值共同组成
-
Map集合的每个元素 key=value 称为一个键值对/键值对对象/Entry对象,Map集合也被叫做"键值对集合"。
-
Map集合中的键不允许重复,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值。
-
-
Map集合的使用场景
{商品1=2, 商品2=1,商品3=2,商品4=3}
需要存储一一对应的数据时,就可以考虑使用Map集合来做
-
Map集合体系
-
Map系列集合的特点
-
HashMap:根据键无序、不重复、无索引
-
LinkedHashMap:根据键有序、不重复、无索引
-
TreeMap:按照键默认大小升序排序、不重复、无索引
-
2.常用方法
-
为什么要先学习Map的常用方法?
-
Map是双列集合的祖宗接口,里面定义的方法能够被所有双列集合继承使用。
-
-
Map接口中常用方法
方法签名 说明 V put (K key, V value) 添加元素 V get (Object key) 根据键获取对应的值 int size (); 获取集合中的元素(键值对)的个数 boolean containsKey (Object key) 判断集合中是否包含指定的键 boolean containsValue (Object value) 判断集合中是否包含指定的值 V remove (Object key); 根据键删除整个元素(键值对) boolean isEmpty (); 判断集合是否为空 void clear(); 清空集合
3.遍历集合
-
Map集合的遍历方式
-
键找值
先获取到Map的全部键的集合,再遍历键的集合,获取到每一个键,根据键取出对应的值。
-
获取全部键的集合
方法签名 说明 Set<K> keySet() 获取全部键的集合 -
根据键获取对应的值
方法签名 说明 V get (Object key) 根据键获取对应的值
-
-
键值对
先获取到Map集合的全部键值对的集合,再遍历键值对的集合,获取到每一个键值对,从键值对中分别取出键和值
-
获取全部键值对的集合
方法签名 说明 Set<Map.Entry<K , V>> entrySet() 获取全部键值对的集合 -
从键值对(Map.Entry<K , V>)中获取键和值
方法签名 说明 K getKey() 获取键值对对象中的键 V getValue() 获取键值对对象中的值
-
-
Lambda表达式
-
Lambda表达式遍历Map集合
Lambda表达式遍历Map集合跟Lambda表达式遍历Collection集合一样,也要借助于forEach方法实现。
Map接口中的方法签名 说明 default void forEach (BiConsunmer<? super K, ? super V> action) 结合Lambda表达式遍历集合 -
Lambda表达式遍历Map集合本质上就是键值对遍历的简化写法
-
-
Stream流
-
Stream流遍历Map集合
Map接口中没有提供获取Stream流的方法,想要用Stream流遍历Map集合,首先要将Map集合转换为Collection单列集合,在获取Collection单列集合的Stream流
-
能将Map集合转换成Collection集合的方法
方法签名 说明 Set<K> keySet () 获取全部键的集合 Collection<V> value () 获取全部值的集合 Set<Map.Entry <K , V>> entrySet 获取全部键值对的集合
-
-
4.集合的嵌套
-
集合的嵌套
-
集合的嵌套指的是集合中的元素又是一个集合。
-
-
集合嵌套的形式
-
List嵌套List
-
List嵌套Map
-
Map嵌套Last
-
Map嵌套Map
-
……
甚至嵌套的集合里面还可以继续嵌套集合
-
File类
1.存储数据的方案
-
变量
double money = 9999.9;
-
对象
String str = new String();
-
数组
int [] arr = new int[10];
-
集合
List <Student> list = new ArraysList<>();
这些数据都是记录在内存中的,内存中的数据在断电或者程序停止时会丢失
文件是非常重要的存储方式,文件中的数据保存在计算机硬盘中。即使断电,或者程序终止了,存储在硬盘文件中的数据也不会丢失。·
-
File
-
File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件、或是文件夹)。
注:File类只能对文件本身进行操作,不能读写在文件里面存储的数据。
-
-
IO流
-
用于读写数据的(可以读写文件,或网络中的数据…)
-
File类:代表文本
-
IO流:读写数据
-
2.创建对象
-
创建File类的对象
File类的构造方法 说明 public File (String pathname) 创建指向指定路径的文件对象 -
注意:
-
File对象既可以代表文件、也可以代表文件夹。
-
File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。
-
-
绝对路径、相对路径
-
绝对路径:从盘符开始
Flile File1 = new File("C:\Data\baby.txt");
-
相对路径:不带盘符,默认直接到当工程下的目录寻找文件
File file2 = new File("模块名\baby.txt")
3.常用方法
File类的常用方法 说明 public boolean exists() 判断文件对象指向的文件或文件夹是否存在 public boolean isFile() 判断当前文件对象指向的是否是文件 public boolean isDirectory() 判断当前文件对象指向的是否是文件夹 public String getName() 获取文件的名称(包含后缀) public long length() 获取文件的大小,返回字节个数,如果是文件夹,结果毫无意义 public String getAbsolutePath() 获取文件的绝对路径 public boolean makdirs() 创建一级或多级文件夹 public boolean delete() 删除文件或空文件夹 -
字符集
1.常见字符集介绍
-
ASCII字符集
-
1967年,ANSI(美国国家标准学会)推出了ASCII字符集(American Standard Code for Information Interchange):美国信息交换标准代码,作为计算机其其他设备的文本字符编码标准。
-
标准ASCII使用1个字节存储一个字符,首位是0,总共可表示128个字符,对美国人来说完全够用。
-
-
GBK(汉字内码扩展规范,国标)
-
汉字编码字符集,包含了2万多个汉字等字符,GBK中一个中文字符编码成两个字节的形式存储。 注意:GBK兼容了ASCII字符集。
-
-
Unicode字符集(统一码,也叫万国码)
-
Unicode字符集是国际组织于1991年发布的,可以容纳世界上所有文字、符号的字符集。
-
Unicode仅仅是一套字符集,最终还要编码成二进制才能将字符存储到计算机中。
-
UTF-32 :用4个字节32位表示一个字符
-
-
UTF-8
-
是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节 英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节。
注意:技术人员在开发时都应该使用UTF-8编码!
-
-
本节要点-TODO注意1中添加为什么会出现乱码
-
ASCII字符集:只有英文、数字、符号等,占1个字节。
-
GBK字符集:汉字占2个字节,英文、数字占1个字节。
-
UTF-8字符集:汉字占3个字节,英文、数字占1个字节。
注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。
注意2:英文,数字一般不会乱码,因为很多字符集都兼容了ASCII编码。
-
2.字符集的编码、解码操作
-
编码、解码
-
编码:将字符转换成计算机能够存储的二进制数据(字节)的过程。
-
解码:是编码的反向操作,将计算机中存储的二进制数据(字节)转换成肉眼可识别的字符(字符串)的过程。
-
-
Java的编码方案
String类的编码方法 说明 public byte[] getBytes() 使用平台的默认字符集将该String编码为字节数组 public byte[] getBytes(String charseName) 使用指定的字符集将该String编码为字节的数组 -
Java的解码方案
String类的构造方法 说明 public String(byte[] bytes) 使用平台的默认字符集解码字节数组来构造新的String public String(byte[] bytes,String charseName) 使用指定的字符集解码指定的字节数组来构造新的String
IO流
1.IO流
-
IO流
-
IO流,又被称为输入(Input)输出(Output)流,是用来读写文件或网络中的数据的。
-
-
IO流的应用场景
-
IO流的学习方法
-
先梳理清楚IO流的分类、体系
-
再逐个学习每种IO流的作用、用法
-
-
IO流的分类
-
按流程的方向分为:
-
-
按流中数据的最小单位分为:
-
整体来看,IO流共分为四大类:
-
字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
-
字节输出流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
-
字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
-
字符输出流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
-
2.字符流
-
IO流的体系
IO流相关的类都位于java.io包下
-
FileReader(文件字符输入流)
-
作用:以内存为基准,把文件中的数据以字符的形式读入到内存中。
-
作用:以内存为基准,把文件中的数据以字符的形式读到内存中。
FileReader类的构造方法 说明 public FileReader(String fileName)throws FileNotFoundException 创建字符输入流通道与源文件路径接通 public FileReader(File file)throws FileNotFoundException 创建字符输入流管道与源文件对象接通 FileReader类的方法 说明 public int read throws IOException 每次读取一个字符返回,如果没有数据可能会返回-1。 public int read(char [] cbuf)throws IOException 每次用一个字符数组去读取数据,返回字符数组读取了多少个字符,如果没有数据可读会返回-1。 public void close()throws IOException 关闭文件字符输入流管道 所有的流都是资源,用完后要记得调用close()方法进行关闭
-
-
FileWriter(文件字符输出流)
-
作用:以内存为基准,把内存中的数据以字符的形式写入到磁盘文件中。
-
作用:以内存为基准,把内存中的数据以字符的形式写入到磁盘文件中
FileWriter类的构造方法 说明 public FileWriter(String fileName)throws IOException 创建字符输出流管道与源文件路径接通 public FileWriter(String fileName,boolean append)throws IOException 创建字符输出流管道与源文件路径接通,可追加写入 FileWriter类的方法 说明 public void write(int c)throws IOException 写一个字符 public void write(String str)throws IOException 写一个字符串 public void write(char cbuf[])throws IOException 写一个字符数组 public abstract void close()throws IOException 关闭文件字符输出流管道
-
-
使用字符输出流的注意事项
-
字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
FileWriter类的方法 说明 public void flush()throws IOException 刷新流,作用是将内存中缓存的数据立即写出到磁盘文件中 public void close()throws IOException 关闭流,关闭之前先刷新流 -
在实际开发中,只要保证每次用完流都关闭,就一定能保证写出去的数据生效
-
4.try-catch-finally
-
finally代码块的特点:无论try中的程序正常执行了,还是出现了异常进入了catch代码块,最后都一定会执行finally代码块中的代码。
-
finally代码块的作用:一般用于在程序执行完成后进行资源的释放操作。
5.从JDK7开始提供了更简单的资源释放方案:try-with-resource
try(定义资源1; 定义资源2;…){
可能出现异常的代码
}catch(异常类名 变量名){
异常处理的代码
}
-
小括号中的资源使用完毕后,会自动调用close()方法,完成对资源的释放
-
try后面的 () 中只能放置资源,否则会报错
-
资源一般指的是最终实现了AutoCloseable接口的类产生的对象
6.文件字节输入流-读字节数据到内存
-
FileInputStream(文件字节输入流)
-
作用:以内存为基准,把文件中的数据以字节的形式读入到内存中
-
作用:以内存为基准,把文件中的数据以字节的形式读入到内存中。
FileInputStream类的构造方法 说明 public FileInputStream(String name)throws FileNotFoundException 创建字节输入流管道与源文件路径接通 public FileInputStream(File file)throws FileNotFoundException 创建字节输入流管道与源文件对象接通 FileInputStream类的方法 说明 public int read()throws IOException 每次读取一个字节返回,如果没有数据可读会返回-1。 public int read(byte b[])throws IOException 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果没有数据可读会返回-1。 public byte[] readAllBytes()throws IOException 一次性读取文件中的全部字节返回(从JDK9开始提供的) public void close()throws IOException 关闭文件字节输入流通道 每次读取一个字节、多个字节,遇到文件中有中文的时候,都可能出现乱码
-
7.缓冲流
对原始字节流进行增强,以提高字节流读写数据的性能。
原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池。
-
字节缓冲流
-
字节缓冲流的作用
-
-
字符缓冲流
-
字符缓冲流的作用
构造方法 说明 public BufferedReader(Reader in) 把原始的字符输入流包装成一个缓冲字符输入流,从而提高读数据的性能 public BufferedWriter(Writer out) 把原始的字符输出流包装成一个缓冲字符输出流,从而提高写数据的性能 -
字符缓冲输入流新增的功能:按行读
BufferedReader中的方法签名 说明 public String readLine()throws IOException 读取一行数据并返回,如果没有数据可读了,返回null -
字符缓冲输出流新增的功能:换行
BufferedWriter中的方法签名 说明 public void newLine()throws IOException 换行
-
多线程
1.线程
-
线程(Thread)是一个程序内部的一条执行流程
-
如果程序中只有条执行流程,那么这个程序就是单线程的程序
2.多线程
多线程是从硬件上实现的多条执行流程的技术,多条线程有CPU负责调度执行。
-
多线程的应用场景
-
QQ,微信等通信软件,京东、淘宝等购物软件背后都离不开多线程技术。
-
-
怎样在程序中创建出多条线程?
-
Java是通过 java.lang.Thread 类的对象来代表线程的。
-
3.多线程的创建方式一:继承Thread类
-
定义一个子类MyThread继承线程类java.long.Thread,并重写run()方法。
-
创建MyTread类的对象
-
调用线程对象的start()方法启动线程(线程启动后还是执行的run方法)。
-
多线程的注意事项:
-
启动线程必须调用start()方法,不能调用run()方法
-
如果直接调用run()方法会被当成普通方法执行,此时还是相对于单线程程序
-
-
不要把主线程任务放到启动子线程之前,否则看不到多线程的效果。
-
不要直接new Thread(),因为Thread类中默认的run()方法没有实际的业务代码,开启的线程没有意义。
-
注意:多线程第一种创建方式代码简单,但线程类继承了Thread类,不能再继承其他类了,不利于线程类功能的拓展。
4.多线程的创建方式二:实现Runnable接口
-
定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
-
创建MyRunnable任务对象
-
把MyRunnable任务对象交给Thread处理
Thread类提供的构造器 作用 public Thread(Runnable target) 将Runnable任务对象封装为Thread线程对象 -
调用线程对象的start()方法启动线程。
-
方法优缺点:
-
优点:任务类只是实现接口,可以继承其他类、实现其他接口,扩展性强。
-
缺点:需要多创建一个Runnable对象。
-
-
匿名内部类写法
Thread类提供的构造器 作用 public Thread(Runnable target) 将Runnable任务对象封装为Thread线程对象 -
可以创建Runnable的匿名内部类对象
-
再交给Thread线程对象
-
在调用线程对象的start()启动线程
-
5.多线程的创建方式三:实现Callable接口
-
创建任务对象
-
定义一个类实现Callable接口,重写call方法,封装要做的事情和要返回的数据
-
把Callable类型的对象封装成FutureTask对象(线程任务对象)
FutureTask类提供的构造器 作用 public FutureTask(Callable<V> callable) 将Callable对象封装为FutureTask对象
-
-
把线程任务对象封装成Thread对象(FutureTask最终实现了Runnable接口,本质上也是Runnable对象)
-
调用Thread对象的start方法启动线程
-
线程执行完毕后,通过FutureTask对象的get方法去获取线程任务执行的结果
FutureTask类提供的方法 作用 public V get()throws Exception 获取线程执行call方法返回的结果
6.Thread类的常用方法和构造器
Thread类的常用方法 | 说明 |
---|---|
public void run() | 线程的任务方法 |
public synchronized viod start() | 启动线程的方法 |
public final String getName() | 获取当前线程的名称,默认名称规则是:Thread-索引 |
public final synchronized void setName(String name) | 修改线程的名称 |
public static native Thread currentThread() | 获取当前正在执行的线程对象 |
public static native void sleep(long millis) | 让当前正在执行的线程休眠指定的毫秒后,再继续执行 |
Thread类的常用构造器 | 说明 |
---|---|
public Thread(String name) | 在创建线程的时候指定线程的名字 |
public Thread(Runnable target) | 将Runnable对象封装为线程对象 |
public Thread(Runnable target,String name) | 将Runnable对象封装为线程对象,并指定线程的名称 |
7.线程同步
-
线程安全
-
线程安全问题
-
多个线程,同时操作同一个贡献资源的时候,可能会出现业务安全问题。
-
-
-
线程同步
-
线程同步是线程安全问题的解决方案。
-
-
线程同步的核心思想
-
让多个线程先后一次访问共享资源,这样就可以避免出现线程安全问题。
-
-
线程同步的常见方案
-
加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能加锁进来。
-
-
方式一:同步代码块
思想:对访问共享资源的核心代码上锁,以此保证线程安全。
synchronized(同步锁对象){ 访问共享资源的核心代码 }
-
同步锁对象的注意事项
-
对于当前同时执行的线程来说,必须使用同一个同步锁对象,否则无效。
-
-
同步锁对象的使用规范
随便选择一个对象作为同步锁对象,好不好呢?
-
不好,因为会影响其他无关线程的执行。
同步锁对象的使用规范
-
建议使用共享资源作为锁对象
-
对于实例方法建议使用this作为锁对象。
-
对于静态方法建议使用字节码(类名.class)对象作为锁对象。
-
-
-
方式二:同步方法
修饰符 synchronized 返回值类型 方法名(形参列表){ 操作共享资源的代码 }
-
同步方法底层原理
-
同步方法底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
-
如果是实例方法:同步方法默认用this作为锁对象。
-
如果是静态方法:同步方法默认用类名.class作为锁对象。
-
-
同步代码块好还是同步方法好?
-
范围上:同步代码块锁的范围更小,同步方法锁范围更大
-
可读性:同步方法更好
-
-
-
方式三:Lock锁
Lock锁是JDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。
Lock是接口,不能直接被实例化,可以采用它的实现类ReentrantLock来构建Lock对象。
ReentrantLock类提供的构造器 作用 public ReentrantLock() 得到一个Lock锁的实现类对象 -
Lock接口的常用方法
方法签名 作用 public void lock() 获得锁 public void unlock() 释放锁 -
8.线程池
线程池是一个可以复用线程的技术
-
当前创建多线程的弊端
用户每次发起一个请求,就要创建一个新线程,而创建新线程的开销很大的,并且请求过多时,肯定会产生大量的线程,这样会严重影响系统的性能。
-
弊端1:用到线程的时候就创建一个新的
-
弊端2:用完之后就销毁当前线程
-
-
线程池
- 如何创建线程池
-
Java从JDK 5.0起提供了代表线程池的接口:ExecutorService
-
如何得到线程池对象?
-
使用ExecutorService的实现类ThreadPoolExecutor创建一个线程池对象
-
-
ThreadPoolExecutor的构造器
ThreadPoolExcutor类提供的构造器 作用 public ThreadPoolExecutor(int cirePookSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable>workQueue,ThreadFactory threadFactory,RejectedExcutionHandler handler) 使用指定的初始化参数创建用过一个新的线程池对象 参数一:corePoolSize:指定线程池的核心线程数量。
参数二:maximumPoolSize:指定线程池的最大线程数量。
参数三:keepAliveTime:指定临时线程的存活时间。
参数四:unit:指定临时线程存活的时间单位(秒,分,时,天)。
参数五:workQueue:指定线程池的任务队列。
参数六:threadFactory:指定线程池的线程工厂。
参数七:handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)。
-
-
线程处理Runnable任务
ExecutorService的常用方法 说明 void execute(Runnable command); 继承自Executor的方法,执行Runnable任务 <T>Future<T> submit(Callable<T> task); 执行Callable任务,返回未来任务对象,用于获取线程返回的结果 void shutdown(); 等全部任务执行完毕后,在关闭线程池! List<Runnable> shutdownNow(); 立刻关闭线程池,停止正在执行的任务,并返回队列中未执行的任务 通常情况下,线程池要一直运行,所以在实际开发中,关闭线程池的方法几乎不用
-
ExcutorService的常用方法
-
线程池的注意事项
-
什么时候开始创建临时线程?
-
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
-
什么时候拒绝新任务?
-
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
-
-
任务拒绝策略
策略 说明 ThreadPoolExecutor.AbortPolicy() 丢弃任务并抛出RejectedExeception异常。是默认的策略 ThreadPoolExecutor.DiscardPolicy() 丢弃任务,但不是抛出异常。这是不推荐的做法 ThreadPoolExecutor.DiscardOldestPolicy() 抛弃队列中等待最久的任务,然后把当前任务加入队列中 ThreadPoolExecutor.CallerRunsPolicy() 有主线程负责调用任务的run()方法从而绕过线程池直接执行
-
-
线程池处理Callable任务
-
ExecutorService的常用方法
ExecutorService的常用方法 说明 void execute(Runnable command); 继承自Executor的方法,执行Runnable任务 <T>Funture<T> submit(Callable<T> task); 执行Callable任务,返回未来任务对象,用于获取线程返回的结果 void shutdown*(); 等全部任务执行完毕后,再关闭线程池! List<Runnable> shutdownNow(); 立刻关闭线程池,停止正在执行的任务,并返回队列中未执行的任务
-
-
ThreadLocal
ThreadLocal并不是一个Thread,而是Thread的局部变量,称为线程局部变量。
ThreadLocal为每个线程都提供了一份单独的存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外不能访问。
-
获取ThreadLocal的对象
ThreadLocal的构造器 说明 public ThreadLocal() 创建一个没有初始值的ThreadLocal对象 ThreadLocal的静态方法 说明 public static <S>ThreadLocal<S> withInitial(Supplier<?extends S> supplier) 创建一个指定初始值的ThreadLocal对象 -
ThreadLocal的常用方法
ThreadLocal的常用方法 说明 public void set(T value) 设置当前线程的线程局部变量的值 public T get() 返回当前线程所对应的线程局部变量的值 public void remove() 移除当前线程的线程局部变量 -
ThreadLocal的应用场景
-
每个用户通过浏览器发起的请求都是一个独立的线程,此时,需要在同一个线程的三层之间共享当前线程的用户ID,该怎样实现呢?
-
ThreadLocal工具类
public class Context{ private static ThreadLocal<Long> threadLocal = new TreadLocal<>(); //设置当前线程的用户ID public static void setCurrentId(Long id){ threadLocal.set(id); } //获取当前线程的用户ID public static Long getCurrentId(){ return threadLocal.get(); } //移除当前线程的用户ID public static void remove(){ threadLocal.remove(); } }
-
-
Collections工具类
-
Collections
Collections是用来简化集合操作的工具类
-
Collection提供的静态方法
Collections类的常用静态方法 说明 public static <T>boolean addAll(Collection<?super T> c,T… elements) 向单列集合中批量添加元素 public static <T extends Comparable<?super T>>void sort(List<T> list) 对List集合中的元素升序排序 public static <T> void sort(List<T> list,Comparator<?super T>c) 对List集合中的元素按照指定规则排序 public static <T> List<T> singletonList(T o) 获取一个只有一个元素且不可改变的List集合 public static <K,V> Map <K,V> singletonMap(K key,V value) 获取一个只有一个元素且不可改变的Map集合 public static final <T> List <T> emptyList() 获取一个没元素且不可以改变的空List集合
反射
1.认识反射/获取类
-
反射(Reflection)
-
反射就是:在运行时加载类,并允许以编程的方式解析出类中的各种成分(成员变量、成员方法、构造器等)。
-
-
反射学什么?
学习获取类的信息、操作它们
-
反射第一步:加载类,获取类的字节码对象;class对象
获取Class对象的三种方式:
-
Class c1=类名.Class
-
调用Class提供的方法:public static Class forName(String package.类名)
-
Object提供的方法:public Class getClass(); Class c3 = 对象.getClass();
-
-
2.获取类的构造器:Constructor对象
-
Class类提供了从字节码对象中获取构造器对象的方法:
Class类的方法签名(不包括异常声明) 说明 public Constructor<?>[] getConstructors() 获取全部被public修饰的构造器 public Constructor<?>[] getDeclaredConstructors() 获取全部已声明的构造器,包括私有的 public Constructor<T> getConstructor(Class<?>… parameterType) 获取指定参数列表的被public修饰的单个构造器 public Constructor<T> getDeclaredConstructor(Class<?>… parameterType) 获取指定参数列表的单个构造器,即使私有的也能获取到 -
获取类的构造器的作用:初始化类的对象并返回
Constructor类的方法签名 说明 public T newInstance(Object … initargs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问权限(暴力反射)
3.获取类的成员变量:Field对象
-
获取类的成员变量
Class类的方法签名(不包括异常声明) 说明 public Field[] getFields() 获取全部被public修饰的成员变量 public Field[] getDeclaredFields() 获取全部已声明的成员变量,包括私有的 public Field getField(String name) 获取指定名称的被public修饰的单个成员变量 public Field getDeclaredField(String name) 获取指定名称的单个成员变量,即使有私有的也能获取到 -
获取类的成员变量的作用:
Field类的方法签名 说明 public Object get(Object obj) 取值 public void set(Object obj,Object value) 赋值 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问权限(暴力反射)
4.获取类的成员方法:Method对象
-
获取成员方法
Class类的方法签名(不包括异常声明) 说明 public Method[] getMethods() 获取全部被public修饰的成员方法 public Method[] getDeclaredMethods() 获取全部已声明的成员方法,包括私有的和继承自父类的 public Method getMethod(String name,Class<?>… parameterTypes) 获取指定名称和参数列表的被public修饰的单个成员方法 public Method getDeclaredMethod(String name,Class<?>… parameterTypes) 获取指定名称和参数列表的单个方法,即使私有的也能获取 -
获取类的成员方法的作用:把方法交给对象执行
Method类的方法签名 说明 public Object invoke(Object obj,Object… args) 把方法交给某个对象执行,并传递方法参数 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问权限(暴力反射)
学会基本使用后,再查看反射的作用和反射的应用场景
-
反射的作用
基本使用:
-
可以得到一个类的全部成分然后操作。
其他作用:
-
可以破坏封装性。
-
可以破坏泛型约束性。
-
最重要的用途是:适合做Java的框架,基本上主流的框架都会基于反射设计出一些通用的功能。
-
注解
1.概述、自定义注解
-
注解(Annotation)
-
注解是Java代码里@开头的特殊标记,比如:@Override、@FuncitonalInterface、@Data等,注解可以在编译时被编译器处理或在运行时被咱们编写的代码处理,以便对程序进行检查或执行特定的操作。
-
注解可以用在类、接口、构造器、方法、成员变量、参数等位置。
-
-
自定义注解
就是自己定义注解并使用。
public @interface 注解名称{
属性类型 属性名() [default 默认值];
}
-
注解中可以定义0到多个属性,属性的定义类似于抽象方法,默认值可选。
-
注解中的特殊属性:value
-
如果注解中只有一个value属性,或者注解中的其他属性都有默认值,使用注解时,属性名称value可以不写。
-
2.元注解
-
元注解指的是:在定义注解的类上方使用的注解。
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override{ }
-
@Target
作用:声明被修饰的注解只能在哪些位置使用
@Target(ElementType.TYPE)
-
TYPE,类,接口
-
FIELD,成员变量
-
METHOD,成员方法
-
PARAMETER,方法参数
-
CONSTRUCTOR,构造器
-
LOCAL_CARIABLE,局部变量
-
-
@Retention
作用:声明注解的保留周期
@Retention(RetentionPolicy.RUNTIME)
-
SOURCE
-
只作用在源代码阶段,字节码文件中不存在。
-
-
CLASS(默认值)
-
保留到字节码文件阶段,运行阶段不存在。
-
-
RUNTIME(开发常用)
-
一直保留到运行阶段。
-
-
-
3.注解的解析
-
注解的解析
-
就是判断类上、方法上、成员变量上是否存在注解,并把注解的内容给解析出来。
-
-
怎样解析注解
-
指导思想:要解析谁上面的注解,就该先拿到谁的对象。
-
如果要解析类上面的注解,则先获取该类的Class对象,再通过Class对象解析其上面的注解。
-
如果要解析成员方法上的注解,则先获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
-
Class、Method、Field、Constructor都实现了AnnotatedElement接口,因此他们都拥有解析注解的能力。
Class类的方法签名(不包括异常声明) 说明 Annotation[] getDeclaredAnnotations() 获取当前对象上面的所有注解 default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断当前对象上有没有指定的注解 default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) 根据注解的字节码对象获取指定的注解
-
动态代理
1.动态代理的设计思想
-
在不改变原始代码的基础上,对代码的功能进行增强。
-
代理是通过接口知道自己代理的对象有哪些行为的。
public interface Star{ String sing(String name); void dance(); }
2.动态代理的代码实现
-
如何为Java对象创建一个代理对象?
java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
Proxy类的静态方法签名 说明 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 获得一个实现了指定接口的代理对象 参数说明
-
参数一:用于指定用哪个类加载器,去加载生成的代理类
-
参数二:指定接口,这些接口用于指定生成的代理长什么样子,也就是有哪些方法
-
参数三:用来指定生成的代理对象要干什么事情
-
集合的原理
1.ArrayList集合的底层原理
-
Collection集合体系
-
List系列集合:添加的元素有序、可重复、有索引
-
ArrayList:有序、可重复、有索引
-
LinkedList:有序、可重复、有索引
底层采用的数据结构不同,应用场景不同
-
-
ArrayList集合内部的数据结构
ArrayList集合内部是基于数组实现的。
-
数组的特点
-
根据索引查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。
-
删除效率低:可能需要把后面很多的数据进行前移。
-
添加效率极低:可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组的扩容。
-
-
ArrayList集合添加元素的底层原理
-
利用无参构造器创建集合时,会在底层先创建一个默认长度为0的空数组:Object[] ElementData={};
ArrayList<String> list = new ArrayList<>();
-
添加第一个元素时,底层会创建一个新的长度为10的数组;接着将元素添加到数组的0号索引位置,并将size自增。
list.add("A"); list.add("B"); list.add("C");
-
-
ArrayList集合适合的应用场景
-
ArrayList底层是基于数组实现的,因此最适合根据索引查询数据的场景;
-
是数据量不大的情况下,使用ArrayList也是很合适的。
-
-
ArrayList集合不适合的应用场景
-
ArrayList集合不适合在数据量大的同时,又要频繁地进行增删改查操作的场景。
-
2.LinkedList集合及底层原理
-
LinkedList集合内部的数据结构
-
LinkedList集合内部是基于双链表实现的。
-
什么是链表?有什么特点?
-
链表是一种常见的数据结构,它是由一些列节点组成,每个节点包含数据值和下一个节点的地址。
-
在BD之间添加一个数据C
-
找到一块儿内存,创建数据C的节点
-
将节点C的下一个节点地址指向节点D
-
将节点B的下一个节点地址指向节点C
-
-
删除CE之间的节点D
-
将数据C的下一个节点指向E
-
将节点D删除
-
-
-
链表的特点一:查询慢,无论查询到哪个数据都要从头节点开始查找
-
链表的特点二:添加元素相对较快
-
链表的特点三:删除元素相对较快
-
什么是双链表?有什么特点
-
双链表的特点:查询慢,增删相对较快,但对收尾元素的操作是极快的。
-
-
-
-
LinkedList适合什么业务?
-
LinkedList底层是基于双链表实现的,而双链表对首尾数据的操作是极快的,因此,LinkedList尤其适合于需要频繁操作首尾元素的业务场景,并且LinkedList中也提供了很多操作首尾元素的API。
LinkedList类操作首尾元素的常用方法 说明 public void addFirst(E e) 将指定的元素插入到列表的开头 public void addLast(E e) 将指定的元素追加到列表的末尾 public E getFirst() 返回列表中的第一个元素 public E getLast() 返回列表中的最后一个元素 public E removeFirst() 从列表中删除并返回第一个元素 public E removeLast() 从列表中删除并返回最后一个元素
-
-
LinkedList的应用场景之一:设计栈(Stack)
-
栈的特点:先进后出,后进先出
-
数据进入栈的过程称为:进栈、压栈(push)
-
数据离开栈的过程称为:出栈、弹栈(pop)
只是首部增删元素,很适合用LinkeedList实现
-
-
LinkedList的应用场景之二:设计队列(queue)
-
队列的特点:先进先出,后进后出
-
数据进入队列的过程称为:入队(enqueue)
-
数据离开队列的过程称为:出队(dequeue)
只是在首尾增删元素,很适合用LinkedList实现
-
3.TreeSet集合的底层原理
-
TreeSet集合内部的数据结构
TreeSet集合内部是基于红黑树实现的。
什么是树?有什么特点?
-
二叉树
树是一种非线性数据结构,由节点和边组成。树由一个根节点开始,每个节点可以有零个或多个子节点,子节点又可以 有自己的子节点,以此类推。
-
二叉树中,任意节点的度<=2
-
度:每一个节点的子节点数量
-
树高:树的总层数
-
根节点:最顶层的节点
-
左子节点
-
右子节点
-
左子树
-
右子树
-
-
二叉查找树
-
在数据基本拍好顺序的情况下,二叉查找树会存在一个问题:
-
二叉树变成了一个类似于单链表的线性结构,查询性能大大降低。
-
-
平衡树
是一种特殊的二叉查找树,目标是在满足二叉查找树规则的前提下,让树尽可能的矮小,以此提高查数据的性能。
-
红黑树
-
是一种自平衡的二叉查找树,也是一种增删改查性能都较好的数据结构。
-
红黑树中的每一个节点要么是红色的,要么是黑色的。
-
红黑树不是通过高度实现平衡的,而是通过"红黑规则"实现的。
-
-
红黑规则:
-
每个节点要么是红色,要么是黑色。
-
根节点一定是黑色的。
-
每个叶子节点(NIL节点)都是黑色的。
-
如果一个节点是红色的,则它的子节点必须是黑色的(不存在两个相邻的红色节点)。
-
从任意节点到其每个叶子节点的所有简单路径上,都包含相同数目的黑色节点。
-
-
-
TreeSet集合存储自定义类型对象
TreeSet集合底层是基于红黑树实现的,数据存储到TreeSet时是需要进行排序的。
不同类型的数据分别是怎样排序的呢?
-
存储数值类型:Integer , Double,默认按照数值本身的大小进行升序排序
-
存储字符串类型:默认按照首字符的编号升序排序
-
存储自定义类型如Student对象,TreeSet默认是无法直接排序的。
自定义排序规则
TreeSet存储自定义类型对象时,必须指定排序规则,可以通过以下两种方式指定比较规则:
-
方式一
-
让自定义的类(如学生类)实现Comparable接口,重写compareTo方法指定比较规则。
-
-
方式二
-
通过调用TreeSet集合的有参数构造器,在构造器参数中设置Comparator比较器对象,在比较器对象中指定比较规则。
public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>( comparator)); }
-
TreeMap集合的底层原理
public TreeSet(){ this(new TreeMap<>()); }
-
从TreeSet的构造器可以看出,创建TreeSet对象的时候,本质上是在创建TreeMap的对象; 因此,TreeSet集合的底层原理本质上就是TreeMap集合的底层原理
public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); }
-
4.HashMap集合的底层原理
-
HashMap集合内部的数据结构
HashMap集合内部是基于哈希表实现的
哈希表是一种基于数组+链表+红黑树实现的增删改查性能都较好的数据结构。
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V>{ HashMap.TreeNode<K,V> parent; // red-black tree links HashMap.TreeNode<K,V> left; HashMap.TreeNode<K,V> right; HashMap.TreeNode<K,V> prev; boolean red; TreeNode(int hash,K key,V val,HashMap.Node<K,V> next){ super(hash,key,val,next); } }
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable,Serializable{ transient Node<K,V>[] table; static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash,K key,V value,Node<K,V> next){ this.hash = hash; this.key = key; this.value = value; this.next = next; } } }
-
HashMap集合内部的数据结构示意图
HashMap创建集合与添加元素的过程
-
利用构造器创建集合后,会创建一个指向null的空数组,数组名为table,加载因子为0.75
-
第一次添加元素时,调用resize()方法创建一个长度为16的数组并赋值给table
-
利用键的哈希值对数组长度取余,计算出键值对要存入的位置。
哈希值就是一个int类型的整数,Java中每个对象都可以调用hashCode()方法获取到一个哈希值。
同一个对象多次调用hashCode()方法返回的哈希值是相同的。 不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞)。
-
判断当前位置是否为null,如果为null,直接存入。
-
如果不为null,表示有元素,则调用键的equals方法比较
-
如果相等,则替换原来位置键值对中的值
-
如果不相等,则存入数组,新元素直接挂在老元素下方
-
-
当添加完元素后,数组中元素的个数大于阈值12(数组长度*加载因子),数组容量自动扩容为原来的2倍
-
扩容后,原来链表中的元素会重新分布到扩容后的数组中,因此,链表长度会自动缩短
-
-
当某个链表的长度等于8,并且此时数组长度大于等于64,会将当前链表转换成红黑树
红黑树是一种增删改查性能都较好的数据结构,整体来看,HashMap增删改查的性能都较好。
5.LinkedHashMap集合的底层原理
-
LinkedHashMap集合内部的数据结构
-
LinkedHashMap继承自HashMap,内部也是基于哈希表(数组+链表+红黑树)实现的。
-
但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
-
网络编程
1.网络通信三要素
-
网络编程
-
可以让设备中的程序与网络上其他设备中的程序进行数据交互的技术(实现网络通信)。
-
-
基本的通信架构
-
基本的通信架构有2种形式:CS架构( Client客户端/Server服务端 ) 、 BS架构(Browser浏览器/Server服务端)。
-
Client-Server(CS)架构
-
Browser-Server(BS)架构
无论是CS架构,还是BS架构的软件都必须依赖网络编程!
-
-
IP地址(设备在网络中的地址,是设备在网络中的唯一标识)
IP(Internet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标识。
目前,被广泛采用的IP地址形式有两种:IPv4、IPv6。
-
IPv4
-
IPv4是Internet Protocol version 4的缩写,它使用32位地址,通常以点分十进制表示。
-
-
IPv6
-
Pv6是Internet Protocol version 6的缩写,它使用128位地址,号称可以为地球上的每一粒沙子编号。
-
IPv6分成8段,每段每四位编码成一个十六进制位表示, 每段之间用冒号(:)分开,将这种方式称为冒分十六进制。
-
-
IP域名(Domain Name)
-
用于在互联网上识别和定位网站的人类可读的名称。 例如: www.baidu.com www.itheima.com
-
-
DNS域名解析(Domain Name System)
-
是互联网中用于将域名转换为对应IP地址的分布式命名系统。它充当了互联网的“电话簿”,将易记的域名映射到数字化的IP地址,使得用户可以通过域名来访问网站和其他网络资源。
-
-
公网IP、内网IP
-
公网IP:是可以连接到互联网的IP地址;
-
内网IP:也叫局域网IP,是只能组织机构内部使用的IP地址;例如,192.168. 开头的就是常见的局域网地址,范围为192.168.0.0--192.168.255.255,专门为组织机构内部使用。
-
-
本机IP
-
127.0.0.1、localhost:代表本机IP,只会寻找当前程序所在的主机。
-
-
IP常用命令
-
ipconfig:查看本机IP地址。
-
ping IP地址:检查网络是否连通。
-
-
InetAddress
-
代表IP地址
-
-
InetAddress的常用方法
InetAddress类的常用方法 说明 public static InetAddress getLocalHost() throws UnknownHostException 获取本机IP,返回一个InetAddress对象 public String getHostName() 获取该ip地址对象对应的主机名。 public String getHostAddress() 获取该ip地址对象中的ip地址信息。 public static InetAddress getByName(String host)throws UnknownHostException 根据ip地址或者域名,返回一个inetAddress对象 public boolean isReachable(int timeout) throws IOException 判断主机在指定毫秒内与该ip对应的主机是否能连通
-
-
端口(应用程序在设备中的唯一标识)
用来标记标记正在计算机设备上运行的应用程序,被规定为一个 16 位的二进制,范围是 0~65535。
-
端口分类
-
周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21)
-
注册端口:1024~49151,分配给用户进程或某些应用程序。
-
动态端口:49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。
-
-
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则报错。
-
-
协议(连接和数据在网络中传输的规则。)
-
通信协议
-
网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
-
为了让全球所有上网设备都能互联互通,需要指定一套统一的标准
-
-
开放式网络互联标准:OSI网络参考模型
-
OSI网络参考模型:全球网络互联标准。
-
TCP/IP网络模型:事实上的国际标准。
OSI网络参考模型 TCP/IP网络模型 各层对应 面向操作 应用层 应用层 HTTP、FTP、SMTP… 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发 表示层 应用层 HTTP、FTP、SMTP… 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发 会话层 应用层 HTTP、FTP、SMTP… 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发 传输层 传输层 UDP、TCP… 选择使用的TCP , UDP协议 网络层 网络层 IP… 封装源和目标IP 数据链路层 数据链路层+ 物理层 比特流… 物理设备中传输 物理层 数据链路层+ 物理层 比特流… 比特流… -
-
传输层的2个通信协议
-
UDP(User Datagram Protocol):用户数据报协议。
-
TCP(Transmission Control Protocol) :传输控制协议。
-
-
UDP协议
-
特点:无连接、不可靠通信。
-
不事先建立连接,数据按照包发,一包数据包含:自己的IP、端口、目的地IP、端口和数据(限制在64KB内)等。
-
发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的 。
-
-
TCP协议
-
特点:面向连接、可靠通信。
-
TCP的最终目的:要保证在不可靠的信道上实现可靠的数据传输。
-
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。
-
-
三次握手建立可靠连接
-
可靠连接:确保通信的双方收发消息都是没问题的(全双工)
-
-
四次挥手断开连接
-
目的:确保通信的双方收发消息都已经完成
-
特点:面向连接、可靠通信。
-
-
2.UDP通信程序
-
UDP通信模型
-
特点:无连接、不可靠通信。
-
不事先建立连接,发送端每次把要发送的数据(限制在64KB内)、接收端IP等信息封装成一个数据包,发出去就不管了。
-
-
UDP通信程序(发送端)
-
创建发送端的DatagramSocket对象
-
创建DatagramPacket数据包对象封装要发送的数据和接收端地址信息
-
调用DatagramSocket对象的send方法将数据包(DatagramPacket)发送出去
-
关闭DatagramSocket对象,释放资源
-
-
UDP通信程序(接收端)
-
创建接收端的DatagramSocket对象,并指定端口号
-
创建DatagramPacket数据包对象,用来接收数据
-
调用DatagramSocket对象的receive方法,传入DatagramPacket对象
-
打印接收到的信息,接收多少,打印多少
-
关闭DatagramSocket对象,释放资源
-
3.TCP通信程序
-
TCP通信模型
-
特点:面向连接、可靠通信。
-
通信双方事先会采用“三次握手”方式建立可靠连接,实现端到端的通信;底层能保证数据成功传给服务端。
-
Java提供了一个java.net.Socket类来实现TCP通信。
-
-
TCP通信程序(发送端)
-
创建发送端的Socket对象,同时指定接收端的IP和端口号
-
调用Socket对象的getOutputStream()方法得到字节输出流对象
-
调用流对象的write方法把数据发送出去
-
关闭流对象和Socket对象,释放资源
-
-
TCP通信程序(接收端)
-
创建接收端的ServerSocket对象,并指定端口号
-
调用accept()方法,等待客户端的连接,连接成功获得一个Socket对象
-
调用getInputStream()方法得到一个字节输入流对象
-
打印接收到的信息,接收多少,打印多少
-
关闭流对象和Socket对象,释放资源
-
4.TCP通信BS架构程序
-
HTTP协议规定的数据格式
-
HTTP协议规定:响应给浏览器的数据必须满足如下格式:
-