-
J2SE 占领桌面程序, 控制台开发 标准版
-
J2ME 占领手机,小家电 嵌入式开发
-
J2EE 占领服务器,web端 企业级开发
三高
-
高并发
-
高可用
-
高性能
Java特性和优势
-
简单性
-
面向对象
-
可移植性(跨*台)
-
高性能
-
分布式
-
动态性(反射)
-
多线程
-
安全性(异常机制)
-
健壮性
JDK, JRE, JVM
JDK
-
java development kit java开发者工具(java, javac, javadoc, jar)
-
jdk包含jre
JRE
-
java runtime environment java运行环境(函数库, 虚拟机)
JVM
-
java virtual machine java虚拟机 (模拟cpu)
安装开发环境
-
jdk下载与安装
# 下载jdk8
# 卸载原有的
# 删除文件包
# 清理环境变量 JAVA_HOME 和 path下的关于java的
# java -version 检查是否删除
# 安装运行文件
-
配置环境变量
# 添加环境变量 系统变量
# 新建JAVA_HOME
路径: F:java\jdk8
# 配置Path变量
# 新建
%JAVA_HOME%\bin
%JAVA_HOME%\jre\bin
# 检查安装
# java -version
# java
# javac
-
目录解析
# bin 可执行文件
# include 存放C语言头文件
# jre java运行环境
# lib java开发库文件
HelloWorld
-
新建Hello.java
-
类名Hello必须和文件名一致
public class Hello{
public static void main(String[] args){
System.out.println("Hello,World!");
}
}
-
命令行窗口
# 当前hello.java文件目录下
# javac编译成.class文件
javac Hello.java
# 运行java程序
java Hello
JAVA程序运行机制
编译型
-
比如: 将一本中文书翻译成英文,
-
编译器
-
速度快
解释型
-
比如: 翻译官, 想要翻译那句,就翻译那句
-
解释器
-
一行一行解释
-
性能消耗. 速度慢
程序运行机制
IDEA安装
-
下载安装文件
-
选择64位和.java
JAVA基础语法
注释
//单行注释
/*
多行注释
多行注释
*/
/**
* 文档注释
*
* @author cyz
* @create 2020/07/10 18-30
*/
标识符
java 所有的组成部分都需要名字, 类名, 变量名以及方法都被称为标识符
以字母, 美元符号($), 下划线, 数字 组成
不能以数字开头
不能使用关键字作为变量名或方法名
大小写敏感
可以使用中文, 但不建议
关键字
java的特殊标识符: public static void class
数据类型
-
java是强类型语言: 先定义才能使用
基本类型 数值类型: 整数类型: byte 1字节 short 2字节 int 4字节 long(L) 8字节 浮点类型: float(F) 4字节 double 8字节 字符类型: char 2字节 boolean类型: 占1位 true/false引用类型:
类: String
接口:
数组:
常见问题
//整数拓展 进制问题 二进制0b: int i = 10010b; 十进制: int i2 = 10; 八进制0: int i3 = 010; 十六进制0x: int i4 = 0x10;//浮点数拓展
银行业务表示: BigDecimal(数学工具类)
float f = 0.1f;//0.1
double d = 1.0/10;//0.1
System.out.println(f == d);//falsefloat f1 = 233333123212f;
float f2 = f1 + 1;
System.out.println(f1 == f2);//true//float: 有限 离散 舍入误差 大约 接*等
//double://字符拓展
char c1 = 'a';
char c2 = '中';
System.out.println(c1);//a
System.out.println((int)c1);//97
System.out.println(c2);//中
System.out.println((int)c1);//20013
//所有字符本质是数字
//编码 Unicode 2字节//转义字符
\t //制表符
\n //换行//布尔值扩展
boolean flag = true;
if(flag==true){}
it(flag){}//等价
类型转换
-
强类型转换 高-->低
-
自动类型转换 低-->高
byte,short,char---->int--->long--->float--->doubleint i = 128;
byte b = (byte)i;//-128 内存溢出/*
注意点:
1. 不能转换boolean类型
2. 高容量转为低容量, 强制转换
3. 不能把对象类型转为不相干的类型
4. 转换时注意内存溢出和精度问题
*///jdk7新特性: 数字分割
int money 10_0000_0000;
int years = 20;
int total = moneyyears;
System.out.println(total);// -1474836480 计算时候溢出
long tota2 = moneyyears;// 默认是int 转换前就出错了
System.out.println(tota2);// -1474836480 计算时候溢出//解决
long total = money*((long)years);
变量
// 可变化的量 变量类型 变量名 = 变量值; 变量类型 变量名=变量值, 变量名=变量值,...;//不建议 程序可读性
变量作用域
-
类变量: static修饰
-
实例变量 定义在类中但不在方法中
-
默认值: 0, 0.0, null, false
-
-
局部变量: 定义在方法中
常量
// 不可变的值 final修饰 final double PI = 3.14;
运算符
# 算术运算符: +, -, *, /, ++, -- # 赋值运算符: = # 关系运算符: >, <, >=, <=, ==, !=, instanceof # 逻辑运算符: &&, ||, ! (断路问题) # 位运算符: &, |, ^, ~, >>, <<, >>> # 条件运算符: ? : # 扩展赋值运算符: +=, -=, *=, /=28 =16 # 怎么最快 2222
2<<3
<< : *2 # 乘2
>> : /2 # 除2
- 连接符
("" + a + b) 和 (a + b + "") 的区别: ""在前面先拼接, 在后面先运算
包机制
// 用于区别类名的命名空间 // 一般使用公司域名倒置作为包名//命名及导入
package 包名;
import 包名;//阿里巴巴开发手册
JavaDoc
//生成API文档 //参数信息 @author 作者名 @version 版本号 @since 指明需要最早使用的jdk版本 @param 参数名 @return 返回值情况 @throws 异常抛出情况// 命令行生成文档
javadoc -encoding UTF-8 -charset UTF-8 Doc.java
//打开 index.html
用户交互Scanner
//next() 空白为结束符 Scanner scanner = new Scanner(System.in); System.out.println("请输入的内容: ");//hello world if(scanner.hasNext()){ String str = scanner.next(); System.out.println("输入的内容为: " + str);//hello } scanner.close();//关闭资源 减少资源占用//nextLine() 回车为结束符
Scanner scanner = new Scanner(System.in);
System.out.println("请输入的内容: ");//hello world
if(scanner.hasNextLine()){
String str = scanner.nextLine();
System.out.println("输入的内容为: " + str);//hello world
}
scanner.close();//关闭资源 减少资源占用// 省略判断
Scanner scanner = new Scanner(System.in);
System.out.println("请输入的内容: ");//hello world
String str = scanner.nextLine();
System.out.println("输入的内容为: " + str);//hello world
scanner.close();//关闭资源 减少资源占用
Scanner scanner = new Scanner(System.in); int i = 0; float f = 0.0f; System.out.println("请输入整数: "); if(scanner.hasNextInt()){ i = scanner.nextInt(); System.out.println("输入的整数为: " + i); }else{ System.out.println("输入的不是整数"); } System.out.println("请输入小数: "); if(scanner.hasNextFloat()){ f = scanner.nextFloat(); System.out.println("输入的小数为: " + f); }else{ System.out.println("输入的不是小数"); } scanner.close();//关闭资源 减少资源占用
顺序结构
//一句一句执行
选择结构
if单选择结构
if (布尔表达式){ //布尔表达式为true执行的语句 }
if双选择结构
if (布尔表达式){ //布尔表达式为true执行的语句 }else { //布尔表达式为false执行的语句 }
if多选择结构
if (布尔表达式1) { //布尔表达式1为true执行的语句 }else if (布尔表达式2) { //布尔表达式2为true执行的语句 }else if (布尔表达式3) { //布尔表达式3为true执行的语句 }else { //布尔表达式都不为true执行的语句 }
嵌套的if结构
if (布尔表达式1) { if (布尔表达式2) { //布尔表达式1为true的前提下 布尔表达式2为true执行的语句 } }
switch多选择结构
switch(expression){ case value : //语句 break; case value : //语句 break; default : //语句 }//case穿透
//switch 变量类型可以是 :byte, short, int, char, String
//case 必须是字符串常量或字面量
循环结构
while
while( 布尔表达式 ){ //布尔表达式为true执行语句 }while(true){
}
do...while
do { //代码语句 }while( 布尔表达式 ); //至少执行一次
for
for(初始化; 布尔表达式; 更新){ //代码语句 } for( ; ; ){}
增强for
for(声明语句 : 表达式){ //代码语句 }int[] numbers = {10,20,30,40,50};
for(int x : numbers){
System.out.println(x);
}
break&continue
// break 退出整个循环 // continue 退出某次循环//通过标记跳出某个指定循环
方法
-
功能块: 实现某额功能的语句块集合
修饰符 返回值类型 方法名(参数类型 参数名){ ... 方法体 ... return 返回值; }// 形参和实参
//java 值传递(拷贝的) 没有 引用传递
方法重载
-
方法名相同
-
参数类型, 参数个数, 参数顺序, 不同
可变参数
-
参数类型后加一个(...)
-
一个方法中只能有一个, 且为最后一个参数
public static void test(int... i) { for (int x : i) { System.out.println(x); } }
递归
-
A方法调用A方法, 自己调用自己
-
包括: 滴归头 和 递归体
-
递归头: 什么时候不调用
-
递归体: 什么时候需要调用
public static void main(String[] args) { int f = f(5); System.out.println(f); }public static int f(int n) { if(n == 1){ return 1; }else { return n*f(n-1); } }</pre>
数组
-
相同类型数据的有序集合
声明数组
数据类型[] 数组名; //或 数据类型 数组名[];//动态初始化 (默认初始化)
数据类型[] 数组名 = new 数据类型[数组大小];
int[] arr = new int[10];//静态初始化
int[] a = {1,2,3};arr[0]
arr.length//数组本身在堆中
特点
-
长度固定
-
元素类型相同
-
数组本身是对象在堆中
数组的使用
-
遍历循环
int[] arr = {1,2,3,4,5}; for(int i = 0; i < arr.length; i++){ System.out.println(arr[i]); }for(int x : arr){
System.out.println(x);
}
-
数组可以作为参数
public static void printArray(int[] arr){ for(int x : arr){ System.out.println(x); } }
-
数据作为返回值
public static int[] recerse(int[] arr){ int[] result = new int[arr.length]; for(int i = 0; i < arr.length; i++){ result[(arr.length)-i -1] = arr[i]; } return result; }
二维数组
int[][] arr = new int[3][2];int[][] a = {{2,3},{3,4},{6,5}};
a.length
a[0].length
Arrays类
int a = {1,4,5,6,7}; //打印 Arrays.toString(a); //排序 升序 Arrays.sort(); //填充 将指定值填充数组 Arrays.fill(a,0);
冒泡排序
-
比较相邻的数, 交换
-
每次都会出一个最大或最小
-
下轮循环少一次排序
public static void main(String[] args) { int[] a = {1,4,5,6,72,2,2,2,25,6,7};int[] sort = sort(a); System.out.println(Arrays.toString(sort)); } public static int[] sort(int[] array){ int temp =0; for(int i = 0; i < array.length-1; i++){ for (int j =0; j < array.length-1-i; j++){ if(array[j+1]>array[j]){ temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } return array; }</pre>
稀疏数组
-
当数组中大部分元素为0,或相同的值时, 使用稀疏数组
-
处理方式:
-
记录数据一共几行几列, 有多少个不同值
-
把不同的值的元素和行列记录在一个小的数组中
-
public class HelloWorld { public static void main(String[] args) { int[][] array1 = new int[11][11]; array1[1][2] = 1; array1[2][3] = 1;System.out.println("=========原数组========"); for (int[] ints : array1) { for (int anInt : ints) { System.out.print(anInt + "\t"); } System.out.println(); } //转化 //获取个数 int sum = 0; for (int i = 0; i < array1.length; i++) { for (int j = 0; j < array1[i].length; j++) { if (array1[i][j] != 0) { sum++; } } } //创建稀疏数组 int[][] array2 = new int[sum + 1][3]; array2[0][0] = array1.length; array2[0][1] = array1.length; array2[0][2] = sum; //存放非零数值 int count = 0; for (int i = 0; i < array1.length; i++) { for (int j = 0; j < array1[i].length; j++) { if (array1[i][j] != 0) { count++; array2[count][0] = i; array2[count][1] = j; array2[count][2] = array1[i][j]; } } } System.out.println("=========稀疏数组========"); for (int[] ints : array2) { for (int anInt : ints) { System.out.print(anInt + "\t"); } System.out.println(); } System.out.println("=========还原数组========"); int[][] array3 = new int[array2[0][0]][array2[0][1]]; for (int i = 1; i < array2.length; i++) { array3[array2[i][0]][array2[i][1]] = array2[i][2]; } for (int[] ints : array3) { for (int anInt : ints) { System.out.print(anInt + "\t"); } System.out.println(); } }
}
内存分析
堆
# 存放new的对象和数组 # 可以被所有的线程共享, 不会存放别的对象引用
栈
# 存放基本变量类型 (会包含这个基本类型的具体数值) # 引用对象的变量 (会存放这个引用在堆里面的具体地址) # 方法
方法区
# 可以被所有的线程共享 # 包含了所有的class和static变量
面向对象
-
以类的方式组织代码, 以对象的方式组织(封装)数据
类和对象的关系
-
类是对象的模板
-
对象是类的具体实例
// 创建对象时默认初始化 和 调用 构造器
构造器
// 和类名相同 // 没有返回值 // 定义了自己的有参构造, 无参构造需要手动定义
封装
// 数据封装, 统一接口方法 // 属性私有, 提供get/set // 隐藏代码实现细节 // 提高程序的安全性, 保护数据 // 增加程序可维护性
继承
-
扩展
// extends // 只有单继承 // 子类继承父类 公有的属性和方法 // 超类 Object
Super
// super: 调用父类公有的 // this: 当前类// 子类构造器会 默认调用父类的构造器
// super()和this() 必须在子类构造器的第一行
// super() 和 this() 不同时出现// 父类没有无参构造, 子类也不能有无参构造
方法重写
-
对父类方法扩展
// 重写父类的的方法 // 不能重写私有的方法 // 子类修饰符可以扩大 但不能缩小 // 抛出的异常可以缩小 但不能扩大
多态
// 父类的引用指向子类对象// 方法的调用只和右边new的谁有关 子类没有找父类
instanceof
// 有上下关系 才可以比较 同级不能比较
类型转换
// 高 转 低 ----> 强转 向下转型 Person obj = new Student(); Student stu = (Student)obj;//低 转 高 向上转型 会丢失一些方法
Student student = new Student();
Person person = student;
static
// 静态的变量和方法 在静态方法区 // 静态变量和方法 可以通过 类名调用 // 被共享 // 跟着类的加载被加载// 静态代码块: 初始化数据
// 匿名代码块 也会随着对象的创建被创建 在构造器之后 可以用于 初始赋值
// final 关键字: 最终
抽象类
// abstract 用于修饰 类 和 方法 // 抽象类不能被实例化 但是抽象类是有构造方法的 // 抽象方法 必须 在抽象类中, 抽象类中可以 有 普通方法 // 继承抽象类的子类必须重写父类的所有抽象方法 除了子类也是抽象类
接口
-
契约
// interface // 接口的方法 默认 修饰 public abstract // 接口都需要有实现类(重写接口的方法) // 接口中的常量: 默认修饰 public static final // 接口不能被实例化, 但是有构造方法
内部类
成员内部类
public class Outer { private int id; public void out(){ System.out.println("这是外部类的方法"); } public class Inner { public void in(){ System.out.println("这是内部类方法"); } } }public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
outer.out();
Outer.Inner in = outer.new Inner();
in.in();
}
}
静态内部类
// 在成员内部类上加上static
局部内部类
public class Outer { //定义在局部 public void method(){ class Inner{ public void in(){} }
}
}
匿名内部类
// 没有名字的内部类
异常机制
-
Exception
-
Error不是异常, 虚拟机错误
-
运行时异常:
-
数组下标越界
-
空指针异常
-
算术异常
-
丢失资源
-
找不到类
-
异常抛出和捕获
try{}catch(Exception e){
e.printStackTrace();//打印错误信息
}finally{}
throws new Exception
//finally 都会执行
//多个异常 从小到大
自定义异常类
public class MyException extends Exception {//detail>10 异常 private int detail; public MyException(int a){ this.detail = a; } @Override public String toString(){ return "MyException{" + "detail=" + detail + "}"; }
}
public class Test {
static void test(int a) throws MyException{ System.out.println("传递的参数是: " + a); if(a>10){ throw new MyException(a); } System.out.println("OK"); } public static void main(String[] args) { try { test(11); } catch (MyException e) { e.printStackTrace(); } }
}
权限修饰符
-
public > protected > (default) > private
-
default不是关键字
public | protected | default | private | |
---|---|---|---|---|
同一个类 | yes | yes | yes | yes |
同一个包 | yes | yes | yes | |
不同包子类 | yes | yes | ||
不同包非子类 | yes |
数组与排序
-
注意二维数组:
-
int[][] arr int arr[][] int[] arr[] int[] g,z[] : 表示一个一位数组, 一个二维数组
-
基础查找
public class Test { public static void main(String[] args) { int[] arr = {10,20,70,10,90,100,1,2}; // 查询元素在数组中第一次出现的位置 int index = getIndexByEle(arr, 10); System.out.println(index);//0 }private static int getIndexByEle(int[] arr, int ele) { for (int i = 0; i < arr.length; i++) { if(ele == arr[i]){ return i; } } return -1; }
}
二分查找(数组必须有序)
public class Test { public static void main(String[] args) { int[] arr = {100, 20, 12, 40, 90, 10, 1, 2}; // 查询元素在数组中第一次出现的位置 二分查找 数组必须有序 Arrays.sort(arr); System.out.println(Arrays.toString(arr)); int index = getIndexByEle(arr, 10); System.out.println(index);//0 }private static int getIndexByEle(int[] arr, int ele) { //定义最小索引 最大索引 中间索引 int minIndex = 0; int maxIndex = arr.length - 1; int centerIndex = (minIndex + maxIndex) / 2; while (minIndex <= maxIndex) { if (ele == arr[centerIndex]) { return centerIndex; } else if (ele > arr[centerIndex]) { minIndex = centerIndex + 1; } else if (ele < arr[centerIndex]) { maxIndex = centerIndex - 1; } centerIndex = (minIndex + maxIndex) / 2; } return -1; }
}
排序算法
冒泡排序
-
相邻元素两两比较, 比较大或小, 一轮得到最大值或最小值 一轮后 减少一次比较
public class Test { public static void main(String[] args) { int[] arr ={24,69,80,57,13}; int swapCount = 0; for (int i = 0; i < arr.length-1; i++) { // 优化 标志 boolean flag = true; //每一轮结束 少一次 for (int j = 0; j < arr.length-1 -i; j++) { if(arr[j] > arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; swapCount++; flag = false; } } if (flag){ break; } }System.out.println(Arrays.toString(arr)); System.out.println("交换次数: " + swapCount); }
}
选择排序
-
将第0个元素 一次和后面的比较, 得到最小值或最大值 在第一个位置
public class Test { public static void main(String[] args) { int[] arr = {24, 69, 80, 57, 13}; for (int index = 0; index < arr.length - 1; index++) { for (int i = index + 1; i < arr.length; i++) { if (arr[index] > arr[i]) { int temp = arr[index]; arr[index] = arr[i]; arr[i] = temp; } } } System.out.println(Arrays.toString(arr)); } }
插入排序
-
将元素插入到一个有序的列表中, 保持有序
public class Test { public static void main(String[] args) { int[] arr = {3,2,1,0,10,20,30,7,8,-2,100}; for (int i = 1; i < arr.length; i++) { int j = i; while (j > 0 && arr[j] < arr[j-1]){ int temp = arr[j]; arr[j] = arr[j-1]; arr[j-1] = temp; j--; } }System.out.println(Arrays.toString(arr)); }
}
//或
public class Test {
public static void main(String[] args) {
int[] arr = {3, 2, 1, 0, 10, 20, 30, 7, 8, -2, 100};
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}System.out.println(Arrays.toString(arr)); }
}
希尔排序
-
缩小增量排序: 对直接插入排序的优化
-
指定增量 为间隔 , 根据间隔进行比较 当间隔为1时 完成排序
-
通过不断缩小增量, 每轮达到大致有序
public class Test { public static void main(String[] args) { int[] arr = {46, 55, 13, 42, 17, 94, 5, 70,9,5,6,89,50,50,255}; System.out.println(Arrays.toString(arr));shellSort(arr); System.out.println(Arrays.toString(arr)); } private static void shellSort(int[] arr) { //定义增量 h // 可以选取数组的一半 // 在优化: 通过克努特序列 //增量选取 int h = 1; h = h*3+1 ---> 1,4,13,40,121,364 // 算出h int jiange = 1; while(jiange <= arr.length/3){ jiange = jiange * 3 + 1; } System.out.println(jiange); for (int h = jiange; h > 0; h = (h-1)/3) { for (int i = h; i < arr.length; i++) { for (int j = i; j > h - 1; j -= h) { if (arr[j] < arr[j - h]) { int temp = arr[j]; arr[j] = arr[j - h]; arr[j - h] = temp; } } } } }
}
快速排序
-
总体分区法
-
选择一个元素作为基准: 比该元素大的放一边, 小的放一边
-
过程挖坑填数法
-
/* 一组元素中, 将第一个位置作为第一个坑位1, 记录基准数 从右边找比基准数 小的数作为坑位2, 将坑位2的数放到坑位1, 在从左边开始找比基准数 大的数作为坑位3 把坑位3 的数放到坑位2, 在从右边找比基准数小的数作为坑位4 把坑位4的数 放到坑位3 依次类推 直到 找完 后 两边的数 就变为 大于基准数的在一边, 小于基准数的在一边 在对两边进行同样的操作 */
public class Test { public static void main(String[] args) { int[] arr = {5, 3, 9, 1, 6, 7, 2, 4, 0, 8};quickSort(arr, 0, arr.length-1); System.out.println(Arrays.toString(arr)); } private static void quickSort(int[] arr, int start, int end) { //找出分左右恋曲的索引位置, 然后对左右两边进行递归调用 if (start < end){ int index = getIndex(arr,start,end); quickSort(arr,start,index-1); quickSort(arr,index+1,end); } } private static int getIndex(int[] arr, int start, int end) { int i = start; int j = end; int x = arr[i]; while (i<j){ //由后向前找比他小的数, 找到后挖出此数填到前一个坑 while (i<j && arr[j] >= x){ j--; } if(i<j){ arr[i]=arr[j]; i++; }
// 由前向后找比他大的数, 找到后挖出此数填到前一个坑
while (i<j && arr[i] < x){
i++;
}
if(i<j){
arr[j]=arr[i];
j--;
}} arr[i] = x;// 把基准数放到最后的位置 return i; }
}
归并排序
-
n个元素的序列, 看成是由n个1个元素的序列组成
public class Test { public static void main(String[] args) { int[] arr = {10,30,2,1,0,8,7,5,19,29}; // int[] arr = {4,5,7,8,1,2,3,6}; //拆分 chaifen(arr,0,arr.length-1);//归并 //guiBing(arr,0,3,arr.length-1); System.out.println(Arrays.toString(arr)); } private static void chaifen(int[] arr, int startIndex, int ednIndex) { //计算中间索引 int centerIndex = (startIndex+ednIndex)/2; if (startIndex<ednIndex){ chaifen(arr,startIndex,centerIndex); chaifen(arr,centerIndex+1,ednIndex); guiBing(arr,startIndex,centerIndex,ednIndex); } } private static void guiBing(int[] arr, int startIndex, int centerIndex, int endIndex) { //定义临时数组 int[] tempArr = new int[endIndex-startIndex+1]; //定义左边数组的起始索引 int i = startIndex; //定义右边数组的起始索引 int j = centerIndex + 1; //定义临时数组起始索引 int index = 0; //比较左右两个数组的元素大小, 往临时数组中放 while(i<=centerIndex&&j<=endIndex){ if(arr[i]<=arr[j]){ tempArr[index] = arr[i]; i++; }else { tempArr[index] = arr[j]; j++; } index++; } //处理剩余元素 while (i<=centerIndex){ tempArr[index]=arr[i]; i++; index++; } while (j<=endIndex){ tempArr[index]=arr[j]; j++; index++; } //将临时数组中的元素替换原数组 for (int k = 0; k <tempArr.length ; k++) { arr[k+startIndex] = tempArr[k]; } }
}
基数排序
-
分配在收集
public class Test { public static void main(String[] args) { int[] arr = {2,1,5,21,31,444,23,33,47,10,903,124,987,100};sortArray(arr); System.out.println(Arrays.toString(arr)); } private static void sortArray(int[] arr) { //定义存放的数组 int[][] tempArr = new int[10][arr.length]; //定义统计数组 int[] counts = new int[10]; //获取数组中的最大值 int max = getMax(arr); //得确定排序轮次 int len = String.valueOf(max).length(); //循环次数 for (int i = 0, n=1; i < len; i++, n*=10) { for (int j = 0; j < arr.length; j++) { // 获取每个位置上的数组 int ys = arr[j]/n%10; tempArr[ys][counts[ys]++]=arr[j]; } //取出桶中的元素 int index = 0; for (int k = 0; k < counts.length; k++) { if(counts[k]!=0){ for (int h = 0; h < counts[k]; h++) { arr[index] = tempArr[k][h]; index++; } counts[k]=0;//清除上一次桶中的数 } } } } private static int getMax(int[] arr) { int max = arr[0]; for (int i = 1; i < arr.length; i++) { if(arr[i] > max){ max = arr[i]; } } return max; }
}
堆排序
-
大顶堆 升序
-
小顶堆 降序
-
二叉树
public class Test { public static void main(String[] args) { int[] arr = {1,0,6,7,2,3,4}; // 大顶堆 //定义开始调整的位置 int startIndex = (arr.length-1)/2; //循环调 for (int i = startIndex; i >= 0 ; i--) { toMaxHeap(arr,arr.length,i); } //变成大顶堆 System.out.println(Arrays.toString(arr)); //在交换顶部 for (int i = arr.length-1; i>0; i--){ int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; //在转换 toMaxHeap(arr,i,0); } System.out.println(Arrays.toString(arr)); }private static void toMaxHeap(int[] arr, int size, int index) { //获取左右子节点的索引 int leftNodeIndex = index * 2 + 1; int rightNodeIndex = index * 2 + 2; //查找最大节点所对应的索引 int maxIndex = index; if(leftNodeIndex<size && arr[leftNodeIndex]>arr[maxIndex]){ maxIndex = leftNodeIndex; } if(rightNodeIndex<size && arr[rightNodeIndex]>arr[maxIndex]){ maxIndex = rightNodeIndex; } //交换位置 if(maxIndex!=index){ int temp = arr[maxIndex]; arr[maxIndex] = arr[index]; arr[index] = temp; // 影响子树 toMaxHeap(arr, size, maxIndex); } }
}
常用类
Object
-
boolean equals (Object obj)
-
String toString()
public class Test { public static void main(String[] args) { Person person = new Person("jack",18); String string = person.toString(); System.out.println(string);//com.cyz.demo05.Person@1b6d3586 //重写Person的toString方法 /* @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }*/ System.out.println(person.toString()); //Person{name='jack', age=18} }
}
package com.cyz.demo05; public class Test { public static void main(String[] args) { Person p1 = new Person("jack",18); Person p2 = new Person("mark",18); boolean flag = p1.equals(p2); System.out.println(flag);//false /* public boolean equals(Object obj) { return (this == obj); } // this -> p1 // obj -> obj // == 比较地址值 */ Person p3 = new Person("mark",18); // Person 重写 equals 方法 /* @Override public boolean equals(Object obj) { if(obj== this){ return true; } if(obj == null){ return false; } if (obj instanceof Person){ Person p = (Person)obj; boolean b = this.name.equals(p.name) && this.age == p.age; return b; } return false; } */ System.out.println(p2.equals(p3)); } }
@Override public boolean equals(Object o) { if (this == o) return true; //使用反射 if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); }
Objects类
-
equals
//解决空指针异常 public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); }
哈希值
// 是一个十进制的整数, 由系统随机给出(地址值, 逻辑地址, 非真实物理地址) // 获取哈希值: hashcode()
hashcode()
public class Test { public static void main(String[] args) { Person p1 = new Person(); int h1 = p1.hashCode(); System.out.println(h1);//460141958Person p2 = new Person(); int h2 = p2.hashCode(); System.out.println(h2);//1163157884 //Person未重写hashCode 使用的是Object的hashcode }
}
clone()
getClass()
notify()
// 唤醒单个线程
wait()
// 和sleep 一样
System
-
currentTimeMillis() 获取系统当前时间毫秒数 一般用于测试程序执行时间
-
arraycopy(源数组, 起始位置, 目标数组,, 目标数据中的起始位置, 要复制的数组元素的数量)
package com.cyz.demo05; import java.util.Arrays;public class Test {
public static void main(String[] args) {
System.out.println(System.currentTimeMillis());//1594556391674int[] arr = {1,2,3,4,5}; int[] arr2 = {6,7,8,9,10}; System.arraycopy(arr,0,arr2,0,3); System.out.println(Arrays.toString(arr)); System.out.println(Arrays.toString(arr2)); }
}
Math类
-
double abs(double num) 绝对值
-
double ceil(double num) 向上取整
-
double floor(double num) 向下取整
-
long round(double num) 四舍五入
-
double pow(double a, double b) a 的 b 次方
public class Test { public static void main(String[] args) { System.out.println(Math.abs(-2));//2 System.out.println(Math.ceil(3.4));//4.0 System.out.println(Math.floor(3.9));//3.0 System.out.println(Math.round(3.6));//4 System.out.println(Math.pow(2,3));//8.0 } }
Random
package com.cyz.demo05; import java.util.Random; public class Test { public static void main(String[] args) { Random random = new Random(); System.out.println(random.nextInt());//范围在int 的整个正负范围System.out.println(random.nextInt(10));//范围在 [0,10) System.out.println(random.nextInt(10)+1);//范围在 [1,11) 也就是[1,10] }
}
UUID
String str = UUID.randomUUID().toString(); System.out.println(str.replaceAll("-",""));//32位 //17257a500fc84a95ba24bc5bbdc71103
File
创建文件
查看文件
修改文件
删除文件
包装类
基本类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
public class Test { public static void main(String[] args) { // 装箱: 基本类型 -> 包装类 //构造方法 Integer in1 = new Integer(1); System.out.println(in1); Integer in2 = new Integer("1"); System.out.println(in2); //静态方法 Integer in3 = Integer.valueOf(2); System.out.println(in3);Integer in4 = Integer.valueOf("2"); System.out.println(in4);
// 拆箱
//成员方法
in1=in1.intValue();
System.out.println(in1);}
}
自动拆箱和装箱 jdk1.5+
// 自动装箱 Integer in = 1;// 自动拆箱 + 自动装箱
in = in + 2;
基本类型&String相互转换
// 直接 + ""// 使用parseInt 处理char其他都有对应
Date类
-
毫秒值: 1000ms = 1s
-
0毫秒 1970年1月1日 0时0分0秒
-
获取系统时间: System.currentTimeMillis()
-
在中国 获取的是 到1970年1月1日 8时0分0秒 东八区
-
Date
public class Test { public static void main(String[] args) { System.out.println(System.currentTimeMillis());//1594544955624 Date date = new Date(); System.out.println(date);//Sun Jul 12 17:13:16 CST 2020date = new Date(0L); System.out.println(date);//Thu Jan 01 08:00:00 CST 1970 date = new Date(1594544955624L); System.out.println(date);//Sun Jul 12 17:09:15 CST 2020 //转为毫秒值 System.out.println(date.getTime());//1594544955624 }
}
SimpleDateFormat
-
format 格式化
-
parse 格式化转回
package com.cyz.demo05;import javax.xml.crypto.Data;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class Test {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String str = sdf.format(date); System.out.println(str);//2020-07-12 17:20:55 // 将指定格式的字符串解析为 Date对象 try { Date date2 = sdf.parse("2020-07-12 17:20:55"); System.out.println(date2);//Sun Jul 12 17:20:55 CST 2020 } catch (ParseException e) { e.printStackTrace(); } }
}
Calendar
import javax.xml.crypto.Data; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date;public class Test {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
System.out.println(c);
/*
java.util.GregorianCalendar[
time=1594546068848,
areFieldsSet=true,
areAllFieldsSet=true,
lenient=true,
zone=sun.util.calendar.ZoneInfo[
id="Asia/Shanghai",
offset=28800000,
dstSavings=0,
useDaylight=false,
transitions=29,
lastRule=null
],
firstDayOfWeek=1,
minimalDaysInFirstWeek=1,
ERA=1,
YEAR=2020,
MONTH=6,
WEEK_OF_YEAR=29,
WEEK_OF_MONTH=3,
DAY_OF_MONTH=12,
DAY_OF_YEAR=194,
DAY_OF_WEEK=1,
DAY_OF_WEEK_IN_MONTH=2,
AM_PM=1,
HOUR=5,
HOUR_OF_DAY=17,
MINUTE=27,
SECOND=48,
MILLISECOND=848,
ZONE_OFFSET=28800000,
DST_OFFSET=0
]*/ //获取 int year = c.get(Calendar.YEAR);//2020 System.out.println(year); int month = c.get(Calendar.MONTH);//6 System.out.println(month); int data = c.get(Calendar.DATE);//12 System.out.println(data); System.out.println(c.get(Calendar.DAY_OF_MONTH));//12 //设置 c.set(Calendar.YEAR,9999); year = c.get(Calendar.YEAR);//9999 System.out.println(year); c.set(Calendar.MONTH,9); month = c.get(Calendar.MONTH);//9 System.out.println(month); c.set(Calendar.DATE,9); data = c.get(Calendar.DATE);//9 System.out.println(data); //同时设置年月日 c.set(8888,8,8); year = c.get(Calendar.YEAR);//8888 System.out.println(year); month = c.get(Calendar.MONTH);//8 System.out.println(month); data = c.get(Calendar.DATE);//8 System.out.println(data); c.add(Calendar.YEAR,2); c.add(Calendar.MONTH,-1); c.add(Calendar.DATE,-1); year = c.get(Calendar.YEAR);//8890 System.out.println(year); month = c.get(Calendar.MONTH);//7 System.out.println(month); data = c.get(Calendar.DATE);//7 System.out.println(data); //将日历对象转换为 日期对象 Date time = c.getTime(); System.out.println(time); // Mon Aug 07 17:41:08 CST 8890 }
}
String类
-
不可变性
// 字面量 "abc" 都是String 的实例对象 共享使用 // 底层是byte[]字节数组
三种构造方法
String() String(char[] array) // 底层还是会先创建byte数组 String(byte[] array)
public class Test { public static void main(String[] args) { String str1 = new String(); System.out.println("第一个字符串为: "+str1);char[] chars = {'a','b'}; String str2 = new String(chars); System.out.println(str2); byte[] byres = {98,99}; String str3 = new String(byres); System.out.println(str3); String str4 = new String("aaa"); System.out.println(str4); //直接创建 也是对象 String str5 = "ccc"; System.out.println(str5); /* 第一个字符串为: ab bc aaa ccc */ }
}
常量池
-
字符串直接使用""双引号创建的就在常量池中
-
常量池中保存的是字节数组的地址值
public class Test { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc";char[] chars = {'a','b','c'}; String str3 = new String(chars); System.out.println(str1 == str2); System.out.println(str1 == str3); System.out.println(str2 == str3); System.out.println(str1.equals(str2)); System.out.println(str1.equals(str3)); System.out.println(str2.equals(str3)); /* true false false true true true ==比较的是地址值 equals比较的是值 */ }
}
常用方法
-
boolean equals(String str) : 比较的字符串的内容
-
常量写左边
-
-
boolean equalsIgnoreCase(String str) : 忽略大小写比较
-
-
int length(): 字符串长度
-
String concat(String str) 字符串拼接
-
char charAt(int index);: 获取指定位置的单个字符
-
int indexOf(String str): 查找字符串在首次出现的位置, 没有返回-1
-
Sttring substring(int index) 截取指定位置开始到最后的字符串
-
Sttring substring(int begin, int end) 截取 [begin,end) 到最后的字符串
-
-
char[] toCharArray() 将字符串拆分成字符数组
-
byte[] getBytes() 获取字符串底层byte[]数组
-
String replace(CharSequence oldString, CharSequence newString) 将出现的老字符替换为新字符
-
-
String[] split(String regex) 按照参数规则 分割字符串
-
注意是正则
-
特殊需要转义
-
public class Test { public static void main(String[] args) { String str1 = "abc"; String str2 = "abc";char[] chars = {'a','b','c'}; String str3 = new String(chars); System.out.println(str1.equals(str2)); System.out.println(str1.equals(str3)); System.out.println(str2.equals(str3)); /* true true true */ }
}
public class Test { public static void main(String[] args) { String str1 = "abc"; String str4 = null; System.out.println(str1.equals(str4)); System.out.println(str4.equals(str1)); /* false //NullPointerException 空指针异常 */ } }
public class Test { public static void main(String[] args) { int length = "sadasdasdasdasdasd".length();//18 System.out.println(length); String str1 = "hello"; String str2 = "World"; String str3 = str1.concat(str2); System.out.println(str1);//hello System.out.println(str2);//World System.out.println(str3);//helloWorld char c = "Hello".charAt(1);//e System.out.println(c); String str4 = "helloWorld"; int index = str4.indexOf("llo");//2 System.out.println(index); int index2 = str4.indexOf("c"); System.out.println(index2);//-1 String str5 = str4.substring(5); System.out.println(str5);//World String str6 = str4.substring(0,5); System.out.println(str6);//hello System.out.println(str4);//helloWorld } }
public class Test { public static void main(String[] args) { char[] chars = "Hello".toCharArray(); System.out.println(chars[0]);//H System.out.println(chars.length);//5 byte[] bytes = "abc".getBytes(); for (int i = 0; i < bytes.length; i++) { System.out.println(bytes[i]); /* 97 98 99 */ } String str1 = "How do you do?"; String o = str1.replace("o", "*"); System.out.println(o);//H*w d* y*u d*? } }
public class Test { public static void main(String[] args) { String str1 = "aaa,bbb,ccc"; String[] arr = str1.split(","); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); /* aaa bbb ccc */ } String str2 = "aaa.bbb.ccc"; String[] arr = str2.split("\\."); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); /* aaa bbb ccc */ } } }
StringBuffer
-
可变长
-
append
-
多线程数据量较大
-
效率低, 线程安全
StringBuilder
-
字符串缓冲区
-
可变长
-
单线程数据量较大
-
效率高, 线程不安全
-
底层也是btye[] 数组 但没有被final修饰, 是可变的
-
在内存中始终是一个数组, 超过容量自动扩容
-
// String 进行相加 中间创建太多的字符串对象, 效率低 // "a" + "b" + "c"
public class Test { public static void main(String[] args) { // 两个构造方法 StringBuilder bu1 = new StringBuilder(); System.out.println("bu1: "+bu1);StringBuilder bu2 = new StringBuilder("abc"); System.out.println("bu2: "+bu2); /* bu1: bu2: abc */
// 成员方法 append 可以是任意数据类型 返回值是this 不需要接收
StringBuilder bu3 = new StringBuilder();
StringBuilder bu4 = bu3.append("aaa");
System.out.println("bu3: "+bu3);
System.out.println("bu4: "+bu4);
System.out.println(bu3==bu4);
/*
bu3: aaa
bu4: aaa
true
*/
bu3.append(1);
bu3.append(true);
bu3.append(0.0);
bu3.append("中");
System.out.println("bu3: "+bu3);//bu3: aaa1true0.0中// 由于返回的是this 可以链式调用 bu3.append(2).append("sss").append("sdd"); System.out.println("bu3: "+bu3);//bu3: aaa1true0.0中2ssssdd }
}
Arrays
-
String toString(数组) 数组变为字符串 [元素1, 元素2, ....]
-
void sort(数组) 升序排序
-
数字和字母升序
-
自定义类型 需要实现Comparable 或 Comparator
-
package com.cyz.demo05;public class Test {
public static void main(String[] args) {
// 两个构造方法
StringBuilder bu1 = new StringBuilder();
System.out.println("bu1: "+bu1);StringBuilder bu2 = new StringBuilder("abc"); System.out.println("bu2: "+bu2); /* bu1: bu2: abc */
// 成员方法 append 可以是任意数据类型 返回值是this 不需要接收
StringBuilder bu3 = new StringBuilder();
StringBuilder bu4 = bu3.append("aaa");
System.out.println("bu3: "+bu3);
System.out.println("bu4: "+bu4);
System.out.println(bu3==bu4);
/*
bu3: aaa
bu4: aaa
true
*/
bu3.append(1);
bu3.append(true);
bu3.append(0.0);
bu3.append("中");
System.out.println("bu3: "+bu3);//bu3: aaa1true0.0中// 由于返回的是this 可以链式调用 bu3.append(2).append("sss").append("sdd"); System.out.println("bu3: "+bu3);//bu3: aaa1true0.0中2ssssdd //反转 bu3.reverse(); System.out.println("bu3: "+bu3);//bu3: ddssss2中0.0eurt1aaa }
}
package com.cyz.demo05; public class Test { public static void main(String[] args) { String str = "hello"; System.out.println("str: " + str); StringBuilder bu = new StringBuilder(str); bu.append("a").append(1).append(true); System.out.println("bu: " + bu); String s = bu.toString(); System.out.println("s: " + s); /* str: hello bu: helloa1true s: helloa1true */ } }
数据结构
栈
// 入口和出口 在集合同一侧 // 入栈或压栈 // 出栈或弹栈 // 先进后出
队列
// 入口和出口 在集合的两侧 // 先进先出
数组
// 查询快: 数组地址是连续的, 根据首地址可以查询到数组, 根据索引可以定位到数据 // 增删慢: 长度不可变, 改变需要创建新数组, 拷贝原数组, 重新赋值 // 重复复制, 销毁原数组, 效率低
链表
// 查询慢: 链表地址不是连续的, 每次查询必须从头开始 // 增删快: 增删对链表结构没有影响 只用把节点地址更改即可 // 每一个元素称为 节点 // 节点: 数组源(存数组) + 两个指针域(存地址) // 自己的地址 + 数据 + 下一个节点的地址//分类:
// 单向链表: 只有一条链, 不能保证元素的顺序(存和取的元素顺序可能不一致)
// 双向链表: 两条链, 一条链专门记录元素的顺序, 是一个有序的集合
红黑树
二叉树
-
分支不能超过两个
// * //左子树 * *//右子树 //树叶 * * * *
排序树/查找树
-
在二叉树的基础上, 元素有大小顺序
-
左子树小, 右子树大
-
查询速度快
*衡树
-
左子树的数量 等于 右子树的数量
-
查询速度快
不*很树
-
左子树的数量 不等于 右子树的数量
* * * * * *
红黑树
-
趋*于*衡树
-
查询速度快, 查询子节点最大次数和最小次数不能超过2倍
-
约束:
-
节点可以是黑色的也可以是红色的
-
根节点是黑色的
-
叶子节点(空节点)是黑色的
-
每个红色的节点的子节点颜色都是黑色的
-
任何一个节点到其叶子节点的所有路径上的黑色节点数相同
-
Collection
-
长度可变, 存对象,类型可以不同
public class Test { public static void main(String[] args) { Collection<String> coll = new ArrayList<>(); System.out.println(coll);//重写了toStringboolean flag = coll.add("a"); System.out.println(flag);//true System.out.println(coll);//[a] coll.add("b"); coll.add("c"); System.out.println(coll);//[a, b, c] System.out.println(coll.size());//3 boolean flag1 = coll.remove("a"); System.out.println(flag1);//true boolean flag2 = coll.remove("a"); System.out.println(flag2);//false boolean flag3 = coll.contains("a"); System.out.println(flag3);//false boolean flag4 = coll.isEmpty(); System.out.println(flag4);//false Object[] arr = coll.toArray(); System.out.println(Arrays.toString(arr));//[b, c] coll.clear(); System.out.println(coll.size());//0 System.out.println(coll.isEmpty());//true }
}
Iterator
Iterator<String> it =coll.iterator(); while (it.hasNext()) { System.out.println(it.next()); /* b c */ }
# 实现原理 Iterator<String> it =coll.iterator(); # 获取迭代对象 it.hasNext() # 判断是否有下一位 it.next() # 取出元素 指针向后移动
// 增强for循环底层实现是迭代器 for (String str : coll){ System.out.println(str); /* b c */ }
List
-
有序可重复, 有索引
public class Test { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("a");System.out.println(list);//[a, b, c, d, a] 有序, 可重复 list.add(3, "chen"); //添加指定位置 System.out.println(list);//[a, b, c, chen, d, a] String removeE = list.remove(2); System.out.println("移除的是: " + removeE);//移除的是: c System.out.println(list);//[a, b, chen, d, a] String setE = list.set(4, "A"); System.out.println("被替换的元素: " + setE);//被替换的元素: a System.out.println(list);//[a, b, chen, d, A] //遍历 for (int i = 0; i < list.size(); i++) { String s = list.get(i); System.out.println(s); } Iterator it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } for (String s : list) { System.out.println(s); } }
}
ArrayList: 底层是数组 查询快 增删慢
-
不同步的, 多线程
-
add
-
get
-
remove
-
contains
-
size
package com.cyz.demo05;import java.util.ArrayList;
import java.util.Random;public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
System.out.println(list);
int num = list.get(1);
System.out.println(num);for (int i = 0; i < list.size(); i++){ System.out.println(list.get(i)); } /* [100, 200] 200 100 200 */ }
}
package com.cyz.demo05; import java.util.ArrayList; import java.util.Random; public class Test { public static void main(String[] args) { ArrayList<Person> list = new ArrayList<>(); Person p1 = new Person("one",1); Person p2 = new Person("two",2); Person p3 = new Person("three",3); Person p4 = new Person("four",4); list.add(p1); list.add(p2); list.add(p3); list.add(p4); for (int i = 0; i < list.size(); i++){ Person person = list.get(i); System.out.println(person.getName()); } /* one two three four */ } }
package com.cyz.demo05; import java.util.ArrayList; import java.util.Random; import java.util.UUID; public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("abc"); list.add("cde"); list.add("asd"); System.out.println(list.contains("a"));//false System.out.println(list.contains("abc"));//true list.remove("abc"); System.out.println(list.contains("abc"));//false list.remove(1); for (int i = 0; i < list.size(); i++){ System.out.println(list.get(i));//cde } } }
LinkedList: 链表实现 查询慢 增删快
-
不能使用多态创建
-
getFirst()
-
getLast()
-
removeFirst()
-
removeLast();
-
addFirst()//push()
-
addLast()//pop()
public class Test { public static void main(String[] args) { show03(); }private static void show03() { LinkedList<String> linked = new LinkedList<>(); linked.add("a"); linked.add("b"); linked.add("c"); System.out.println(linked);//[a, b, c] String first = linked.removeFirst();
// linked.pop();//等价
System.out.println("移除的元素: " + first);//移除的元素: a
System.out.println(linked);//[b, c]String last = linked.removeLast(); System.out.println("移除的元素: " + last);//移除的元素: c System.out.println(linked);//[b] } private static void show02() { LinkedList<String> linked = new LinkedList<>(); linked.add("a"); linked.add("b"); linked.add("c"); System.out.println(linked);//[a, b, c] if (!linked.isEmpty()) { //判断是否为空 String first = linked.getFirst(); System.out.println(first);//a String last = linked.getLast(); System.out.println(last);//c } linked.clear();//清空 } private static void show01() { // 创建不能使用多态 LinkedList<String> linked = new LinkedList<>(); linked.add("a"); linked.add("b"); linked.add("c"); System.out.println(linked);//[a, b, c] linked.addFirst("w");
// linked.push("w"); 等价
System.out.println(linked);//[w, a, b, c]linked.addLast("n"); System.out.println(linked);//[w, a, b, c, n] }
}
Vector
-
单例集合的鼻祖
-
底层也是数组, 同步的, 单线程 实现可增长的数组
-
实现 List
-
elements遍历
-
hasMoreElements()
-
nextElement()
-
Stack
-
继承Vector
Set
-
无序不可重复
-
继承Collection 无序没有索引
HashSet: 底层哈希表 + 红叉树 无索引 不可重复 获取无序 多线程, 不同步
-
哈希表结构: 查询速度快
public class Test { public static void main(String[] args) { Set<Integer> set = new HashSet<>(); set.add(1); set.add(2); set.add(3); set.add(4);Iterator<Integer> it = set.iterator(); while (it.hasNext()) { Integer n = it.next(); System.out.println(n); } }
}
-
存储数据结构(哈希表)
//1.8之前: 哈希表: 数组 + 链表; //1.8之后: 哈希表: 数组 + 红黑树(提高查询速度) // 哈希表特点: 查询速度快//数组结构: 把元素进行分组,(相同哈希值的元素一组) 存的哈希值
//链表/红黑树结构: 连接哈希值相同的元素
//在1.8之后如果链表长度超过8位就会转为红黑树//存数据的到集合中 先计算元素的哈希值
-
不重复的原理
// 调用add() 时会调用 hashCode方法 计算哈希值 // 查看集合中是否有相同哈希值的元素 // 有的话 通过equals() 比较 如果返回false 则存入//存储的元素必须重写hashCode和equals方法
LinkedHashSet
-
底层哈希表 + 链表 无索引 不可重复, 获取有序
public class Test { public static void main(String[] args) { HashSet<String> set = new HashSet<>(); String s1 = new String("abc"); String s2 = new String("abc"); set.add(s1); set.add(s2); set.add("d"); set.add("c"); set.add("abc"); System.out.println(set);//[abc, c, d]LinkedHashSet<String> linked = new LinkedHashSet<>(); linked.add(s1); linked.add(s2); linked.add("d"); linked.add("c"); linked.add("abc"); System.out.println(linked);//[abc, d, c] }
}
-
LinkedHashSet 底层哈希表 + 链表 无索引 不可重复, 获取有序
TreeSet: 底层二叉树 一般用于排序
Map
-
键值对 key不允许重复
-
数据类型可以不同
HashMap
-
无序, 存和取的顺序可能不一致
-
底层是哈希表
哈希表:
-
jdk1.7 数组 + 链表(单向链表)
-
jdk1.8 hash表 = 数组+ 链表 +红黑树
public class Test { public static void main(String[] args) { show01(); }private static void show02() { //key和value数据类型不同 Map<String,Integer> map = new HashMap<>(); map.put("a",1); map.put("b",2); map.put("c",3); map.put("d",4); System.out.println(map);//{a=1, b=2, c=3, d=4} Integer a = map.remove("a"); System.out.println(a);//1 Integer e = map.remove("e"); System.out.println(e);//null System.out.println(map);//{b=2, c=3, d=4} } private static void show01() { // key相同时为 替换 Map<String,String> map = new HashMap<>(); String a = map.put("1", "a"); System.out.println(a);//null String b = map.put("1", "b"); System.out.println(b);//a System.out.println(map);//{1=b} map.put("2","c"); map.put("3","d"); map.put("4","3"); System.out.println(map);//{1=b, 2=c, 3=d, 4=3} String s = map.get("1"); System.out.println(s);//b boolean b1 = map.containsKey("1"); System.out.println(b1);//true String s2 = map.get("5"); System.out.println(s2);//null boolean b2 = map.containsKey("5"); System.out.println(b2);//false }
}
public class Test { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("a", 1); map.put("b", 2); map.put("c", 3); map.put("d", 4); // Set<K> keySet() 把Map集合的所有ket取出来存到Set中 // Set 可以使用迭代器 或 增强for Set<String> set = map.keySet(); for (String s : set) { System.out.println(s + "=" + map.get(s)); } /* a=1 b=2 c=3 d=4 */ Iterator<String> it = set.iterator(); while (it.hasNext()) { String key = it.next(); Integer value = map.get(key); System.out.println(key + "=" + value); } /* a=1 b=2 c=3 d=4 */ } }
public class Test { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("a", 1); map.put("b", 2); map.put("c", 3); map.put("d", 4); // Map.Entry<K,V>: 存放键值对 Map集合一创建就存在 Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); Iterator<Map.Entry<String, Integer>> it = entrySet.iterator(); while (it.hasNext()) { Map.Entry<String, Integer> entry = it.next(); System.out.println(entry.getKey() + "=" + entry.getValue()); } /* a=1 b=2 c=3 d=4 */ for ( Map.Entry<String, Integer> entry : entrySet){ System.out.println(entry.getKey() + "=" + entry.getValue()); } /* a=1 b=2 c=3 d=4 */ } }
-
使用自定义类型时, 需要重写 hashCode 和 equals 保证key唯一性
linkedHashMap
-
哈希表 + 链表(记录元素顺序)
-
有序
-
存储元素和取出顺序元素一致
public class Test { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("a", 1); map.put("c", 3); map.put("b", 2); map.put("d", 4); System.out.println(map);//{a=1, b=2, c=3, d=4}LinkedHashMap<String,Integer> linked = new LinkedHashMap<>(); linked.put("a", 1); linked.put("c", 3); linked.put("b", 2); linked.put("d", 4); System.out.println(linked);//{a=1, c=3, b=2, d=4} }
}
public class Test { public static void main(String[] args) { // Hashtable 单线程, 同步 线程安全的 速度慢 key和value不能为null 底层也是哈希表 // 被HashMap取代 HashMap<String, String> map = new HashMap<>(); map.put(null,"a"); map.put("b",null); map.put(null,null); System.out.println(map);//{null=null, b=null} Hashtable<String, String> mapt = new Hashtable<>(); // mapt.put(null,"a");//NullPointerException // mapt.put("b",null);//NullPointerException // mapt.put(null,null);//NullPointerException mapt.put("a","b"); System.out.println(mapt);//{a=b} } }
TreeMap
集合优化方法 of jdk9新特性
public class Test { public static void main(String[] args) { // jdk9 新特性 // static <E> list<E> of (E..elements) // 前提: 集合中存储的个数已经确定, 不在改变时使用 // of方法只适用于list接口, Set接口, Map接口, 不适用于接口的实现类 // of方法的返回值是一个不可变的集合, 不能使用add, put方法 // Set和Map使用时不能有重复的元素List<String> list = List.of("a","b","c","d"); System.out.println(list);
// list.add("w"); //不可操作异常
// Set<String> set = Set.of("a","b","c","c"); // 非法参数异常
Set<String> set = Set.of("a","b","c","d");
System.out.println(set);
// set.add("w");// Map<String,Integer> map = Map.of("a",1,"b",2,"a",3); 非法参数异常
Map<String,Integer> map = Map.of("a",1,"b",2,"c",3);
System.out.println(map);
// map.put("w",1); //不可操作异常
}
}
Collections工具类
-
<T> boolean addAll(Collection<T> c, T... elements)
-
void shuffle()
-
<T> void sort(List<T> list)
-
<T> void sort(List<T> list, Comparator<? super T>)
public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); //添加多个 Collections.addAll(list, "a", "b", "c", "d"); System.out.println(list);//[a, b, c, d] //打乱集合 Collections.shuffle(list); System.out.println(list);//[a, b, d, c]ArrayList<Integer> list01 = new ArrayList<>(); list01.add(1); list01.add(3); list01.add(2); System.out.println(list01);//[1, 3, 2] Collections.sort(list01);//默认升序 System.out.println(list01);//[1, 2, 3] Collections.sort(list); System.out.println(list);//[a, b, c, d] //对于自定义类 需要实现Comparable接口 中的 CompareTo 方法 ArrayList<Person> list3 = new ArrayList<>(); list3.add(new Person("1",18)); list3.add(new Person("2",20)); list3.add(new Person("1",15)); System.out.println(list3); //[Person{name='1', age=18}, Person{name='2', age=20}, Person{name='1', age=15}] Collections.sort(list3); System.out.println(list3); //[Person{name='2', age=20}, Person{name='1', age=18}, Person{name='1', age=15}] }
}
public class Person implements Comparable<Person> {
...
@Override
public int compareTo(Person o) {
// return 0; //认为元素相同
// return this.getAge() - o.getAge();//升序
return o.getAge() - this.getAge();//降序
}
}
Comparable和Comparator的区别
//Comparable: 自己(this)和别人(参数)比较, 自己需要实现Comparable接口, 重写CompareTo()//Comparator: 相当于找一个第三方的裁判, 比较两个
public class Test { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(3); list.add(2); System.out.println(list);//[1, 3, 2] Collections.sort(list, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1-o2;//升序 } }); System.out.println(list);//[1, 2, 3] } }
public class Test { public static void main(String[] args) { ArrayList<Person> list = new ArrayList<>(); list.add(new Person("1",18)); list.add(new Person("2",20)); list.add(new Person("3",15)); System.out.println(list); //[Person{name='1', age=18}, Person{name='2', age=20}, Person{name='3', age=15}] Collections.sort(list, new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return o1.getAge() - o2.getAge();//升序 } }); System.out.println(list); //[Person{name='3', age=15}, Person{name='1', age=18}, Person{name='2', age=20}] } }
泛型
-
约束, 避免类型转换之间的问题
-
泛型类型 作为参数类型使用
class ArrayList<String> { boolean add(String a){}; }
-
可以使用在类, 方法, 接口
public <M> void method(M a){}
-
泛型通配符?
public class Test { public static void main(String[] args) { // ? 代表任意的数据类型 // 不能创建对象使用 // 只能作为方法的参数使用ArrayList<String> list1 = new ArrayList<>(); list1.add("a"); list1.add("b"); ArrayList<Integer> list2 = new ArrayList<>(); list2.add(1); list2.add(2); printArray(list2); } private static void printArray(ArrayList<?> list) { Iterator it =list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } }
}
-
上限 ? extends E
-
下限 ? super E
斗地主案例
/** * 斗地主案例: * 特殊牌: 小王, 大王 * 其他52张牌 * 定义一个数组/集合 存储4种花色: ♠,♥,♣,♦ * 定义一个数组/集合, 存储13个序号 2,A,K....3 * 循环嵌套遍历两个数组/集合, 组装52张牌 * <p> * 洗牌: * void shuffle(List<?> list) * 随机打乱集合顺序 * <p> * 发牌 * 要求1人17张牌 剩余3张最为底牌 * (0~53) % 3 * 定义4个集合存放玩家的牌和底牌 * <p> * 看牌 * 打印集合 */ public class Test { public static void main(String[] args) { //准备牌 ArrayList<String> poker = new ArrayList<>(); String[] colors = {"♠", "♥", "♣", "♦"}; String[] numbers = {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"}; // 存 大王, 小王 poker.add("大王"); poker.add("小王"); // 嵌套遍历两个数组 for (String number : numbers) { for (String color : colors) { poker.add(color + number); } }//洗牌 shuffle Collections.shuffle(poker); // 发牌 //定义玩家 + 底牌 ArrayList<String> player01 = new ArrayList<>(); ArrayList<String> player02 = new ArrayList<>(); ArrayList<String> player03 = new ArrayList<>(); ArrayList<String> diPai = new ArrayList<>(); //遍历集合 // i >=51 发底牌 for (int i = 0; i < poker.size(); i++) { // 获取牌 String p = poker.get(i); if(i>=51){ diPai.add(p); }else if(i % 3 == 0){ player01.add(p); }else if(i % 3 == 1){ player02.add(p); }else if(i % 3 == 2){ player03.add(p); } } //看牌 System.out.println("p1: " + player01); System.out.println("p2: " + player02); System.out.println("p3: " + player03); System.out.println("dp: " + diPai); }
}
IO流
字节流
输出OutputStream
输入InputStream
字符流
Reader
Writer
节点流
charArrayReader,Writer
inputstream
outputstream
StringReader, Writer
pipe(管道流)
PipedOutputStream
File(,,,)