文章目录

  • 第11章 枚举和注解
    • 11.1举例
    • 11.2枚举的二种实现方式
    • 11.3enum 实现接口
    • 11.4注解的理解
    • 11.4基本的 Annotation 介绍
  • 第12章 异常-Exception
    • 12.1异常介绍
    • 12.2异常体系图
    • 12.2异常 处理方式
  • 第13章 常用类
    • 13.1包装类
    • 13.2String 类
      • 13.2.1StringBuffer 类
      • 13.2.2StringBuilder 类
      • 13.2.3String、StringBuffer 和 StringBuilder 的比较
    • 13.3Math 类
    • 13.4Arrays 类
    • 13.5System 类
    • 13.6BigInteger 和 BigDecimal 类
    • 13.7日期类
  • 第 14 章集合
    • 14.1 集合的理解和好处
      • 14.1.1 数组
      • 14.1.2 集合
    • 14.2 集合的框架体系
    • 14.3 Collection 接口和常用方法
      • 14.3.1 Collection 接口实现类的特点
      • 14.3.2 Collection 接口遍历元素方式 1-使用 Iterator(迭代器)
      • 14.3.3 Collection 接口遍历元素方式 1-for 循环增强
    • 14.4 List 接口和常用方法
      • 14.3.4 List 的三种遍历方式
    • 14.5ArrayList 底层结构和源码分析
    • 14.6LinkedList 底层结构
    • 14.7Set 接口和常用方法
    • 14.8Set 接口实现类-LinkedHashSet
    • 14.9Map 接口和常用方法
      • 14.9.1 Map 接口实现类的特点
      • 14.9.2 Map 接口常用方法
      • 14.9.3 Map 接口遍历方法
    • 14.10Map 接口和常用方法
      • 14.10.1Map 接口实现类-HashMap
      • 14.11.2Map 接口实现类-Hashtable
      • 14.11.3Map 接口实现类-Properties
      • 14.11.4总结-开发中如何选择集合实现类(记住)
      • 14.11.5Collections 工具类
  • 第 15 章泛型
    • 15.1泛型出现的原因
    • 15.2泛型的理解和好处
    • 15.3泛型的语法
    • 15.4自定义泛型
    • 15.4JUnit

第11章 枚举和注解

11.1举例

要求创建季节(Season) 对象,请设计并完成。
但是,季节的值是有限的几个值(4个季节),不可以再多。
就可以用枚举来解决
枚举(enumeration,简写enum),是一组常量的集合。(属于一种特殊的类,里面只包含一组有限的特定的对象)。

11.2枚举的二种实现方式

  1. 自定义类实现枚举
  2. 使用 enum 关键字实现枚举

自定义类实现枚举-应用案例:

package com.hspedu.enum_;
public class Enumeration02 {public static void main(String[] args) {System.out.println(Season.AUTUMN);System.out.println(Season.SPRING);}
}
//演示字定义枚举实现
class Season {//类private String name;private String desc;//描述//定义了四个对象, 固定. public static final Season SPRING = new Season("春天", "温暖");public static final Season WINTER = new Season("冬天", "寒冷");public static final Season AUTUMN = new Season("秋天", "凉爽");public static final Season SUMMER = new Season("夏天", "炎热");//1. 将构造器私有化,目的防止 直接 new//2. 去掉 setXxx 方法, 防止属性被修改//3. 在 Season 内部,直接创建固定的对象//4. 优化,可以加入 final 修饰符private Season(String name, String desc) {this.name = name;this.desc = desc;}public String getName() {return name;}public String getDesc() {return desc;}@Overridepublic String toString() {return "Season{" +"name='" + name + '\'' +", desc='" + desc + '\'' +'}';}
}

自定义类实现枚举-小结:
进行自定义类实现枚举,有如下特点:

  1. 构造器私有化
  2. 本类内部创建一组对象[四个 春夏秋冬]
  3. 对外暴露对象(通过为对象添加 public final static 修饰符)
  4. 可以提供 get 方法,但是不要提供 set

enum 关键字实现枚举-快速入门

package com.hspedu.enum_;
public class Enumeration03 {public static void main(String[] args) {System.out.println(Season2.AUTUMN);System.out.println(Season2.SUMMER);
}
}
//演示使用 enum 关键字来实现枚举类
enum Season2 {//类
//如果使用了 enum 来实现枚举类
//1. 使用关键字 enum 替代 class
//2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
// SPRING("春天", "温暖") 解读 常量名(实参列表)
//3. 如果有多个常量(对象), 使用 ,号间隔即可
//4. 如果使用 enum 来实现枚举,要求将定义常量对象,写在前面
//5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"), SUMMER("夏天", "炎热")/*, What()*/;private String name;private String desc;//描述private Season2() {//无参构造器}private Season2(String name, String desc) {this.name = name;this.desc = desc;}public String getName() {return name;}public String getDesc() {return desc;}@Overridepublic String toString() {return "Season{" +"name='" + name + '\'' +", desc='" + desc + '\'' +'}';}
}

enum 关键字实现枚举注意事项

  1. 当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类
  2. 传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”), 这里必须知道,它调用的是哪个构造器.
  3. 如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略
  4. 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
  5. 枚举对象必须放在枚举类的行首

    javac编译,javap反编译
    ![-

enum 常 2 用方法说明:
使用关键字 enum 时,会隐式继承 Enum 类, 这样我们就可以使用 Enum 类相关的方法。[看下源码定义.]
public abstract class Enum<E extends Enum>
implements Comparable, Serializable {
}

  1. toString:Enum 类已经重写过了,返回的是当前对象
    名,子类可以重写该方法,用于返回对象的属性信息
  2. name:返回当前对象名(常量名),子类中不能重写
  3. ordinal:返回当前对象的位置号,默认从 0 开始
  4. values:返回当前枚举类中所有的常量
  5. valueOf:将字符串转换成枚举对象,要求字符串必须
    为已有的常量名,否则报异常!
  6. compareTo:比较两个枚举常量,比较的就是编号!

11.3enum 实现接口

  1. 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而 Java 是单继承机制。
  2. 枚举类和普通类一样,可以实现接口,如下形式。
    enum 类名 implements 接口 1,接口 2{}

11.4注解的理解

1)注解(Annotation)也被称为元数据(Metadata),用于修饰解释、包、类、方法、属性、构造器、局部变量等数据信息。
2)和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
3)在javase中,注释的使用目的比较简单,例如标记过时时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。

11.4基本的 Annotation 介绍

使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元

