#### 1.1 ==null对象不可以调用方法==,会导致空指针异常NullPointerException
> eg:String str = null;
> str.equals("zs");
#### 1.2 创建LinkedList(双向链表)时,==有first(指向第一个节点)和last(调用完add之后指向最后添加的节点)==,①先创建新节点,存储值和赋值prev指向(上一个last节点),②再把上一个last节点的next指向当前last节点
##### prev element next
#### 1.3 ==Collection集合都可以用iterator来遍历数据,这也是toString和foreach的底层==
#### 1.3 集合包括Collection和Map(键值对);Collection(接口)集合包含List(接口)和Set(接口)集合
#### 1.3.1 List集合的实现类有ArrayList(动态数组)和LinkedList(双向链表),使用方法是一样的,遍历方式包括for循环、foreach、iterator;
#### 1.3.2 Set集合包括TreeSet(底层是TreeMap)和HashSet(HashMap),==Set集合只能先删再添加==,Set的遍历方式包括foreach、iterator;
#### 1.3.3 Map集合包括TreeMap(红黑树)和HahsMap(动态数组+链表+红黑树),==Map集合的Key只能先删除再添加,Value可以覆盖==,==Map的遍历方式只能通过①keySet()和②entrySet()方法转换为Set集合,再通过foreach、iterator来遍历输出==;
#### 1.3.4 对于==TreeXXX==**来说,底层是红黑树,在add()时就会排序,所以**==如果要存储自定义对象,需要①实现自然排序(Comparable)或者②传递比较器(Comparator)==;
#### 1.3.5 对于==HashXXX==**来说,底层是Hash表(动态数组+链表)+红黑树,在put()时会按hash值存储,所以**==如果要存储自定义对象,需要对Key对象①重写hashCode()和②equals()方法==;
#### 2.异常的处理,分为运行时异常(可处理可不处理)和检查时异常(必须处理)
> try:执行可能产生异常的代码
catch:捕获异常,并处理异常
finally:最终总会执行(除非JVM停止)
throw new :手动抛出异常
throws:声明异常
```
try{
//可能出现异常的代码
}catch(异常种类 变量名){
//异常的处理代码
//如e.printStack() e.getMessage()
}finally{
//无论是否异常都会执行,可以释放资源等
}
```
```
public class TestException3 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int result=0;
try {
System.out.println("请输入第一个数字");
int num1=input.nextInt();//InputMismatchException
System.out.println("请输入第二个数字");
int num2=input.nextInt();
result=num1/num2;//发生异常// ArethmicException
//手动退出JVM
//System.exit(0);
}catch (Exception e) {//捕获 Exception:是所有异常的父类
//处理
//e.printStackTrace();
System.out.println(e.getMessage());
}finally {
System.out.println("释放资源...");
}
System.out.println("结果是:"+result);
System.out.println("程序结束了...");
}
}
```
```
public void setAge(int age) {
if(age>0&&age<=120) {
this.age = age;
}else {
//抛出异常
throw new RuntimeException("年龄不符合要求");
}
}
```
> 编写自定义异常
需继承Exception或Exception的子类,代表特定问题。
```
public AgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
```
#### 3.常用类
##### 3.1 装箱拆箱(JDK1.5之后自动装箱拆箱)
==最大的作用是使得基本数据类型也可以作为对象进行一些行为,比如调用方法,作为对象参数,返回为对象==
> 装箱
1.构造方法 new Integer()
2.静态方法 valueOf() (推荐用静态方法,因为静态方法省资源,不用创建对象)
>
> 拆箱
> 1.方法XXXvalue()
> 2.静态方法 parseXXX()
##### 3.2 Character(==字符的包装类,也算工具类==)
> //isDigit 是否是数字
//isLetter 是否是字母
//isUpperCase 是否是大写字母
//isLowerCase 是否是小写字母
//isLetterOrDigit 是否是字母或者数字
##### 3.3 Obeject类
==是所有类的父类或者间接父类,包含了hashCode()、equals()、toString()等方法,构造方法 public Object(){}==
> == 和 equals() 的区别
1.==是关系运算符,equals()是方法
2.==如果是引用类型是判断内存地址,equals()也是比较内存地址
3.当equals()重写之后,可以判断内容是否相等
==重写equals方法==
```
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//手动重写equals()方法,用来比较内容
@Override
public boolean equals(Object obj) {
//判断内存地址是否相等
if (this == obj) {
return true;
}
//判断对象类型是否相等
if (obj instanceof User) {
User user = (User) obj;
//判断内容是否相等
if (this.getName().equals(user.getName())) {
if (this.getAge() == user.getAge()) {
return true;
}
}
return false;
}
return false;
}
}
```
#### 4. String、StringBuffer、StringBuilder
> 1.String 是==不可变的字符序列==
> StringBuffer(线程安全)和StringBuilder(线程不安全)是==可变的字符序列==
```
String常用方法:
charAt(int index)返回 char指定索引处的值。
String concat(String str)将指定的字符串连接到该字符串的末尾。
boolean contains(CharSequence s)当且仅当此字符串包含指定的char值序列时才返回true。boolean equals(Object anObject)将此字符串与指定对象进行比较。
byte[] getBytes()使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中。
int indexOf(int ch)返回指定字符第一次出现的字符串内的索引。
boolean isEmpty()返回 true如果,且仅当 length()为 0 。
int length()返回此字符串的长度。
System.out.println(str.length());//16
String replace(char oldChar, char newChar)返回从替换所有出现的导致一个字符串 oldChar在此字符串 newChar 。
String[] split(String regex)将此字符串分割为给定的 regular expression的匹配。
System.out.println(Arrays.toString(str.split("c")));//[ab, defghab, defghab, deab]
String substring(int beginIndex)返回一个字符串,该字符串是此字符串的子字符串。
System.out.println(str.substring(5));//fghabcdefghabcdeabc
char[] toCharArray()将此字符串转换为新的字符数组。
str = "AbCDefGh";
System.out.println(Arrays.toString(str.toCharArray()));//[A, b, C, D, e, f, G, h]
String toLowerCase()将所有在此字符 String使用默认语言环境的规则,以小写。
String toUpperCase()将所有在此字符 String使用默认语言环境的规则大写。
String trim()返回一个字符串,其值为此字符串,并删除任何前导和尾随空格。
str = " abcd ef g h ";
System.out.println(str.trim());//"abcd ef g h"
```
```
StringBuilder的常用方法:
末尾追加 append()
capacity() 返回当前容量
charAt(int index) 返回 char在指定索引在这个序列值
delete(int start, int end) 删除此序列的子字符串中的字符。
StringBuilder insert(int offset, int i) 将第二个 int参数的字符串表示插入到此序列中。
reverse() 反转
截取 -- 从开始索引截取到末尾索引
substring(int start, int end)
System.out.println(sb.substring(2, 6));//[start,end)
```
#### 5. Date类和SimpleDateFormat
```
1.new Date() 格林威治时间
2.new Date(long date) 使用给定的毫秒时间值构造一个 Date对象。(要加时区小时时间,东八区+8小时)
```
```
public class Demo02 {
public static void main(String[] args) {
Date date = new Date();
System.out.println("格林威治时间:" + date);//格林威治时间 Tue Nov 09 20:00:24 CST 2021
//2021-11-09 20:00:00
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//调用方法格式化时间
String timeStr = sdf.format(date);
System.out.println("格式化时间:" + timeStr);
//在1970年1月1日 00:00:00的基准时间上添加一个小时
Date date1 = new Date(1000 * 60 * 60);
String time1 = sdf.format(date1);
System.out.println(time1);//东八区,+8小时
}
}
```
#### 6. BigInteger和BigDecimal
> BigInteger:大长度的 int 类型包装类
> BigDecimal:精准运算的类,可小数运算,可大数运算
#### 7. System
> Syste.exit() 退出JVM,0表示正常退出,非0表示非正常退出
> System.gc() 运行垃圾回收器
#### 8. 内部类
> 1.成员内部类(一般新建外部类,再通过外部类新建内部类)
2.局部内部类(不可以有访问修饰符,只能在方法内使用,在内部类外面创建对象)
3.==静态内部类==(在外部通过外部类.内部类创建,类型为内部类,常用于底层代码,在底层代码中,有时用来作为对象类比如Node<E>)
4.==匿名内部类==(适用于创建之后只使用一次或者少次的情况)
```
public class Demo01 {
public static void main(String[] args) {
//静态内部类,通过外部类直接调用,但是内部类还是要new
//Inner inner = Outer.new Inner();
Outer.Inner inner = new Outer.Inner();
inner.setId(10);
System.out.println(inner.getId());
}
}
```
```
public class Demo01 {
public static void main(String[] args) {
//匿名内部类,适用于创建之后使用一次或者少次的情况
MyInterfaceImpl mii = new MyInterfaceImpl();
mii.method();
System.out.println("------多态---------");
MyInterface mi = new MyInterfaceImpl();
mi.method();
System.out.println("-------匿名内部类-------");
MyInterface mi2 = new MyInterface() {
@Override
public void method() {
System.out.println("通过匿名内部类的方式实现了接口的method方法");
}
};
mi2.method();
}
}
```
#### 9. Collection集合(是接口)
##### ==++传入的参数都要是对象,因为基本数据类型有装箱类(自动装箱),所以万物皆对象++==
##### 9.1 List集合(是接口),==有序可重复==
> 1.==ArrayList:底层是动态数组==,初始化长度为0,当第一次添加时将长度改为10,每次要扩容1.5倍
==LinkedList:底层是双向链表==,first指向第一个节点,last指向已存储的最后一个节点,理论长度无限长
==Vector:元老级,底层是动态数组==,线程安全的集合,遍历方式和iterator有点相似
```
ArrayList和LinkedList方法相同,因为都实现了List类,
只不过底层不一样,常用方法有:
//添加 boolean add(Object o)
//修改 E set(int index, E element)
//删除 boolean remove(@Nullable Object o)
//查找 E get(int index)
//迭代器 Iterator<E> iterator()
```
##### ArrayList 和 LinkedList的异同
> 1.ArrayList 底层是动态数组,LinkedList 底层是双向链表
> 2.ArrayList 查询比 LinkedList 更快
> 3.如果不需要扩容,ArrayList 末尾追加比 LinkedList 更快
> 4.修改对象 ArrayList 比 LinkedList 更快
> 5.中间插入和中间删除不同情况效率不一致
> 6.ArrayList 长度有限,LinkedList 理论上长度无限
[![IsqXDg.png](https://z3.ax1x.com/2021/11/13/IsqXDg.png)](https://imgtu.com/i/IsqXDg)
[![IsLP2V.png](https://z3.ax1x.com/2021/11/13/IsLP2V.png)](https://imgtu.com/i/IsLP2V)
##### Vector类(很少用,但是实现了和ArrayList一样(存疑)的方法)
```
import java.util.Enumeration;
import java.util.Vector;
public class Demo02 {
public static void main(String[] args) {
//Vector
Vector vector = new Vector();
//
vector.addElement("a");
vector.addElement("b");
vector.addElement("c");
//Enumeration<E> elements() 返回此向量的组件的枚举。
//相当于Vector的迭代器
Enumeration elements = vector.elements();
while (elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
}
}
```
##### 9.2 栈(类)和队列(接口,实现类是LinkedList)
> ++**==栈和队列都是List的子类,所以也都能使用父类的方法,比如iterator()==**++
> Stack:栈,用完即删,后进先出(LIFO)
> Queue:队列,用完即删,先进先出(FIFO)
```
Stack和Queue的常用方法:
Stack Queue
特点 后进先出 先进先出
类型 类 接口
底层 动态数组 双向链表
存储 add()/push() add()
取栈顶/队首元素 peek() peek()
用删栈顶/队首元素 pop() poll()
是否为空 isEmpty()
容量 size() size()
(迭代器) Collection集合都可以用,隐式存在输出中
```
##### 9.3 迭代器 iterator 调用方法
> Iterator<E> iterator() 以正确的顺序返回该列表中的元素的迭代器。
> 调用.iterator()方法,返回一个迭代器,通过while(.hasNext())和.next()循环打印数据
```
//iterator()
Iterator it = ll.iterator();
System.out.println("迭代器iterator遍历方式:");
//hasNext() next()
while (it.hasNext()) {
System.out.println(it.next());
}
```
##### 9.4 Set集合(是接口),==无序不可重复==
> 1.TreeSet:无序可排序,不可重复(有比较才不重复),不能存储null
**++==要实现“不可重复”,底层调用了TreeMap的put()方法,需要①实现自然排序或者②传递比较器==++**
> 2.HashSet:无序不可重复,可以存储null,在索引为0的位置(不一定是开头)
++**==要实现“不可重复”,底层调用了HashMap的put()方法,需要重写hashCode()方法和equals()方法==**++
```
自然排序:
存储进 TreeSet 集合的对象类必须实现 Comparable 接口,重写 compareTo(),
在 compareTo()里制定排序规则,返回正数存储的对象往右子树方向,
返回负数存储的对象往左子树方向,返回0则不存储
比较器:
在创建 TreeSet 集合对象的时候,传递 Comparator 接口的实现类对象,
重写 Comparator 接口的 compare() ,在 compare() 里制定排序规则
自然排序 vs 比较器
1.使用自然排序需要改变存储对象类的结构
2.使用比较器会额外添加多一个类
3.当比较器与自然排序共存的时候,使用比较器进行排序
```
```
public class Demo01 {
public static void main(String[] args) {
TreeSet<User> set = new TreeSet<>(new Comparator<User>() {
//以 age 从小到大排序,如果 age 相同以 id 从大到小排序
@Override
public int compare(User user1, User user2) {
if(user1.getAge() != user2.getAge()){
return user1.getAge() - user2.getAge();
}
return user2.getId() - user1.getId();
}
});
set.add(new User(1,"zs",18));
set.add(new User(6,"ls",20));
set.add(new User(3,"ww",16));
set.add(new User(2,"z6",18));
set.add(new User(5,"t7",39));
set.add(new User(4,"w8",18));
set.forEach(item -> System.out.println(item));
}
}
```
[![IsLm5R.jpg](https://z3.ax1x.com/2021/11/13/IsLm5R.jpg)](https://imgtu.com/i/IsLm5R)
[![IsLK8x.jpg](https://z3.ax1x.com/2021/11/13/IsLK8x.jpg)](https://imgtu.com/i/IsLK8x)
#### 10. Map接口(k-v 键值对)
##### 10.1 TreeMap 无序可排序
> 对key进行排序,key不可重复;value可以重复,可以为null
> 存储自定义对象时,要①实现自然排序(Comparable)或者②传递比较器(Comparator)
```
public class Demo02 {
public static void main(String[] args) {
TreeMap<User, String> map = new TreeMap<>(new Comparator<User>() {
@Override
public int compare(User user1, User user2) {
return user2.getId() - user1.getId();
}
});
map.put(new User(1),"zs");
map.put(new User(3),"ls");
map.put(new User(2),"ww");
map.put(new User(1),"zs");
//按照id从大到小排序
System.out.println(map);
//两种遍历的方式
//1.keySet
Set<User> set1 = map.keySet();
Iterator<User> it1 = set1.iterator();
while (it1.hasNext()){
System.out.println(it1.next());
}
//2.EntrySet
Set<Map.Entry<User, String>> set2 = map.entrySet();
Iterator<Map.Entry<User, String>> it2 = set2.iterator();
while (it2.hasNext()){
Map.Entry<User, String> entry = it2.next();
User key = entry.getKey();
String value = entry.getValue();
System.out.println("Key:"+key+"Value:"+value);
}
}
}
```
##### 10.2 HashMap
> 底层是hash表(动态数组+链表)+红黑树,无序,key不可重复,value可以重复
> 存储自定义对象时,要重写Key对象的①hashCode()和equals()方法
```
public class Demo02 {
public static void main(String[] args) {
HashMap<Object, Object> map = new HashMap<>();
map.put(new Person(1),new User(1));
map.put(new Person(2),new User(2));
map.put(new Person(1),new User(2));
map.put(new Person(2),new User(1));
map.put(new Person(1),new User(1));
System.out.println(map);
}
}
```
```
public class Person {
private int id;
public Person(int id) {
this.id = id;
}
public Person() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
'}';
}
}
```