拼图小游戏(Day16)
JFrame 窗体
JFrame jFrame = new JFrame();
// 设置窗体宽高
jFrame.setSize(400, 500);
// 设置窗体标题
jFrame.setTitle("测试弹窗");
// 设置窗体置顶
jFrame.setAlwaysOnTop(true);
// 设置窗体居中
jFrame.setLocationRelativeTo(null);
// 设置窗体关闭模式
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 取消窗体默认居中,如此设置坐标生效
jFrame.setLayout(null);
// 窗体可见
jFrame.setVisible(true);
菜单
JFrame jFrame = new JFrame();
// 菜单行
JMenuBar jMenuBar = new JMenuBar();
// 菜单具体栏
JMenu jMenu = new JMenu("功能");
// 菜单具体栏下拉框
JMenuItem jMenuItem1 = new JMenuItem("重新开始");
JMenuItem jMenuItem2 = new JMenuItem("退出");
jMenu.add(jMenuItem1);
jMenu.add(jMenuItem2);
jMenuBar.add(jMenu);
jFrame.setJMenuBar(jMenuBar);
窗体内容
用于短文本字符串或图像或两者的显示区域。
// 填充一个图片
public static void addImage(JFrame jFrame) {
// 创建图标对象
ImageIcon imageIcon = new ImageIcon("C:/workspace/lv_learn/image/1.png");
// jLabel填充图标
JLabel jLabel = new JLabel(imageIcon);
// jLabel设置坐标和宽高
jLabel.setBounds(0, 0, 105, 105);
// 窗体填充jLabel
jFrame.getContentPane().add(jLabel);
}
// 填充一个动作监听按钮1
public static void addActionButton1(JFrame jFrame) {
JButton jButton = new JButton("动作监听1");
jButton.setBounds(105, 0, 105, 30);
// 设置监听方式1: 使用匿名内部类
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("动作监听捕获1");
}
});
jFrame.getContentPane().add(jButton);
}
// 填充一个鼠标监听按钮1
public static void addMouseButton1(JFrame jFrame) {
JButton jButton = new JButton("鼠标监听1");
jButton.setBounds(0, 105, 105, 30);
jButton.addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("鼠标释放");
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("鼠标按下");
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("鼠标划出");
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("鼠标划入");
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("鼠标点击");
}
});
jFrame.add(jButton);
}
// 填充一个键盘监听按钮1
public static void addKeyButton1(JFrame jFrame) {
JButton jButton = new JButton("键盘监听1");
jButton.setBounds(0, 105 * 2, 105, 30);
jButton.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
System.out.println("键盘按下之后");
}
@Override
public void keyReleased(KeyEvent e) {
System.out.println("键盘释放");
int keyCode = e.getKeyCode();
switch (keyCode) {
case 65:
System.out.println("键盘释放A");
break;
case 66:
System.out.println("键盘释放B");
break;
default:
System.out.println("键盘释放未知");
break;
}
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println("键盘按下");
}
});
jFrame.add(jButton);
}
窗体内容美化(Day17)
- 拼图图片位置整体偏移至窗体中间
- 加入背景图,背景图的加入位置放在拼图图片后面,原因是先加入的图片会再后加入图片的上方。
- 为拼图图片设置边框
- 将拼图图片的路径由绝对路径修改为相对路径(模块名/…)
移动图片
- 整个窗体设置键盘监听事件, jFrame.setKeyListener…
- 记录空白拼图下标 x,y
- 键盘松开逻辑判断设置,注意空白拼图的左移,相当于图片的右移(逻辑比较绕)
- 键盘松开逻辑判断后,重新设置一次拼图 initImage
- 重新设置需要窗体内容部分(jFrame.getContentPane().removeAll()),删除当前的拼图部分,最后重新repaint一下(jFrame.getContentPane().repaint())
弹出提示图
- 窗体对象设置键盘监听事件, jFrame.setKeyListener…
- 键盘按下显示提示图
- 键盘松开还原拼图
其他(略)
常用API(Day18)
Math
package com.itheima.day18;
public class MathTest {
public static void main(String[] args) {
// abs 取值范围最小值不能取到绝对值
System.out.println(Math.abs(-11)); // 11
System.out.println(Math.abs(11)); // 11
System.out.println(Math.abs(-2147483648)); // -2147483648
System.out.println(Math.abs(-2147483647)); // 2147483647
// ceil
// floor
// round
System.out.println(Math.ceil(11.2)); // 12.0
System.out.println(Math.ceil(-11.2));// -11.0
System.out.println(Math.floor(11.2)); // 11.0
System.out.println(Math.floor(-11.2));// -12.0
System.out.println(Math.round(11.2));// 11.0
System.out.println(Math.round(11.5));// 12.0
System.out.println(Math.round(-11.2));// -11.0
System.out.println(Math.round(-11.6));// -12.0
// pow
// sqrt
// cbrt
System.out.println(Math.pow(2, 3)); // 8.0
System.out.println(Math.sqrt(16)); // 4.0
System.out.println(Math.cbrt(8)); // 2.0
// max
// min
System.out.println(Math.max(3, 2)); // 3
System.out.println(Math.min(3, 2)); // 2
// random
for (int i = 0; i < 100; i++) {
System.out.println(Math.ceil(Math.random() * 100)); // 1.0~100.0
}
}
}
System
package com.itheima.demo;
public class SystemTest {
public static void main(String[] args) {
// exit 终止java虚拟机
// 0:正常结束 非0:异常结束
//System.exit(0);
// currentTimeMillis(); 记录当前事件距离时间原点的毫秒差值
// 时间原点:1970.01.01 00:00:00
// 北京东八区时间原点:1970.01.01 08:00:00
long start = System.currentTimeMillis();
System.out.println(start);
// arraycopy(数组源头,数组源头开始下标,拷贝数组,数组开始下标,拷贝长度)
// 注意1:如果都是基本数据类型,则数据类型必须保持一致,否则报错
try {
int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double[] arr2 = new double[10];
System.arraycopy(arr1, 0, arr2, 0, arr1.length);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
} catch (Exception e) {
System.out.println(e.toString());
}
// 注意2:如果都是引用数据类型,子类对象可以拷贝给父类对象
try {
Student[] arr1 = {new Student("张三", 18), new Student("李四", 19), new Student("王五", 20)};
Person[] arr2 = new Person[10];
System.arraycopy(arr1, 0, arr2, 3, arr1.length);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
} catch (Exception e) {
System.out.println(e.toString());
}
// 注意3:如果超出拷贝数组长度,报错
try {
Student[] arr1 = {new Student("张三", 18), new Student("李四", 19), new Student("王五", 20)};
Person[] arr2 = new Person[3];
System.arraycopy(arr1, 0, arr2, 1, 3);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
public Student(String name, int age) {
super(name, age);
}
}
Runtime
package com.itheima.demo;
import java.io.IOException;
public class RuntimeTest {
public static void main(String[] args) throws IOException {
// getRuntime() 获取当前程序运行环境
Runtime runtime = Runtime.getRuntime();
// exit 终止JVM
// runtime.exit(0);
// availableProcessors 返回JVM可用的处理器的数目
System.out.println(runtime.availableProcessors());
// 返回JVM最大使用的内存大小byte
System.out.println(runtime.maxMemory() / 1024 / 1024);
// 返回JVM已经获取的内存大小byte
System.out.println(runtime.totalMemory() / 1024 / 1024);
// 返回JVM未使用的内存大小byte
System.out.println(runtime.freeMemory() / 1024 / 1024);
// exec 执行cmd命令
runtime.exec("notepad");
// shutdown -s 默认一分钟后关机
// shutdown -s -t 秒数
// shutdown -a 终止关机
// shutdown -r 关机重启
}
}
Object和Objects
package com.itheima.demo;
public class ObjectTest {
public static void main(String[] args) {
Object object = new Object();
System.out.println(object);
// object.toString() 全类名+@+十六进制地址
System.out.println(object.toString());
//object.equals(..) 返回地址比较的结果
System.out.println(object.equals("12"));
String str = "123";
StringBuilder stringBuilder = new StringBuilder("123");
// String.equals(..) 先比较地址是否相同,如果相同return true
// 否则比较是不是都是String类型的数据,如果不是return false
// 如果是则比较字符是否一一对应
System.out.println(str.equals(stringBuilder)); // false
// StringBuilder没有重写equals方法,调用的是object方法
System.out.println(stringBuilder.equals(str)); // false
}
}
package com.itheima.demo;
import java.util.Objects;
import java.util.StringJoiner;
public class Object2Test {
public static void main(String[] args) throws CloneNotSupportedException {
// clone() 类继承Cloneable接口后
// 默认的克隆方式是浅克隆
// 意思就是把栈中的值传给新的对象
// 深克隆需要自定义方法,或者引用第三方工具类
Teacher t1 = new Teacher("张三", 18, new String[]{"吃饭", "睡觉", "打豆豆"});
Teacher t2 = (Teacher) t1.clone();
t1.interests[0] = "学习";
System.out.println(t1);
System.out.println(t2);
System.out.println(t1 == t2); // false
System.out.println(t1.interests == t2.interests); // 深克隆 false 浅克隆 true
System.out.println("===============================");
//Objects
// equals 进行了空判定,返回为false
// isNull 是否为空
// nonNull 是否不为空
Teacher t3 = null;
Teacher t4 = null;
System.out.println(Objects.equals(t1, t2)); // false
System.out.println(Objects.equals(t2, t3)); // false
System.out.println(Objects.equals(t3, t4)); // false
System.out.println(Objects.isNull(t1)); // false
System.out.println(Objects.isNull(t3)); // true
System.out.println(Objects.nonNull(t1)); // true
System.out.println(Objects.nonNull(t3)); // false
}
}
// 克隆必须实现Cloneable
class Teacher implements Cloneable {
String name;
int age;
String[] interests;
public Teacher(String name, int age, String[] interests) {
this.name = name;
this.age = age;
this.interests = interests;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// return super.clone();
Teacher t2 = (Teacher) super.clone();
String[] newStrs = new String[interests.length];
System.arraycopy(interests, 0, newStrs, 0, interests.length);
t2.interests = newStrs;
return t2;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", interests=" + interestsStr() +
'}';
}
private String interestsStr() {
StringJoiner stringJoiner = new StringJoiner(",", "[", "]");
for (int i = 0; i < interests.length; i++) {
stringJoiner.add(interests[i]);
}
return stringJoiner.toString();
}
}
BigInteger
package com.itheima.demo;
import java.math.BigInteger;
import java.util.Random;
public class BigIntegerTest {
public static void main(String[] args) {
// 1.new BigInteger(int,random) 随机0 ~ 2^4 - 1
BigInteger bigInteger1 = new BigInteger(4, new Random());
System.out.println(bigInteger1);
// 2.new BigInteger(str) str转大整数
BigInteger bigInteger2 = new BigInteger("100");
System.out.println(bigInteger2);
// 3.new BigInteger(str,int) 其他进制转十进制
BigInteger bigInteger3 = new BigInteger("100", 2);
System.out.println(bigInteger3);
// 4.BigInteger.valueOf(long) long转大整数
// valueOf(-16~16)是类的静态属性值赋予的
// 超出long的最大值报错
BigInteger bigInteger4 = BigInteger.valueOf(100l);
System.out.println(bigInteger4);
System.out.println("==============================");
BigInteger b1 = BigInteger.valueOf(10);
BigInteger b2 = BigInteger.valueOf(2);
// 1.add
BigInteger b3 = b1.add(b2);
System.out.println(b3); // 12
// 2.subtract
BigInteger b4 = b1.subtract(b2);
System.out.println(b4); // 8
// 3.multiply
BigInteger b5 = b1.multiply(b2);
System.out.println(b5); // 20
// 4.divide
BigInteger b6 = b1.divide(b2);
System.out.println(b6); //5
// 5.divideAndRemainder
BigInteger[] b7 = b1.divideAndRemainder(b2);
System.out.println(b7[0] +" "+b7[1]); //5 0
// 6.equals
System.out.println(b1.equals(b2)); // false
// 7.pow
BigInteger b8 = b1.pow(2);
System.out.println(b8); // 100
// max/min
BigInteger b9 = b1.max(b2);
BigInteger b10 = b1.min(b2);
System.out.println(b9 == b1); //true
System.out.println(b9 == b2); //false
System.out.println(b10 == b1); //false
System.out.println(b10 == b2); //true
// intValue
int b11 = b1.intValue();
System.out.println(b11); // 10
// signum 代码正负号 或零
// [] 从大到小存储划分32位的int数据[...,64~33,32~1]
// 理论最大范围:int最大数的int范围的幂次方
}
}
BigDecimal
package com.itheima.demo;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalTest {
public static void main(String[] args) {
// 1.浮点型的运算可能会因为小数位转换成二进制后过长,从而丢失了超出长度的二进制位的数据
// 导致浮点数的运算之间也出现了误差
// BigDecimal的出现解决了两个浮点数的两个问题
// 一. 可以存储更大的浮点数数据
// 二. 可以进行浮点数的精确运算
// 2.实例化BigDecimal的方式
// 一. 如果数据过大 new BigDecimal(str)
// 二. 如果是小的浮点数 BigDecimal.valueOf(double)
// 三. 如果是0~10包括10的整数 BigDecimal.valueOf(long) 节省内存空间
BigDecimal bd1 = new BigDecimal(0.226);
BigDecimal bd2 = new BigDecimal("0.226");
BigDecimal bd3 = BigDecimal.valueOf(0.226);
BigDecimal bd4 = BigDecimal.valueOf(10);
BigDecimal bd5 = BigDecimal.valueOf(10);
BigDecimal bd6 = BigDecimal.valueOf(11);
BigDecimal bd7 = BigDecimal.valueOf(11);
System.out.println(bd1); // 有误差 0.2260000000000000064392935428259079344570636749267578125
System.out.println(bd2); // 0.226
System.out.println(bd3); // 0.226
System.out.println(bd4 == bd5); // true
System.out.println(bd6 == bd7); // false
// 3.常用的运算方法
BigDecimal bd8 = BigDecimal.valueOf(10);
BigDecimal bd9 = BigDecimal.valueOf(4);
BigDecimal bd10 = BigDecimal.valueOf(3);
// 加
System.out.println(bd8.add(bd9)); // 14
// 减
System.out.println(bd8.subtract(bd9)); // 6
// 乘
System.out.println(bd8.multiply(bd9)); // 40
// 除
System.out.println(bd8.divide(bd9)); // 2.5 除尽
try {
System.out.println(bd8.divide(bd10)); // 除不尽报异常
} catch (Exception e) {
System.out.println(e.toString());
}
// 四舍五入保留两位小数
System.out.println(bd8.divide(bd10, 2, RoundingMode.HALF_UP)); // 3.33
// 4.底层存储是将double->byte[] 报错每一位的ASCII码,包括负号
BigDecimal bigDecimal1 = BigDecimal.valueOf(-3.33);
// -3.33 -> [45,51,46,51,51]
BigDecimal bigDecimal2 = BigDecimal.valueOf(3.33);
// 3.33 -> [51,46,51,51]
}
}
Arrays
package com.itheima.demo;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysTest {
public static void main(String[] args) {
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 1.Arrays.toString(数组): 数组转换成数组字符串
System.out.println(Arrays.toString(nums));
// 2.Arrays.copyOf(旧数组,新数组长度);
System.out.println("---------------------------------------------------");
System.out.println(Arrays.toString(Arrays.copyOf(nums, nums.length - 1))); // 部分拷贝
System.out.println(Arrays.toString(Arrays.copyOf(nums, nums.length)));
System.out.println(Arrays.toString(Arrays.copyOf(nums, nums.length + 1))); // 超出进行赋默认值
// 3.Arrays.copyOfRange(旧数组,开始下标,结束下标) 包左不包右
System.out.println("---------------------------------------------------");
System.out.println(Arrays.toString(Arrays.copyOfRange(nums, 0, 2)));
System.out.println(Arrays.toString(Arrays.copyOfRange(nums, 2, nums.length)));
// 4.Arrays.binarySearch(数组,查询值) 数组必须是正有序数据
System.out.println("---------------------------------------------------");
System.out.println(Arrays.binarySearch(nums, 1)); // 0
System.out.println(Arrays.binarySearch(nums, 11));// -11
System.out.println(Arrays.binarySearch(nums, 0)); // -1
// 5.Arrays.fill(值) 填充覆盖原始数据
System.out.println("---------------------------------------------------");
Arrays.fill(nums, 100);
System.out.println(Arrays.toString(nums));
// 6.Arrays.sort(数组)
System.out.println("---------------------------------------------------");
Integer[] nums1 = { 1, 7, 8, 9, 10, 2, 3, 4, 5, 6 };
// Arrays.sort(nums1);
// System.out.println(Arrays.toString(nums1)); // 正序
// 插值排序 + 二分查找
Arrays.sort(nums1, new Comparator<Integer>() {
/**
* o1 插入值 o2 二分查找值
*/
@Override
public int compare(Integer o1, Integer o2) {
System.out.println("o1:" + o1 + ",o2:" + o2);
return o2 - o1;
}
});
System.out.println(Arrays.toString(nums1));// -11
}
}
正则表达式(Day19)
1. 字符数据的校验
更详细的正则相关字符说明查询Pattern API
链接:https://doc.qzxdp.cn/jdk/17/zh/api/java.base/java/util/regex/Pattern.html
package com.itheima.demo;
public class PatternTest {
public static void main(String[] args) {
// 正则表达式主要是为了快速校验而出现的数据
// 1.字符类
System.out.println("a".matches("[abc]")); //true
System.out.println("a".matches("[^123]")); //非 true
System.out.println("a".matches("[a-bd-f]"));// 和 true
System.out.println("a".matches("[a-c&&c-e]")); // 交集 false
System.out.println("c".matches("[a-c&&c-e]")); // true
System.out.println("c".matches("[a-c&&[^c-e]]")); // false
System.out.println("=====================================");
// 2.预定义字符类
System.out.println("a".matches("\\d")); //[0-9] false
System.out.println("a".matches("\\D")); //[^0-9] true
System.out.println("a".matches("\\w")); //[a-zA-Z0-9] true
System.out.println("a".matches("\\W")); //[^a-zA-Z0-9_] //false
System.out.println("a".matches(".")); // 任意字符(\n除外) true
System.out.println("a".matches("\\."));// . false
System.out.println("=====================================");
// 3.所有格量词类
System.out.println("aa".matches("\\w?")); //0或1 false
System.out.println("aa".matches("\\w+")); //1或n true
System.out.println("aa".matches("\\w*")); //0或n true
System.out.println("aa".matches("\\w{2}")); // 2 true
System.out.println("aaa".matches("\\w{2,}")); // >=2 true
System.out.println("aaa".matches("\\w{2,3}")); // >=2 <=3 true
// 4. | 并集
// 5. (?i) 忽略大小写
// 6. () 分组
}
}
2.文本数据的爬取
package com.itheima.demo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternTest02 {
public static void main(String[] args) {
String text = "JDK是java开发工具,最常用的JDK有JDK7,JDK8,JDK17";
// 1.定义正则表达式对象
Pattern pattern = Pattern.compile("JDK\\d{0,2}");
// 2.生成指定文本的匹配器
Matcher matcher = pattern.matcher(text);
// 3.遍历
// 3.1 matcher.find() 记录是否匹配成功,匹配成功返回true,内部记录开始的索引,和结束索引+1
while(matcher.find()){
// 3.2 matcher.group() 记录匹配成功的数据
System.out.println(matcher.group());
}
}
}
3.文本数据爬取拓展
package com.itheima.demo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternTest03 {
public static void main(String[] args) {
// ?= 爬取匹配数据且只打印指定部分数据
// ?: 爬取匹配数据打印匹配数据
// ?! 爬取不满足匹配设置的数据, 且只打印指定部分数据
String text = "JDK是JAVA开发工具,最常用的JDK版本有JDK7,JDK8,JDK17;JDK21也即将成为稳定的版本";
Pattern pattern1 = Pattern.compile("JDK(?=\\d{0,2})");
Matcher matcher1 = pattern1.matcher(text);
while (matcher1.find()) {
System.out.print(matcher1.group() + " ");
}
// result: JDK JDK JDK JDK JDK JDK
System.out.println("");
Pattern pattern2 = Pattern.compile("JDK(?:\\d{0,2})");
Matcher matcher2 = pattern2.matcher(text);
while (matcher2.find()) {
System.out.print(matcher2.group() + " ");
}
// result: JDK JDK JDK7 JDK8 JDK17 JDK21
System.out.println("");
Pattern pattern3 = Pattern.compile("JDK(?!\\d{2})");
Matcher matcher3 = pattern3.matcher(text);
while (matcher3.find()) {
System.out.print(matcher3.group() + " ");
}
// result: JDK JDK JDK JDK
// 正则匹配器默认是贪婪爬取,即尽可能匹配的更长
// 在+ * 等数量词后面加上问号(?) 变成非贪婪爬取,即尽可能匹配的更短
System.out.println("");
Pattern pattern4 = Pattern.compile("JDK\\d+");
Matcher matcher4 = pattern4.matcher(text);
while(matcher4.find()){
System.out.print(matcher4.group()+" ");
}
// JDK JDK JDK7 JDK8 JDK17 JDK21
System.out.println("");
Pattern pattern5 = Pattern.compile("JDK\\d+?");
Matcher matcher5 = pattern5.matcher(text);
while(matcher5.find()){
System.out.print(matcher5.group()+" ");
}
// JDK JDK JDK7 JDK8 JDK1 JDK2
// 字符串的相关方法的正则应用,需要以API的方法为准
// 例子:
// matches(String regex)
// replaceAll(String regex, String replacement)
// replaceFirst(String regex, String replacement)
// split(String regex)
// split(String regex, int limit)
System.out.println("");
String text1 = "吕懿洋afljsldkjflkj1243李桂祥asjdflkdjsflkj李敏";
// && 后面追加的也要用[] 括起来
System.out.println(text1.replaceAll("[\\w&&[^_]]+","vs")); // 吕懿洋vs李桂祥vs李敏
String[] array = text1.split("[\\w&&[^_]]+");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" "); // 吕懿洋 李桂祥 李敏
}
}
}
4.捕获分组和非捕获分组
package com.itheima.demo;
public class PatternTest04 {
public static void main(String[] args) {
// 1.分组 ()
// 以左括号为准记录组数,从1开始
// 正则表达式默认是捕获分组 \\1代表捕获第一组的值
System.out.println("a123a".matches("(.).+\\1")); // true
System.out.println("b456b".matches("(.).+\\1")); // true
System.out.println("17891".matches("(.).+\\1")); // true
System.out.println("&abc&".matches("(.).+\\1")); // true
System.out.println("===================================");
System.out.println("abc123abc".matches("(.+).+\\1")); // true
System.out.println("b456b".matches("(.+).+\\1")); // true
System.out.println("123789123".matches("(.+).+\\1")); // true
System.out.println("&!@abc&!@".matches("(.+).+\\1")); // true
System.out.println("===================================");
System.out.println("aaa123aaa".matches("((.)\\2*).+\\1")); // true
System.out.println("bbb456bbb".matches("((.)\\2*).+\\1")); // true
System.out.println("111789111".matches("((.)\\2*).+\\1")); // true
System.out.println("&&abc&&".matches("((.)\\2*).+\\1")); // true
System.out.println("ababcab".matches("((.)\\2*).+\\1")); // false
System.out.println("===================================");
String str = "我要学学学学学学编编编编编编编程程程程程程程程程程程";
// $1 约等于 \\1
System.out.println(str.replaceAll("(.)\\1+","$1")); // 我要学编程
//2. ?: ?! ?= 都是非捕获分组,是没有需要的
System.out.println(str.replaceAll("(.)(?:\\1)\\1*","$1")); // 我要学编程
}
}
日期类(Day20)
JDK7版本相关
Date类
package com.glad.flowable;
import java.util.Date;
import java.util.Random;
public class DateTest01 {
public static void main(String[] args) {
// 1.时间知识普及:
// 格林威治标准时间 标准开始时间: 1970.01.01 00:00:00 GMT
// 中国:东八区时间 +8小时
// 日本:东九区时间 +9小时
// 2.创建Date对象
Date d1 = new Date(); // 返回当前时区当前时间
System.out.println(d1);
Date d2 = new Date(0L); // 返回当前时区开始时间
System.out.println(d2);
// 3.设置时间
d1.setTime(1000L); // 加1秒
System.out.println(d1);
// 4.获取时间
long time1 = d1.getTime();
System.out.println(time1); // 1000
// 小练1: 获取当前时间和当前时间+1年
Date d3 = new Date();
long time2 = d3.getTime();
Date d4 = new Date(time2 + 1000L * 60 * 60 * 24 * 365);
System.out.println(d3);
System.out.println(d4);
// 小练2: 随机生成两个时间,判断日期大小
Random random = new Random();
Date d5 = new Date(Math.abs(random.nextInt()));
Date d6 = new Date(Math.abs(random.nextInt()));
long time3 = d5.getTime();
long time4 = d6.getTime();
System.out.println(d5);
System.out.println(d6);
if (time3 > time4) {
System.out.println("第一个大");
} else if (time4 > time3) {
System.out.println("第二个大");
} else {
System.out.println("一样大");
}
}
}
SimpleDateFormat类
用于解析字符串转换成日期,或者格式化日期转换成字符串
package com.itheima.demo;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest {
public static void main(String[] args) throws ParseException {
// SimpleDateFormat作用
// 1.格式化日期,返回字符串
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat();
System.out.println(sdf.format(date));
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf2.format(date));
// 2.解析字符串,返回日期,注意:解析内容必须和格式化内容保持一致
Date date1 = sdf2.parse("2024-01-11 20:53:34");
System.out.println(date1);
// 字符串2011-11-11 -> 日期2011年11月11日
String dateStr = "2011-11-11";
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdf4 = new SimpleDateFormat("yyyy年MM月dd日");
System.out.println(sdf4.format(sdf3.parse(dateStr)));
// 秒杀时间是2023年11月11日 0:0:0 ~ 2023年11月11日 0:10:0
String d1 = "2023年11月11日 0:0:0";
String d2 = "2023年11月11日 0:10:0";
String d3 = "2023年11月11日 0:1:0";
String d4 = "2023年11月11日 0:11:0";
SimpleDateFormat sdf5 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date d11 = sdf5.parse(d1);
Date d22 = sdf5.parse(d2);
Date d33 = sdf5.parse(d3);
Date d44 = sdf5.parse(d4);
long start = d11.getTime();
long end = d22.getTime();
if (start <= d33.getTime() && end >= d33.getTime()) {
System.out.println("小红参与了");
} else {
System.out.println("小红没参与了");
}
if (start <= d44.getTime() && end >= d44.getTime()) {
System.out.println("小蓝参与了");
} else {
System.out.println("小蓝没参与了");
}
System.out.println(d11);
System.out.println(d22);
}
}
Calendar类
package com.itheima.demo;
import java.util.Calendar;
import java.util.Date;
public class CalendarTest {
public static void main(String[] args) {
// Calendar的出现是便于我们对时间的操作
// 1.设置时间
// 细节1:Calendar不是new出来的
Calendar c1 = Calendar.getInstance(); // 默认发挥当前时区时间
System.out.println(c1);
c1.setTime(new Date(0L)); // 时间原点
System.out.println(c1);
c1.setTimeInMillis(1000L); // 时间原点+1秒
System.out.println(c1);
// 2.改变时间
// 月份是0~11 星期从周日开始1~7
c1.set(1, 2000); // 设置年为2000
c1.set(2,11); // 设置月为12月
System.out.println(c1);
// 3.加减时间
c1.add(2,1); // +一个月
System.out.println(c1);
}
}
JDK8版本相关
注意:JDK8的日期对象,为了线程安全,都是不可变的。对日期对象的操作都会生成一个新的日期对象。
ZoneId类
package com.itheima.demo;
import java.time.ZoneId;
import java.util.Set;
public class ZoneIdTest {
public static void main(String[] args) {
// 1.获取Java支持的所有时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
System.out.println(availableZoneIds);
// 2.获取当前时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);
// 3.指定一个时区
ZoneId of = ZoneId.of("Africa/Monrovia");
System.out.println(of);
}
}
Instant类
package com.itheima.demo;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class InstantTest {
public static void main(String[] args) {
// 1.默认获取当前时间(无时区)
Instant now = Instant.now();
System.out.println(now);
// 2.指定毫秒/秒/纳秒对应的无时区时间
Instant instant = Instant.ofEpochMilli(0L);
Instant instant1 = Instant.ofEpochSecond(1L);//+1
Instant instant2 = Instant.ofEpochSecond(1L, 1000000000L);//+2
System.out.println(instant);
System.out.println(instant1);
System.out.println(instant2);
// 3.加入时区
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
System.out.println(zonedDateTime);
// 4.比较时间
boolean before = instant.isBefore(instant1);
System.out.println(before); // false
boolean after = instant.isAfter(instant1);
System.out.println(after);
// 5.修改时间
Instant instant3 = instant.plusMillis(1000L);
System.out.println(instant3);
Instant instant4 = instant.minusMillis(1000L);
System.out.println(instant4);
}
}
ZonedDateTime
package com.itheima.demo;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ZonedDateTimeTest {
public static void main(String[] args) {
// 1.获取当前时间(有时区)
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
// 2.指定有时区的时间(两种方式)
ZonedDateTime of = ZonedDateTime.of(2024, 1, 14, 11, 12, 12, 0, ZoneId.systemDefault());
ZonedDateTime of1 = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
System.out.println(of);
System.out.println(of1);
// 3.修改时间
ZonedDateTime zonedDateTime = of.withYear(2025);
System.out.println(zonedDateTime);
// 4.减时间
ZonedDateTime zonedDateTime1 = of.minusYears(1L);
System.out.println(zonedDateTime1);
// 5.加时间
ZonedDateTime zonedDateTime2 = of.plusYears(1L);
System.out.println(zonedDateTime2);
}
}
DateTimeFormatter
package com.itheima.demo;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatTest {
public static void main(String[] args) {
// 日期格式化类
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EE a");
// 获取当前时区时间
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
// 格式化当前时区时间转换成字符串打印
String format = dateTimeFormatter.format(zonedDateTime);
System.out.println(format);
}
}
LocalDate
package com.itheima.demo;
import java.time.LocalDate;
import java.time.Month;
public class LocalDateTest {
public static void main(String[] args) {
// 1.获取当前日期
LocalDate now = LocalDate.now();
System.out.println(now);// 2024-1-15
// 2.设置日期
LocalDate of = LocalDate.of(2024, 1, 15);
System.out.println(of);// 2024-1-15
// 3.获取日期信息
int year = of.getYear();
Month month = of.getMonth();
int value = month.getValue();
System.out.println(year);// 2024
System.out.println(value);// 1
// 4.设置日期信息
LocalDate localDate = of.withYear(2025);
System.out.println(localDate);// 2025-1-15
// 5.加日期信息
LocalDate localDate1 = of.minusYears(1);// 2023-1-15
System.out.println(localDate1);
// 6.减少日期信息
LocalDate localDate2 = of.plusYears(1); // 2025-1-15
System.out.println(localDate2);
}
}
LocalTime
package com.itheima.demo;
import java.time.LocalTime;
public class LocalTimeTest {
public static void main(String[] args) {
// 1.获取当前时间
LocalTime now = LocalTime.now();
System.out.println(now); // 19:27...
// 2.指定时间
LocalTime of = LocalTime.of(20, 30, 10, 1);
System.out.println(of);//20:30:10.000000001
// 3.设置时间信息
LocalTime localTime = of.withHour(21);
System.out.println(localTime);//21:30:10.000000001
// 4.获取时间信息
int hour = of.getHour();
System.out.println(hour);//20
// 5.加时间信息
LocalTime localTime1 = of.plusHours(1);
System.out.println(localTime1);//21:30:10.000000001
// 6.减时间信息
LocalTime localTime2 = of.minusHours(1);
System.out.println(localTime2);//19:30:10.000000001
}
}
LocalDateTime
package com.itheima.demo;
import java.time.LocalDateTime;
public class LocalDateTimeTest {
public static void main(String[] args) {
// 1.获取当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println(now);// 2024-1-15T19:34:1 ...
// 2.指定日期时间
LocalDateTime of = LocalDateTime.of(2024, 1, 15, 19, 34, 1, 1);
System.out.println(of);// 2024-1-15T19:34:1 000000001
// 3.设置日期时间信息
LocalDateTime localDateTime = of.withHour(20);
System.out.println(localDateTime);// 2024-1-15T20:34:1 000000001
// 4.获取日期时间信息
int value = of.getMonth().getValue();
System.out.println(value);// 1
// 5.加日期时间信息
LocalDateTime localDateTime1 = of.plusMonths(1);
System.out.println(localDateTime1); // 2024-2-15T19:34:1 000000001
// 6.减日期时间信息
LocalDateTime localDateTime2 = of.minusMonths(1);
System.out.println(localDateTime2);// 2023-12-15T19:34:1 000000001
}
}
Duration
package com.itheima.demo;
import java.time.Duration;
import java.time.LocalDateTime;
public class DurationTest {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime bir = LocalDateTime.of(1999, 5, 29, 0, 0);
// 1.记录两个日期时间的差值(时,分,秒)
Duration between = Duration.between(bir, now);
System.out.println(between);
// 2.不同单位下的差值
long l1 = between.toDays(); // 天
System.out.println(l1);
long l = between.toHours(); // 小时
System.out.println(l);
long l2 = between.toMinutes(); // 分钟
System.out.println(l2);
long l3 = between.toSeconds(); // 秒
System.out.println(l3);
}
}
Period
package com.itheima.demo;
import java.time.LocalDateTime;
import java.time.Period;
public class PeriodTest {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime bir = LocalDateTime.of(1999, 5, 29, 0, 0);
// 1.日期差值对象(年,月,日)
Period between = Period.between(bir.toLocalDate(), now.toLocalDate());
System.out.println(between);
// 2.不记录整体差值
int years = between.getYears();
int months = between.getMonths();
int days = between.getDays();
System.out.println(years);
System.out.println(months);
System.out.println(days);
/**
* 结果案例
* P24Y7M17D
* 24
* 7
* 17
*/
}
}
ChronoUnit
package com.itheima.demo;
import java.time.LocalDateTime;
import java.time.MonthDay;
import java.time.temporal.ChronoUnit;
public class ChronoUnitTest {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime bir = LocalDateTime.of(1999, 5, 29, 0, 0);
// 各个单位下的差值比较
long between = ChronoUnit.YEARS.between(bir, now);
long between1 = ChronoUnit.MONTHS.between(bir, now);
long between2 = ChronoUnit.DAYS.between(bir, now);
long between3 = ChronoUnit.HOURS.between(bir, now);
long between4 = ChronoUnit.MINUTES.between(bir, now);
long between5 = ChronoUnit.SECONDS.between(bir, now);
System.out.println(between);
System.out.println(between1);
System.out.println(between2);
System.out.println(between3);
System.out.println(between4);
System.out.println(between5);
System.out.println("==========拓展API==========");
// 只关注月份和天
MonthDay bir1 = MonthDay.of(5, 29);
MonthDay now1 = MonthDay.from(now);
System.out.println(bir1.equals(now1));
}
}
包装类
Integer装箱和拆箱
package com.itheima.demo;
public class IntegerTest {
public static void main(String[] args) {
// 1.什么是包装类
// 基本数据类型对应的类
Integer i = Integer.valueOf(10); // 装箱操作,把int装入Integer对象中
int j = i.intValue(); // 拆箱操作,把Integer对象拆成int
Integer result = Integer.valueOf(i.intValue() + j);
System.out.println(result);
// 2.JDK5后,包装类引入了什么新特性
// 实现了自动装箱和自动拆箱
Integer i1 = 10;
int j1 = i1;
Integer result1 = i1 + j1;
System.out.println(result1);
}
}
Integer的进制转换和字符串解析
package com.itheima.demo;
public class Integer2Test {
public static void main(String[] args) {
// 1.十进制转换成其他进制字符串
String s1 = Integer.toBinaryString(100); //110010
String s2 = Integer.toOctalString(100); // 144
String s3 = Integer.toHexString(100); // 64
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
// 2.字符串解析成其他数据类型
Integer num = Integer.parseInt("100"); // 必须是数字,否则报异常
Double num1 = Double.parseDouble("100");
System.out.println(num + num1); //200.0
}
}
算法基础(Day21)
查找算法
基本查找(顺序查找)
数据不要求有序
二分查找
要求是有序数据
package com.itheima.demo;
public class TwoDivideTest {
public static void main(String[] args) {
// 1.定义一个有序的数组
int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 2.要查询的数据
int search = 3;
// 3.查询数据对应的下标
int index = -1;
// 4. 查询的次数
int count = 0;
// 5. 索引最小值
int min = 0;
// 6. 索引最大值
int max = nums.length - 1;
while (true) {
// 查询次数+1
count++;
// 如果索引最小值大于最大值结束查询
if (min > max) {
break;
} else {
// 中间索引
int middle = (min + max) / 2;
if (search < nums[middle]) {
// 查询数据 在 中间索引值 左侧 max = middle - 1
max = middle - 1;
} else if (search == nums[middle]) {
// 查询数据 等于 中间索引值 结束最小值查询
index = middle;
break;
} else {
// 查询数据 在中间索引值 右侧 min = middle + 1
min = middle + 1;
}
}
}
System.out.println(index);
System.out.println(count);
}
}
插值查找
要求数据有序,适用于有序且分布均匀的数据
package com.itheima.demo;
/**
* 插值查找
*/
public class InterpolationSearchTest {
public static void main(String[] args) {
// 1.定义一个有序(间隔均匀)的数组
int[] nums = {0, 2, 4, 6, 7, 9};
// 2.定义要查找的值
int searchNum = 6;
// 3.定义下标最小值
int minIndex = 0;
// 4.定义下标最大值
int maxIndex = nums.length - 1;
// 5. 定义查询值索引
int searchIndex = -1;
int count = 0;
while (true) {
count++;
// 6.如果最小索引大于最大索引 未找到结束查询
if (minIndex > maxIndex) {
break;
}
// 7.定义自适应中间下标
// 7.1 最小值下标(偏移量) + ((查询值-最小值)/(最大值-最小值)) * (最大值下标 - 最小值下标)
int autoIndex = minIndex + (searchNum - nums[minIndex]) * (maxIndex - minIndex) / (nums[maxIndex] - nums[minIndex]);
if (nums[autoIndex] == searchNum) {
searchIndex = autoIndex;
break;
} else if (searchIndex < nums[autoIndex]) {
maxIndex = autoIndex - 1;
} else {
minIndex = autoIndex + 1;
}
}
System.out.println(searchIndex);
System.out.println(count);
}
}
分块查找
要求块间不相交,块内无序
情况1:块间有序
package com.itheima.demo;
public class PiecemealSearchTest {
public static void main(String[] args) {
// 1.定义一个不完全有序的数据
int[] nums = {5, 3, 4, 2, 1,
10, 8, 7, 6, 9,
11, 15, 16, 13, 14};
// 2.分为有序块
Piece piece = new Piece(5, 0, 4);
Piece piece1 = new Piece(10, 5, 9);
Piece piece2 = new Piece(16, 10, 14);
// 3.创建索引表
Piece[] pieces = {piece, piece1, piece2};
// 4.查询值
int searchNum = 16;
// 5.获取查询值下标
int searchIndex = getIndex(searchNum, nums, pieces);
// 6.打印查询值
System.out.println(searchIndex);
}
private static int getIndex(int searchNum, int[] nums, Piece[] pieces) {
// 7.获取指定块
Piece piece = getPiece(searchNum, pieces);
if (piece == null) {
return -1;
}
// 8.顺序查找获取下标
for (int i = piece.startIndex; i <= piece.endIndex; i++) {
if (nums[i] == searchNum) {
return i;
}
}
// 9.找不到返回-1
return -1;
}
private static Piece getPiece(int searchNum, Piece[] pieces) {
// 顺序遍历索引表
for (Piece piece : pieces) {
if (searchNum <= piece.max) {
return piece;
}
}
return null;
}
}
class Piece {
int max;
int startIndex;
int endIndex;
public Piece(int max, int startIndex, int endIndex) {
this.max = max;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
}
情况2:块间无序
package com.itheima.demo;
public class PiecemealSearchTest1 {
public static void main(String[] args) {
// 1.定义无序的数据
int[] nums = {9, 8, 7, 6, 2, 3, 4, 5, 10, 15, 13, 16, 20, 18, 19};
// 2.分块无交集
Piece1 piece1 = new Piece1(6, 9, 0, 3);
Piece1 piece11 = new Piece1(2, 5, 4, 7);
Piece1 piece12 = new Piece1(10, 15, 8, 11);
Piece1 piece13 = new Piece1(16, 20, 12, 15);
// 3.创建索引表
Piece1[] piece1s = {piece1, piece11, piece12, piece13};
// 4.定义查找值
int searchNum = 21;
// 5.获取查找值下标
int searchIndex = getIndex(searchNum, nums, piece1s);
// 6.打印下标
System.out.println(searchIndex);
}
private static int getIndex(int searchNum, int[] nums, Piece1[] piece1s) {
// 7.获取指定块
Piece1 piece1 = getPiece(searchNum, piece1s);
// 8. 顺序遍历块获取下标
if (piece1 == null) {
return -1;
}
for (int i = piece1.startIndex; i <= piece1.endIndex; i++) {
if (nums[i] == searchNum) {
return i;
}
}
return -1;
}
private static Piece1 getPiece(int searchNum, Piece1[] piece1s) {
for (Piece1 piece1 : piece1s) {
if (searchNum <= piece1.max && searchNum >= piece1.min) {
return piece1;
}
}
return null;
}
}
class Piece1 {
int min;
int max;
int startIndex;
int endIndex;
public Piece1(int min, int max, int startIndex, int endIndex) {
this.min = min;
this.max = max;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
}
排序算法
冒泡排序
思想:一组数据,从左到右两两比较,小的放前,大的放后
/**
* 冒泡排序
*
* @param nums
* @return
*/
public static int[] maoPao(int[] nums) {
int count = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = 0; j < nums.length - 1 - i; j++) {
count++;
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
System.out.println("冒泡count:" + count);
return nums;
}
选择排序
思想:一组数据从索引0开始,索引0与后面的数据依次比较,小的放前,大的放后
/**
* 选择排序
*
* @param nums
* @return
*/
public static int[] xuanZe(int[] nums) {
int count = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i + 1; j < nums.length; j++) {
count++;
if (nums[i] > nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
System.out.println("选择count:" + count);
return nums;
}
插入排序
思想:将数组分为有序和无序的两组数据,无序数据从右往左依次比较有序数据,插入合适位置
/**
* 插入排序
*
* @param nums
* @return
*/
public static int[] chaRu(int[] nums) {
int count = 0;
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i; j >= 0; j--) {
count++;
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
} else {
break;
}
}
}
System.out.println("插入count:" + count);
return nums;
}
递归算法
/**
* 累加递归
*
* @param num
* @return
*/
public static int leiJia(int num) {
if (num > 1) {
return num + leiJia(num - 1);
} else {
return num;
}
}
快速排序
思想:以数组开始索引元素为基准数,数组首先从右向左找小于基准数的停下,然后从左往右找大于基准数的停下,两者交换,当两个寻找下标相同时,与基准数替换,称基准数归位,基准数的左右两边进行重复的递归操作,当开始下标大于结束下标时,结束递归
/**
* 快速排序
*
* @param nums
* @return
*/
public static void kuaiSu(int[] nums, int start, int end) {
if (start > end) {
return;
}
int i = start;
int j = end;
// 注意:如果基准数时索引0的值,则必须先移动end,再移动start
int index1 = start;
while (start < end) {
if (nums[end] > nums[index1]) {
end--;
continue;
}
if (nums[start] < nums[index1]) {
start++;
continue;
}
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
}
int temp = nums[index1];
nums[index1] = nums[end];
nums[end] = temp;
kuaiSu(nums, i, start - 1);
kuaiSu(nums, start + 1, j);
}
Lambda表达式
- Lambda表达式的作用?
简化了匿名内部类的创建 - Lambda表达式使用前提?
匿名内部类必须是有且仅有一个抽象方法的接口,才可以使用Lambda表达式 - Lambda表达式好处?
使得代码更简洁、更灵活、更紧凑 - 完整格式:
(参数类型 参数名)->{return xxxx;}
- 省略格式:
参数名->xxxx
package com.itheima.demo;
public class LambdaTest {
public static void main(String[] args) {
// 匿名内部类
swimming(new Swim() {
@Override
public void swimming() {
System.out.println("swimming...");
}
});
System.out.println("----------------------");
// Lambda表达式
swimming(() -> {
System.out.println("swimming...");
});
}
public static void swimming(Swim swim) {
swim.swimming();
}
}
interface Swim {
void swimming();
}
集合进阶(Day22)
单列集合顶层接口(Collection)
/**
* 1.单列集合顶层接口入门
*/
public static void CollectionInit() {
Collection<Student> list = new ArrayList<>();
// 1.添加元素 boolean add(E e)
// 细节1:Set添加重复元素时为false
list.add(new Student("张三", 18));
list.add(new Student("李四", 20));
list.add(new Student("张三", 18));
System.out.println(list);
// 2.清空集合 clear()
// list.clear();
// System.out.println(list);
// 3.删除元素 boolean remove(E e)
list.remove(new Student("张三", 18));
System.out.println(list);
// 4.是否包含元素 boolean contains(Object obj)
System.out.println(list.contains(new Student("张三", 18)));
// 5.列表是否为空
System.out.println(list.isEmpty());
// 6.列表的长度
System.out.println(list.size());
}
迭代器(Iterator)
使用场景:遍历过程中需要删除元素时使用
/**
* 2.迭代器遍历
*
* @return
*/
public static void iteratorTest() {
Collection<Student> list = new ArrayList<>();
list.add(new Student("张三", 18));
list.add(new Student("李四", 20));
// 1.获取Iterator
// 细节:Iterator方式遍历,不依赖索引,通过创建指针,移动指针实现遍历
Iterator<Student> iterator = list.iterator();
// 2.指针指向存在元素
while (iterator.hasNext()) {
// 3.获取指针元素,移动指针
Student student = iterator.next();
System.out.println(student);
try {
// list.remove(student);
iterator.remove();
} catch (Exception e) {
// ConcurrentModificationException
e.printStackTrace();
}
}
try {
// 细节1:指针指向不存在元素情况下,获取指针元素 报NoSuchElementException
// 细节2:next不会归位,迭代器遍历没有回头路
// 细节3:while中不应该存在多个next,可能会包NoSuchElementException
// 细节4:不能再遍历过程中用集合的方式增删数据,可以用迭代器自带的方法进行删除
iterator.next();
} catch (Exception e) {
e.printStackTrace();
}
}
增强For和Lambda表达式
场合:适用于仅遍历的场合使用
/**
* 3.增强for遍历
*/
public static void forTest() {
Collection<Student> list = new ArrayList<>();
list.add(new Student("张三", 18));
list.add(new Student("李四", 20));
// 增强for
// 1.作用 简化迭代器代码的书写
// 2.底层 就是迭代器遍历
// 3.使用范围 单列集合和数组
// 4.JDK支持版本 JDK5+
for (Student student : list) {
// 细节1: 修改for的变量内部属性会改变list中的值
student.setAge(student.getAge() + 1);
// 细节2: 修改for的变量本身不会改变集合中的值
student = new Student("张三", 20);
}
for (Student student : list) {
System.out.println(student);
}
System.out.println("-------------------------------------");
// Lambda表达式遍历JDK8+
// 匿名内部类方式遍历list集合
list.forEach(new Consumer<Student>() {
@Override
public void accept(Student student) {
System.out.println(student);
}
});
System.out.println("-------------------------------------");
// Lambda表达式方式遍历list集合
list.forEach(student -> System.out.println(student));
}
单列有序集合接口(List)
List的存取是有序的,数据可以重复,有索引
/**
* 4.单列集合List
*/
public static void listTest() {
List<Student> list = new ArrayList<>();
// 1. 指定下标添加数据
list.add(new Student("张三", 18));
list.add(new Student("王五", 22));
list.add(1, new Student("李四", 20));
System.out.println(list);
// 2. 指定下标设置数据
System.out.println("-------------------------------------");
list.set(1, new Student("李四1", 20));
System.out.println(list);
// 3. 指定下标删除
System.out.println("-------------------------------------");
list.remove(1);
System.out.println(list);
// 4. 获取指定下标值
System.out.println("-------------------------------------");
System.out.println(list.get(1));
}
单列集合List遍历特有方式
使用场景:
- 需要索引时,用普通for循环遍历
- 需要再遍历时,添加数据时,用列表迭代器遍历
/**
* 5.单列集合List特有遍历
*/
public static void listIteratorTest() {
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 18));
list.add(new Student("王五", 22));
list.add(1, new Student("李四", 20));
// 普通for循环遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("-------------------------------------");
// 列表迭代器遍历
ListIterator<Student> iteratorList = list.listIterator();
while (iteratorList.hasNext()) {
System.out.println(iteratorList.next());
iteratorList.add(new Student("老刘", 25));
}
System.out.println("-------------------------------------");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
数据结构
- 栈:先进后出
- 队列:先进先出
- 数组(数据在内存中的存储是连续的)
查询速度快(初始地址值+索引)
删除效率低(原始数据删除,后面数据前移)
插入效率低(插入位置后面数据后移,再插入元素) - 链表
链表的各个节点在内存中的存储时不连续的
查询速度低(所有的查询都要从头开始查询)
删除效率高(相较于数组)
插入效率高(相较于数组)
ArrayList的扩容机制
- ArrayList的数据存储底层是数组
- 对于创建空参的ArrayList,底层数组长度为0
- 第一次加入数据时,底层数据会进行扩容 首次扩容为10 一次加入数据超出10 则扩容为加入数据长多
- 当首次扩容数组被填满再次添加数据, 底层数组会扩容1.5倍,若加入数据超出1.5倍(10->15),则扩容为加入(数据长度+底层数组原长)
LinkedList区别与ArrayList
- LinkedList的底层是双向链表 链表结点在堆内存的存储是不连续的
- 其中有头结点和尾结点开始都为null
- 如果添加一个结点,则头尾结点都存储该结点的地址值
- 如果再添加一个结点,则尾结点等于添加的结点,且添加结点创建时,填充前个结点为原尾结点地址,原尾结点的下一个结点则存在新结点地址
iterator迭代器底层
- list.iterator()是创建时,当前下标为0 上一轮下标为-1
- iterator.hasNext()是判断当前下标!=size则为true
- iterator.next()是让当前下标后移一位,上一轮下标为原当前下标,并返回原当前下标对应的数据
泛型
- 应用场景:
当定义一个类、方法、接口的数据类型不确定,可以使用泛型类,泛型方法,泛型接口
泛型类在定义对象的时候确定数据类型
泛型方法在调用方法的时候确定数据类型
泛型接口在定义实现类确定泛型 - 泛型什么时候出现的,泛型出现的作用或好处
泛型在JDK5出现
JDK5之前都是Object,泛型出现后,不仅在编译阶段约束数据类型,还将运行阶段可能出现的强转报错提前至编译阶段,泛型在确定类型后,可以存储本类及其子类,泛型出现可以调用泛型类的特有行为 - 如果类型希望是某个类的子类(包括它自己)或者父类(包括它自己)可以用
? extends 类名
或? super 类名
,其中?是泛型通配符 - 注意泛型不能是基本数据类型,只能使用基本数据类型的包装类
// 所有的方法都可以用这个泛型
// 泛型类:泛型定义在类名后面的类
// 同理 泛型接口:泛型定义在接口名后面的接口
class MyArrayList<E> {
Object[] objs = new Object[10];
int size;
void add(E e) {
objs[size++] = e;
}
@SuppressWarnings("unchecked")
E get(int index) {
return (E) objs[index];
}
// 泛型方法:泛型定义在方法修饰符后面的方法
<T> void show(T t) {
System.out.println("Hello " + t);
}
@Override
public String toString() {
return Arrays.toString(objs);
}
}
树
相关名词:
父节点
左子节点
右子节点
度:子节点的数目
二叉树:任意节点的度都小于或等于2
树高:总层数
左子树
右子树
二叉树的演变
1.普通的二叉树数据存储是无规律的
2.查找二叉树也称搜索二叉树,排序二叉树,遵循的规则是数据大小左节点 < 当前节点 < 右节点
3.二叉树遍历方式:
前序遍历 当前节点 左子树 右子树
中序遍历 左子树 当前节点 右子树
后序遍历 左子树 右子树 当前节点
层序遍历 按层遍历
4.平衡二叉树 任意节点的左子树和右子树层数差小于等于1
平衡二叉树的旋转机制
平衡二叉树有左旋和右旋两种方式,不平衡点降阶为左子树时,原左子树作为不平衡点的右子树,降为右子树时,原右子树作为不平衡点的左子树。
对于插入平衡二叉树的节点进行旋转的情况分为四类:
左左:不平衡点的左子节点的左子树上追加数据,不平衡点仅需要一次右旋完成
左右:不平衡点的左子节点的右子树上追加数据,左子节点完成一次左旋后,不平衡完成一次右旋完成
右右:不平衡点的右子节点的右子树上追加数据,不平衡点仅需要一次左旋完成
右左:不平衡点的右子节点的左子树上追加数据,右子节点完成一次右旋后,不平衡完成一次左旋完成
红黑树
红黑树的特点:
- 所有的节点只能是黑色或者红色
- 根节点必定为黑色
- 节点之间不可能红红相连
- 如果一个节点没有子节点或者父节点,则将会指向Nil节点,Nil节点也会视叶节点,Nil节点一定是黑色
- 任意一个节点到后代叶节点的简单路径,黑色节点的数目完全一致
红黑树添加节点的规则:
- 添加的节点默认设置为红色
- 若添加的节点为根节点 则直接变成黑色
- 若添加的节点不是根节点则分情况讨论
- 若添加的节点的父节点是黑色,不做任何操作
- 若添加的节点的父节点是红色则分情况讨论
- 若添加的节点的叔叔节点为红色,则叔叔节点和父节点都变为黑色,祖父节点变为红色,如果祖父节点是根节点则变为黑色,若不是根节点,祖父节点作用目标节点进一步处理
- 若添加的节点的叔叔节点为黑色,且添加节点为左子节点时,父节点变为黑色,祖父节点变为红色,以祖父节点进行右旋(左左,右右)
- 若添加的节点的叔叔节点为黑色,且添加节点为右子节点时,以父节点进行左旋,并将原父节点作为目标节点进一步处理(左右,右左)
Set系列集合
List集合和Set集合之间的区别?
List集合:有序,可重复,有索引
Set集合:无序,不重复,无索引
无序?
存取顺序不一致
Set集合的实现类
- HashSet: 无序,不重复,无索引
- LinkedHashSet: 有序,不重复,无索引
- TreeSet: 可排序,不重复,无索引
HashSet
- 底层:初始化时长度为16,加载因子0.75的数组,叫table
- HashSet在增加元素时,首先根据哈希值&(数组长度-1)确定插入下标,如果下标没有数据,则直接填入,若有数据则(JDK7)新数据连接旧数据,(JDK8)旧数据连接新数据
- 之所以存取不一致,是因为取时,从下标零开始遍历,每个元素遍历完毕才取下一个索引数据
- 因为底层数据结构问题,JDK8更是加入了红黑树,所以没有索引
- HashSet保证去重的原理是,重写了equals和hashCode方法,保证了在属性完全相同的时候,插入的数据会和插入索引的链表进行equals比较,相同则不插入
- JDK8在底层链表长度大于8并且数组长度大于64时,变成红黑树
LinkedHashSet
加入了双向链表属性,保证了前后数据的关联性,保证了数据的存取时有序的
TreeSet
- TreeSet底层是红黑树
- 对于数值类型的数据,默认按照升序排列,Integer,Double,Float实现了Comparable方法
- 对于字符或者我字符串的数据,默认按照Ascii码进行升序排列
- 对于存储的数据是自定义类对象,要求该类必须实现Comparable接口,重写compareTo方法,自定义排序规则,否则报运行时异常
- 当默认的Comparable接口的排序不满足需求时,可以使用TreeSet(Comparator comparator)构造方法进行排序
- 实现方法compareTo(T t)/compare(T t1,T t2),返回负数,放在红黑树左边,返回正数,放在红黑树右边,返回零表示重复数据,不添加