三个基本的 Annotation:

  1. @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法。
  2. @Deprecated: 用于表示某个程序元素(类, 方法等)已过时。
  3. @SuppressWarnings: 抑制编译器警告
    4)@interface不是interface,是注解类


    all,抑制所有警告
    boxing,抑制与封装/拆装作业相关的警告
    cast,抑制与强制转型作业相关的警告
    dep-ann,抑制与淘汰注释相关的警告
    deprecation,抑制与淘汰的相关警告
    fallthrough,抑制与 switch 陈述式中遗漏 break 相关的警告
    finally,抑制与未传回 finally 区块相关的警告
    hiding,抑制与隐藏变数的区域变数相关的警告
    incomplete-switch,抑制与 switch 陈述式(enum case)中遗漏项目相关的警告
    javadoc,抑制与 javadoc 相关的警告
    nls,抑制与非 nls 字串文字相关的警告
    null,抑制与空值分析相关的警告
    rawtypes,抑制与使用 raw 类型相关的警告
    resource,抑制与使用 Closeable 类型的资源相关的警告
    restriction,抑制与使用不建议或禁止参照相关的警告
    serial,抑制与可序列化的类别遗漏 serialVersionUID 栏位相关的警告
    static-access,抑制与静态存取不正确相关的警告
    static-method,抑制与可能宣告为 static 的方法相关的警告
    super,抑制与置换方法相关但不含 super 呼叫的警告
    synthetic-access,抑制与内部类别的存取未最佳化相关的警告
    sync-override,抑制因为置换同步方法而遗漏同步化的警告
    unchecked,抑制与未检查的作业相关的警告
    unqualified-field-access,抑制与栏位存取不合格相关的警告
    unused,抑制与未用的程式码及停用的程式码相关的警告
    关于 SuppressWarnings 作用范围是和你放置的位置相关, 比如 @SuppressWarnings 放置在 main 方法,那么抑制警告的范围就是 main
    ,通常我们可以放置具体的语句, 方法, 类.
    @SuppressWarnings 源码
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {String[] value();
}

//(1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE
//(2) 该注解类有数组 String[] values() 设置一个数组比如 {“rawtypes”, “unchecked”, “unused”}

  1. Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
  2. Target // 指定注解可以在哪些地方使用
  3. Documented //指定该注解是否会在 javadoc 体现
  4. Inherited //子类会继承父类注解

说明:
只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值:
@Retention 的三种值

  1. RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释
  2. RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解。 这是默认值
  3. RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注解

第12章 异常-Exception

12.1异常介绍


将该代码块->选中->快捷键 ctrl + alt + t -> 选中 try-catch
什么是异常?
程序运行过程中产生的不正常的情况统称为异常!
Throwable 类是 Java 语言中所有错误或异常的超类。提供了错误堆栈实现等一系列方法。 有两个直接子类:Error & Exception

程序错误一般分为三种:

1.编译错误;2.运行时错误;3.逻辑错误。

(1)编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置,这个也是我们在刚接触编程语言最常遇到的问题。

(2)运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。

(3)逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。

12.2异常体系图


java几种常见的异常:
运行时异常:
1java.lang.ArrayIndexOutOfBoundsException 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
2,ArithmeticException 算术错误情形,如以零作除数,算术条件异常。
3 java.lang.SecurityException 安全性异常
4,IllegalArgumentException 方法接收到非法参数,非法参数异常!
5,java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常
6,java.lang.NegativeArraySizeException 数组长度为负异常
7 java.lang.ClassNotFoundException 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
8 java.lang.NullPointerException 空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
9,java.lang.NumberFormatException(数字格式转换异常)
10,java.lang.ClassCastException(强制类型转换异常)

IOException
1, IOException 操作输入流和输出流时可能出现的异常
2, EOFException 文件已结束异常
3, FileNotFoundException 文件未找到异常
4,SQLException 操作数据库时,查询表可能发生异常
5,ClassNotFoundException 加载类,而该类不存在时,异常
6,lllegalArguementException 参数异常

12.2异常 处理方式




try-catch 异常处理



public class TryCatchDetail02 {public static void main(String[] args) {//1.如果 try 代码块有可能有多个异常
//2.可以使用多个 catch 分别捕获不同的异常,相应处理
//3.要求子类异常写在前面,父类异常写在后面try {Person person = new Person();//person = null;System.out.println(person.getName());//NullPointerExceptionint n1 = 10;int n2 = 0;int res = n1 / n2;//ArithmeticException} catch (NullPointerException e) {System.out.println("空指针异常=" + e.getMessage());} catch (ArithmeticException e) {System.out.println("算术异常=" + e.getMessage());} catch (Exception e) {System.out.println(e.getMessage());} finally {}
}
}
class Person {private String name = "jack";public String getName() {return name;}
}




throws 异常处理:


自定义异常:

自定义异常的步骤
当我们接收Person对象年龄时,要求范围在 18 - 120 之间,否则抛出一个自定义异常(要求 继承RuntimeException),并给出提示信息

package com.hspedu.customexception_;
public class CustomException {public static void main(String[] args) /*throws AgeException*/ {int age = 180;//要求范围在 18 – 120 之间,否则抛出一个自定义异常if(!(age >= 18 && age <= 120)) {//这里我们可以通过构造器,设置信息throw new AgeException("年龄需要在 18~120 之间");}System.out.println("你的年龄范围正确.");}
}//自定义一个异常//老韩解读//1. 一般情况下,我们自定义异常是继承 RuntimeException//2. 即把自定义异常做成 运行时异常,好处时,我们可以使用默认的处理机制//3. 即比较方便
class AgeException extends RuntimeException {public AgeException(String message) {//构造器super(message);}
}

throw和throws的区别:

这只是有点相似的关键字,并没有任何关联,要学会区分。
throw是用在方法体里面的,一般是放在判断情况的后面,手动抛出异常。
throws只能用在需要捕获异常的方法的方法名的括号后面使用。

第13章 常用类

13.1包装类

包装类的分类:

  1. 针对八种基本数据类型相应的引用类型—包装类
  2. 有了类的特点,就可以调用类中的方法。

