JAVA三大版本
- 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);//false
float 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--->double
int 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 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);
冒泡排序
- 比较相邻的数, 交换
- 每次都会出一个最大或最小
- 下轮循环少一次排序
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,或相同的值时, 使用稀疏数组
- 处理方式:
- 记录数据一共几行几列, 有多少个不同值
- 把不同的值的元素和行列记录在一个小的数组中
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
局部内部类
}
}
匿名内部类
// 没有名字的内部类
异常机制
- Exception
- Error不是异常, 虚拟机错误
- 运行时异常:
- 数组下标越界
- 空指针异常
- 算术异常
- 丢失资源
- 找不到类
异常抛出和捕获
try{
}catch(Exception e){
e.printStackTrace();//打印错误信息
}finally{
}
throws new Exception
//finally 都会执行
//多个异常 从小到大
自定义异常类
//detail>10 异常
private int detail;
public MyException(int a){
this.detail = a;
}
@Override
public String toString(){
return "MyException{" +
"detail=" + detail +
"}";
}
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[] : 表示一个一位数组, 一个二维数组
基础查找
private static int getIndexByEle(int[] arr, int ele) {
for (int i = 0; i < arr.length; i++) {
if(ele == arr[i]){
return i;
}
}
return -1;
}
二分查找(数组必须有序)
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;
}
排序算法
冒泡排序
- 相邻元素两两比较, 比较大或小, 一轮得到最大值或最小值 一轮后 减少一次比较
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));
}
}
插入排序
- 将元素插入到一个有序的列表中, 保持有序
System.out.println(Arrays.toString(arr));
}
System.out.println(Arrays.toString(arr));
}
希尔排序
- 缩小增量排序: 对直接插入排序的优化
- 指定增量 为间隔 , 根据间隔进行比较 当间隔为1时 完成排序
- 通过不断缩小增量, 每轮达到大致有序
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 依次类推
直到 找完 后 两边的数 就变为 大于基准数的在一边, 小于基准数的在一边
在对两边进行同样的操作
*/
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++;
}
}
arr[i] = x;// 把基准数放到最后的位置
return i;
}
归并排序
- n个元素的序列, 看成是由n个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];
}
}
基数排序
- 分配在收集
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;
}
堆排序
- 大顶堆 升序
- 小顶堆 降序
- 二叉树
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()
*/
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()
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(源数组, 起始位置, 目标数组,, 目标数据中的起始位置, 要复制的数组元素的数量)
int[] 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
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 |
Integer in4 = Integer.valueOf("2");
System.out.println(in4);
}
自动拆箱和装箱 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
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 格式化转回
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
*/
//获取
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)
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
*/
}
常量池
- 字符串直接使用""双引号创建的就在常量池中
- 常量池中保存的是字节数组的地址值
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) 按照参数规则 分割字符串
- 注意是正则
- 特殊需要转义
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"
StringBuilder bu2 = new StringBuilder("abc");
System.out.println("bu2: "+bu2);
/*
bu1:
bu2: abc
*/
// 由于返回的是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
StringBuilder bu2 = new StringBuilder("abc");
System.out.println("bu2: "+bu2);
/*
bu1:
bu2: abc
*/
// 由于返回的是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
- 长度可变, 存对象,类型可以不同
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
- 有序可重复, 有索引
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
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()
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();
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.addLast("n");
System.out.println(linked);//[w, a, b, c, n]
}
Vector
- 单例集合的鼻祖
- 底层也是数组, 同步的, 单线程 实现可增长的数组
- 实现 List
- elements遍历
- hasMoreElements()
- nextElement()
Stack
- 继承Vector
Set
- 无序不可重复
- 继承Collection 无序没有索引
HashSet: 底层哈希表 + 红叉树 无索引 不可重复 获取无序 多线程, 不同步
- 哈希表结构: 查询速度快
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
- 底层哈希表 + 链表 无索引 不可重复, 获取有序
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表 = 数组+ 链表 +红黑树
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
- 哈希表 + 链表(记录元素顺序)
- 有序
- 存储元素和取出顺序元素一致
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新特性
List<String> list = List.of("a","b","c","d");
System.out.println(list);
Collections工具类
- <T><T> c, T... elements)
- void shuffle()
- <T><T> list)
- <T><T> list, Comparator<? super T>)
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}]
}
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){
}
- 泛型通配符?
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
斗地主案例
//洗牌 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(,,,)