- 不需要提供 setXxx 方法,因为枚举对象的值通常只读
- 对枚举对象 / 属性 使用 final + static 共同修饰,实现底层优化
- 枚举对象名通常使用全部大写,常量的命名规范
- 枚举对象根据需要,可以有多个属性
1】构造器私有化
2】本类内部创建一组对象
3】对外暴露对象 (通过为对象添加 public static final 修饰符)
4】可以提供 get 方法,但是不要提供 set 方法
public class enumeration01 {
public static void main(String[] args) {
System.out.println(Season.WINTER);
}
}
class Season {
private String name;
private String desc;
//定义四个对象
//如果使用static 属性会导致类的加载
//所以可以优化:static final
public static final Season SPRING = new Season("春天", "温暖");
public static final Season SUMMER = new Season("夏天", "炎热");
public static final Season AUTUMN = new Season("秋天", "凉爽");
public static final Season WINTER = new Season("冬天", "寒冷");
//1. 将构造器私有化,目的防止其他类 new
//2. 去掉setXXX方法,防止属性被修改
//3. 在Season 内部,直接创建固定的对象
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + ''' +
", desc='" + desc + ''' +
'}';
}
}
enum关键字实现枚举
public class enumeration02 {
public static void main(String[] args) {
System.out.println(Season02.SUMMER);
}
}
enum Season02 {
//如果使用enum 关键字来实现枚举
//1.使用关键字 enum 替代 class
//2. public static final Season SPRING = new Season("春天", "温暖");
// SPRING("春天", "温暖") ——> 常量名(实参列表)
//3. 如果有多个常量(对象) 使用 ,号间隔即可
//4. 如果使用enum 来实现枚举,要求将定义常量对象写在前面
//5、如果使用无参构造器创建枚举对象,则实参列表和小括号可以省略
SPRING("春天", "温暖"), SUMMER("夏天", "炎热"), AUTUMN("秋天", "凉爽"), WINTER("冬天", "寒冷"), WHAT;
private String name;
private String desc;
private Season02(String name, String desc) {
this.name = name;
this.desc = desc;
}
private Season02() {}//无参构造器
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + ''' +
", desc='" + desc + ''' +
'}';
}
}
使用注意:
1、当我们使用 enum关键字 开发一个枚举类时,默认会 extends Enum类
2、传统的 public static final Season02 = new Season02("春天","温暖");
简化成 SPRING("春天","温暖") 这里使用哪个构造器
3、如果使用无参构造器 创建枚举对象,则实参列表和小括号都可以省略
4、当有多个枚举对象时,使用 ,号间隔,最后一个以 ;号结尾
5、枚举对象必须放在枚举类的行首
enum常用方法
-
toString :Enum类已重写过,返回当前枚举对象名,子类可以重写该方法,用于返回对象信息
-
name : 返回当前对象名(常量名)子类不能重写
-
ordinal :返回当前对象位置号,默认从0开始
-
values :返回当前枚举类中所有常量
-
valuesOf :将字符串转换成枚举对象,要求字符串必须是已有的常量名,否则报错
-
compareTo :比较两个枚举常量,比较其编号
package enumeration; public class enumMethod { public static void main(String[] args) { //使用Season02 枚举类,演示各个方法 Season02 winter = Season02.WINTER; //输出枚举对象的名称 System.out.println(winter.toString()); //ordinal() 输出的是该枚举对象的次序/编号 //WINTER 枚举对象是第4个 因此输出为3(从0开始) System.out.println(winter.ordinal()); //从反编译可以看出 values方法,返回 Season02[] //含有定义的所有枚举对象 Season02[] values = Season02.values(); System.out.println("===遍历取出枚举对象(增强for)==="); for(Season02 season02 : values) { System.out.println(season02); } //valuesOf:将字符串转换成枚举对象,要求字符必须为已有常量名,否则报错 //执行流程: //1.根据你输入的 “XXX” 到 Season02的枚举对象去查找 //2.如果找到了就返回,如果没找到就报错 Season02 winter1 = Season02.valueOf("WINTER"); System.out.println("winter1=" + winter1); System.out.println(winter1 == winter);//true //compareTo : 比较两个枚举常量 比较的是编号 //相当于 Season02.SUMMER的编号[1] - Season02.WINTER的编号[3] System.out.println(Season02.SUMMER.compareTo(Season02.WINTER));//-2 } }增强 for循环
int[] nums = {1, 4, 9}; //普通for循环 for (int i = 0; i < nums.length; i++) { System.out.println(nums[i]); } //增强for循环 //执行流程:依次从nums取值赋给i 若取出完毕就退出for循环 for(int i : nums) { System.out.println("i=" + i); }
使用 enum关键字后,不能再继承其他类,因为enum隐式继承Enum,java是单继承机制
public class enumDetail {
public static void main(String[] args) {
COCO.TEA.make();
}
}
enum COCO implements MilkTea {
TEA;
@Override
public void make() {
System.out.println("coco奶茶");
}
}
interface MilkTea {
public void make();
}
注解
@Override
- @Override 表示指定重写父类的方法
- 如果不写 @Override 注解,而父类仍有该方法,仍构成重写
- @Override 只能修饰方法,不能修饰其他类、包、属性等
- 查看 @Override注解 源码为 @Target(ElementType.METHOD) 说明 只能修饰方法
- @Target 是修饰注解的注解,称为元注解
public class Override_ {
}
class Father {
public void say() {};
}
class Son extends Father {
//1. @Override 注解方法放在say方法上,表示子类的say方法是重写了父类的say方法
//2. 这里如果没有写 @Override 还是重写父类 fly方法
//3. 如果写了 @Override注解,编译器会去检查该方法是否真的重写了父类的方法
// 如果的确重写了,则编译通过,如果没有构成重写,则编译报错
//4. @Override 的定义
// 如果发现 @interface 表示一个 注解类
@Override
public void say() {
super.say();
}
// @Override 【报错】
// public void fly() {
// System.out.println();
// }
}
@Deprecated
- @Deprecated 用于表示某个程序元素(类,方法等)已过时
- 可以修饰类、方法、字段、包、参数 等
- @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
- @Deprecated 的作用可以做到新旧版本的兼容和过渡
package com.Annotation;
public class Deprecated_ {
public static void main(String[] args) {
OldSyrups oldSyrups = new OldSyrups();
oldSyrups.OldMethod01();
}
}
//1. @Deprecated 修饰某个元素,表示该元素已经过时
//2. 即不再推荐使用,但是仍可以使用
//3. 查看 @Deprecated注解 的源码
//4. 可以修饰 方法、类、字段、包、参数等
//5. @Documented 可以作为版本升级过渡使用
@Deprecated
class OldSyrups {
@Deprecated
public void OldMethod01() {}
}
@SuppressWarnings
| 关键字 | 用途 |
|---|---|
| all | to suppress all warnings |
| boxing | to suppress warnings relative to boxing/unboxing operations |
| cast | to suppress warnings relative to cast operations |
| dep-ann | to suppress warnings relative to deprecated annotation |
| deprecation | to suppress warnings relative to deprecation |
| fallthrough | to suppress warnings relative to missing breaks in switch statements |
| finally | to suppress warnings relative to finally block that don’t return |
| hiding | to suppress warnings relative to locals that hide variable |
| incomplete-switch | to suppress warnings relative to missing entries in a switch statement (enum case) |
| nls | to suppress warnings relative to non-nls string literals |
| null | to suppress warnings relative to null analysis |
| rawtypes | to suppress warnings relative to un-specific types when using generics on class params |
| restriction | to suppress warnings relative to usage of discouraged or forbidden references |
| serial | to suppress warnings relative to missing serialVersionUID field for a serializable class |
| static-access | o suppress warnings relative to incorrect static access |
| synthetic-access | to suppress warnings relative to unoptimized access from inner classes |
| unchecked | to suppress warnings relative to unchecked operations |
| unqualified-field-access | to suppress warnings relative to field access unqualified |
| unused | to suppress warnings relative to unused code |
package com.Annotation;
import java.util.ArrayList;
import java.util.List;
public class SuppressWarnings {
//1. 当我们不希望看见警告时,可以使用 @SuppressWarnings注解 来抑制警告信息
//2. 在{""} 中可以写入不希望抑制(不显示)警告信息
//3. 关于 @SuppressWarnings 的作用方位时和你放置的位置有关
// 通常可以放置在具体的语句,方法,或者更大的范围
//4. @SuppressWarnings 源码
//(1) 放置位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
//(2) 该注解有数组 String[] value() 设置一个数组比如 {"rawtypes", "unchecked", "unused"}
@java.lang.SuppressWarnings({"rawtypes", "unchecked", "unused"})
public static void main(String[] args) {
List list = new ArrayList();
list.add("jack");
list.add("tom");
list.add("mary");
int i;
System.out.println(list.get(1));
}
}
元注解
元注解是负责对其它注解进行说明的注解
@Retention 注解@Retention 用于描述注解的生命周期,也就是该注解被保留的时间长短。@Retention 注解中的成员变量(value)用来设置保留策略,value 是 java.lang.annotation.RetentionPolicy 枚举类型,RetentionPolicy 有 3 个枚举常量,如下所示。
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在 class 文件中有效(即 class 保留)
- RUNTIME:在运行时有效(即运行时保留)
生命周期大小排序为 SOURCE < CLASS < RUNTIME,前者能使用的地方后者一定也能使用。如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS 注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
@Target 注解@Target 注解用来指定一个注解的使用范围,即被 @Target 修饰的注解可以用在什么地方。@Target 注解有一个成员变量(value)用来设置适用目标,value 是 java.lang.annotation.ElementType 枚举类型的数组,下表为 ElementType 常用的枚举常量。
| 名称 | 说明 |
|---|---|
| CONSTRUCTOR | 用于构造方法 |
| FIELD | 用于成员变量(包括枚举常量) |
| LOCAL_VARIABLE | 用于局部变量 |
| METHOD | 用于方法 |
| PACKAGE | 用于包 |
| PARAMETER | 用于类型参数(JDK 1.8新增) |
| TYPE | 用于类、接口(包括注解类型)或 enum 声明 |
@Documented 是一个标记注解,没有成员变量。用 @Documented 注解修饰的注解类会被 JavaDoc 工具提取成文档。默认情况下,JavaDoc 是不包括注解的,但如果声明注解时指定了 @Documented,就会被 JavaDoc 之类的工具处理,所以注解类型信息就会被包括在生成的帮助文档中
@Inherited@Inherited 是一个标记注解,用来指定该注解可以被继承。使用 @Inherited 注解的 Class 类,表示这个注解可以被用于该 Class 类的子类。就是说如果某个类使用了被 @Inherited 修饰的注解,则其子类将自动具有该注解。
异常public class exception01 {
public static void main(String[] args) {
int n1 = 2;
int n2 = 0;
//快捷键 ctrl + alt + T
try {
int res = n1 / n2;
} catch (Exception e) {
System.out.println("错误原因=" + e.getMessage());//显示错误信息
}
System.out.println("程序继续执行...");
}
}
基本概念
异常体系图
小结:
- 异常分为两大类,运行时异常和编译时异常
- 运行时异常:编译器不要求强制处理的异常,一般指编程时的逻辑错误,是应避免其出现的异常【java.lang.RuntimeException类及它的子类 都是运行时异常】
- 运行异常可不作处理,保证程序的可读性和运行效率
- 编译时异常:是编译器要求必须处理的异常
1】NullPointerException 空指针异常
当应用程序试图在需要对象的地方使用 null 时,抛出该异常
public class NullPointerException {
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
}
2】ArithmeticException 数学运算异常
当出现异常的运算条件时,抛出此异常
public class ArithmeticException {
public static void main(String[] args) {
int n1 = 2;
int n2 = 0;
int res = n1 / n2;//除数不能=0
}
}
3】ArrayIndexOutOfBoundsException 数组下标越界异常
用非法索引访问数组时抛出的异常,如果索引为负数或者大于等于数组大小,则该索引为非法索引
public class ArrayIndexOutOfBoundsException {
public static void main(String[] args) {
int[] arr = {1, 3, 5};
for (int i = 0; i <= arr.length; i++) {//不能是 <=
System.out.println(arr[i]);
}
}
}
4】ClassCastException 类型转换异常
当试图将对象强制转换为不是实例的子类时,抛出该异常
public class ClassCastException {
public static void main(String[] args) {
B b = new B();//向上转型
B b2 = (B) b;//向下转型
C c2 = (B) b;//抛出ClassCastException异常
}
}
class A {}
class B extends A {}
class C extends A {}
5】NumberFormatException 数字格式不正确
当应用程序视图将字符串转换成一种数据类型,但该字符串不能转换为适当格式时,抛出该异常
public class exception01 {
public static void main(String[] args) {
String name = "绿军总冠军";
int num = Integer.parseInt(name);//抛出异常
System.out.println(num);
}
}
编译异常
编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译
异常处理异常处理就是当异常发生时,对异常处理的方式
1】try-catch-finally程序员在代码中捕获发生的异常,自行处理
如果代码未抛出异常,则catch 不执行,直接执行finally 可以没有finally
try-catch 方式处理异常说明
public class TryCatchDetail {
public static void main(String[] args) {
//1.如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块
//2.如果异常没有发生,则顺序执行try的代码块,不会进入catch
//3.如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用代码 finally
try {
String str = "123";
int a = Integer.parseInt(str);
System.out.println("数字=" + a);
} catch (NumberFormatException e) {
throw new RuntimeException(e.getMessage());
} finally {
System.out.println("finally代码被执行");
}
System.out.println("程序继续执行...");
}
}
public class TryCatch {
public static void main(String[] args) {
//1. 如果try代码块有可能有多个异常
//2. 可以使用多个catch 分别捕获不同的异常,相应处理
//3. 要求子类异常写在前面,父类异常卸载后面
try {
Person person = new Person();
// person = null;
System.out.println(person.getName());//NullPointerException
int 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) {
throw new RuntimeException(e);
} finally {
}
}
}
class Person {
private String name = "jack";
public String getName() {
return name;
}
}
public class TryCatch_ {
public static void main(String[] args) {
try {
int n1 = 10;
int n2 = 2;
System.out.println(n1 / n2);
}
finally {
System.out.println("执行了finally...");
}
System.out.println("程序继续执行...");
}
}
练习
import java.util.Scanner;
public class homework01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个整数");
String num;
do {
try {
num = scanner.next();
int realNum = Integer.parseInt(num);
break;
} catch (Exception e) {
System.out.println("请重新输入");
}
} while (true);
System.out.println("你输入的数=" + num);
}
}
2】throws
import java.io.FileInputStream;
public class Throws01 {
public static void main(String[] args) {}
public void f2() throws Exception {
//创建了一个文件流对象
//1. FileNotFoundException 编译异常
//2. 可以使用 try-catch-finally
//3. 使用throws 跳出异常,让调用f2方法的调用者(方法)处理
//4. throws后面的异常类型可以是方法中产生的异常类,也可以是它的父类
//5. throws 关键字后面可以是 异常列表,即可以抛出多个异常
FileInputStream fis = new FileInputStream("d://aa.txt");
}
}
将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者时JVM
public class exception02 {
//若没有显示使用try-catch-finally
//默认使用throws
public static void main(String[] args) throws Exception {
int n1 = 1;
int n2 = 0;
int res = n1 / n2;
}
}
throws 处理机制 1.try-catch-finally 和 throws 二选一 如果没有显示处理异常,默认使用throws
使用细节
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Throws02 {
public static void main(String[] args) {
f2();
}
public static void f2() {
//1. 对于编译异常,程序中必须处理:try-catch 或 throws
//2. 对于运行时异常,程序中如果没有处理,默认throws的方法处理
int n1 = 10;
int n2 = 0;
double res = n1 / n2;
}
public static void f1() {
//1. 因为 f3() 方法抛出的是一个编译异常
//2. 即这是,就要 f1() 必须处理这个异常【throws 或 try-catch】
try {
f3();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void f3() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d://aa.txt");
}
public static void f4() {
//1. 在f4() 中调用方法 f5() 是OK
//2. 原因是 f5() 抛出的是【运行异常】
//3. java中,不要求程序员处理,存在默认处理机制
f5();
}
public static void f5() throws RuntimeException {}
}
class Father {
public void method() throws RuntimeException {}
}
class Son extends Father {
//4. 在throws 过程中,如果方法 try-catch,就相当于处理异常,就可以不必throws
@Override
public void method() throws RuntimeException {}
}
自定义异常
基本概念:
当程序中出现了某些 “错误” ,但是该错误信息并没有在 Throwable 子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息
自定义异常步骤:
- 定义类:自定义异常类名(自己编写)extends Exception 或 RuntimeException
- 如果继承 Exception 属于编译异常
- 如果继承 RuntimeException 属于运行异常(一般来说,继承RuntimeException)
public class CustomException01 {
public static void main(String[] args) {
int age = 180;
//要求范围在 18——120 之间,否则抛出一个异常
if (! (age >=10 && age <= 120)) {
throw new AgeException("年龄需要在 18——120 之间");
}
System.out.println("年龄范围正确");
}
}
//自定义一个异常
//1. 一般情况下,我梦定义异常是继承 RuntimeException
//2. 即把自定义异常做成 运行时异常,好处【可以使用默认处理机制】
class AgeException extends RuntimeException {
public AgeException(String message) {
super(message);
}
}
throw 和 throws 的区别
练习
public class homework01 {
public static void main(String[] args) {
try {
if (! (args.length == 2)) {
throw new ArrayIndexOutOfBoundsException("参数个数错误");
}
int n1 = Integer.parseInt(args[0]);
int n2 = Integer.parseInt(args[1]);
double res = cal(n1, n2);
System.out.println("计算结果=" + res);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
} catch (NumberFormatException e) {
System.out.println("参数格式不正确,需要输入整数");
} catch (ArithmeticException e) {
System.out.println("出现除0异常");
}
}
public static int cal(int n1, int n2) {
return n1 / n2;
}
}
常用类
包装类
包装类 和 基本数据转换
- jdk5 以前手动装箱和拆箱方式,装箱:基本数据类型——>包装类型,反之,拆箱
- jdk5 以后(含jdk5)的自动装箱和拆箱方式
- 自动装箱底层调用 valueOf方法,比如Interger.valueOf()
public class Integer01 {
public static void main(String[] args) {
//int --> Integer 的装箱和拆箱
//jdk5 以前手动装箱和拆箱
//手动装箱 int --> Integer
int n1 = 10;
Integer integer = new Integer(n1);//第一种方式
Integer integer1 = Integer.valueOf(n1);//第二种方式
//手动拆箱 Integer --> int
int i = integer.intValue();
//jdk5 以后(含jdk5)可以自动装箱和拆箱方式
int n2 = 20;
//自动装箱
Integer integer2 = n2;//底层使用的是 Integer.valueOf(n2)
//自动拆箱
int n3 = integer2;//底层仍使用 intValue()方法
//========================================
char c1 = 'a';
//手动装箱
Character character = new Character(c1);
Character character1 = Character.valueOf(c1);
//手动拆箱
character.charValue();
//自动装箱
char c2 = 'b';
Character character2 = c2;//底层使用 Character.valueOf(c2)
//自动拆箱
char c3 = character2;//底层仍然使用 charValue()方法
}
}
三元运算符【是一个整体】先提升优先级,所以输出--> 1.0 if-else 是分开的 不会提升优先级所以输出--> 1而不是1.0包装类型 和 String类型的相互转换
public class WrapperVSString {
public static void main(String[] args) {
//包装类(Integer)-->String
Integer i = 10;
//方式1
String s1 = i.toString();
//方式2
String s2 = i + "";
//方式3
String s3 = String.valueOf(i);
//String-->包装类(Integer)
String str4 = "绿军总冠军";
//方式1
Integer i2 = Integer.parseInt(str4);//使用到了自动装箱
//方式2
Integer i3 = new Integer(str4);//构造器
}
}
面试题
public class Test01 {
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i==j);//false
//所以,范围如果在 -128~127 就直接返回
Integer m = 1;//底层 Integer.valueOf(1); -->阅读源码
Integer n = 1;
System.out.println(m == n);//true
//所以,范围如果在 -128~127 就直接返回
//否则, 就new Integer(xx)
Integer x = 128;
Integer y = 128;
System.out.println(x == y);//false
}
}
public class Test02 {
public static void main(String[] args) {
Integer i1 = new Integer(127);
int i2 = 127;
System.out.println(i1 == i2);//T
//只要有基本数据类型,判断的是值是否相同
}
}
String类
两种创建 String对象的方式
创建字符串最简单的方式如下:
String str = "Runoob";
在代码中遇到字符串常量时,这里的值是 “Runoob”,编译器会使用该值创建一个 String 对象。
和其它对象一样,可以使用关键字和构造方法来创建 String 对象。
用构造函数创建字符串:
String str2=new String("Runoob");
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:
String s1 = "Runoob"; // String 直接创建
String s2 = "Runoob"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Runoob"); // String 对象创建
String s5 = new String("Runoob"); // String 对象创建
两种创建String对象的区别
方式一;String s = "hsp"
方式二:String s2 = new String("hsp")
String的内存分布图
public class String01 {
public static void main(String[] args) {
//1.String 对象用于保存字符串,也就是一串字符序列
//2.“jack” 字符串常量,双引号括起来的字符序列
//3.字符串的字符使用Unicode字符编码:一个字符(不区分字母还是汉字)占两个字节
//4.String 类有很多构造函数,构造器重载
//6.String 是 final类 不能被其他类继承
//7.String 有属性:private final char value[]; 用于存放字符串内容
//8.注意:value 是一个 final类型,不可以修改【即value不能指向新的地址,但是单个字符内容可以变化】
String name = "jack";
name = "tom";
final char[] value = {'a', 'b', 'c'};
char[] v2 = {'t', 'o', 'm'};
value[0] = 'H';
// value = v2; 这里不可以更改 属性value的地址
}
}
String类【练习】
字符串的特性
1】String 是一个 final 类,代表不可变的字符序列
2】字符串是不可变的,一个字符串对象一旦被分配,其内容不可变
//以下语句创建了几个对象?【2个对象】 String s1 = "hello"; s1 = "haha"; //内存布局图如下
//以下语句创建了几个对象?【1个对象】 String a = "hello" + "abc"; //编译器进行优化,判断创建的常量池对象,是否有对象引用 //String a = "hello"+"abc"; ==> 优化等价于 String a = "helloabc";
重要规则:
String c1 = "ab" + "cd"; 常量相加,看的是池 String c1 = a + b; 变量相加,在堆中
import java.lang.String;
public class StringExercise08 {
public static void main(String[] args) {
String a = "hello";//创建 a对象
String b = "abc";//创建 b对象
//1. 先 创建一个 StringBuilder sb = StringBuilder();
//2. 执行 sb.append("hello");
//3. sb.append("abc")
//4. String c = sb.toString()
//最后其实是 c 指向堆中的对象(String) value[] --> 池中的 "helloabc"
String c = a + b; //创建了几个对象?【3个对象】
String d = "helloabc";
System.out.println(c == d);//false
String e = "hello" + "abc";
System.oout.println(e == d);//true
}
}
String对象特性【练习】
String类的常见方法
1】equals 比较内容是否相同,区分大小写
String str1 = "hello"; String str2 = "Hello"; System.out.println(str1.equals(str2));//false
2】equalsIgnoreCase 忽略大小写判断内容是否相同
public class StringMethod {
public static void main(String[] args) {
String name = "JACK";
if ("jack".equalsIgnoreCase(name)) {
System.out.println("True");//输出
} else {
System.out.println("False");
}
}
}
3】length 获取字符串的个数,字符串的长度
System.out.println("塔图姆牛逼".length());//5
4】indexOf 获取字符在字符串对象中第一次出现的索引,索引从0开始,如果找不到,返回 -1
String s1 = "abc@de@dfgab";
int index = s1.indexOf('@');
System.out.println(index);//3
//可以是字符串
System.out.println("首次出现ab的位置=" + s1.indexOf("ab"));//输出第一次出现a的位置=0
5】lastIndexOf 获取字符在字符串中最后一次出现的索引,索引从0开始,如果找不到返回 -1
String s1 = "abc@de@dfgab";
index = s1.lastIndexOf('@');//6
System.out.println(index);
System.out.println("最后出现ab的位置=" + s1.lastIndexOf("ab"));//输出最后出现a的位置=10
6】substring 截取指定范围的内容
String name1 = "hello,张三";
//下面name1.substring(6) 从索引开始截取后面所有的内容
System.out.println(name1.substring(6));//张三
//name1.substring(0,5)表示从索引0开始截取,截取到第5-1=4的位置
System.out.println(name1.substring(0,5));//hello
//name1.substring(2,5)表示从索引2开始截取,截取到第5-1=4的位置
System.out.println(name1.substring(2,5));//llo
7】toUpperCase 转换成大写
8】toLowerCase 转换成小写
public class StringMethod2 {
public static void main(String[] args) {
String s = "hello";
System.out.println(s.toUpperCase());//HELLO
System.out.println(s.toLowerCase());//hello
}
}
9】concat 拼接字符串
String s1 = "白起";
s1 = s1.concat("万人屠").concat("秦国名将").concat("invincible");
System.out.println(s1);//白起万人屠秦国名将invincible
10】replace 替换字符串中的字符
String s2 = "peace and war war war";
String s11 = s2.replace("war", "love");
System.out.println(s2);//peace and war war war
System.out.println(s11);//peace and love love love
11】split 分割字符串,对于某些分割字符,我们需要转义【比如:| 或 】
String poem = "锄禾日当午@汗滴禾下土@谁知盘中餐@粒粒皆辛苦";
//1. 以 @ 为标准对 poem 进行分割,返回一个 数组
String[] split = poem.split("@");
for (int i = 0; i < split.length; i++) {
System.out.println(split[i]);
}
//2. 在对字符串进行分割时如果有特殊字符,需要加入转义符-->
String poem2 = "E:\aaa\bbb";
String[] split2 = poem2.split("\\");
System.out.println("====分割后的内容====");
for (int i = 0; i < split2.length; i++) {
System.out.println(split2[i]);
}
12】toCharArray 转换成字符数组
String ss = "happy";
char[] chars = ss.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
13】compareTo 比较两个字符串的大小
//compareTo 比较两个字符串的大小,
//如果前者大则返回正数,后者大返回负数,如果相等返回0
//(1) 如果长度相同,并且每个字符也相同,就返回0
//(2) 如果长度相同或不相同,但在比较时可以区分大小
//(3) 如果前面的部分都相同,就返回 str1.length - str2.length
String a = "fac";
String b = "jac";
//char(“102”) f - char("108") j = -4
System.out.println(a.compareTo(b));//-4
compareTo 源码
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
14】format 格式化字符串
String name = "jack";
int age = 20;
double score = 211.985;
char gender = '男';
//1. %s, %d, %.2f, %c 称为占位符
//2. 这些占位符由后面变量来替换
//3. %s ——> 字符串来替换
//4. %d ——> 整数来替换
//5. %.2f ——> 表示小数来替换,替换后,会保留小数点后两位【进行四舍五入处理】
//6. %c ——> 使用char类型替换
// String info = String.format("姓名是%s年龄是%d成绩是%.2f性别是%c",name, age, score, gender);
String StrFormat = "姓名是%s 年龄是%d 成绩是%.2f 性别是%c";
String info2 = String.format(StrFormat, name, age, score, gender);
System.out.println(info2);
StringBuffer类
基本介绍
public class StringBuffer01 {
public static void main(String[] args) {
//1. StringBuffer 的直接父类是 AbstractStringBuilder
//2. StringBuffer 实现了 Serializable 即StringBuffer对象可以串行化
//4. StringBuffer 是一个 final 类,不能被继承
StringBuffer stringBuffer = new StringBuffer();
}
}
String类 和 StringBuffer类 区别
StringBuffer的构造器public class StringBuffer02 {
public static void main(String[] args) {
//1. 创建一个 容量为 16的 char[] 用于存放字符内容
StringBuffer stringBuffer = new StringBuffer();
//2. 通过构造器指定 char[] 容量
StringBuffer stringBuffer1 = new StringBuffer(100);
//3. 通过给一个 String 创建 StringBuffer, char[] 容量就是 str.length() + 16;
StringBuffer stringBuffer2 = new StringBuffer("hello");
}
}
String和StringBuffer相互转换
String ——> StringBuffer
public class StringBuffer03 {
public static void main(String[] args) {
//String-->StringBuffer
//方式一: 使用构造器
//注意: 返回的结果是StringBuffer对象,对 str 本身没有影响
String str = "hello future";
StringBuffer stringBuffer = new StringBuffer(str);
//方式二: 使用 append 方法
StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer.append(str);
}
}
StringBuffer ——> String
public class StringBuffer03 {
public static void main(String[] args) {
//StringBuffer-->String
StringBuffer stringBuffer2 = new StringBuffer("绿军总冠军");
//方法一: 使用StringBuffer提供的 toString方法
String s = stringBuffer2.toString();
//方法二: 使用构造器
String s1 = new String(stringBuffer2);
}
}
StringBuffer常用方法
1】append 增
2】delete 删
3】replace 改
4】indexOf 查
5】insert 插入
6】length 长度
package StringBuffer;
public class StringBufferMethod {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("凯尔特人");
//增
s1.append("塔图姆");//凯尔特人塔图姆
s1.append("牛逼").append("10000").append("绿军总冠军");//凯尔特人塔图姆牛逼10000绿军总冠军
System.out.println(s1.toString());
//删
s1.delete(9, 14);
System.out.println(s1.toString());//凯尔特人塔图姆牛逼绿军总冠军
//改
//使用 勇士 替换 索引 [9, 11) 的字符
s1.replace(9, 11, "勇士");
System.out.println(s1.toString());//凯尔特人塔图姆牛逼勇士总冠军
//查
//查找指定的字符串在字符串第一次出现的索引,如果找不到返回 -1
int indexOf = s1.indexOf("塔图姆");
System.out.println(indexOf);
//插入
//在索引为4的位置插入 ”杜兰特“,原来索引为4的内容自动后移
s1.insert(4, "杜兰特");
System.out.println(s1.toString());//凯尔特人杜兰特塔图姆牛逼勇士总冠军
//长度
System.out.println(s1.length());
}
}
练习
import java.util.Scanner;
public class StringBufferExercise01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入工资: ");
String price = scanner.next();
StringBuffer sb = new StringBuffer(price);
// 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);
}
}
StringBuilder类
基本介绍
StringBuilder 和 StringBuffer 均代表可变的字符序列
package StringBuilder;
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 关键字,因此在单线程的情况下使用 StringBuilder
StringBuilder stringBuilder = new StringBuilder();
}
}
String、StringBuffer 和 StringBuilder比较
package StringBuilder;
public class StringVsStringBuilderVsStringBuffer {
public static void main(String[] args) {
long startTime = 0L;
long endTime = 0L;
String text = "";
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) {
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
StringBuffer buffer = new StringBuffer("");
startTime = System.currentTimeMillis();
for (int i = 0; i < 80000; i++) {
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++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
}
}
Math类
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数
1】abs 绝对值
package Math_;
public class mathMethod {
public static void main(String[] args) {
int abs = Math.abs(-9);
System.out.println(abs);//9
}
}
2】pow 求幂
double pow = Math.pow(2, 4);//2的4次方
System.out.println(pow);
3】ceil 向上取整,返回 >= 该参数的最小整数
double ceil = Math.ceil(-3.002);
System.out.println(ceil);//-3.0
double ceil2 = Math.ceil(3.9);
System.out.println(ceil2);//4.0
4】floor 向下取整,返回 <= 该参数的最大整数
double floor = Math.floor(-3.002);
System.out.println(floor);//-4.0
double floor2 = Math.floor(3.9);
System.out.println(floor2);//3.0
5】round 四舍五入 Math.floor(该参数+ 0.5)
long round = Math.round(2.6);
System.out.println(round);//3
6】sqrt 求开方
double sqrt = Math.sqrt(-9.0);
System.out.println(sqrt);//NaN = Not a Number 表示一个无效的操作结果
double sqrt2 = Math.sqrt(9.0);
System.out.println(sqrt2);//3.0
7】random 求随机数 返回的是 0 <= x < 1 之间的一个随机小数
获取 a - b 之间的一个随机整数公式:
int num = (int)(Math.random() * (b-a+1) + a)
//思考: 请写出获取 a-b 之间的一个随机整数,a,b均为整数, 比如 a = 2,b = 7
//即返回一个数x 2 <= x <= 7
//解读:Math.random() * (b-a) 返回的就是 0 <= 数 <= b-a
//(1) (int)(a) <= x <= (int)(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 < 8 小数
// 2 + Math.random() * 6 返回 2 <= x < 8 小数
// (int) (2 + Math.random() * 6) ——> 2 <= x <= 7
//(3)公式是 (int)(int)(a + Math.random() * (b-a +1))
for (int i = 0; i < 10; i++) {
System.out.println((int)( 2 + Math.random() * (7 - 2 + 1)));
}
}
8】max 返回最大值
9】min 返回最小值
int min = Math.min(1, 9);
int max = Math.max(2, 6);
System.out.println("最小值=" + min);
System.out.println("最大值=" + max);
Arrays类
Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)
Arrays类常用方法1】tostring 返回数组的字符串形式
package Arrays_;
import java.util.Arrays;
public class ArraysMethod {
public static void main(String[] args) {
Integer[] integers = {2, 1, 90};
System.out.println(Arrays.toString(integers));
}
}
tostring 源码
public static String toString(Object[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(String.valueOf(a[i]));
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
2】sort 排序(自然排序和定制排序)
自然排序
package Arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysMethod {
public static void main(String[] args) {
Integer[] integers = {2, 1, 90};
System.out.println(Arrays.toString(integers));
Integer arr[] = {1, -2, 31, 9, 100};
//1. 可以直接使用冒泡排序,也可以直接使用Arrays的sort方法 排序
//2。 因为数组是引用类型,所以通过sort排序 会直接影响到实参
Arrays.sort(arr);//默认排序方法
System.out.println("===排序后1===");
System.out.println(Arrays.toString(arr));
Integer arr2[] = {5, 1, -4, 90, 3};
//3. sort是重载的,可以通过传入一个接口 comparator 实现定制排序
Arrays.sort(arr2, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer)o1;//向下转型
Integer i2 = (Integer)o2;
return i2 - i1;
}
});
System.out.println("===排序后2===");
System.out.println(Arrays.toString(arr2));
}
}
定制排序
package Arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysSortCustom {
public static void main(String[] args) {
int[] arr = {1, -1, 3, 80, 5};
// m1(arr);
m2(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
int i1 = (Integer) o1;//拆箱
int i2 = (Integer) o2;
return i2 - i1;
}
});
System.out.println(Arrays.toString(arr));
}
//冒泡 + 定制
public static void m2(int[] arr, Comparator c) {
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length -1 -i; j++) {
//数组排序由 c.compare(arr[j], arr[j+1]) 返回的值决定
if ((c.compare(arr[j], arr[j+1]) < 0)) {//动态绑定
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
//冒泡排序
public static void m1(int[] arr) {
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length -1 -i; j++) {
if (arr[j] < arr[j+1]) {
arr[j] = temp;
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
3】binarySearch 通过二分搜索进行查找,要求必须排序好
package Arrays_;
import java.util.Arrays;
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] arr = {1, 3, 90, 123, 226};
//binarySearch 通过二分搜索进行查找,【要求必须排序好】
//1. 使用binarySearch 二叉查找
//2. 要求该数组是有序的,如果该数组是无序的,不能使用binarySearch
//3. 如果数组中不存在该元素,就返回 return -(low + 1); // key not found.
// low ——> 该数应该存在的索引
// 例如:456 索引为5,但是不存在这个数,就返回 -(5+1) = -6
int index = Arrays.binarySearch(arr, 457);
System.out.println("index=" + index);//-6
}
}
4】copyOf 数组元素的复制
//1. 从 arr 数组中,拷贝 arr.length个元素到 newArr数组中
//2. 如果拷贝的长度 > arr.length 就在新数组的后面 插入 null
//3. 如果拷贝长度 <0 就抛出异常NegativeArraySizeException
//4。 该方法的底层使用的是 System.arraycopy()
Integer[] newArr = Arrays.copyOf(arr, arr.length);
System.out.println(Arrays.toString(newArr));
5】fill 数组元素的填充
Integer[] num = new Integer[]{9, 6, 8};
//1. 使用 100000 去填充 num数组,可以理解成是替换原来的元素
Arrays.fill(num, 100000);
System.out.println(Arrays.toString(num));
6】equals 比较两个数组元素内容是否完全一致
Integer[] arr2 = {1, 3, 90, 123};
//1. 如果 arr 和 arr2 数组的元素一样,则返回true
//2. 如果不是完全一样,就返回false
boolean equals = Arrays.equals(arr, arr2);
System.out.println("equals=" + equals);
7】asList 将一组值,转换成 list
//1. asList方法,会将(2, 4, 6, 8, 10)数据转成一个List 集合
//2. asList 编译类型 list(接口)
//3. asList 运行类型 java.util,Arrays$ArrayList,
// 即是Arrays类的静态内部类 private static class ArrayList extends AbstractList
// implements RandomAccess, java.io.Serializable
List asList = Arrays.asList(2, 4, 6, 8, 10);
System.out.println("asList=" + asList);
System.out.println("asList的运行类型 " + asList.getClass());
练习
package Arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysExercise01 {
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("梦", 50);
books[1] = new Book("三国演绎", 5);
books[2] = new Book("水浒", 150);
books[3] = new Book("知音漫客zzz", 20);
//按照书名长度排序
Arrays.sort(books, new Comparator() {
@Override
public int compare(Book o1, Book o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
return book1.getName().length() - book2.getName().length();
}
});
System.out.println(Arrays.toString(books));
}
}
class Book {
private String name;
private int price;
public Book(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "name=" + getName() + "price=" + getPrice();
}
}
package Arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysExercise01 {
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("梦", 50);
books[1] = new Book("三国演绎", 5);
books[2] = new Book("水浒", 150);
books[3] = new Book("知音漫客zzz", 20);
//按照价格排序
Arrays.sort(books, new Comparator() {
@Override
public int compare(Book o1, Book o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
int priceDifferent = book1.getPrice() - book2.getPrice();
if (priceDifferent > 0) {
return 1;
} else if (priceDifferent < 0) {
return -1;
} else {
return 0;
}
}
});
System.out.println(Arrays.toString(books));
}
}
class Book {
private String name;
private int price;
public Book(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
return "name=" + getName() + "price=" + getPrice();
}
}
System类
1】exit 退出当前程序
package System_;
public class SystemMethod {
public static void main(String[] args) {
System.out.println("ok1");
//1.exit(0) 表示程序退出
//2. 0表示一个状态 【正常状态】
System.exit(0);
System.out.println("ok2");
}
}
2】arraycopy 复制数组元素
比较适合底层,一般使用 Arrays.copyOf 完成复制数组
int[] src = {1, 2, 3};
int[] ints = new int[3];
// 【源数组】
// src – the source array.
// 【srcPos 从源数组的哪个索引位置开始拷贝】
// srcPos – starting position in the source array.
// 【dest 目标数组,即把源数组的数据拷贝到那个数组】
// dest – the destination array.
// 【destPos 把源数组的数据拷贝到 目标数组的哪个索引】
// destPos – starting position in the destination data.
// 【length 从源数组拷贝多少个数据到目标数组】
// length – the number of array elements to be copied.
System.arraycopy(src, 0, ints, 0, 3);
System.out.println(Arrays.toString(ints));
3】currentTimeMillens 返回当前时间距离 1970-1-1 的毫秒数
4】gc 运行垃圾回收机制
package System_;
public class Systemgc {
public static void main(String[] args) {
Car car = new Car("宝马");
car = null;
System.gc();
}
}
class Car {
private String name;
public Car(String name) {
this.name = name;
}
@Override
protected void finalize() throws Throwable {
System.out.println("进行销毁");
}
}
BigInteger类
BigInteger 适合保存比较大的整型
package BigInteger_;
import java.math.BigInteger;
public class BigInteger01 {
public static void main(String[] args) {
//编程时,需要处理很大的整数,long不够用,可以使用BigInteger类来搞定
BigInteger bigInteger = new BigInteger("10009900009999999999999999999");
System.out.println(bigInteger);
//1. 在对 BigInteger 进行加减乘除,需要使用对应的方法,不能直接 + - * /
//2. 可以创建一个要操作的 BigInteger 然后进行相应操作
BigInteger bigInteger2 = new BigInteger("100");
//加
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);
}
}
BigDecimal 类
BigDecimal 适合保存精度更高的浮点型(小数)
package BigDecimal_;
import java.math.BigDecimal;
public class bigDecimal {
public static void main(String[] args) {
BigDecimal bigDecimal = new BigDecimal("10.9999999999999999999999");
BigDecimal bigDecimal2 = new BigDecimal("1.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));
//否则可能出现 ArithmeticException 异常【无限循环小数】
//调用 divide 方法时,需要指定精度 BigDecimal.ROUND_CEILING
//如果出现无限循环小数,就会保留 分子的 精度
System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));
}
}
日期类
第一代日期类
1】Date :精确到毫秒,代表特定的瞬间
2】SimpleDateFormat :指定格式
3】parse :把String 格式转换为 Date
package Date_;
import java.text.ParseException;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Date1 {
public static void main(String[] args) throws ParseException {
//1.获取当前时间
//2.这里的Date类 是在java.util包
Date d1 = new Date();
System.out.println("当前日期= " + d1);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = simpleDateFormat.format(d1);
System.out.println("当前时期= " + format);
//指定毫秒数获取时间
Date d2 = new Date(1991991919);
System.out.println(d2);
//1. 可以把一个格式化的 String 转成一个对应的 Date
//2. 得到Date 仍然在输出时,按照国外形式,如果希望指定格式输出,需要使用 SimpleDateFormat 转换
//3. 在把String ——> Date 使用的sdf 格式需要和你给出的String格式一样,否则会抛出转换异常
String s = "1996年02月26日 10:20:36 星期六";
Date parse = simpleDateFormat.parse(s);//alt + enter 快捷键抛出异常
System.out.println("parse" + parse);
System.out.println("转回= " + simpleDateFormat.format(parse));
}
}
第二代日期类
第二代日期类,主要是 Calender 类
1】public abstract class Calender extends Object implements Serializable, Cloneable, Comparable
2】Calender 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MOUTH、DAY_OF_MOUTH、HOUR等日历字段之间的转换提供了一些方法,并且为操作日历字段(了例如获得下星期的日期)提供了一些方法
package Date_.Calender_;
import java.util.Calendar;
public class Calender01 {
public static void main(String[] args) {
//1. Calender 是一个抽象类,并且构造器是 protected
//2. 可以通过 getInstance() 来获取实例
//3. 提供大量方法和字段
//4. Calender 没有提供对应的格式化类,因此需要程序员自己组合来输出(灵活)
//5. 如果需要按照24小时制来获取时间 Calendar.HOUR ==改成==> Calendar.Hour_OF_
Calendar c = Calendar.getInstance();//创建日历类的对象
System.out.println("c=" + c);
//获取日历类的某个日历字段
System.out.println("年:" + c.get(Calendar.YEAR));
//因为 Calender 返回月的时候,是按照 0 开始编号,所以+1
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) + "时");
}
}
第三代日期类
1】LocalDate (日期/年月日):只包含日期,可以获取日期字段【以下方法JDK8加入】
2】LocalTime(时间/时分秒):只包含时间,可以获取时间字段
3】LocalDateTime :包含日期+时间,可以获取日期和时间字段
package LocalDate;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoField;
public class LocalDate_ {
public static void main(String[] args) {
// 使用 now() 返回当前日期对象
LocalDateTime ldt = LocalDateTime.now();//LocalDate.now;//LocalTime.now;
System.out.println(ldt);
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());
LocalDate now = LocalDate.now();//获取年月日
System.out.println(now.getYear());
LocalTime now2 = LocalTime.now();//获取时分秒
System.out.println(now2.get(ChronoField.HOUR_OF_AMPM));
System.out.println(now2.get(ChronoField.HOUR_OF_DAY));
}
}
4】DateTimeFormatter 格式日期类
类似于SimpleDateFormat
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(格式); String str = dtf.format(日期对象);
DateTimeFormatter d = DateTimeFormatter.ofPattern("yyyy年MM月 HH时mm分ss秒");
String format = d.format(ldt);
System.out.println("格式化后的日期=" + format);
5】Instant 时间戳
package Instant_;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.time.Instant;
public class Instant_ {
public static void main(String[] args) {
//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();
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//4.提供 plus 和 minus 方法可以对当前时间进行加或者减
//898天后,是什么时间
LocalDateTime localDateTime = ldt.plusDays(898);
System.out.println("898天后=" + dateTimeFormatter.format(localDateTime));
//3456分钟之前
LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
System.out.println("3456分钟前=" + localDateTime2);
}
}
本章练习
String翻转
package homework_;
public class homework01 {
public static void main(String[] args) {
String arr = "abcdefghi";
System.out.println("===交换前===");
System.out.println(arr);
try {
arr = reverse(arr, 1, 4);
} catch (Exception e) {
System.out.println(e.getMessage());
return;
}
System.out.println("===交换后===");
System.out.println(arr);
}
public static String reverse(String str, int start, int end) {
// 对输入的参数做一个验证
//(1) 写出正确的情况
//(2) 然后取反
if (! (str != null && start >= 0 && end < str.length() && end > start)) {
throw new RuntimeException("参数传入不正确");
}
char[] chars = str.toCharArray();
char temp;
for (int i = start, j = end; i < j; i++, j--) {
temp = chars[i];
chars[i] = chars[j];
chars[j] = chars[i];
}
return new String(chars);
}
}
注册处理
package homework_;
import java.util.Scanner;
public class homework02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("======注册页面========");
System.out.println("请设置用户名");
String userName = scanner.next();
System.out.println("请设置密码");
String passWord = scanner.next();
System.out.println("请输入email");
String emailxxx = scanner.next();
try {
userRegister(userName, passWord, emailxxx);
System.out.println("注册成功!!!");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void userRegister(String name, String pwd, String email) {
if (! (name == null && pwd == null && email == null) ) {
throw new RuntimeException("参数不能为空!");
}
int userLength = name.length();
if (! (userLength >= 2 && userLength <= 4 )) {
throw new RuntimeException("用户名长度为2或3或4");
}
if (! (pwd.length() == 6 && isDigital(pwd)) ) {
throw new RuntimeException("密码长度为6,且必须为数字");
}
int i = email.indexOf('@');
int j = email.indexOf('.');
if (! (i > 0 && j > i)) {
throw new RuntimeException("email 必须包含@ 且@ 在. 前");
}
}
public static boolean isDigital(String str) {
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] < '0' && chars[i] > '9') {
return false;
}
}
return true;
}
}
字符串统计
package homework_;
public class homework03 {
public static void main(String[] args) {
String name = "Han Shun Ping";
changeForm(name);
}
public static void changeForm(String name) {
if (name == null) {
System.out.println("不能为空");
return;
}
String[] names = name.split(" ");
if (names.length != 3) {
System.out.println("输入格式不正确 xxx xxx xxx");
return;
}
String format = String.format("%s,%s .%c", names[2], names[0], names[1].toUpperCase().charAt(0));
System.out.println(format);
}
}
package homework_;
public class homework04 {
public static void main(String[] args) {
String test = "ZheJiang University 985 211";
method01(test);
}
public static void method01(String str) {
if (str == null) {
System.out.println("不能为空");
return;
}
int AWord = 0;
int aword = 0;
int number = 0;
int Other = 0;
char[] chars = str.toCharArray();
for (int i = 0; i <= chars.length - 1; i++) {
if (chars[i] >= '0' && chars[i] <= '9') {
number++;
} else if (chars[i] >= 'a' && chars[i] <= 'z') {
aword++;
} else if (chars[i] >= 'A' && chars[i] <= 'Z') {
AWord++;
} else {
Other++;
}
}
System.out.println("数字有" + number + "个");
System.out.println("大写字母有" + AWord + "个");
System.out.println("小写字母有" + aword + "个");
System.out.println("其他类型有" + Other + "个");
}
}
集合
集合体系框架图
- 集合主要是两组(单列集合、双列集合)
- Collection 接口有两个重要的子接口 List Set ,他们的实现子类都是单列集合
- Map 接口的实现子类 是双列集合,存放 K-V 键值对
- Collection 实现类可以存放多个元素,每个元素可以是 Object
- 有些 Collection 的实现类,可以存放重复的元素,有些不可以
- 有些 Collection 的实现类,有些是有序的(List),有些不是有序的(Set)
- Collection 接口没有直接的实现子类,是通过它的子接口Set 和 List 来实现的
package collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Collection_ {
//以 ArrayList 实现类来演示
@SuppressWarnings("all")
public static void main(String[] args) {
//add 添加单个元素
List list = new ArrayList();
list.add("三国");
list.add("水浒");
list.add(true);
list.add(100);
System.out.println(list);
//remove 删除指定元素
// list.remove("三国");
list.remove(3); //按照索引删除
System.out.println(list);
//contains 查找元素是否存在
System.out.println(list.contains(true));//true
System.out.println(list.contains(100));//false
//size 获取元素个数
System.out.println(list.size());//3
//isEmpty 判断是否为空
System.out.println(list.isEmpty());//false
//clear 清空
list.clear();
System.out.println(list);//[]
//addAll 添加多个元素
ArrayList list2 = new ArrayList();
list2.add("斗罗大陆");
list2.add(200);
list.addAll(list2);
System.out.println(list);
//containsAll 查找多个元素是都都存在
System.out.println(list.containsAll(list2));//true
//removeAll 删除多个元素
list.removeAll(list2);
System.out.println(list);//[]
}
}
Collection 接口遍历元素的方式
1】使用 Iterator(迭代器)
基本介绍
- Iterator 对象称为迭代器,主要用于遍历 Collection 集合中的元素
- 所有实现了 Collection接口的集合类都有一个 iterator () 方法,用于返回一个实现了 Iterator 接口的对象,即可以返回一个迭代器
- Iterator 的结构
- Iterator 仅用于遍历集合,Iterator 本身并不存放对象
**【注意】**在调用 iterator.next() 方法之前必须调用 iterator.hasNext() 进行检测,若不调用,且下一条记录无效,直接调用 iterator.next() 会抛出 NoSuchElementException 异常
package collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class iterator_ {
public static void main(String[] args) {
Collection list = new ArrayList();
list.add(new Dog("罗威纳", 4000));
list.add(new Dog("边牧", 2000));
list.add(new Dog("柯基", 1000));
System.out.println(list);
//现在遍历 list 集合
//1. 先得到 list 对应的 迭代器
//2. 使用 while 循环遍历
Iterator iterator = list.iterator();
//itit ——> 快速生成 while
// ctrl + j 显示所有快捷方式
while (iterator.hasNext()) {//判断是否还有数据
//返回下一个元素,类型是Object
Object dogs = iterator.next();
System.out.println("dogs=" + dogs);
}
//3. 当退出 while 循环后,这时iterator 迭代器指向最后一个元素
// iterator.next(); --> NoSuchElementException
//4. 如果希望再次遍历,需要重置迭代器
iterator = list.iterator();
System.out.println("====第二次遍历===");
while (iterator.hasNext()) {
Object dogs2 = iterator.next();
System.out.println("dogs2=" + dogs2);
}
}
}
class Dog {
private String name;
private int price;
public Dog(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
}
2】for 循环增强
增强 for循环,可以代替 iterator 迭代器,特点:增强 for 就是简化版的 iterator,本质一样,只能用于遍历经济和或数据
基本语法
for(元素类型 元素名 :集合或数组名) {
访问元素
}
package collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionFor_ {
public static void main(String[] args) {
Collection list = new ArrayList();
list.add(new Dog("罗威纳", 4000));
list.add(new Dog("边牧", 2000));
list.add(new Dog("柯基", 1000));
//使用增强for
//1. 增强for 底层仍然是迭代器
//2. 增强for可以理解成就是简化版的 迭代器遍历
//3. 快捷方式 I
for (Object dogs : list) {
System.out.println("dogs=" + dogs);
}
//增强for 也可以直接在数组使用
int[] nums = new int[3];
nums[0] = 10;
nums[1] = 20;
nums[2] = 30;
for (int i : nums) {
System.out.println(i);
}
}
}
List接口
List接口基本介绍
List 接口是 Collection 接口的子接口
- List 集合类中元素有序(即添加顺序和取出顺序一致)且可重复
- List 集合中的每个元素都有其对应的顺序索引,即支持索引
- List 容器中的元素都对应的一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
- JDK API 中的 List 接口的实现类有:Vector、ArrayList、LinkedList 等等还有很多
package list;
import java.util.ArrayList;
public class list_ {
public static void main(String[] args) {
//1. List 集合类中元素有序(即添加顺序和取出顺序一致)且可重复
ArrayList arrayList = new ArrayList();
arrayList.add("jack");
arrayList.add("tom");
arrayList.add("jam");
arrayList.add("mary");
arrayList.add("tom");
System.out.println(arrayList);
//2. List 集合中的每个元素都有其对应的顺序索引,即支持索引
// 索引从 0 开始
System.out.println(arrayList.get(3));//mary
}
}
List接口常用方法
package list;
import java.util.ArrayList;
import java.util.List;
public class ListMethod {
public static void main(String[] args) {
List l = new ArrayList();
l.add("唐三");
l.add("奥斯卡");
//1. void add(int index, Object ele) 在index位置插入ele元素
// 在index = 1 的位置插入
l.add(1,"马红俊");
System.out.println(l);
//2. boolean addAll(int index, Collection eles) 从index位置开始将 eles中所有元素添加进来
ArrayList l2 = new ArrayList();
l2.add("jack");
l2.add("tom");
// 在index = 2 的位置 插入
l.addAll(2, l2);
System.out.println(l);
//3. Object get(int index) 获取指定index 位置的的元素
System.out.println(l.get(4));//奥斯卡
//4. int indexOf(Object obj) 返回obj在集合中首次出现的位置
l.add("唐三");
System.out.println(l.indexOf("唐三"));//0
//5. int lastIndexOf(Object obj) 返回obj 在当前集合中末次出现的位置
System.out.println(l);
System.out.println(l.lastIndexOf("唐三"));//5
//6. Object remove(int index) 移除指定的index位置的元素,并且返回此元素
l.remove(3);
System.out.println(l);
//7. Object set(int index, Object ele) 设置指定的index位置的的元素ele 【相当于替换】
l.set(0, "泰坦巨猿");
System.out.println(l);
//8. List subList(int fromIndex, int toIndex) 返回从fromIndex 到 toIndex位置的子集合
// 返回的自集合 【fromIndex <= xxx < toIndex】
List returnList = l.subList(2, 4);
System.out.println("returnList=" + returnList);//jack 奥斯卡
}
}
练习
package list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListExercise {
public static void main(String[] args) {
List l = new ArrayList();
//添加10个以上元素
for (int i = 0; i < 12; i++) {
l.add("luck" + i);
}
System.out.println("list02=" + l);
//在2号位插入一个一个元素
l.add(1, "哈哈哈哈哈哈");
System.out.println(l);
//获得第5个元素
System.out.println(l.get(4));
//删除第6个元素
System.out.println(l.remove(5));
//修改第7个元素
l.set(6, "wonderful哈哈哈");
System.out.println(l);
//使用迭代器遍历集合
Iterator iterator = l.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
}
}
List的三种遍历方式
package list;
import java.util.*;
public class ListFor {
public static void main(String[] args) {
//List 接口实现子类 Vector LinkedList
// List list = new Vector();
// List list = new LinkedList();
List list = new ArrayList();
list.add("tom");
list.add("jack");
list.add("鱼香肉丝");
list.add("糖醋里脊");
//遍历
//1. 迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
//2. 增强for循环
System.out.println("===增强for===");
for (Object o : list) {
System.out.println("o=" + o);
}
//3. 普通for循环
System.out.println("===普通for===");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
练习
package list;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
@SuppressWarnings("all")
public class ListExercise02 {
public static void main(String[] args) {
List arrayList = new ArrayList();
// List linkedList = new LinkedList();
// List VectorList = new Vector();
arrayList.add(new Book("红楼梦", 90, "曹雪芹"));
arrayList.add(new Book("三国", 60, "罗贯中"));
arrayList.add(new Book("水浒", 80, "施耐庵"));
arrayList.add(new Book("西游记", 10, "吴承恩"));
//冒泡排序
sort(arrayList);
for (Object o : arrayList) {
System.out.println(o);
}
}
//静态方法
public static void sort(List list) {
int temp = 0;
int listSize = list.size();
for (int i = 0; i < listSize - 1; i++) {
for (int j = 0; j < listSize - 1 - i; j++) {
//取出对象
Book 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);
}
}
}
}
}
class Book {
private String name;
private int price;
private String author;
public Book(String name, int price, String author) {
this.name = name;
this.price = price;
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "n名称:" + name + "tt价格:" + price + "tt作者:" + author;
}
}
ArrayList 类
注意事项
- premits all elements ,including null , ArrayList 可以存放 null 并且是多个
- ArrayList 是由数组来实现数据存储的
- ArrayList 基本等同于 Vector ,除了ArrayList 是线程不安全的(执行效率高)在多线程情况下,不建议使用ArrayList
-
ArrayList 中维护了一个Object 类型的数组 elementData 【transient Object[] elementData;】
transient 修饰的变量 不会被序列化
-
当创建 ArrayList 对象时,如果使用的是无参构造器,则初始 elementData 容量为0 ,第一次添加,则扩容 elementData 为 10, 如果需要再次扩容,则扩容 elementData 为1.5倍
-
如果使用的是指定大小的构造器,则初始 elementData 容量为指定大小,如果需要扩容,则直接扩容 elementData 为1.5倍
调用ArrayList有参构造器
Vector 类-
Vector基本介绍
public class Vector
extends AbstractList implements List , RandomAccess, Cloneable, java.io.Serializa -
Vector 底层也是一个对象数组 protected Object[] elementData;
-
Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized
-
在开发中需要线程同步安全的,考虑使用Vector
Vector底层结构和ArrayList的比较
Vector底层结构源码分析调用Vector有参构造器
LinkedList 类 LinkedList 基本介绍底层结构
- LinkedList 实现了双向链表和双端队列特点
- 可以添加任意元素(元素可以重复)包括null
- 线程不安全,没有实现同步
双向列表模拟
package List_LinkedList;
public class LinkedList {
public static void main(String[] args) {
//模拟一个简单的双向链表
Node jack = new Node("jack");
Node tom = new Node("tom");
Node ham = new Node("ham");
//连接三个结点,形成双向链表
//jack --> tom --> ham
jack.next = tom;
tom.next = ham;
//ham --> tom --> jack
ham.pre = tom;
tom.pre = jack;
Node first = jack;//让first引用指向jack,就是双向链表的头结点
Node last = ham;//让last引用指向ham, 就是双向链表的尾结点
//===========================================================
//从头到尾遍历
System.out.println("===从头到尾遍历===");
while (true) {
if (first == null) {
break;
}
//输出first 信息
System.out.println(first);
first = first.next;
}
System.out.println("===从尾到头遍历===");
while (true) {
if (last == null) {
break;
}
//输出first 信息
System.out.println(last);
last = last.pre;
}
//===========================================================
//jack 和 tom 之间插入 关羽
//1. 先创建一个 Node 结点,name 就是 关羽
Node guanyu = new Node("关羽");
guanyu.next = tom;
guanyu.pre = jack;
jack.next = guanyu;
tom.pre = guanyu;
//让first 再次指向 jack
first = jack;
System.out.println("===插入信息后 从头到尾遍历===");
while (true) {
if (first == null) {
break;
}
//输出first 信息
System.out.println(first);
first = first.next;
}
//让last 指向 ham
last = ham;
System.out.println("===插入信息后 从尾到头遍历===");
while (true) {
if (last == null) {
break;
}
//输出last信息
System.out.println(last);
last = last.pre;
}
}
}
class Node {
public Object item;//真正存放数据的地方
public Node pre;//指向上一个结点
public Node next;//指向后一个结点
public Node(Object name) {
this.item = name;
}
@Override
public String toString() {
return "Node name=" + item;
}
}
LinkedList 底层结构
增删改查CRUD
LinkedList 增
package List_LinkedList;
import java.util.LinkedList;
@SuppressWarnings("all")
public class LinkedListCRUD {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
System.out.println(linkedList);
}
}
LinkedList 删
package List_LinkedList;
import java.util.LinkedList;
@SuppressWarnings("all")
public class LinkedListCRUD {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
System.out.println(linkedList);
linkedList.remove();//删除第一个元素
LinkedList 改
LinkedList 查
LinkedList 类的三种遍历方式- 迭代器
- 增强for循环
- 普通for循环
//因为LinkedList 是 实现了List接口,所以其遍历方式:
//1. 迭代器
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
//2. 增强for循环
for (Object o : linkedList) {
System.out.println(o);
}
//3。 普通for循环
for (int i = 0; i
System.out.println(linkedList.get(i));
}
ArrayList 和 LinkedList 比较
如何选择:
- 如果改查操作多,选择ArrayList
- 如果增删操作多,选择LinkedList
- 一般来说,在程序中,80%-90%都是查询,所以大部分情况选择ArrayList
- 在一个项目中,根据业务灵活选择,可能一个模块使用ArrayList 另一个模块 使用LInkedList
- 两个线程都是不安全的
- 无序(添加和取出的顺序不一致),没有索引
- 不允许重复元素,所以最多包含一个null
- JDK API 中的set接口实现类有:
和List接口一样,Set接口也是Collection的子接口,因此,常用方法和 Collection接口一样
Set接口的遍历方式同Collection的遍历方式一样,因为Set接口是实现了Collection接口的子接口
- 迭代器
- 增强for
- 不能使用索引的方式来获取
package Set;
import java.util.HashSet;
import java.util.Iterator;
public class SetMethod {
public static void main(String[] args) {
//1. 以Set 接口的实现类 HashSet 来解释Set 接口的方法
//2. set 接口的实现类的对象(Set接口对象),不能存放重复元素,可以存放null
//3. set 接口的对象存放数据是无序的(即添加顺序和取出顺序不一致)
//4, 注意:取出顺序和添加顺序虽不一致,但取出顺序是固定的
HashSet hashSet = new HashSet();
hashSet.add("jack");
hashSet.add("lara");
hashSet.add("mary");
hashSet.add("lara");//重复元素
hashSet.add(null);
hashSet.add(null);
System.out.println("hashset=" + hashSet);
//遍历方式
//1. 迭代器
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
//2. 增强for
// 增强for底层源码调用的是迭代器
for (Object o : hashSet) {
System.out.println("o=" + o);
}
//set接口对象不能通过索引来获取【不能使用普通for】
}
}
HashSet 类
-
HashSet 实现了Set 接口
-
HashSet 实际上是 HashMap
public HashSet() { map = new HashMap<>(); } -
可以存放 null 值,但只能有一个null
-
HashSet 不保证元素是有序的,取决hash后,再确定索引的结果【即, 不保证存放元素的顺序和取出顺序一致】
-
不能有重复元素/对象
package Set_HashSet;
import java.util.HashSet;
import java.util.Set;
@SuppressWarnings("all")
public class HashSet01 {
public static void main(String[] args) {
Set set = new HashSet();
System.out.println(set.add("jack"));//T
System.out.println(set.add("jack"));//false
System.out.println(set.add("mary"));//T
System.out.println(set.add("tom"));//T
System.out.println(set.add(null));//T
System.out.println(set.add(null));//false
set = new HashSet();
System.out.println(set);//[]
//HashSet 不能添加相同的元素
set.add("lucy");//添加陈功
set.add("lucy");//失败
set.add(new Dog("puppy"));//ok
set.add(new Dog("puppy"));//ok
System.out.println("set=" + set);
//面试题
//查看add源码
set.add(new String("hello"));//ok
set.add(new String("hello"));//失败
System.out.println("面试题的set=" + set);
}
}
class Dog {
private String name;
public Dog(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + ''' +
'}';
}
}
HashSet底层机制
HashSet 底层HashMap, HashMap底层是**(数组+链表+红黑树)**
package Set_HashSet;
public class HashSet02 {
public static void main(String[] args) {
//模拟一个 HashSet的底层(HashMap 底层结构)
//1. 创建一个数组,数组类型是 Node[]
//2. Node[] 数组 称为 table(表)
Node[] table = new Node[16];
System.out.println("table=" + table);
//3, 创建结点
Node john = new Node("john", null);
table[2] = john;
Node jack = new Node("jack", null);
john.next = jack; //将 jack结点 挂载到 john
Node lucy = new Node("lucy", null);
jack.next = lucy; //将lucy结点 挂载到 jack
Node rose = new Node("Rose", null);
table[3] = rose; //把rose放到索引为3的位置
System.out.println("table=" + table);
}
}
class Node { //结点,存储数据,可以指向下一个结点,从而形成链表
Object item; //存放数据
Node next; //可以指向下一个结点
public Node(Object item, Node next) {
this.item = item;
this.next = next;
}
}
分析HashSet的添加元素底层是如何实现的
分析HashSet的扩容机制和转成红黑树的机制
package Set_HashSet;
import java.util.HashSet;
@SuppressWarnings("all")
public class HashSet04 {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
for (int i = 0; i <= 7; i++) {
hashSet.add(new B(i));
}
for (int i = 0; i <= 7; i++) {
hashSet.add(new C(i));
}
}
}
class B {
private int n;
public B(int n) {
this.n = n;
}
@Override
public int hashCode() {
return 100;
}
}
class C {
private int n;
public C(int n) {
this.n = n;
}
@Override
public int hashCode() {
return 200;
}
}
分析HashSet的添加元素底层如何实现【 hash() + equals() 】
package Set_HashSet;
import java.util.HashSet;
import java.util.Objects;
public class HashSetExercise {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add(new Employee("jack", 10));
set.add(new Employee("jack", 20));
set.add(new Employee("jack", 10));
System.out.println(set);
}
}
class Employee {
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
思考题
package Set_HashSet;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@SuppressWarnings("all")
public class HashSetExercise02 {
public static void main(String[] args) {
Set hashSet = new HashSet();
hashSet.add(new Employee_("jack", 2000, new MyDate(2010, 2, 14)));
hashSet.add(new Employee_("tom", 2000, new MyDate(2020, 3, 24)));
hashSet.add(new Employee_("jack", 2000, new MyDate(2010, 2, 14)));
System.out.println(hashSet);
}
}
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;
}
@Override
public String toString() {
return "Employee_{" +
"name='" + name + ''' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
@Override
public 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);
}
@Override
public int hashCode() {
return Objects.hash(name, birthday);
}
}
class MyDate {
private Integer year;
private Integer month;
private Integer day;
public MyDate(Integer year, Integer month, Integer day) {
this.year = year;
this.month = month;
this.day = day;
}
@Override
public String toString() {
return year + "年" + month + "月" + day + "日";
}
@Override
public 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);
}
@Override
public int hashCode() {
return Objects.hash(year, month, day);
}
}
LinkedHashSet 类
-
LinkedHashSet 是 HashSet 的子类
-
LinkedHashSet 底层是一个 LinkedHashMap,底层维护了一个 (数组 + 双向链表)
-
LinkedHashSet 根据元素的 hashCode 值来决定元素的储存位置,同时使用链表维护元素的次序,这使得元素看起来是以插入的顺序保存的
【加入顺序和取出顺序一致】
-
LinkedHashSet 不允许添加重复元素
package LindedHashSet_;
import java.util.LinkedHashSet;
import java.util.Set;
@SuppressWarnings("all")
public class LinkedHashSetSource {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add(new Person("AAA", 120));
set.add(666);
set.add(666);
set.add(new String("CCC"));
set.add("hsp");
System.out.println("set=" + set);
//1. LinkedHashSet 加入顺序和取出元素/数据顺序一致
//2. LinkedHashSet 底层维护的是一个 LinkedHashMap(是HashMap的子类)
//3. LinkedHashSet 底层结构 (数组table + 双向链表)
//4. 添加第一次时,直接将 数组table 扩容到16, 存放的结点类型是 LinkedHashMap$Entry
//5. 数组是 HashMap$Node[] 存放的元素/数据是 LinkedHashMap$Entry 类型
}
}
class Person {
private String name;
private int num;
public Person(String name, int num) {
this.name = name;
this.num = num;
}
}
package LindedHashSet_;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
public class LinkedHashSetExercise {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add(new Car("保时捷", 1000));//oK
set.add(new Car("宝马", 500));//ok
set.add(new Car("保时捷", 1000));//ok——> 重写hashCode 和 equals 方法后 添加失败
set.add(new Car("奔驰", 600));//ok
System.out.println("set=" + set);
}
}
class Car {
private String name;
private double price;
public Car(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "nCar{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
// @Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
// Car car = (Car) o;
// return Double.compare(car.price, price) == 0 && Objects.equals(name, car.name);
// }
@Override
public int hashCode() {
return Objects.hash(name, price);
}
}
TreeSet 类
package Set_TreeSet;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSet1 {
public static void main(String[] args) {
//调用无参构造器 创建TreeSet时【无序】
// TreeSet treeSet = new TreeSet();
//使用TreeSet 提供的一个构造器,可以传入一个比较器(匿名内部类)
//并指定排序规则
//根据字符先后排序
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//下面 调用String的 compareTo方法,默认比较 字符的大小
return ((String)o2).compareTo((String)o1);
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
System.out.println(treeSet);
//1. 构造器把传入的比较对象,赋给 TreeSet的底层的 TreeMap属性
//2. 在调用 treeSet.add("tom"),在底层会执行到 以下代码
}
}
package Set_TreeSet;
import java.util.Comparator;
import java.util.TreeSet;
public class Tree_SetExercise {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//根据字符长度排序
return ((String)o2).length() - ((String)o1).length();
}
});
treeSet.add("jack");//length = 4
treeSet.add("tim");
treeSet.add("wo");
treeSet.add("j");
treeSet.add("mary");//length = 4 不能加进去 因为此时比较结果 = 0
System.out.println(treeSet);
}
}
Map接口
- Map与Collection 并列存在,用于保存具有映射关系的数组:key-value
- Map 中的 key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中
- Map 中的 key 不允许重复【原因和 HashSet 一样】
- Map 中的 value 可以重复
- Map 的 key 可以为 null ,value 也可以为 null ,注意 key 为 null 只能有一个, value 为 null 可以多个
- 常用String 类作为 Map 的 key
- key 和 value 之间存在单向一对一的关系,即通过指定的 key 总能找到对应的 value
package Map_;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("all")
public class Map01 {
public static void main(String[] args) {
Map map = new HashMap();//k-v
map.put("No1", "王师傅");//k-v
map.put("No2","刘守元");//k-v
map.put("No1", "鸭子");//当有相同的Key时,就等价于替换
map.put("No3", "鸭子");//k-v Map 中 value 可以重复
map.put(null, null);//k-v
//key 只能有一个 null ,value 可以多个 null
map.put(null, "郭艾伦");//等价替换
map.put("No4", null);//k-v
map.put("No5", null);//k-v
//常用String 类作为 Map 的 key
Object obj = new Object();
map.put(obj,"hello world");//k-v
map.put(1, "大耳朵图图");
//通过get方法,传入 key ,会返回对应的 value
System.out.println(map.get(obj));
System.out.println(map);
}
}
- Map 存放数据的 key-value 示意图,一对 k-v 是放在一个HashMap$Node 中的,又因为Node 实现了 Entry 接口
package Map_;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("all")
public class MapSource_ {
public static void main(String[] args) {
Map map = new HashMap();
map.put("No1", "詹姆斯");
map.put("No2", "科比");
map.put("No3", "乔丹");
//1. k-v 最后是 HashMap$Node nobe = newNode(hash, key, value, null)
//2. k-v 为了啊方便程序员遍历,创建了 EntrySet 集合, 该集合存放的元素的类型 Entry
// 而一个 Entry 对象就有k, v
// 即:transient Set> entrySet;
//3. entrySet 中,定义的类型是 Map.Entry, 但是实际上存放的还是 HashMap$Node
// 因为 static class Node implements Map.Entry
Set set = map.entrySet();
System.out.println(set.getClass());
for (Object obj : set) {
//System.out.println(obj.getClass()); //HashMap$Node
//为了从 HashMap$Node 取出 k-v
//1. 先向下转型
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "-" + entry.getValue());
}
Set set1 = map.keySet();//存放所有数据的 key
System.out.println(set1);
Collection values = map.values();//存放所有数据的 value
System.out.println(values);
}
}
Map接口的常用方法
package Map_;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({"all"})
public class MapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("詹姆斯", new Team("热火", 5));
map.put("詹姆斯", "湖人");
map.put("塔图姆", "凯尔特人");
map.put("库里", "勇士");
map.put("克莱汤普森", "勇士");
map.put(null, "篮网");
map.put("东七七", null);
System.out.println(map);
//remove 根据键删除映射关系
map.remove(null);
System.out.println(map);
//get(key) 根据键获取值
System.out.println(map.get("詹姆斯"));//返回类型是 Object
//size 获取元素个数
System.out.println("k-v有= " + map.size());//5
//isEmpty 判断个数是否为 0
System.out.println(map.isEmpty());//boolean 类型
//clear 清空
map.clear();
System.out.println(map);
//containsKey 查找键是否存在
System.out.println(map.containsKey("库里"));//true
System.out.println(map.containsValue("篮网"));//F 已删除
}
}
class Team {
private String name;
private int num;
public Team(String name, int num) {
this.name = name;
this.num = num;
}
}
Map接口的遍历方法
package Map_;
import java.util.*;
public class MapFor {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("詹姆斯", "湖人");
map.put("塔图姆", "凯尔特人");
map.put("库里", "勇士");
map.put("克莱汤普森", "勇士");
map.put(null, "篮网");
map.put("东七七", null);
//第一组:先取出所有的Key ,通过 key 取出对应的Value;
Set keyset = map.keySet();
//(1) 增强for
for (Object key : keyset) {
System.out.println(map.get(key));
}
//(2) 迭代器
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(map.get(key));
}
//第二组:取出所有的values
Collection values = map.values();
//因为编译类型是 Collection 所以有2种方式遍历
//(1) 迭代器
System.out.println("===取出所有values 迭代器===");
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object value1 = iterator1.next();
System.out.println(value1);
}
//(2) 增强for
System.out.println("===取出所有values 增强for===");
for (Object value2 : values) {
System.out.println(value2);
}
//第三组:通过EntrySet 来获取 k-v
Set entrySet = map.entrySet();
//(1) 增强for
System.out.println("===通过EntrySet 增强for===");
for (Object entry : entrySet) {
//将entry 转成 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
//(2) 迭代器
System.out.println("===通过EntrySet 迭代器===");
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Object entry2 = iterator2.next();
//HashMap$Node--实现--> Map.Entry (getKey,getValue)
//向下转向 Map.Entry
Map.Entry m2 = (Map.Entry) entry2;
System.out.println(m2.getKey() + "-" + m2.getValue());
}
}
}
练习
package Map_;
import java.util.*;
@SuppressWarnings("all")
public class MapExercise {
public static void main(String[] args) {
Map map = new HashMap();
Worker jack = new Worker("jack", 19000, "2020");
Worker mary = new Worker("mary", 6000, "2019");
Worker tim = new Worker("tim", 18000, "2021");
map.put(jack.getId(), jack);
map.put(mary.getId(), mary);
map.put(tim.getId(), tim);
map.put(1, "larr");
//第一种遍历方式
System.out.println("===第一种遍历方式===");
Set keySet = map.keySet();
for (Object key : keySet) {
if (map.get(key) instanceof Worker) {
Worker w = (Worker) map.get(key);
if (w.getSalary() > 10000) {
System.out.println(w);
}
}
}
//第二种遍历方式
System.out.println("===第二种遍历方式===");
Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
if (map.get(key) instanceof Worker) {
Worker w = (Worker) map.get(key);
if (w.getSalary() > 10000) {
System.out.println(w);
}
}
}
//第三种遍历模式
System.out.println("===Entry 遍历方式===");
Set entrySet = map.entrySet();
if (entrySet instanceof Worker) {
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Map.Entry entry = (Map.Entry) iterator2.next();
Worker worker = (Worker) entry.getValue();
if (worker.getSalary() > 10000) {
System.out.println(worker);
}
}
}
//第四种遍历方式
System.out.println("===values 遍历方式=== ");
Collection values = map.values();
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object o1 = iterator1.next();
if (o1 instanceof Worker) {
Worker w1 = (Worker) o1;
if (w1.getSalary() > 10000) {
System.out.println(w1);
}
}
}
}
}
class Worker {
private String name;
private double salary;
private String id;
public Worker(String name, double salary, String id) {
this.name = name;
this.salary = salary;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "n姓名" + name + "t工资=" + salary + "t编号id " + id;
}
}
HashMap类
- Map接口的常用实现类:HashMap、Hashtable 和 Properties
- HashMap 是 Map 接口使用最频率最高的实现类
- HashMap 是以 key-value对 的方式来存储数据的(HashMap$Node)
- key 不能重复,但是value 可以重复,允许使用null 键和 null值
- 如果添加相同的 key,则会覆盖原来的 key-value,等同于修改(key不会替换,value会替换)
- 与HashSet一样,不保证映射顺序,因为底层是以hash表的方式存储的(JDK8 的 HashMap 底层: 数组+ 链表 + 红黑树)
- HashMap没有实现同步,因此线程不安全 ,方法没有做同步互斥的操作,没有 synchronized
扩容机制【和HashSe相同】
- HashMap底层维护了Node类型的数组 table,默认为null
- 当创建对象时,将加载因子(loadFactor)初始化为 0.75
- 当添加 key-value 时,通过 key 的哈希值得到 table 的索引,然后判断该索引处是否有元素,如果没有元素直接添加,如果该索引处有元素,继续判断该元素的 key 是否和准备加入的 key 相等,如果相等,则直接替换 value;如果不相等需要判断时树结构还是链表结构,做出相应处理,如果添加时返现容量不够,则需要扩容
- 第一次添加,则需要扩容 table 容量为16,临界值(threshold)12
- 以后再扩容,则需要扩容 table 容量为原来的 2 倍,临界值为原来的2倍(即24),依次类推
- 在Java8中,如果一条链表的元素个数超过了 TREEIFY_THRESHOLD ( 默认值为8 ),并且 table的大小 >= MIN_TREEIFY_CAPACITY (默认值为64) 就会进行树化(红黑树)
0 --> 16 (12) --> 32 (24) --> 64 (64 * 0.75 = 48) --> 128 (96)
最大容量是 2 ^ 30 = 1,073,741,824
Hashtable类 基本介绍- 存放的元素是键值对:即 K-V
- Hashtable的键和值都不能为null 【HashMap 允许键和值为null】
- Hashtable 使用方法基本上和 HashMap一样
- Hashtable 是线程安全的(synchronized),HashMap 是线程不安全的
package Map_MapTable;
import java.util.Hashtable;
public class HashTableExercise {
public static void main(String[] args) {
Hashtable table = new Hashtable();
table.put("john", 100);//ok
table.put("lucy", 100);//ok
table.put("tim", 100);//ok
table.put("tim", 60);//替换
table.put("mary", null);//NullPointerException异常
table.put(null, 100);//NullPointerException异常
System.out.println(table);
//Hashtable的底层机制
//1. 底层有数组 Hashtable$Entry[] 初始化为 11
//2. 临界值 threshold 8 --> 11 * 0.75
//3. 按照它自己的扩容机制进行的
}
}
Hashtable扩容机制
1. 执行方法 private void addEntry(int hash, K key, V value, int index) 添加 k-v 封装到 Entry 2. 当 if (count >= threshold) 满足时,就进行扩容 3. 按照 int newCapacity = (oldCapacity << 1) + 1; 的大小进行扩容 【11 * 2 + 1 = 23】Hashtable 和 HashMap 对比 Properties类 基本介绍
- Properties类继承自 Hashtable类并且实现了 Map接口,也是使用一种键值对的形式来保存数据
- 他的使用特点和Hashtable类似
- Properties 还可以用于 从xxx.properties 文件中,加载数据到 Properties类对象,并进行读取和修改
- 说明:工作后 xxx.properties 文件通常作为配置文件
package Map_Properties;
import java.util.Properties;
public class Properties_ {
public static void main(String[] args) {
Properties properties = new Properties();
// properties.put(null, 200);//空指针异常
// properties.put("ton", 100);//空指针异常
//增
properties.put("jack", 60);
properties.put("mary", 80);
properties.put("lucy", 70);
properties.put("lucy", 20);//替换
System.out.println(properties);
//删
properties.remove("jack");
System.out.println(properties);
//改
properties.put("mary", "hello world");
System.out.println(properties);
//查
System.out.println(properties.get("mary"));
System.out.println(properties.getProperty("mary"));//如果 value运行类型是 String类型则返回该value ,否则返回 null
}
}
TreeMap 类
package Map_TreeMap;
import java.util.Comparator;
import java.util.TreeMap;
@SuppressWarnings("all")
public class TreeMap_ {
public static void main(String[] args) {
//使用默认的构造器,创建TreeMap 是无序的
// TreeMap treeMap = new TreeMap();
//按照传入的字符串 k的大小进行排序
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String) o1).compareTo((String) o2);
}
});
treeMap.put("jack", "杰克");
treeMap.put("tom", "汤姆");
treeMap.put("smith", "史密斯");
treeMap.put("kristina", "罗纳尔多");
System.out.println(treeMap);
//按照传入的 字符串k 的长度进行比较
TreeMap treeMap1 = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
treeMap1.putAll(treeMap);
treeMap1.put("john", "约翰");//替换 "jack" value ——> 输出 jack=约翰
System.out.println(treeMap1);
//底层源码
}
}
⭐总结 - 如何选择集合实践类
记住!!!
1】先判断存储的类型(一组对象【单列】或一组键对值【双列】)
2】一组对象【单列】: Collection接口
允许重复:List
增删多:LinkedList 【底层维护了一个双向列表】
改查多:ArrayList 【底层维护 Object 类型的可变数组】
不允许重复:Set
无序:HashSet 【底层是 HashMap,维护了一个哈希表 ,即(数组 + 链表 + 红黑树)
排序:TreeSet
插入和取出顺序一致:LinkedHashSet 【底层维护 数组 + 双向链表】
3】一组键对值:Map
键无序:HashMap 【底层是:哈希值 jdk7 :数组 + 链表 jdk8:数组 + 链表 + 红黑树】
键排序:TreeMap
键插入和取出顺序一致:LinkedHashMap
读取文件:Properties
- Collections 是一个操作 Set、List 和 Map 等集合的工具类
- Collections 中提供了一系列静态的方法对集合元素进行排序、查找和修改等操作
【排序操作:均为 static 方法】 - reverse(List) :反转 List 中的元素的顺序
- shuffle(List) : 对 LIst 集合元素进行随机排序
- sort(List) :根据元素的自然顺序对指定 List 集合元素进行升序排序
- sort(List,Comparator) :根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List,int,int) :将指定 List 集合中的 i 处元素 和 j 处元素进行交换
package Collections_;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Collections_Method {
public static void main(String[] args) {
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
//reverse(List) 反转 List 中的元素顺序
Collections.reverse(list);
System.out.println("reverse方法 " + list);
//shuffle(List) 对 List 集合元素进行随机排序
for (int i = 0; i < 5; i++) {
Collections.shuffle(list);
System.out.println("shuffle方法 " + list);
}
//sort(List) 根据元素的自然顺序对指定 List 集合元素升序排序
Collections.sort(list);
//k < m < s < t
System.out.println("sort(List)方法 " + list);
//sort(List, Comparator) 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//安全校验
if (o1 instanceof String && o2 instanceof String) {
//按照字符串长度大小排序
return ((String) o1).length() - ((String) o2).length();
}
return 0;
}
});
System.out.println("sort(List, Comparator)方法 " + list);
//swap(List, int, int) 将指定 List 集合中的 i 处元素 和 j 处元素进行交换
Collections.swap(list, 1, 3);
System.out.println("swap方法" + list);
Collections.swap(list, 0, 100);//抛出 IndexOutOfBoundsException 索引越界异常
}
}
package Collections_;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@SuppressWarnings("all")
public class Collections_Method2 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("jack");
list.add("tim");
list.add("king");
list.add("milan");
list.add("he");
list.add("jack");
//Object max(Collection) 根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("自然顺序最大元素=" + Collections.max(list));
//Object max(Collection, Comparator) 根据 Comparator 指定的顺序,返回给定集合中的最大元素
//例如:返回长度的最大元素
Object maxObject = Collections.max(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
System.out.println("长度最大的元素=" + maxObject);
//Object min(Collection)
System.out.println("自然排序最小元素= " + Collections.min(list));
//Object min(Collection, Comparator)
Object minObject = Collections.min(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
System.out.println("长度最小的元素=" + minObject);
//int frequency(Collection, Object) 返回指定集合中指定元素出现的次数
System.out.println("jack出现的次数=" + Collections.frequency(list, "jack"));
//void copy(List dest, List src) 将src中的内容复制到dest中
//为了完成一个完整的拷贝,需要先给dest 赋值,大小为list.size()
ArrayList dest = new ArrayList();
for (int i = 0; i < list.size(); i++) {
dest.add("");
}
//拷贝
Collections.copy(dest, list);
System.out.println("拷贝后的=" + dest);
//boolean replaceAll(List list, Object oldVal, Object newVal) 使用新值替换 List 对象的所有旧值
//如果list中,有jack 就替换成 杰克
Collections.replaceAll(dest, "jack", "杰克");
System.out.println("dest替换后=" + dest);
}
}
本章练习
package HomeWork;
import java.util.ArrayList;
public class homework1 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add(new News("周杰伦新专辑"做自己的英雄"霸榜三个月"));//有引号需要添加转义符
arrayList.add(new News("是时候崛起了阿森,人的潜力是无限的,不要给自己设限度,加油,有梦就去追"));
int size = arrayList.size();
for (int i = size - 1; i >= 0; i--) {
// System.out.println(arrayList.get(i));
News news = (News)arrayList.get(i);
System.out.println(processTitle(news.getTitle()));
}
}
//专门写一个方法,处理显示新闻标题
public static String processTitle(String title) {
if (title == null) {
return "";
}
if (title.length() > 15) {
return title.substring(0, 15) + "...";//[0,15)
} else {
return title;
}
}
}
class News {
private String title;
private String content;
public News(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "标题为 " + title;
}
}
package HomeWork;
import java.util.ArrayList;
import java.util.Iterator;
@SuppressWarnings("all")
public class homework2 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
Car car = new Car("宝马", 400000);
Car car1 = new Car("奔驰", 600000);
//1. add 添加单个元素
arrayList.add(car);
arrayList.add(car1);
System.out.println(arrayList);
arrayList.remove(car);
//2. remove 删除指定元素
arrayList.remove(car);
System.out.println(arrayList);
//3. contains 查找元素是否存在
System.out.println(arrayList.contains(car1));//true
//4. size 获取元素个数
System.out.println("元素个数=" + arrayList.size());
//5. isEmpty 判断是否为空
System.out.println(arrayList.isEmpty());//false
//6. clear 清空
arrayList.clear();
System.out.println(arrayList);//[]
//7. addAll 添加多个元素
ArrayList arr = new ArrayList();
arr.add(new Car("保时捷", 900000));
arr.add(new Car("悍马", 30000));
arrayList.addAll(arr);
System.out.println("添加后=" + arrayList);
//8. containsAll 查找多个元素是否存在
System.out.println("是否多个元素存在" + arrayList.containsAll(arr));//true
//9. removeAll 删除多个元素
// arrayList.removeAll(arr);
System.out.println(arrayList);//[]
//遍历
System.out.println("==================增强for 遍历=================");
for (Object o : arrayList) {
System.out.println(o);
}
System.out.println("==================迭代器 遍历=================");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if (obj instanceof Car) {
if (((Car) obj).getName().length() > 2) {
System.out.println(obj);//保时捷
};
}
}
}
}
class Car {
private String name;
private int price;
public Car(String name, int price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "nCar{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package HomeWork;
import java.util.*;
@SuppressWarnings("all")
public class homework3 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("jack", 650);
map.put("tom", 1200);
map.put("smith", 2900);
System.out.println(map);
//1. 将jack的工资改为2600元
map.put("jack", 2600);
//2. 将所有员工工资加薪 100元
//keySet
Set set = map.keySet();
for (Object key : set) {
//更新
map.put(key, (Integer) map.get(key) + 100);
}
System.out.println("更新后" + map);
//遍历遍历所有员工
//EntrySet
System.out.println("======遍历======");
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
System.out.println(entry.getKey() + "-" + entry.getValue());
}
//取出所有员工工资
System.out.println("======遍历所有工资======");
Collection values = map.values();
for (Object value : values) {
System.out.println("工资=" + value);
}
}
}
HashSet
HashSet有以下特点
- 不能保证元素的排列顺序,顺序有可能发生变化
- 不是同步的
- 集合元素可以是null,但只能放入一个null
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
【自然排序】
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
【定制排序】
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
最重要:
1、TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值。
2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
3、HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。
package HomeWork;
import java.util.TreeSet;
public class homework5 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
//分析源码
treeSet.add(new Person());//抛出ClassCastException异常 原因:没有实现Comparator接口
}
}
class Person implements Comparable{//实现Comparator接口即可解决
@Override
public int compareTo(Object o) {
return 0;
}
}
));
arr.add(new Car(“悍马”, 30000));
arrayList.addAll(arr);
System.out.println(“添加后=” + arrayList);
//8. containsAll 查找多个元素是否存在
System.out.println(“是否多个元素存在” + arrayList.containsAll(arr));//true
//9. removeAll 删除多个元素
// arrayList.removeAll(arr);
System.out.println(arrayList);//[]
//遍历
System.out.println("==================增强for 遍历=================");
for (Object o : arrayList) {
System.out.println(o);
}
System.out.println("==================迭代器 遍历=================");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if (obj instanceof Car) {
if (((Car) obj).getName().length() > 2) {
System.out.println(obj);//保时捷
};
}
}
}
}
class Car {
private String name;
private int price;
public Car(String name, int price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "nCar{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
[外链图片转存中...(img-W1T3Tl0X-1655954739789)]
```java
package HomeWork;
import java.util.*;
@SuppressWarnings("all")
public class homework3 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("jack", 650);
map.put("tom", 1200);
map.put("smith", 2900);
System.out.println(map);
//1. 将jack的工资改为2600元
map.put("jack", 2600);
//2. 将所有员工工资加薪 100元
//keySet
Set set = map.keySet();
for (Object key : set) {
//更新
map.put(key, (Integer) map.get(key) + 100);
}
System.out.println("更新后" + map);
//遍历遍历所有员工
//EntrySet
System.out.println("======遍历======");
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
System.out.println(entry.getKey() + "-" + entry.getValue());
}
//取出所有员工工资
System.out.println("======遍历所有工资======");
Collection values = map.values();
for (Object value : values) {
System.out.println("工资=" + value);
}
}
}
[外链图片转存中…(img-6T2dWXgf-1655954739789)]
HashSet
HashSet有以下特点
- 不能保证元素的排列顺序,顺序有可能发生变化
- 不是同步的
- 集合元素可以是null,但只能放入一个null
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
【自然排序】
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
【定制排序】
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
最重要:
1、TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值。
2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
3、HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。
[外链图片转存中…(img-JRMUisDG-1655954739790)]
package HomeWork;
import java.util.TreeSet;
public class homework5 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
//分析源码
treeSet.add(new Person());//抛出ClassCastException异常 原因:没有实现Comparator接口
}
}
class Person implements Comparable{//实现Comparator接口即可解决
@Override
public int compareTo(Object o) {
return 0;
}
}
[外链图片转存中…(img-lqO13oBw-1655954739790)]