    包装类和基本数据的转换:
//演示 int <--> Integer 的装箱和拆箱
//jdk5 前是手动装箱和拆箱
//手动装箱 int->Integer
int n1 = 100;
Integer integer = new Integer(n1);
Integer integer1 = Integer.valueOf(n1);
//手动拆箱
//Integer -> int
int i = integer.intValue();
//jdk5 后,就可以自动装箱和自动拆箱
int n2 = 200;
//自动装箱 int->Integer
Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2)
//自动拆箱 Integer->int
int n3 = integer2; //底层仍然使用的是 intValue()方法

包装类型和 String 类型的相互转换:

//包装类(Integer)->String
Integer i = 100;//自动装箱
//方式 1
String str1 = i + "";//这里只是得到一个字符串“100”,并没有改变i,所以i打印出来还是100
//方式 2
String str2 = i.toString();
//方式 3
String str3 = String.valueOf(i);
//String -> 包装类(Integer)
String str4 = "12345";
Integer i2 = Integer.parseInt(str4);//使用到自动装箱
Integer i3 = new Integer(str4);//构造器
//parseInt() 方法用于将字符串参数作为有符号的十进制整数进行解析。
//valueOf() 方法用于返回给定参数的原生 Number 对象值,参数可以是原生数据类型, String等

Integer 类和 Character 类的常用方法:

System.out.println(Integer.MIN_VALUE); //返回最小值
System.out.println(Integer.MAX_VALUE);//返回最大值
System.out.println(Character.isDigit('a'));//判断是不是数字
System.out.println(Character.isLetter('a'));//判断是不是字母
System.out.println(Character.isUpperCase('a'));//判断是不是大写
System.out.println(Character.isLowerCase('a'));//判断是不是小写
System.out.println(Character.isWhitespace('a'));//判断是不是空格
System.out.println(Character.toUpperCase('a'));//转成大写
System.out.println(Character.toLowerCase('A'));//转成小写

Integer 类面试题
1.看看下面代码,输出什么结果? 为什么?

public class WrapperExercise02 {public static void main(String[] args) {Integer i = new Integer(1);Integer j = new Integer(1);System.out.println(i == j); //False,因为==比较应用类型时,看是不是同一个对象,很明显这里不是同一个对象//所以,这里主要是看范围 -128 ~ 127 就是直接返回/*老韩解读//1. 如果 i 在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从数组返回//2. 如果不在 -128~127,就直接 new Integer(i)public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}*/Integer m = 1; //底层 Integer.valueOf(1); -> 阅读源码Integer n = 1;//底层 Integer.valueOf(1);System.out.println(m == n); //T//所以,这里主要是看范围 -128 ~ 127 就是直接返回//,否则,就 new Integer(xx);Integer x = 128;//底层 Integer.valueOf(1);Integer y = 128;//底层 Integer.valueOf(1);System.out.println(x == y);//False,不在-128~127范围内,所以就返回new Interger,因此就是两个不同的对象}
}

2.看看下面代码,输出什么结果?

public class WrapperExercise03 {public static void main(String[] args) {//示例一Integer i1 = new Integer(127);Integer i2 = new Integer(127);System.out.println(i1 == i2);//F//示例二Integer i3 = new Integer(128);Integer i4 = new Integer(128);System.out.println(i3 == i4);//F//示例三Integer i5 = 127;//底层 Integer.valueOf(127)Integer i6 = 127;//-128~127System.out.println(i5 == i6); //T//示例四Integer i7 = 128;Integer i8 = 128;System.out.println(i7 == i8);//F//示例五Integer i9 = 127; //Integer.valueOf(127)Integer i10 = new Integer(127);System.out.println(i9 == i10);//F//示例六Integer i11=127;int i12=127;//只有有基本数据类型,判断的是//值是否相同System.out.println(i11==i12); //T//示例七Integer i13=128;int i14=128;System.out.println(i13==i14);//T}
}

13.2String 类

String 类的理解:

6. String 是 final 类,不能被其他的类继承
7. String 有属性 private final char value[]; 用于存放字符串内容
8. 一定要注意:value 是一个 final 类型, 不可以修改:即 value 不能指向新的地址,但是单个字符内容是可以变化

创建 String 对象的两种方式:


字符串的特性:

面试题:


1、Java中的StringBuffer类是动态字符串数组。
2、StringBuffer类包含append()方法,append()方法相当于“+”,将指定的字符串追加到此字符序列。
3、StringBuffer.append()追加的字符串在同一个内存地址。

String 类的常见方法:

// 1.toUpperCase 转换成大写
String s = "heLLo";
System.out.println(s.toUpperCase());//HELLO
// 2.toLowerCase转换成小写
System.out.println(s.toLowerCase());//hello
// 3.concat 拼接字符串
String s1 = "宝玉";
s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");
System.out.println(s1);//宝玉林黛玉薛宝钗 together
// 4.replace 替换字符串中的字符
s1 = "宝玉 and 林黛玉 林黛玉 林黛玉";
//在 s1 中,将 所有的 林黛玉 替换成薛宝钗
// 老韩解读: s1.replace() 方法执行后,返回的结果才是替换过的. // 注意对 s1 没有任何影响
String s11 = s1.replace("宝玉", "jack");
System.out.println(s1);//宝玉 and 林黛玉 林黛玉 林黛玉
System.out.println(s11);//jack and 林黛玉 林黛玉 林黛玉
// 5.split 分割字符串, 对于某些分割字符,我们需要 转义比如 | \\等
String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
//老韩解读:
// 1. 以 , 为标准对 poem 进行分割 , 返回一个数组
// 2. 在对字符串进行分割时,如果有特殊字符,需要加入 转义符 \
String[] split = poem.split(",");
poem = "E:\\aaa\\bbb";
split = poem.split("\\\\");
System.out.println("==分割后内容===");
for (int i = 0; i < split.length; i++) {System.out.println(split[i]);
}
// 6.toCharArray 转换成字符数组
s = "happy";
char[] chs = s.toCharArray();
for (int i = 0; i < chs.length; i++) {System.out.println(chs[i]);
}
// 7.compareTo 比较两个字符串的大小,如果前者大,
// 则返回正数,后者大,则返回负数,如果相等,返回 0
// 老韩解读
// (1) 如果长度相同,并且每个字符也相同,就返回 0
// (2) 如果长度相同或者不相同,但是在进行比较时,可以区分大小
// 就返回 if (c1 != c2) {// return c1 - c2;
// }
// (3) 如果前面的部分都相同,就返回 str1.len - str2.len
String a = "jcck";// len = 3
String b = "jack";// len = 4
System.out.println(a.compareTo(b)); // 返回值是 'c' - 'a' = 2 的值
// 8.format 格式字符串
/* 占位符有:
* %s 字符串 %c 字符 %d 整型 %.2f 浮点型
*
*/
String name = "john";
int age = 10;
double score = 56.857;
char gender = '男';
//将所有的信息都拼接在一个字符串. String info =
"我的姓名是" + name + "年龄是" + age + ",成绩是" + score + "性别是" + gender + "。希望大家喜欢我!
";
System.out.println(info);
//老韩解读
//1. %s , %d , %.2f %c 称为占位符
//2. 这些占位符由后面变量来替换
//3. %s 表示后面由 字符串来替换
//4. %d 是整数来替换
//5. %.2f 表示使用小数来替换,替换后,只会保留小数点两位, 并且进行四舍五入的处理
//6. %c 使用 char 类型来替换
String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 性别是%c.希望大家喜欢我!";
String info2 = String.format(formatStr, name, age, score, gender);
System.out.println("info2=" + info2);
}
}

13.2.1StringBuffer 类

public class StringBuffer01 {public static void main(String[] args) {//老韩解读
//1. StringBuffer 的直接父类 是 AbstractStringBuilder
//2. StringBuffer 实现了 Serializable, 即 StringBuffer 的对象可以串行化
//3. 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final
// 该 value 数组存放 字符串内容,引出存放在堆中的
//4. StringBuffer 是一个 final 类,不能被继承
//5. 因为 StringBuffer 字符内容是存在 char[] value, 所有在变化(增加/删除)
// 不用每次都更换地址(即不是每次创建新对象), 所以效率高于 StringStringBuffer stringBuffer = new StringBuffer("hello");}
}

String VS StringBuffer

String 和 StringBuffer 相互转换

//看 String——>StringBuffer
String str = "hello tom";
//方式 1 使用构造器
//注意: 返回的才是 StringBuffer 对象,对 str 本身没有影响
StringBuffer stringBuffer = new StringBuffer(str);
//方式 2 使用的是 append 方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);
//看看 StringBuffer ->String
StringBuffer stringBuffer3 = new StringBuffer("韩顺平教育");
//方式 1 使用 StringBuffer 提供的 toString 方法
String s = stringBuffer3.toString();
//方式 2: 使用构造器来搞定
String s1 = new String(stringBuffer3);

StringBuffer 类常见方法

StringBuffer s = new StringBuffer("hello");
//增
s.append(',');// "hello,"
s.append("张三丰");//"hello,张三丰"
s.append("赵敏").append(100).append(true).append(10.5);//"hello,张三丰赵敏 100true10.5" System.out.println(s);//"hello,张三丰赵敏 100true10.5"
//删
/*
* 删除索引为>=start && <end 处的字符
* 解读: 删除 11~14 的字符 [11, 14)
*/
s.delete(11, 14);
System.out.println(s);//"hello,张三丰赵敏 true10.5"
//改
//老韩解读,使用 周芷若 替换 索引 9-11 的字符 [9,11)
s.replace(9, 11, "周芷若");
System.out.println(s);//"hello,张三丰周芷若 true10.5"
//查找指定的子串在字符串第一次出现的索引,如果找不到返回-1
int indexOf = s.indexOf("张三丰");
System.out.println(indexOf);//6
//插
//老韩解读,在索引为 9 的位置插入 "赵敏",原来索引为 9 的内容自动后移
s.insert(9, "赵敏");
System.out.println(s);//"hello,张三丰赵敏周芷若 true10.5"
//长度
System.out.println(s.length());//22
System.out.println(s);
package com.hspedu.stringbuffer_;
public class StringBufferExercise01 {public static void main(String[] args) {String str = null;// okStringBuffer sb = new StringBuffer(); //oksb.append(str);//需要看源码 , 底层调用的是 AbstractStringBuilder 的 appendNull()/*private AbstractStringBuilder appendNull() {int c = count;ensureCapacityInternal(c + 4);final char[] value = this.value;value[c++] = 'n';value[c++] = 'u';value[c++] = 'l';value[c++] = 'l';count = c;return this;}*/System.out.println(sb.length());//4System.out.println(sb);//null//下面的构造器,会抛出 NullpointerExceptionStringBuffer sb1 = new StringBuffer(str);//看底层源码 super(str.length() + 16);System.out.println(sb1);}
}

练习:

package com.hspedu.stringbuffer_;
import java.util.Scanner;
public class StringBufferExercise02 {public static void main(String[] args) {/*思路分析1. 定义一个 Scanner 对象,接收用户输入的 价格(String)2. 希望使用到 StringBuffer 的 insert ,需要将 String 转成 StringBuffer3. 然后使用相关方法进行字符串的处理代码实现*///new Scanner(System.in)String price = "8123564.59";StringBuffer sb = new StringBuffer(price);//先完成一个最简单的实现 123,564.59//找到小数点的索引,然后在该位置的前 3 位,插入,即可// int i = sb.lastIndexOf(".");// sb = sb.insert(i - 3, ",");//上面的两步需要做一个循环处理,才是正确的for (int i = sb.lastIndexOf(".") - 3; i > 0; i -= 3) {sb = sb.insert(i, ",");}System.out.println(sb);//8,123,564.59}
}

13.2.2StringBuilder 类


StringBuilder 常用方法:

package com.hspedu.stringbuilder_;
/**
* @author 韩顺平
* @version 1.0
*/
public class StringBuilder01 {public static void main(String[] args) {//老韩解读//1. StringBuilder 继承 AbstractStringBuilder 类//2. 实现了 Serializable ,说明 StringBuilder 对象是可以串行化(对象可以网络传输,可以保存到文件)//3. StringBuilder 是 final 类, 不能被继承//4. StringBuilder 对象字符序列仍然是存放在其父类 AbstractStringBuilder 的 char[] value;// 因此,字符序列是堆中//5. StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字,因此在单线程的情况下使用// StringBuilderStringBuilder stringBuilder = new StringBuilder();}
}

13.2.3String、StringBuffer 和 StringBuilder 的比较


StringVsStringBufferVsStringBuilder.java 效率 : StringBuilder > StringBuffer > String

package com.hspedu.stringbuilder_;
public class StringVsStringBufferVsStringBuilder {public static void main(String[] args) {long startTime = 0L;long endTime = 0L;StringBuffer buffer = new StringBuffer("");startTime = System.currentTimeMillis();for (int i = 0; i < 80000; i++) {//StringBuffer 拼接 20000 次buffer.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuffer 的执行时间:" + (endTime - startTime));StringBuilder builder = new StringBuilder("");startTime = System.currentTimeMillis();for (int i = 0; i < 80000; i++) {//StringBuilder 拼接 20000 次builder.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuilder 的执行时间:" + (endTime - startTime));String text = "";startTime = System.currentTimeMillis();for (int i = 0; i < 80000; i++) {//String 拼接 20000text = text + i;}endTime = System.currentTimeMillis();System.out.println("String 的执行时间:" + (endTime - startTime));}
}

13.3Math 类

// Math 常用的方法(静态方法)
//1.abs 绝对值
int abs = Math.abs(-9);
System.out.println(abs);//9
//2.pow 求幂
double pow = Math.pow(2, 4);//2 的 4 次方
System.out.println(pow);//16
//3.ceil 向上取整,返回>=该参数的最小整数(转成 double);
double ceil = Math.ceil(3.9);
System.out.println(ceil);//4.0
//4.floor 向下取整,返回<=该参数的最大整数(转成 double)
double floor = Math.floor(4.001);
System.out.println(floor);//4.0
//5.round 四舍五入 Math.floor(该参数+0.5)
long round = Math.round(5.51);
System.out.println(round);//6
//6.sqrt 求开方
double sqrt = Math.sqrt(9.0);
System.out.println(sqrt);//3.0
//7.random 求随机数
// random 返回的是 0 <= x < 1 之间的一个随机小数
// 思考:请写出获取 a-b 之间的一个随机整数,a,b 均为整数 ,比如 a = 2, b=7
// 即返回一个数 x 2 <= x <= 7
// 老韩解读 Math.random() * (b-a) 返回的就是 0 <= 数 <= b-a
// (1) (int)(a) <= x <= (int)(a + Math.random() * (b-a +1) )
// (2) 使用具体的数给小伙伴介绍 a = 2 b = 7
// (int)(a + Math.random() * (b-a +1) ) = (int)( 2 + Math.random()*6)
// Math.random()*6 返回的是 0 <= x < 6 小数
// 2 + Math.random()*6 返回的就是 2<= x < 8 小数
// (int)(2 + Math.random()*6) = 2 <= x <= 7
// (3) 公式就是 (int)(a + Math.random() * (b-a +1) )
for(int i = 0; i < 100; i++) {System.out.println((int)(2 + Math.random() * (7 - 2 + 1)));
}
//max , min 返回最大值和最小值
int min = Math.min(1, 9);
int max = Math.max(45, 90);
System.out.println("min=" + min);
System.out.println("max=" + max);

13.4Arrays 类

Arrays 类常见方法:


package com.hspedu.arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArrayExercise {public static void main(String[] args) {Book[] books = new Book[4];books[0] = new Book("红楼梦", 100);books[1] = new Book("金瓶梅新", 90);books[2] = new Book("青年文摘 20 年", 5);books[3] = new Book("java 从入门到放弃~", 300);//(1)price 从大到小// Arrays.sort(books, new Comparator() {// //这里是对 Book 数组排序,因此 o1 和 o2 就是 Book 对象// @Override// public int compare(Object o1, Object o2) {// Book book1 = (Book) o1;// Book book2 = (Book) o2;// double priceVal = book2.getPrice() - book1.getPrice();// //这里老师进行了一个转换// //如果发现返回结果和我们输出的不一致,就修改一下返回的 1 和 -1// if(priceVal > 0) {// return 1;// } else if(priceVal < 0) {// return -1;// } else {// return 0;// }// }// });//(2)price 从小到大// Arrays.sort(books, new Comparator() {// //这里是对 Book 数组排序,因此 o1 和 o2 就是 Book 对象// @Override// public int compare(Object o1, Object o2) {// Book book1 = (Book) o1;// Book book2 = (Book) o2;// double priceVal = book2.getPrice() - book1.getPrice();// //这里老师进行了一个转换// //如果发现返回结果和我们输出的不一致,就修改一下返回的 1 和 -1// if(priceVal > 0) {// return -1;// } else if(priceVal < 0) {// return 1;// } else {// return 0;// }// }// });//(3)按照书名长度从大到小Arrays.sort(books, new Comparator() {//这里是对 Book 数组排序,因此 o1 和 o2 就是 Book 对象@Overridepublic int compare(Object o1, Object o2) {Book book1 = (Book) o1;Book book2 = (Book) o2;//要求按照书名的长度来进行排序return book2.getName().length() - book1.getName().length();}});System.out.println(Arrays.toString(books));}
}
class Book {private String name;private double price;public Book(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;
}
public void setPrice(double price) {this.price = price;
}
@Override
public String toString() {return "Book{" +"name='" + name + '\'' +", price=" + price +'}';}
}

13.5System 类

System 类常见方法:

//1. exit(0) 表示程序退出
//2. 0 表示一个状态 , 正常的状态
System.exit(0);
//arraycopy :复制数组元素,比较适合底层调用,
// 一般使用 Arrays.copyOf 完成复制数组
int[] src={1,2,3};
int[] dest = new int[3];// dest 当前是 {0,0,0}
System.arraycopy(src, 0, dest, 0, src.length);
// int[] src={1,2,3};
System.out.println("dest=" + Arrays.toString(dest));//[1,2,3]
// srcPos: 从源数组的哪个索引位置开始拷贝
// dest : 目标数组,即把源数组的数据拷贝到哪个数组
// destPos: 把源数组的数据拷贝到 目标数组的哪个索引
// length: 从源数组拷贝多少个数据到目标数组
//currentTimeMillens:返回当前时间距离 1970-1-1 的毫秒数
System.out.println(System.currentTimeMillis());

13.6BigInteger 和 BigDecimal 类


BigInteger 和 BigDecimal 常见方法:

当我们编程中,需要处理很大的整数,long 不够用可以使用 BigInteger 的类来搞定。

BigInteger bigInteger = new BigInteger("23788888899999999999999999999");
BigInteger bigInteger2 = new
BigInteger("10099999999999999999999999999999999999999999999999999999999999999999999999999999999");
System.out.println(bigInteger);
//1. 在对 BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接进行 + - * /
//2. 可以创建一个 要操作的 BigInteger 然后进行相应操作
BigInteger add = bigInteger.add(bigInteger2);
System.out.println(add);//
BigInteger subtract = bigInteger.subtract(bigInteger2);
System.out.println(subtract);//减
BigInteger multiply = bigInteger.multiply(bigInteger2);
System.out.println(multiply);//乘
BigInteger divide = bigInteger.divide(bigInteger2);
System.out.println(divide);//除

当我们需要保存一个精度很高的数时,double 不够用可以是 BigDecimal。

BigDecimal bigDecimal = new BigDecimal("1999.11");
BigDecimal bigDecimal2 = new BigDecimal("3");
System.out.println(bigDecimal);
//1. 如果对 BigDecimal 进行运算,比如加减乘除,需要使用对应的方法
//2. 创建一个需要操作的 BigDecimal 然后调用相应的方法即可
System.out.println(bigDecimal.add(bigDecimal2));
System.out.println(bigDecimal.subtract(bigDecimal2));
System.out.println(bigDecimal.multiply(bigDecimal2));
//System.out.println(bigDecimal.divide(bigDecimal2));//可能抛出异常 ArithmeticException
//在调用 divide 方法时,指定精度即可. BigDecimal.ROUND_CEILING
//如果有无限循环小数,就会保留 分子 的精度
System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));

13.7日期类

1 第一代日期类

//1. 获取当前系统时间
//2. 这里的 Date 类是在 java.util 包
//3. 默认输出的日期格式是国外的方式, 因此通常需要对格式进行转换
Date d1 = new Date(); //获取当前系统时间
System.out.println("当前日期=" + d1);
Date d2 = new Date(9234567); //通过指定毫秒数得到时间
System.out.println("d2=" + d2); //获取某个时间对应的毫秒数//1. 创建 SimpleDateFormat 对象,可以指定相应的格式
//2. 这里的格式使用的字母是规定好,不能乱写
SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 hh:mm:ss E");
String format = sdf.format(d1); // format:将日期转换成指定格式的字符串
System.out.println("当前日期=" + format);//1. 可以把一个格式化的 String 转成对应的 Date
//2. 得到 Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换
//3. 在把 String -> Date , 使用的 sdf 格式需要和你给的 String 的格式一样,否则会抛出转换异常
String s = "1996 年 01 月 01 日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println("parse=" + sdf.format(parse));

2 第二代日期类

//1. Calendar 是一个抽象类, 并且构造器是 private
//2. 可以通过 getInstance() 来获取实例
//3. 提供大量的方法和字段提供给程序员
//4. Calendar 没有提供对应的格式化的类,因此需要程序员自己组合来输出(灵活)
//5. 如果我们需要按照 24 小时进制来获取时间, Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY
Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
System.out.println("c=" + c);//2.获取日历对象的某个日历字段
System.out.println("年:" + c.get(Calendar.YEAR));
// 这里为什么要 + 1, 因为 Calendar 返回月时候,是按照 0 开始编号
System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
System.out.println("小时:" + c.get(Calendar.HOUR));
System.out.println("分钟:" + c.get(Calendar.MINUTE));
System.out.println("秒:" + c.get(Calendar.SECOND));
//Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" +
c.get(Calendar.DAY_OF_MONTH) +
" " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) );

3 第三代日期类

//1. 使用 now() 返回表示当前日期时间的 对象
LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now();//LocalTime.now()
System.out.println(ldt);
//2. 使用 DateTimeFormatter 对象来进行格式化
// 创建 DateTimeFormatter 对象
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dateTimeFormatter.format(ldt);
System.out.println("格式化的日期=" + format);System.out.println("年=" + ldt.getYear());
System.out.println("月=" + ldt.getMonth());
System.out.println("月=" + ldt.getMonthValue());
System.out.println("日=" + ldt.getDayOfMonth());
System.out.println("时=" + ldt.getHour());
System.out.println("分=" + ldt.getMinute());
System.out.println("秒=" + ldt.getSecond());//提供 plus 和 minus 方法可以对当前时间进行加或者减
//看看 890 天后,是什么时候 把 年月日-时分秒
LocalDateTime localDateTime = ldt.plusDays(890);
System.out.println("890 天后=" + dateTimeFormatter.format(localDateTime));
//看看在 3456 分钟前是什么时候,把 年月日-时分秒输出
LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
System.out.println("3456 分钟前 日期=" + dateTimeFormatter.format(localDateTime2));

DateTimeFormatter 格式日期类:

Instant 时间戳:

//1.通过 静态方法 now() 获取表示当前时间戳的对象
Instant now = Instant.now();
System.out.println(now);
//2. 通过 from 可以把 Instant 转成 Date
Date date = Date.from(now);
//3. 通过 date 的 toInstant() 可以把 date 转成 Instant 对象
Instant instant = date.toInstant()

第 14 章集合

14.1 集合的理解和好处

前面我们保存多个数据使用的是数组,那么数组有不足的地方,我们分析一下

14.1.1 数组

14.1.2 集合

14.2 集合的框架体系

