Java
Java基本语法
//先赋值在a再加 |
位运算
A = 0011 1100
B = 0000 1101
A&B(同1):0000 1100
A|B(1则1):0011 1101
~B:1111 0010
位计算:
<< *2
// >> /2
Scanner
Scanner scanner = new Scanner(System.in); |
Switch
Switch(data){ |
While
white(true){ |
do..while
//先执行后判断 |
结束循环
//跳出循环 |
可变参数
test(1,2) |
数组 – Arrays
int[] a=new int[9]; |
动态数组 – ArrayList
- 吵创建空参 – 默认长度为0
- 扩容为当前容量的1.5倍
//自定义类型的数组Objiect,<类型>和前面一样即可省略 |
多维数组
int a[][]=new int[2][2]; |
面向对象
//Student |
封装
1.私有(private)get/set
Student student=new Stuent(); |
修饰符
public
: 可以被任何类访问。private
: 只能在同一类中访问。protected
: 只能在同一类、同一包中的子类或不同包的子类访问。- 包默认(无修饰符):只能在同一包中访问。
Static
static属于类,非static属于对象
伴随类加载而加载
//静态 – 类名.方法直接调用
- 静态只能访问静态
代码块
//匿名代码块 --跟随对象产生 -- 使用:可赋初始值 |
String
1.Strin是java定义好的一个类。定义在java.lang包中,所以使用的时候不需要导包。
2.Java程序中的所有字符串文字(例如“abcdefg”),都被实为此类的对象。
3.字符串不可变,它们的值在创建后不能被更改
常用方法
- 字符串长度:
int length()
: 返回字符串的长度,即包含的字符数。- 索引访问字符:
char charAt(int index)
: 返回指定索引位置的字符。- 截取子字符串:
String substring(int beginIndex)
: 从指定索引开始截取子字符串。String substring(int beginIndex, int endIndex)
: 从指定索引范围内截取子字符串。- 比较字符串:
boolean equals(Object obj)
: 比较字符串内容是否相同。boolean equalsIgnoreCase(String str)
: 忽略大小写比较字符串内容是否相同。- 查找子字符串:
int indexOf(String str)
: 查找子字符串的第一次出现位置。int lastIndexOf(String str)
: 查找子字符串的最后一次出现位置。- 替换字符:
String replace(char oldChar, char newChar)
: 替换字符串中的字符。String replace(CharSequence target, CharSequence replacement)
: 替换子字符串。- 转换大小写:
String toLowerCase()
: 将字符串转换为小写。String toUpperCase()
: 将字符串转换为大写。- 去除空白字符:
String trim()
: 去除字符串前后的空白字符。- 分割字符串:
String[] split(String regex)
: 根据正则表达式将字符串分割为字符串数组。- 检查前缀和后缀:
boolean startsWith(String prefix)
: 检查字符串是否以指定前缀开始。boolean endsWith(String suffix)
: 检查字符串是否以指定后缀结尾。- 字符序列与字符串互转:
String valueOf(char[] data)
: 将字符数组转换为字符串。char[] toCharArray()
: 将字符串转换为字符数组。- **intern()**,首先会检查字符串常量池中是否有对应的字符串,如果存在则返回这个字符串的引用;否则会先将字符串添加到字符串常量池中,然后再返回这个字符串的引用
- 创建
String string1 = new String(); |
StringTable(串池/字符串常量池)
- 字面量方式为字符串赋值时 – 存在则复用,不存在不参加对象,在串池中创建,这是 Java 中的字符串驻留(String Interning)机制
保存在串池,记录串池里面的地址值
String a = "a"; |
- new字符对象
保存在堆里面,记录的是堆里面的地址值
拼接原理
- 没有变量 – 不产生多余对象,直接在串池拿取
如果有变量参与,每一行拼接的代码,都会在内存中创建新的字符串,浪费内存
JDK1.8之前 :拼接使用到 StringBuilder
变量 + 字符 = 产生两个对象(StringBuilder+String): 因为s1已经在串池,直接拿出来
例如
String c1 = "a";
String c2 = "b";
String c3 = "c";
String c4 = c1+c2+c3;
//产生四个对象,两个StringBuilder 和 两个 String (toString底层就是 new String)
//1.c1+c2,创建 StringBuilder 从 串池拿取数据进行拼接 tostring 生成 c1+c2 String对象
// (c1+c2)+c3,创建 StringBuilder 从 串池拿取(c1+c2)数据进行拼接 tostring 生成 (c1+c2)+c3 String对象
JKD1.8 ==> 系统会预估要字符串拼接之后的总大小,把要拼接的内容都放在数组中,此时也是产生一个新的字符串
比较
- == 比较的是地址
基本类型:比较的是具体的数据值
引用数据类型:比较的是地址值
- 字符串比较值
- 字符串遍历
String str = "辰呀CP"; |
拼接:会产生较多的字符串对象【+ 拼接一次产生一个对象】,影响内存
StringBuilder
- 可以看成一个容器,创建之后里面的内容是可变的,不会使用串池
- 可使用链式编程
- 默认容量 16,扩容 2倍+2,如果还不满足,则为实际的数据的长度
使用场景:拼接、反转
- 构造方法:
- 成员方法
StringJoiner
- 可以定义间隔符、前缀和后缀,方便拼接
- 构造方法:
- 成员方法
StringJoiner stringJoiner = new StringJoiner("-","[","]"); |
StringBuffer
扩容
扩容的逻辑就是创建一个新的 char 数组,将现有容量扩大一倍再加上2,如果还是不够大则直接等于需要的容量大小。扩容完成之后,将原数组的内容复制到新数组,最后将指针指向新的 char 数组。常用方法
StringBuffer append(xxx):拼接字符串 |
比较与总结
- String
- String是被final修饰的类,不能被继承;
- String实现了Serializable和Comparable接口,表示String支持序列化和可以比较大小;
- String底层是通过char类型的数据实现的,并且被final修饰,所以字符串的值创建之后就不可以被修改,具有不可变性。
- 面试题
面试题:String、StringBuffer和StringBuilder的异同?
相同点:底层都是通过char数组实现的
不同点:
- String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
- StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
- 如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。
面向对象
Person person = new Person(); // 创建一个Person类的对象
抽象类 - abstract
1.不能new 这个抽象类,只能靠子类去实现,约束!
2.抽象类中可以写普通方法
3.抽象方法必须在抽象类中
public abstract class chouxianglei{ |
接口 – interface
可以多继承多接口
作用:
1,约束
2,定义一些方法,让不同的人实现10–>1,接口中没有构造方法~
3.public abstract //void save();
4.public static final //int age=18;
5,接口不能被实例化
6.implements可以实现多个接口
7,必须要重写接口中的方法~
//接口中的所有的定义都是抽象的 public abstract |
继承 – extends
//单继承
//子类继承了父类,就会拥有父类的全部方法(共有),不需要定义,直接实例化子列进行方法的调用
1.Object类
//所有类默认继承Object类
2.Super
super注意点:
1.super调用父类的构造方法,必须在构造方法的第一个
2.super必须只能出现在子类的方法或者构造方法中!
3.super和this不能同时调用构造方法!
Vs this
代表的对象不同:
this:本身调用者这个对象
super:代表父类对象的应用
前提
this:没哟继承也可以使用
super:只能在继承条件才可以使用
构造方法
this();本类的构造
super():父类的构造!
//this 指向当前类 |
3.重写
重写:需要有继承关系,子类重写父类的方法!
1.方法名必须相同
2.参数列表列表必须相同
3.修饰符:范围可以扩大但不能缩小:public>Protected>Default>private
4.抛出的异常:范围,可以被缩小,但不能扩大;ClassNotFoundException–>Exception(大)
重写,子类的方法和父类必要一致;方法体不同!
①当父类和子类方法都是静态方法时,方法的调用只和左边定义的数据类型有关
//父类 |
①当父类和子类方法都是非静态 –>重写 父类的方法
//父类 |
多态
- JAVA 面向对象之多态
- 多态的弊端是不能访问子类的特有功能
多态注意事顶:
1.多态是方法的多态,属性没有多态
2.父类和子类,有联系类型转换异常!CLassCastException/
3。存在条件:继承关系,方法需要重写,父类引用指向子类对象!(Father f1 new Son();)
- 成员变量: 使用的是父类的
- 成员方法: 由于存在重写现象,所以使用的是子类的
- 静态成员: 随着类的加载而加载,谁调用就返回谁的
类型转换
判断 a instanceof A
JDK14:判断是否为A类型,是则转 : a instanceof A aa
类
内部类
- 内部类是定义在另一个类OuterClass内部的类。内部类可以访问其外部类的成员变量和方法
public class OuterClass { |
静态内部类
静态内部类是定义在另一个类内部,并使用关键字 static
修饰的内部类。它不依赖于外部类的实例,可以像独立的类一样使用。
public class OuterClass { |
局部内部类
局部内部类是定义在方法内部的类,它只在该方法内部可见
public class OuterClass { |
匿名内部类
- 匿名内部类是一种在声明和创建的同时定义类的方式,通常用于创建临时的、一次性的类实例
public class AnonymousInnerClassExample { |
定义了一个接口
Greeting
,它有一个greet
方法。然后,在main
方法中,我们使用匿名内部类创建了一个实现Greeting
接口的对象,并在匿名内部类中实现了greet
方法。我们没有显式地声明一个具体的类,而是直接在创建对象的同时定义了它。
public class TestLambdal { |
遍历
迭代器遍历
迭代器在java中的类是Iterator,迭代器是集合专用的遍历方式。
- 一次性,想要一次遍历后复位,需要重新创建迭代器
Collection<String> collection = new ArrayList<>(); |
为什么使用
- 遍历统一性:迭代器提供了一种统一的遍历方式,无论是遍历集合、列表、集还是映射,都可以使用相似的迭代器接口。这使得代码更具通用性和可维护性。
- 避免并发问题:在多线程环境下,使用迭代器可以帮助防止并发问题。迭代器通常在创建时绑定到特定集合,因此多个线程可以同时使用不同的迭代器遍历集合,而不会出现冲突。
- 支持删除操作:迭代器通常提供了安全的删除元素的方法,允许在遍历过程中从集合中删除元素而不会破坏遍历的状态。这是使用基本 for 循环时不容易实现的。
- 性能优势:对于某些集合实现,迭代器可能会更高效,特别是在遍历大型集合时。迭代器的内部实现可以针对特定集合类型进行优化。
- 保护封装性:使用迭代器可以隐藏集合的内部实现细节,从而提供更好的封装性。这使得集合类可以更灵活地修改其内部实现而不影响外部代码。
- 不需要索引:迭代器允许您遍历集合而无需关心索引或位置。这对于不支持随机访问的集合(如链表)非常有用。
增强循环
//for-Each 无下标 |
Lambda表达式
- 函数式接口
- 只有一个抽象方法
- 原写法
public class TestLambdal { |
- 推导lambda写法
public class TestLambdal { |
- 简化写法
public class TestLambda2 { |
总结:
lambada表达式只能有一行代码的情况下才能简化成一行,如果有多行,那么就用代码块包裹
前提是接口为函数式接口
多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号(a,b),
System
- 获取当前时间结点:currentTimeMillis
long start = System.currentTimeMillis() |
- 拷贝数组
System.arraycopy(数据源组,起始索引,目的地数组,起始索引,拷贝个数) |
正则表达式
.matches(“”)
{number}:出现次数
?:可有可无
[区间]
//获取正则表达式的对象 |
异常
使用throws抛出异常,则上一层方法要处理该异常,否则继续往上抛
例如:在实现类中不处理异常,选择往上抛,则接口要处理异常,如果不处理则要继续往上抛,直接抛到有人处理或者到顶层方法(main)处理,main不可继续往上抛
处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
在多重catch:块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
对于不确定的代码,也可以加上try-catch,处理潜在的异常
尽量去处理异常,切忌只是简单地调用printStackTrace()去打印输出
具体如何处理异常,要根据不同的业务需求和l异常类型去决定
尽量添加finally语句块去释放占用的资源
try - catch - finally – 捕捉并处理
(最高异常类型 Throwable 异常都可捕捉到)
//捕捉多个异常,异常类型从小到大
try{//监控区
//代码块
}catch(异常类型 e){
//异常处理代码模块--关闭/回滚
}catch(ArithmeticException e){//可捕捉多个异常
e.printStackTrace();
}finally{//处理后续工作(可无)
//释放资源
}
throw – throws 抛出异常不处理
//假设在这个方法中,处理不了这个异常,方法上抛出异常throws --在catch进行捕捉
public void test(int a,int b) throws ArithmeticException{
if(b==0){
throw new ArithmeticException();//主动抛出异常,一般在方法中使用--throw
}
}
自定义异常
//定义一个类继承Exception
public class CException extends Exception{
private int a;
public MyException(int a){
this.a=a;
}
//toString:异常的打印信息
public String toString(){
}
}
//使用
//方法中
throw new CException(a)
try{
}catch(CException e){
}
常用API
Date
//对象 |
Arrays
//将数组转为字符串 |
Collection
//Collection是一个接口,我们不能直接创建他的对象。且Collection是 list 和 set 的共性接口 |
List集合体系
- ArrayList:基于动态数组实现的List集合。
- LinkedList:基于双向链表实现的List集合。
- Vector:一个古老的同步(线程安全)的List实现,不太推荐使用。
- CopyOnWriteArrayList:一个线程安全的List,适合读多写少的情况。
ArrayList
- ArrayList 底层是基于数组实现的,ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
List<String> list = new ArrayList<>(); |
- 添加元素:
boolean add(E e)
:将元素添加到ArrayList的末尾。void add(int index, E element)
:在指定的位置插入元素。- 获取元素:
E get(int index)
:获取指定位置的元素。- 修改元素:
E set(int index, E element)
:将指定位置的元素替换为新元素。- 删除元素:
boolean remove(Object o)
:删除第一个匹配指定元素的项。E remove(int index)
:删除指定位置的元素。- 检查元素是否存在:
boolean contains(Object o)
:检查列表是否包含指定元素。boolean isEmpty()
:检查列表是否为空。- 获取列表大小和容量:
int size()
:返回列表中的元素数量。int capacity()
:返回ArrayList的当前容量。void ensureCapacity(int minCapacity)
:确保ArrayList的容量至少为minCapacity。void trimToSize()
:将ArrayList的容量调整为其当前大小。- 清空列表:
void clear()
:删除ArrayList中的所有元素。- 获取子列表:
List<E> subList(int fromIndex, int toIndex)
:获取指定范围的子列表。- 查找元素索引:
int indexOf(Object o)
:返回指定元素的第一个匹配项的索引。int lastIndexOf(Object o)
:返回指定元素的最后一个匹配项的索引。- 将ArrayList转换为数组:
Object[] toArray()
:将ArrayList转换为Object类型的数组。T[] toArray(T[] a)
:将ArrayList转换为指定类型的数组。
LinkedList
基于双向链表数据结构的列表
实现了List接口,LinkedList还额外实现了Deque接口,正因为 LinkedList 实现了 Deque 接口,所以LinkedList 还可以当作队列来使用。
LinkedList 支持列表操作,队列操作以及双端队列操作,因此可以用于多种不同的情况。
LinkedList<String> linkedList = new LinkedList<>(); |
常见操作:
- 添加元素:
add(element)
: 在链表末尾添加元素。addFirst(element)
: 在链表开头添加元素。addLast(element)
: 在链表末尾添加元素。- 获取元素:
getFirst()
: 获取链表的第一个元素。getLast()
: 获取链表的最后一个元素。get(index)
: 根据索引获取元素。- 遍历链表:
- 使用增强型 for 循环或迭代器遍历。
- 删除元素:
removeFirst()
: 删除第一个元素。removeLast()
: 删除最后一个元素。remove(index)
: 删除指定索引位置的元素。- 判断是否包含某个元素:
contains(element)
: 判断链表是否包含指定元素。- 获取链表的大小:
size()
: 获取链表的大小。- 清空链表:
clear()
: 清空链表中的所有元素。
Vector
- 支持线程安全的操作
Vector<String> vector = new Vector<>(); |
- 添加元素:
addElement(Object obj)
:将指定的元素添加到Vector的末尾。add(int index, Object element)
:在指定的位置插入元素。- 获取元素:
elementAt(int index)
:获取指定位置的元素。firstElement()
:获取第一个元素。lastElement()
:获取最后一个元素。- 修改元素:
set(int index, Object element)
:将指定位置的元素替换为新元素。- 删除元素:
removeElement(Object obj)
:从Vector中删除指定元素的第一个匹配项。removeElementAt(int index)
:删除指定位置的元素。clear()
:删除Vector中的所有元素。- 容量控制:
capacity()
:返回Vector的当前容量。ensureCapacity(int minCapacity)
:确保Vector的容量至少为minCapacity。trimToSize()
:将Vector的容量调整为其当前大小
CopyOnWriteArrayList
//1. |
CopyOnWriteArrayList 与 Vector
- Vector的存在add方法是synchronized的,效率比较低
- CopyOnWriteArrayList 的add方法不是同步方法,使用的是lock锁
Set集合体系
- HashSet:
java.util.HashSet
是Set接口的一个常见实现类,它使用哈希表来存储元素,不保证元素的顺序,而且不允许重复元素。由于哈希表的性质,HashSet的查找、插入和删除操作通常都具有很高的性能。- LinkedHashSet:
java.util.LinkedHashSet
是HashSet的子类,它保持了元素插入的顺序,可以用来实现有序的集合。LinkedHashSet在迭代时按插入顺序访问元素。- TreeSet:
java.util.TreeSet
是Set接口的另一个实现类,它基于红黑树(Red-Black Tree)实现,能够保持元素的自然顺序或根据指定的排序规则对元素进行排序。TreeSet是有序的,但要求元素必须是可比较的(实现了Comparable
接口或使用Comparator
进行比较)。
使用场景
HashSet
哈希值
对象的整数表现形式
1.如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
2.如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
3.但是在小部分情况下,不同硒属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
- 表示不包含重复元素的集合
// 创建一个HashSet |
- 添加元素:
boolean add(E e)
:向Set中添加元素,如果元素已存在,则不会重复添加。- 删除元素:
boolean remove(Object o)
:从Set中删除指定元素,如果元素存在且删除成功,则返回true。void clear()
:删除Set中的所有元素。- 检查元素是否存在:
boolean contains(Object o)
:检查Set中是否包含指定元素。boolean isEmpty()
:检查Set是否为空。int size()
:返回Set中的元素数量。- 遍历集合:
- Set接口不提供直接索引访问元素的方法,通常需要使用迭代器或转换为List等方式进行遍历。
- 集合操作:
boolean addAll(Collection<? extends E> c)
:将另一个集合中的所有元素添加到当前Set中。boolean removeAll(Collection<?> c)
:从当前Set中移除与另一个集合中相同的所有元素。boolean retainAll(Collection<?> c)
:保留当前Set中与另一个集合中相同的元素,删除其他元素。boolean containsAll(Collection<?> c)
:检查当前Set是否包含另一个集合中的所有元素。- 转换为数组:
Object[] toArray()
:将Set转换为Object类型的数组。<T> T[] toArray(T[] a)
:将Set转换为指定类型的数组。- 迭代器:
Iterator<E> iterator()
:返回用于迭代Set的迭代器。- 比较集合:
boolean equals(Object o)
:比较Set与另一个对象是否相等。int hashCode()
:返回Set的哈希码值。
LinkedHashSet
Set<Student> set = new LinkedHashSet<>(); |
TreeSet
- 和Collection的API类似
比较规则
public class Student implements Comparable<Student>{ |
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() { |
总结
Java Doc文档
/** |
泛型
约束:声明当前的指定类型,进行统一数据类型,方便代码编辑的时候进行代码检查,获取数据不需要强转了
1、泛型中不能写基本数据类型 – 使用包装类
2、指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
3、如果不写泛型,类型默认是Object
泛型类
public class MyArrayList<E> { |
泛型方法
public class ListUtil{ |
泛型接口
//1.实现类给出具体的类型 |
通配符
泛型不具备继承性,但是数据具备继承性
- 泛型里面写的是什么类型,那么只能传递什么类型的数据。
- 要想实现传递 子父类型,使用通配符
public class GenericDemo { |
枚举
- 枚举:用于表示一组有限的常量值
- 常量可以设置属性和定义方法
- 常量的属性实际就是 方法的属性,需要定义和构造、set和get
- 枚举类中,每个常量可以有自己的属性,如果不设置属性,外部获取的当前常量,则返回的值是当前常量的值,且不需要设置构造函数和get和set
枚举常量的构造函数不能使用
private
、public
、protected
或default
等访问修饰符,也不能显式声明为private
或public
方法。枚举常量的构造函数默认为private
,这意味着它们只能在枚举内部使用。这是因为枚举常量在枚举类之外不应该被直接创建或访问,而是由编译器隐式管理。
public enum RCode { |
RCode smsCodeGivecode = RCode.SUCC; |
数据结构
二叉树
遍历
①前序遍历:根 左 右
②中序遍历:左 根 右
③后序遍历:左 右 根
④层序遍历:一层一层的去遍历
平衡二叉树
规则:任意节点左右子树高度差不超过1
左旋
- 左旋:让出的给右节点
右旋
- 右旋:让出的给左节点
红黑树
规则
添加节点
Map
HashMap
存取位置不一致
默认创建长度为 16 加载因子为 0.75 的数组
Entry对象记录键值对
利用键计算哈希值决定存储索引
null则添加,key一样则覆盖,key不一样,出现哈希碰撞的话,
JDK8 之前:
- 新数据添加到数组中,而旧数据挂载在新数据下面,形成链表
- 在JDK 1.7中,HashMap的扩容机制是在扩容时将桶的数量翻倍
JDK8
- 新数据挂载在旧数据下面,形成链表,当链表长度超过 8 && 数组长度>64的时候,链表自动转为红黑树
- 遍历
1、获取全部键,再通过键获取值
HashMap<String, String> map = new HashMap<>(); |
2、
HashMap
常用的成员方法:
- **put(K key, V value)**:将键值对添加到
HashMap
中。如果键已存在,则新的值会替代旧值。- **get(Object key)**:根据键获取对应的值。
- **remove(Object key)**:根据键删除键值对。
- **containsKey(Object key)**:检查是否存在指定键。
- **containsValue(Object value)**:检查是否存在指定值。
- **size()**:返回
HashMap
中键值对的数量。- **isEmpty()**:检查
HashMap
是否为空。- **clear()**:清空
HashMap
中的所有键值对。- **keySet()**:返回包含
HashMap
所有键的集合。- **values()**:返回包含
HashMap
所有值的集合。- **entrySet()**:返回包含
HashMap
所有键值对的集合。- **putAll(Map<? extends K, ? extends V> m)**:将另一个映射的键值对添加到当前
HashMap
中。- **replace(K key, V newValue)**:替换键对应的值。
- **getOrDefault(Object key, V defaultValue)**:根据键获取对应的值,如果键不存在,则返回默认值。
- **computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)**:根据键计算值,如果键不存在,则执行提供的计算函数。
- **computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)**:根据键计算值,如果键存在,则执行提供的计算函数。
- **forEach(BiConsumer<? super K,? super V> action)**:对每个键值对执行指定操作。
HashTable
和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。
默认加载因子是 0.75
Hashtable的构造函数
// 默认构造函数。 |
Hashtable的API
synchronized void clear() |
LinkedHashSet
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(); |
TreeMap
- 比较规则
Map<String, String> map = new TreeMap<>(new Comparator<String>() { |
方法引用
方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参和返回值,需要跟抽象方法的形参返回值保持一致
4.被引用方法的功能需要满足当前的需求
public class demo1 { |
引用静态方法
- · 换为 ::
ArrayList<String> list = new ArrayList<>(); |
引用成员方法
- 引用处不能是静态方法
- 其他类: new 类()::方法
public class StringOperation { |
ArrayList<String> list = new ArrayList<>(); |
引用构造方法
- 原写法
List<Student> collect = list.stream().map(new Function<String, Student>() { |
- 使用方法引用
//bean |
其他调用方式
list.stream().map(new Function<String, String>() { |
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
4.被引用方法的功能需要满足当前的需求
抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法在Stream流当中,第一个参数一般都表示流里面的每一个数据。假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
局限性:
不能引用所有类中的成员方法。
是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
Integer[] integers = list.stream().toArray(new IntFunction<Integer[]>() { |
总结
File
File
类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO
流来完成。
使用
//1.根据文件路径创建文件对象 |
获取并遍历
File f = new File("D:\\1.JavaRoute\\Java"); |
创建与删除
/** |
IO流
分类
字节流
- 每次只能操作一个字节
输出流–写出
- 写出的是单个字节数据 – 十进制
/** |
- 同一个流多次写入为 :追加
FileOutputStream fileOutputStream = new FileOutputStream("D:\\1.JavaRoute\\Java\\c.txt"); |
FileOutputStream fileOutputStream = new FileOutputStream("D:\\1.JavaRoute\\Java\\c.txt",true); |
输入流–读入
- 读取之后,read.方法的底层还会进行将字节进行解码并转成十进制
//输入流--读取 |
文件拷贝
- 单个文件
//输入流 |
- 考贝一个文件夹,考虑子文件夹
public class TestCopy { |
- 加密与解密
//加密与解密 |
字符集
UTF-8是 Unicode 字符集的一种编码方式
编码与解码
字符流
- 相比字节流,字符流存在缓冲区,如果不手动刷新或者关闭流,数据不会存储到文件中
FileReader–读入
FileReader fileReader = new FileReader("D:\\1.JavaRoute\\Java\\c.txt"); |
一次性读取多个数据 使用 char数组
//read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中 |
FileWrite–写出
- 只能字符,数字的话默认为10进制后后转为二进制进行编码
File file = new File("D:\\1.JavaRoute\\Java\\file.txt"); |
/** |
缓冲区
存在缓冲区(大小:8192):一次性读取全部字节存入内存,再从内容读取
一次性读取一个字节,如果字节符合中文编码(负数),则一次性读取3个字节,并进行解码为10进制对应的字符,如果想显示对应的数据,需要强转为字符(char)
打印流
只能写出,不能读入
使用场景:System.out.print()
//特殊的打印流,系统中的标准输出流,是不能洐闭,在系统中是唯一的。
PrintStream out = System.out;
out.printf("此打印流在虚拟机启动的时候,由虚拟机创建,默认指向控制台");
字节打印流
- 原样写出:写入什么数据就写入什么数据,不转为二进制查询ASCII码表
PrintStream printStream = new PrintStream(new FileOutputStream("D:\\1.JavaRoute\\Java\\Test\\print.txt",true),true, "UTF-8"); |
字符打印流
PrintWriter printWriter = new PrintWriter(new FileWriter("D:\\1.JavaRoute\\Java\\Test\\print.txt",true),true); |
序列化
序列化流
- 把对象写出到文件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\1.JavaRoute\\Java\\Test\\Student.txt")); |
对象需要实现 序列化接口
/**
* Serializable接口里面是没有抽象方法,标记型接口
* 一且实现了这个接口,那么就表示当前的Student类可以被序列化
*/
public class Student implements Serializable {
}
反序列化流
- 把存储到文件中的对象反序列化成java对象
//反序列化流 |
序列化流和反序列化流的常见问题:
①版本号
- 当序列化存储到文件中后 对象构造发生变化 反序列化回来会报错
private static final long serialVersionUID = 版本号L;
②指定属性不被序列化,反序列化得到的是null
//transient:瞬态关键字,属性防止序列化,
private transient String address;