-
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);//460141958
Person 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 2020
date = 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);//重写了toString
boolean 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(,,,)
浙公网安备 33010602011771号