  1. 集合主要是两组(单列集合 , 双列集合)
  2. Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
  3. Map 接口的实现子类 是双列集合,存放的 K-V
ArrayList arrayList = new ArrayList();
arrayList.add("jack");
arrayList.add("tom");
HashMap hashMap = new HashMap();
hashMap.put("NO1", "北京");
hashMap.put("NO2", "上海");

14.3 Collection 接口和常用方法

14.3.1 Collection 接口实现类的特点


Collection 接口常用方法,以实现子类 ArrayList 来演示:

List list = new ArrayList();
// add:添加单个元素
list.add("jack");
list.add(10);//list.add(new Integer(10))
list.add(true);// remove:删除指定元素
//list.remove(0);//删除第一个元素
list.remove(true);//指定删除某个元素// contains:查找元素是否存在
System.out.println(list.contains("jack"));//T// size:获取元素个数
System.out.println(list.size());//2// isEmpty:判断是否为空
System.out.println(list.isEmpty());//F// clear:清空
list.clear();
System.out.println("list=" + list);// addAll:添加多个元素
ArrayList list2 = new ArrayList();
list2.add("红楼梦");
list2.add("三国演义");
list.addAll(list2);// containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));//T
// removeAll:删除多个元素
list.add("聊斋");
list.removeAll(list2);

14.3.2 Collection 接口遍历元素方式 1-使用 Iterator(迭代器)

快捷方式:输入itit,按enter.
显示所有的快捷键的的快捷键 ctrl + j
如果需要再次遍历,需要重置迭代器。

14.3.3 Collection 接口遍历元素方式 1-for 循环增强

14.4 List 接口和常用方法


void add(int index, Object ele):在 index 位置插入 ele 元素

List list = new ArrayList();
//在 index = 1 的位置插入一个对象
list.add(1, "韩顺平");

boolean addAll(int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来

List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1, list2);

Object get(int index):获取指定 index 位置的元素
int indexOf(Object obj):返回 obj 在集合中首次出现的位置
int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
Object remove(int index):移除指定 index 位置的元素,并返回此元素
Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合

14.3.4 List 的三种遍历方式

//遍历
//1. 迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()) {Object obj = iterator.next();System.out.println(obj);
}//2. 增强 for
for (Object o : list) {System.out.println("o=" + o);
}//3. 使用普通 for
for (int i = 0; i < list.size(); i++) {System.out.println("对象=" + list.get(i));
}

冒泡排序:

//价格要求是从小到大
public static void sort(List list) {int listSize = list.size();for (int i = 0; i < listSize - 1; i++) {for (int j = 0; j < listSize - 1 - i; j++) {//取出对象 BookBook book1 = (Book) list.get(j);Book book2 = (Book) list.get(j + 1);if (book1.getPrice() > book2.getPrice()) {//交换list.set(j, book2);list.set(j + 1, book1);}}
}

14.5ArrayList 底层结构和源码分析

ArrayList 的注意事项:
1.允许所以元素,包括null,ArrayList可以加入多个null
2.ArrayList是又数组来实现数据存储
3.ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高),在多线程下,不建议使用ArrayList.

ArrayList 的底层操作机制源码分析:


Vector 底层结构和源码剖析:

public class Vector_ {public static void main(String[] args) {//无参构造器//有参数的构造Vector vector = new Vector(8);for (int i = 0; i < 10; i++) {vector.add(i);}vector.add(100);System.out.println("vector=" + vector);
//解读源码
//1. new Vector() 底层
/*
public Vector() {this(10);
}
补充:如果是 Vector vector = new Vector(8);
走的方法:
public Vector(int initialCapacity) {this(initialCapacity, 0);
}
2. vector.add(i)
2.1 //下面这个方法就添加数据到 vector 集合
public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;
}
2.2 //确定是否需要扩容 条件 : minCapacity - elementData.length>0
private void ensureCapacityHelper(int minCapacity) {// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}
2.3 //如果 需要的数组大小 不够用,就扩容 , 扩容的算法
//newCapacity = oldCapacity + ((capacityIncrement > 0) ?
// capacityIncrement : oldCapacity);
//就是扩容两倍. private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);
}
*/
}
}

Vector 和 ArrayList 的比较:

14.6LinkedList 底层结构



ArrayList 和 LinkedList 的比较:

14.7Set 接口和常用方法

1.Set无序,没有索引
2.不允许重复元素,所以最多包含一个null

和 List 接口一样, Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样.

Set接口的遍历方式:
同Collection的便利方式一样,因为Set接口是Collection接口的子接口
1.可以使用迭代器
2.增强for
3.不能使用索引的方式来获取

Set 接口实现类-HashSet:

  1. HashSet在执行 add 方法后,会返回一个 boolean 值,如果添加成功,返回 true, 否则返回 false
    2.可以通过 remove 指定删除哪个对象
public class HashSet02 {public static void main(String[] args) {HashSet set = new HashSet();System.out.println(set.add("john"));//TSystem.out.println(set.add("lucy"));//TSystem.out.println(set.add("john"));//FSystem.out.println(set.add("jack"));//TSystem.out.println(set.add("Rose"));//TSystem.out.println("set=" + set);//3 个set.remove("john");System.out.println("set=" + set);//3 个}
}

结果:
HashSet底层是HashMap,HashMap底层是数组+链表+红黑树。

源码解读:

HashSet hashSet = new HashSet();
hashSet.add("java");//到此位置,第 1 次 add 分析完毕. hashSet.add("php");//到此位置,第 2 次 add 分析完毕
hashSet.add("java");
System.out.println("set=" + hashSet);//1. 执行 HashSet()
public HashSet() {map = new HashMap<>();
}
//2. 执行 add()
public boolean add(E e) {return map.put(e, PRESENT)==null;//(static) PRESENT = new Object();
}
//3.执行 put() , 该方法会执行 hash(key) 得到 key 对应的 hash 值 算法 h = key.hashCode()) ^ (h >>> 16)
public V put(K key, V value) {//key = "java" value = PRESENT 共享return putVal(hash(key), key, value, false, true);
}
//4.执行 putVal
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i; //定义了辅助变量//table 就是 HashMap 的一个数组,类型是 Node[]//if 语句表示如果当前 table 是 null, 或者 大小=0//就是第一次扩容,到 16 个空间. if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;//(1)根据 key,得到 hash 去计算该 key 应该存放到 table 表的哪个索引位置//并把这个位置的对象,赋给 p//(2)判断 p 是否为 null//(2.1) 如果 p 为 null, 表示还没有存放元素, 就创建一个 Node (key="java",value=PRESENT)//(2.2) 就放在该位置 tab[i] = newNode(hash, key, value, null)
if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);
else {//一个开发技巧提示: 在需要局部变量(辅助变量)时候,在创建Node<K,V> e; K k; //
//如果当前索引位置对应的链表的第一个元素和准备添加的 key 的 hash 值一样
//并且满足 下面两个条件之一:
//(1) 准备加入的 key 和 p 指向的 Node 结点的 key 是同一个对象
//(2) p 指向的 Node 结点的 key 的 equals() 和准备加入的 key 比较后相同
//就不能加入
if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;
//再判断 p 是不是一颗红黑树, //如果是一颗红黑树,就调用 putTreeVal , 来进行添加
else if (p instanceof TreeNode)e =((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {//如果 table 对应索引位置,已经是一个链表, 就使用 for 循环比较
//(1) 依次和该链表的每一个元素比较后,都不相同, 则加入到该链表的最后
// 注意在把元素添加到链表后,立即判断 该链表是否已经达到 8 个结点
// , 就调用 treeifyBin() 对当前这个链表进行树化(转成红黑树)
// 注意,在转成红黑树时,要进行判断, 判断条件
// if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))
// resize();
// 如果上面条件成立,先 table 扩容. // 只有上面条件不成立时,才进行转成红黑树
//(2) 依次和该链表的每一个元素比较过程中,如果有相同情况,就直接 break
for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD(8) - 1) // -1 for 1sttreeifyBin(tab, hash);break;
}
if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;
p = e;}
}
if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}
}
++modCount;
//size 就是我们每加入一个结点 Node(k,v,h,next), size++
if (++size > threshold)resize();//扩容
afterNodeInsertion(evict);
return null;
}



package HashSet01;import java.util.HashSet;
import java.util.Objects;/*** @author * @version 1.0*/
public class HashSet01 {public static void main(String[] args) {HashSet hashSet = new HashSet();hashSet.add(new Employee("jack",30000,new MyDate("2019","12","31")));//okhashSet.add(new Employee("tom",4000,new MyDate("2023","1","11")));//okhashSet.add(new Employee("jack",20000,new MyDate("2019","12","31")));//nohashSet.add(new Employee("jack",30000,new MyDate("2000","12","31")));//okfor (Object o :hashSet) {System.out.println(o);}}
}class Employee{private String name;private double sal;private MyDate birthday;public Employee(String name, double sal, MyDate birthday) {this.name = name;this.sal = sal;this.birthday = birthday;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSal() {return sal;}public void setSal(double sal) {this.sal = sal;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "Employee{" +"name='" + name + '\'' +", sal=" + sal +", birthday=" + birthday +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Employee employee = (Employee) o;return Objects.equals(name, employee.name) && Objects.equals(birthday, employee.birthday);}@Overridepublic int hashCode() {return Objects.hash(name, birthday);}
}class MyDate{String year;String month;String day;public MyDate(String year, String month, String day) {this.year = year;this.month = month;this.day = day;}public String getYear() {return year;}public void setYear(String year) {this.year = year;}public String getMonth() {return month;}public void setMonth(String month) {this.month = month;}public String getDay() {return day;}public void setDay(String day) {this.day = day;}@Overridepublic String toString() {return "MyDate{" +"year='" + year + '\'' +", month='" + month + '\'' +", day='" + day + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;MyDate myDate = (MyDate) o;return Objects.equals(year, myDate.year) && Objects.equals(month, myDate.month) && Objects.equals(day, myDate.day);}@Overridepublic int hashCode() {return Objects.hash(year, month, day);}
}

14.8Set 接口实现类-LinkedHashSet


14.9Map 接口和常用方法

14.9.1 Map 接口实现类的特点


14.9.2 Map 接口常用方法

put:添加,修改都可

Map map = new HashMap();
map.put("邓超", new Book("", 100));//OK

remove:根据键删除映射关系

map.remove(null);

get:根据键获取值

Object val = map.get("鹿晗");

size:获取元素个数

System.out.println("k-v=" + map.size());

isEmpty:判断个数是否为 0

System.out.println(map.isEmpty());

clear:清除 k-v

map.clear();

containsKey:查找键是否存在

System.out.println("结果=" + map.containsKey("hsp"));

14.9.3 Map 接口遍历方法


containsKey:查找键是否存在
keySet:获取所有的键
entrySet:获取所有关系K-V
values:获取所有的值

//第一组: 先取出 所有的 Key , 通过 Key 取出对应的 Value
Set keyset = map.keySet();//(1) 增强 for
System.out.println("-----第一种方式-------");
for (Object key : keyset) {System.out.println(key + "-" + map.get(key));
}
//(2) 迭代器
System.out.println("----第二种方式--------");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {Object key = iterator.next();System.out.println(key + "-" + map.get(key));
}//第二组: 把所有的 values 取出
Collection values = map.values();
//这里可以使用所有的 Collections 使用的遍历方法
//(1) 增强 for
System.out.println("---取出所有的 value 增强 for----");
for (Object value : values) {System.out.println(value);
}//(2) 迭代器
System.out.println("---取出所有的 value 迭代器----");
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()) {Object value = iterator2.next();System.out.println(value);
}//第三组: 通过 EntrySet 来获取 k-v
Set entrySet = map.entrySet();// EntrySet<Map.Entry<K,V>>
//(1) 增强 for
System.out.println("----使用 EntrySet 的 for 增强(第 3 种)----");
for (Object entry : entrySet) {//将 entry 转成 Map.EntryMap.Entry m = (Map.Entry) entry;System.out.println(m.getKey() + "-" + m.getValue());
}
//(2) 迭代器
System.out.println("----使用 EntrySet 的 迭代器(第 4 种)----");
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {Object entry = iterator3.next();//System.out.println(next.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)//向下转型 Map.EntryMap.Entry m = (Map.Entry) entry;System.out.println(m.getKey() + "-" + m.getValue());}
}

14.10Map 接口和常用方法

14.10.1Map 接口实现类-HashMap


14.11.2Map 接口实现类-Hashtable


Hashtable 和 HashMap 对比:

14.11.3Map 接口实现类-Properties

14.11.4总结-开发中如何选择集合实现类(记住)

14.11.5Collections 工具类

排序操作:(均为 static 方法)

package com.hspedu.collections_;
import java.util.*;
@SuppressWarnings({"all"})
public class Collections_ {public static void main(String[] args) {//创建 ArrayList 集合,用于测试. List list = new ArrayList();list.add("tom");list.add("smith");list.add("king");list.add("milan");list.add("tom");// reverse(List):反转 List 中元素的顺序Collections.reverse(list);System.out.println("list=" + list);// shuffle(List):对 List 集合元素进行随机排序// for (int i = 0; i < 5; i++) {//      Collections.shuffle(list);//        System.out.println("list=" + list);// }// sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序Collections.sort(list);System.out.println("自然排序后");System.out.println("list=" + list);// sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序//我们希望按照 字符串的长度大小排序Collections.sort(list, new Comparator() {@Overridepublic int compare(Object o1, Object o2) {//可以加入校验代码.return ((String) o2).length() - ((String) o1).length();}});System.out.println("字符串长度大小排序=" + list);// swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换//比如Collections.swap(list, 0, 1);System.out.println("交换后的情况");System.out.println("list=" + list);//Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素System.out.println("自然顺序最大元素=" + Collections.max(list));//Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素//比如,我们要返回长度最大的元素Object maxObject = Collections.max(list, new Comparator() {@Overridepublic int compare(Object o1, Object o2) {return ((String)o1).length() - ((String)o2).length();}});System.out.println("长度最大的元素=" + maxObject);//Object min(Collection)//Object min(Collection,Comparator)//上面的两个方法,参考 max 即可//int frequency(Collection,Object):返回指定集合中指定元素的出现次数System.out.println("tom 出现的次数=" + Collections.frequency(list, "tom"));//void copy(List dest,List src):将 src 中的内容复制到 dest 中ArrayList dest = new ArrayList();//为了完成一个完整拷贝,我们需要先给 dest 赋值,大小和 list.size()一样for(int i = 0; i < list.size(); i++) {dest.add("");}//拷贝Collections.copy(dest, list);System.out.println("dest=" + dest);//boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值//如果 list 中,有 tom 就替换成 汤姆Collections.replaceAll(list, "tom", "汤姆");System.out.println("list 替换后=" + list);}
}

查找、替换:

第 15 章泛型

15.1泛型出现的原因

使用传统方法的问题分析:
1)不能对加入到集合ArrayList中的数据类型进行约束(不安全)
2)遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响
因此,引入泛型解决前面的问题

15.2泛型的理解和好处

泛型的好处:

15.3泛型的语法

泛型的声明:

泛型的实例化:
泛型使用的注意事项和细节:

课堂练习:

package com.hspedu.generic;
import java.util.ArrayList;
import java.util.Comparator;
/**
* @author 韩顺平
* @version 1.0
*/
@SuppressWarnings({"all"})
public class GenericExercise02 {public static void main(String[] args) {ArrayList<Employee> employees = new ArrayList<>();employees.add(new Employee("tom", 20000, new MyDate(1980,12,11)));employees.add(new Employee("jack", 12000, new MyDate(2001,12,12)));employees.add(new Employee("tom", 50000, new MyDate(1980,12,10)));System.out.println("employees=" + employees);employees.sort(new Comparator<Employee>() {@Overridepublic int compare(Employee emp1, Employee emp2) {//先按照 name 排序,如果 name 相同,则按生日日期的先后排序。【即:定制排序】//先对传入的参数进行验证if(!(emp1 instanceof Employee && emp2 instanceof Employee)) {System.out.println("类型不正确..");return 0;}//比较 nameint i = emp1.getName().compareTo(emp2.getName());if(i != 0) {return i;}//下面是对 birthday 的比较,因此,我们最好把这个比较,放在 MyDate 类完成//封装后,将来可维护性和复用性,就大大增强. return emp1.getBirthday().compareTo(emp2.getBirthday());}});System.out.println("==对雇员进行排序==");System.out.println(employees);}
}

15.4自定义泛型

因为静态是和类相关的,在类加载时,对象还没有创建,所以,如果静态方法和静态属性使用了泛型,JVM 就无法完成初始化。

自定义泛型接口:

自定义泛型方法:

泛型的继承和通配符:

15.4JUnit


第11-15章枚举|异常|常用类|集合|泛型相关推荐

  1. Day 7 2021.3.8Final-权限修饰符-部分常用类-集合-泛型

    Day 7 2020.3.8 Final关键字 package com.hong.Day007.Demo01; /* final关键字代表最终的.不可改变的 常见四种用法: 1.可以用来修饰一个类 格 ...

  2. 【2023】Kotlin教程 第二篇 面向对象与函数式编程 第15章 数据容器——数组和集合 15.2 集合概述

    [2023]Kotlin教程 文章目录 [2023]Kotlin教程 第二篇 面向对象与函数式编程 第15章 数据容器--数组和集合 15.2 集合概述 第二篇 面向对象与函数式编程 第15章 数据容 ...

  3. 浅谈Java锁,与JUC的常用类,集合安全类,常用辅助类,读写锁,阻塞队列,线程池,ForkJoin,volatile,单例模式不安全,CAS,各种锁

    浅谈JUC的常用类 JUC就是java.util.concurrent-包下的类 回顾多线程 Java默认有几个线程? 2 个 mian.GC Java 真的可以开启线程吗? 开不了,点击源码得知:本 ...

  4. 包,内部类,常用类,集合

    包--package 分包 实际开发中,用的都是多级包(不同的包下放不同的代码) 公司域名反写(中间加"."隔开) 包名: service------业务层代码:逻辑判断 dao( ...

  5. 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符

    学习资料 • 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值 • C++ 基类构造函数带参数的继承方式及派生类的初始化 定义拷贝构造函数 [注意]对派生类进行拷贝构造时,如果想让基类的成 ...

  6. 第十二章:Java_常用类

    1. String类: 不可变的字符序列(如:String str = "atguigu"; str += "javaEE")底层使用char[]存放.Stri ...

  7. 第九章总结 java常用类

    9.1 包装类 Java是一种面向对象的语言,但在Java中不能定义基本数据类型的对象,为了能将基本数据类型视为对象进行处理,Java提出了包装类的概念,它主要是将基本数据类型封装在包装类中,如in ...

  8. Java常用类工具-泛型

    .选择 以下语句正确的是:(多选) AB A. List list=new ArrayList(); B. List list=new ArrayList<>(); C. 已知Cat是An ...

  9. Think in Java第四版 读书笔记9第15章 泛型

    Think in Java第四版 读书笔记9第15章 泛型 泛型:适用于很多很多的类型 与其他语言相比 Java的泛型可能有许多局限 但是它还是有很多优点的. 本章介绍java泛型的局限和优势以及ja ...

最新文章

  1. Android Intent hasExtra()方法的使用
  2. 阅读笔记 CCL: Cross-modal Correlation Learning with Multi-grained Fusion by Hierarchical Network
  3. 基于MATLAB的OSPF协议网络仿真
  4. IEEE公布2.5G和5G以太网IEEE 802.3bz标准
  5. SAP云平台里两种类型的WebIDE
  6. 前端学习---css基本知识
  7. 文件循环读取_一个案例轻松认识Python文件处理提取文件中的数字
  8. ride上点击用例不能显示edit信息_接口测试平台代码实现61: 多接口用例1
  9. 【整理之路二】百度地图的路径规划和调用本机地图导航
  10. 学习channel设计:从入门到放弃
  11. Android doc|Getting Started| Training部分 --翻译 Working with System Permissions
  12. VBS中转换二进制数据为字符串常用办法
  13. layui参考文档地址
  14. 儿童吹泡泡水简单配方_最好的吹泡泡水的制作方法
  15. Python3爬取拉钩网职位,并分析
  16. 彼时彼刻,正如此时此刻——评《让×××飞》
  17. 高德地图:创建多个覆盖区域
  18. 「圆桌」无人驾驶何时来?| 甲子引力
  19. PS 学习笔记 03-移动工具图层概念
  20. gephi 使用简介汇总

热门文章

  1. springboot整合mybatis框架,超详细
  2. java activerecord.db_JFinal 源码分析 [DB+ActiveRecord]
  3. 数据仓库DW、ODS、DM及其区别总结
  4. VS2013与有道词典冲突
  5. Android Bluetooth蓝牙enable过程
  6. 基于Linux搭建开源配置管理中心apollo
  7. 华硕ROG Strix B360-5+ i5 9600K黑苹果EFI引导文件
  8. Android7.0从蓝牙导入联系人开发的实现
  9. Python计算机视觉编程第六章——图像聚类(K-means聚类,DBSCAN聚类,层次聚类,谱聚类,PCA主成分分析)
  10. linux 查询wwid命令,wwid、uuid、lun、multipath、hba、udev总结