最基础的Java知识,必须掌握的Java基础
环境变量配置
JAVA_HOME:配置的是jdk的根目录
path:配置bin目录(%JAVA_HOME%\bin)
基本格式
类名必须和文件名保持一致
1 2 3 4 5 6 7
| public class 类名{ public static void main(String[] args) { } }
|
java工具包
jdk:java开发工具包(java development kit),代码编写依赖jdk
jre:java运行环境(java runtime environment),提供javav程序运行的环境
jvm:java虚拟机(java virtual machine),确切说程序是在jvm里面运行的(只认识class字节码文件)
常用cmd命令
dir:显示当前路径下的目录
cd:路径操作
cls:清除当前屏幕
javadoc 程序名.java:生成Doc文档
cmd运行步骤
先写程序
编译:javac 程序名.java
执行:java 程序名
注释
单行注释://注释内容 快捷键:Ctrl+/
多行注释:/*注释类容*/ 快捷键:Ctrl+Shift+/
文档注释:/**注释内容*/(对类和文档进行解释)
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public class name{ public static void main(String[] args) { System.out.println("HelloWorld");
} }
|
目录文件夹
src文件夹:源文件夹 里面存放(包package)java文件
bin文件夹:存放编译之后的(包package)class文件
Class–>Package规范:公司域名后缀名+公司名称+其他
com/cn/edu.java.other
设置相关
字体大小调节
1
| Window->Preferences->Appearance->Colors and Fonts->Basic->Text Font
|
设置统一编码格式为UTF-8
1
| Window->Preferences->workspace->Text file encoding
|
设置注释格式
1
| windows-->preference-->Java-->Code Style-->Code Templates-->code-->new Java files
|
变量的定义和注意事项
变量定义后,不赋值不能使用
变量有自己的作用范围,变量的有效范围定义在一对大括号内
变量不允许重复定义
数据类型
基本数据类型(四类八种)
Java默认数据类型是int
整数默认类型是int,小数默认类型是double
整数:byte/short/int/long
byte:1个字节 -128~127
short:2个字节
**int(默认):4个字节
long:8个字节(过大的数后面加上**L)
小数:float/double(默认)
float:4个字节
double:8个字节
布尔:boolean(默认false)
boolean:1个字节
单个字符:char(默认是’’)
char:2个字节
引用数据类型
String:字符串类(默认是null)
String + 基本类型:字面量数据类型
数组:数据类型[] 数组变量名 = new 数据类型[长度]
任意引用数据类型都存在堆里面
数据类型转换
自动类型转换:**范围小(byte)的可以直接转换为范围大(int)**的
byte -> short -> int -> long -> float -> double
1 2 3 4 5 6 7 8 9 10
| public class DateVonvert { public static void main(String[] args) { double b = 1000; System.out.println(b);
byte b = 111; int j = b; System.out.println(j); } }
|
强制类型转换:被转后的数据类型 变量名 = (被转后的数据类型)要被转的数据
1 2 3 4 5 6 7 8 9 10 11
| public class DateVonvert { public static void main(String[] args) { double dd = 3.14;
int ii = (int) dd; System.out.println(ii);
byte bb = (byte) 200; System.out.println(bb); } }
|
运算符
算术运算符
+ 加法,连接
- 减法
* 乘法
/ 除法
**%**取模,取余数
++ 自增1
– 自减1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Operator { public static void main(String[] args) { System.out.println("5+5="+5+5); int i = 5; int j = i++; System.out.println(i); System.out.println(j); int m = 5; int n = ++m; System.out.println(m); System.out.println(n); }
}
|
赋值运算符
= / += / -= / /= / %=
1 2 3 4 5 6 7 8 9 10 11
| public class Operator { public static void main(String[] args) { byte b = 1; b = (byte)(b + 1); System.out.println(b); byte b1 = 1; b1 += 1; System.out.println(b); } }
|
比较运算符
== / != / <** / **> / <=** / **>=
结果只有 true 或者 false
比较字符串是否一致:名称1.equals(名称2)
逻辑运算符
对两个boolean类型数据之间进行计算结果也是boolean类型
& 与:一个false,结果就是false
| 或:一个true,结果就是true
^ 异或:两边相同为false,不相同为true
! 取反:**!true为false !false为true**
&& 短路与:一边是false,另一边不运行
|| 短路或:一边是true,另一边不运行
三元运算符
公式:布尔表达式?结果1:结果2
结果1和结果2数据类型保持一致
布尔表达式是true,三元运算符结果就是–>结果1
布尔表达式是false,三元运算符结果就是–>结果2
1 2 3 4 5 6
| public class Operator { public static void main(String[] args) { System.out.println(3>2?99:88); System.out.println(3>5?99:88); } }
|
循环控制语句
If Else
1 2 3 4 5 6 7 8
| if(表达式){ }else if(表达式2){
}else{ }
|
While/Do While
两者区别:
while 先判断是否满足条件 满足就执行循环体
do while 无论满不满足循环体都先执行一次
1 2 3 4 5 6 7
| while(判断条件){ }
do{ }while(判断条件);
|
Switch Case
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
switch(表达式){
case 表达式1: 代码逻辑; break; case 表达式2: 代码逻辑; break; case 表达式n: 代码逻辑; break;
default: 代码逻辑; break; }
|
For
1 2 3 4 5 6 7 8
| for(表达式1;表达式2;表达式3){ }
for(数组元素数据类型 变量名称:数组变量名){ }
|
Break,Continue,Return
Break:直接终止整个循环体,不能单独使用在if里
Continue:结束本次循环体,开始下个循环
Return:结束整个方法
Scanner使用
**Scanner input = new Scanner(System.in);**,定义输入
**int a = input.nextInt();**,接收用户输入
**input.close()**,关闭流
断点调试
先双击行首数字出
F6程序往下走一步
F8走到下一个断点处
数组
一维数组
语法
1 2 3
| 数据类型 变量名 = new 数据类型 数据类型 变量名 = {值1,值2,值3,值n} **获取数组长度**:数组名.length;
|
二维数组
语法
1 2 3 4 5 6 7 8 9 10
| 数据类型[][] 变量名 = 数据类型[m][n] 数据类型[][] 变量名 = 数据类型[m][] 数据类型[][] 变量名 = \{\{元素1\},\{元素2\},\{元素3\}\};
String[][] strArr = new String[3][4]; System.out.println(strArr.length); System.out.println(strArr[0].length);
|
Arrays工具类
1 2 3 4 5
| Arrays.toString(arr); Arrays.sort(arr); Arrays.copyof(源数组,新数组长度); Arrays.equals(数组1,数组2); Arrays.binarySearch(数组名, 要查找的元素);
|
排序(Sort)
冒泡排序
效率最慢
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int[] arr = {23,2,44,1};
for(int i = 0; i<arr.length-1; i++) { for (int j = 0; j < arr.length-1-i; j++) { if(arr[j]>arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }
|
选择排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| for(int i = 0; i<arr.length-1; i++) { int min = arr[i]; int minindex = i; for (int j = i+1; j < arr.length; j++) { if (min>arr[j]) { min = arr[j]; minindex = j; } } int temp2 = arr[i]; arr[i] = arr[minindex]; arr[minindex] = temp2; }
|
插入排序
效率最快
1 2 3 4 5 6 7 8 9 10 11
| for (int i = 1; i < arr.length; i++) { int temp = arr[i]; int leftindex = i-1;
while (leftindex >= 0 && arr[leftindex] > temp) { arr[leftindex + 1] = arr[leftindex]; leftindex--; } arr[leftindex + 1] = temp; }
|
类和对象
类的创建
1 2 3 4 5 6 7
| public class 类名{ static String name; static String gender; static int age; }
|
类的方法
- 权限修饰符:public static(公共的),protected(受保护的),private(私有的),默认(default)
- 方法返回值:数据类型,void(无返回值数据类型)
- 方法名():规范:首字母小写,第二个单词字母大写,名字不能重复
- 方法的参数:形式参数,形参 所有数据类型都可以充当形参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void method1() { System.out.println("无参无返回值"); }
public static String method2() { System.out.println("无参有返回值"); String str = "hello"; return str; }
public static void method3(int[] arr,int num,int...obj) { System.out.println("有参无返回值"); System.out.println(arr); }
public static int method4(String str,int i) { System.out.println("有参有返回值"); return i; }
|
可变参数:数据类型…参数名字,可变参数本质上是一个数组
可变参数注意事项:
- 一个方法中,可变参数只能有一个
- 可变参数必须写在参数列表的最后一位
创建对象
语法:类名 对象名 = new 类名();
1 2
| Person zhangSan = new Person(); System.out.println(zhangSan);
|
调用类的属性和方法
1 2 3 4
| zhangSan.name = "张三"; zhangSan.gender = "男"; zhangSan.age = 20; System.out.println(zhangSan.name);
|
调用方法
语法:方法名();
1 2 3 4 5
| public static void method1() { System.out.println("无参无返回值"); }
method1()
|
方法重载
- 方法名相同
- 参数数据类型,参数顺序不一样
- 不考虑返回值和权限修饰符
1 2 3 4 5 6 7 8
| public Animal() { }
public Animal(String name1) { name = name1; }
|
成员变量和局部变量
- 存在位置不一样:成员变量在类里面,局部变量在方法里面
- 作用范围不一样:成员变量在类里任何地方都可以访问,局部变量只可以在方法里面使用
- 内存储存位置不一样:成员变量在堆里,局部变量在栈里
- 初始值不一样:成员变量有初始值,不需要初始化,局部变量没有初始值,必须初始化
枚举类
定义语法:
1 2 3
| public enum Test(){ '这是枚举类' }
|
注意:
- 枚举类必须先定义对象(实例),再定义成员变量和成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public enum Test(){ '对象(实例),多个对象中间用逗号隔开' MONDAY, '默认基于无参构造创建的对象' TUESDAY, WEDNESDAT, THURSDAY("周四"); '使用有参构造创建对象' '想获得对象中的参数值,通过调用对象的get方法获得' '成员变量' private String name; public Integer id; '枚举类中的所有构造方法都必须是私有的' private Week(){} private Week(String name){} }
|
- 枚举类中的对象值一般不允许修改,所以一般只给get方法
面向对象三大特性
封装
对私有属性提供对外的公开访问方法:使用**setter()和getter()**方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private int age; String tname; public void setAge(int age1) { if (age1 < 22) { System.out.println("年龄不合法!"); System.out.println("年龄默认设置为22岁!"); age1 = 22; } age = age1; }
public int getAge() { return age; }
|
lombok使用教程
this关键字
- 当成员变量与局部变量重名的时候,可以使用this来辨别,this指代的是当前对象
- this充当实参
- this可以调用构造函数this(),必须在代码的第一行
- this可以访问属性
- this不能在static所修饰的方法中运用
static关键字
- 静态方法里面不能访问非静态成员
- 如果是static修饰的成员变量,最好初始化
- 静态方法中不能使用this
- 可以和任何权限修饰符一起使用:public/private/protected/final
- 数据是让所有对象共享的
静态代码块:
1 2 3 4 5 6 7 8 9
| static { 初始化数据,不管创不创建对象都走 只运行一次 System.out.println("静态代码块"); } { 只有在创建对象的时候才会走这句话 System.out.println("普通代码块"); }
|
继承(extends)
语法:public class 类1 extends 类2{},一个类只能继承一个类
子类对象创建时会默认先执行父类的无参构造
super
- 访问父类构造方法(super())
- 访问父类的成员变量和成员方法(super.父类变量名/方法名)
方法重写(override)
前提条件:必须要有层级关系
- 方法重写出现在子类里面
- 方法名,形式参数必须和父类保持一致
- 子类访问权限修饰符 >= 父类的
- 子类返回值类型 <= 父类的
- 重写父类方法前面加上:**@Override**
权限修饰符
- public:可以修饰类和成员变量,在整个项目中都是友好的
- protected:可以修饰成员变量,在整个包内和子类中友好
- 默认不写:可以修饰类和成员变量,在包内友好
- private:可以修饰成员变量,在本类中友好
- final:可以修饰常量,被修饰的方法中不能被重写,在继承中不被继承
多态
发生多态条件:
- 父类对象指向任何一个子类的实例(对象)
- 编译时数据类型(=左边)与运行时数据类型(=右边)不一致时
- 子类对象转成父类实例向上转型
- 创建对象发生多态:父类对象 名称 = new 子类对象();
- 父类对象转成子类实例(强制转换),向下转型,要配合instanceof一起使用
- 访问成员变量看**=左边的数据,访问成员方法看=右边**
弊端:无法访问子类特有的成员(变量、方法)
instanceof
使用:父类实例 instanceof 子类对象
抽象类和接口
抽象类
使用条件:当所有子类都需要重新父类的逻辑时,父类方法体就变得没有意义,就把父类方法声明成抽象的方法
使用方法:访问权限修饰符 abstract 返回值类型 方法名();
注意:抽象类不能创建对象,体现在多态上,抽象类的构造方法主要是满足子类对象的创建
接口(interface)
创建接口
1 2 3
| public interface 接口名{
}
|
项目命名规范
- ****Dao/DAO.java,UserDao.java
- ****Service.java,UserService.java
接口中的内容
常量必须为public static final修饰,常量名字必须都是大写
抽象方法必须为publice abstract修饰
JDK1.8之后有普通方法,但必须使用default static修饰
访问父类的普通方法使用super.方法名()
接口的作用
- 接口可以通过implements实现多调用,一个类可以实现多个接口
- 主要用于多态的使用
- 接口和接口之间可以实现多继承
接口和抽象类的区别
共同点:都不能实例化,都用于多态
不同点:接口只有常量和抽象方法和default/static所修饰的功能方法,抽象类有成员变量,成员方法,抽象方法,构造方法,静态代码块
异常
异常Exception(类) —> 可以处理
错误Error(类) —> JVM抛出,程序直接终止
它们有共同的父类:Throwable
异常可以分为两大类:
- 可检测到的异常checkedException:PasreException,SQLException,ClassNotFoundException,IOException
- 运行时的异常RuntimeException:NPE,ClassCastException
捕获异常的方法
**String getMessage()**:获得详细的异常信息字符串内容
**void printStackTrace()**:将详细异常信息通过流打印(输出)至控制台
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 出现多个异常的情况下,只走其中一个异常,就是说catch只走一次!
try{ 可能会出现异常的代码
}catch(异常类 变量名 ){ 捕获具体的异常类的
1.后端开发(服务器端开发)--->java项目运行在Linux服务器 异常日志记录异常信息(将异常信息写入异常日志文件) slf4j log4j
2.异常信息传递 (throw) 将异常信息从底层到顶层全部输出。 将当前异常类对象 封装到 级别高的异常对象里面
3.异常工具类返回的错误信息
return ServerResponse.error("msg","code"); }catch(异常类 变量名 ){ 处理异常信息的方式 System.out.println(exception.getMessage());
exception.printStackTrace(); } finally{
释放资源
不管是否有异常出现 都会执行的 }
|
抛出异常 throws
throw 声明抛出一个具体的异常对象
- 异常信息传递 (throw)
- 结束程序
- 与自定义异常结合使用
1 2 3 4 5 6 7 8 9 10 11 12
| public static void a() throws ArithmeticException{
将异常类抛出给上级(调用者); System.out.println("异常之前"); }
public static int calMoney(String boorowTime, String returnTime) if(boorowTime == null || returnTime == null){ 抛出一个异常信息 throw new NullPointerException("参数数据不能为null") 遇见throw程序直接结束 }
|
将String时间数据转换为Data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| String pattren = "yyyy-MM-dd HH-mm-ss"; SimpleDataFormat dateFormat = new SimpleDataFormat(pattren);
try{ Data borrowData = dateFormat.parse(boorowTime); Data returnData = dateFormat.parse(returnTime);
long borrow = borrowData.gettimr(); long return1 = returnData.gettimr();
int hour = (int)((return1 - borrow)/1000/3600); } catch(ParseException e){ e.printStackTrace(); }
|
lang包常用类
Integer
包装类分为四类八种
Byte,Shory,Integer,Long,Float,Double,Character,Boolean
成员变量的数据类型使用包装类
Integer介绍:
- final所修饰的类
- 继承于Number
- 实现了一个**Comparable<Integer>**接口
- 赋值只能给数字类型和数字类型的字符串
基本类型的数据转换成了一个包装类 —> 自动装箱操作
包装类的对象转换成基本类型的数据 —> 自动拆箱操作
1 2 3 4 5 6 7 8 9 10 11 12 13
| int num1 = num;
Integer num2 = new Integer(100); Integer num3 = new Integer("100");
int num4 = 100; Integer num5 = 100; Integer num6 = 100; Integer num7 = 200; int num8 = 200;
System.out.println(num2=num2); false
|
这里实现了包装类的拆箱操作
1 2 3 4
| System.out.println(num2=num4); true System.out.println(num4=num5); true
System.out.println(num1=num4); false
|
整数缓存池:数组 Short[] Integer[] Long[],范围在-128~127之间,
两个数比较在这之间为True,否则为False
1 2 3 4 5 6
| Integer num5 = 100; Integer num6 = 100; Integer num7 = 200; int num8 = 200; System.out.println(num5=num6); true System.out.println(num7=num8); false
|
Integer功能方法
比较数据类型是否一致
1 2 3 4 5 6 7 8
| System.out.println(num1.equals(num2));
System.out.println(Integer.compare(num1, num2));
System.out.println(num1.compareTo(num2));
System.out.println(Objects.equals(num1, num2));
|
String 和 Integer转换
1 2 3 4 5
| String strNum = "100"; int num = new Integer(strNum); Integer num2 = Integer.valueOf(strNum); Integer num3 = Integer.parseInt(strNum); Integer num4 = Integer.parseInt(strNum,2);
|
Integer 转换成 String
1 2 3 4
| Integer in = 100; String str = in.toString(); int i = 10; String j = i + "";
|
Character
Character功能方法
将字符串转换为指定进制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| System.out.println(Character.MAX_RADIX); System.out.println(Character.MIN_RADIX); String str = "110"; char[] chs = str.toCharArray();
System.out.println(Character.digi(chs[0], 10));
Character ch1 = '我';
if(Character.isLetter(ch1)){ 判断是否为大小写字母 Character.toLowerCase(ch1); Character.toUpperCase(ch1); }else if(Character.is.Digit(ch1)){ 判断是否为数字 }else if(Character.isWhitesace(' ')){ 判断是否为空字符串 }
|
Math
获得随机数
求几次幂
四舍五入
求一个数的平方根
最大值最小值
1 2
| Math.max(10,1) Math.min(10,1)
|
获取绝对值
Object(基类/超类)
获得对象的哈希码值(返回值是int)
获得一个对象(类/接口字节码文件)
判断元素是否为空
1
| Objects.requireNonNull(元素名);
|
在另外一个线程里面唤醒另外一个正在wait的线程
线程等待
1 2 3
| wait(); wait(long timeout); wait(long timeout, int nanos);
|
创建(克隆)对象,获得一个对象的副本
1 2 3 4
| clone(); 浅克隆: 对于包装类,String-->克隆的是数据 其它引用类型-->克隆的是地址 深克隆:其它引用类型-->重新开辟内存
|
Class
表示正在运行的类或者接口(获得正在运行的类或者接口的class文件)
反射最基本的一个类–>获得类/接口的所有内容
一般用于底层的封装和框架的开源
获得Class类的对象的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 创建一个Class类的实例 Person person = new Person(); Class clazz = person.getClass(); clazz.getName(); clazz.getSimpleName();
创建一个Class类的实例 Class clazz = Person.class;
创建一个Class类的实例 try{ Class.forName("给类或者接口的全限定名称"); Object obj = clazz.newInstance(); }catch(ClassNotFoundException e){ e.printStackTrace(); }
|
返回到类的类加载器(bin目录)
查找具有给定名称的资源
1
| clazz.getResourceAsStream("资源文件路径");
|
获得类的属性 对属性赋值(Field类)
1 2
| Field[] fields = clazz.getFields(); fields = clazz.getDeclaredFields();
|
String
实现了java.io.Serializable, Comparable<String>, CharSequence接口
创建字符串
1 2 3 4 5 6 7
| 构造 String str1 = new String();
String str2 = new String("hello");
byte[] bytes = {78,98,99} String str3 = new String(bytes);
|
获得字符串的字节内容
1 2 3 4 5 6 7 8 9 10 11
| 注意编码和解码格式统一
System.out.println("哈哈哈哈".getBytes());
System.out.println("哈哈哈哈".getBytes("GBK").length);
System.out.println("哈哈哈哈".getBytes(),"UTF-8");
Charset代表具体的编码格式
System.out.println(Charset.defaultCharset());
|
将字符数组转换为字符串内容
1 2
| char[] ch = {23,'a','家','好'}; String str4 = new String(ch);
|
toCharArray字符数组转换为字符串内容操作
1
| String str4 = new String("啊啊啊啊".toCharArray());
|
String功能方法
获得字符串指定索引的字符内容(返回值是char类型)
1 2 3 4 5 6 7
| str.charAt(1);
字符串之间的比较(返回值是int类型) str.compareTo("abc"); str.compareToIgnoreCase("ABC"); str.equals("abc"); str.equalsIgnoreCase("ABC");
|
将指定的字符串内容追加到字符串的末尾(返回值是String类型)
判断字符串中是否包含指定字符序列内容(返回值是boolean类型)
将任意类型的数据转换为字符串(返回值是String类型)
判断字符串中是否以某个类型开头和结尾(返回值是boolean类型)
1 2 3 4 5
| str.endsWith("a"); str.startsWith("b");
返回字符串的哈希吗值 str.hashCode();
|
获得指定字符串第一次出现的索引位置(返回值是int类型)
1 2 3
| 找不到指定的字符串内容返回值是-1 str.indexOf("a"); str.indexOf("a",1)
|
获得指定字符串最后一次出现的索引位置(返回值是int类型)
1 2 3
| 找不到指定的字符串内容返回值是-1 str.lastIndexOf("a"); str.lastIndexOf("a",1);
|
获得当前字符串的副本(返回值是String类型)
判断字符串是否是空(返回值是boolean类型)
使用分隔符连接字符串内容(返回值是String类型)
1
| String.join("_","a","b","c");
|
判断字符串是否匹配正则的要求(返回值是boolean类型)
使用指定字符串替换字符串内容(返回值是String类型)
1 2 3 4
| str.replace('a','b'); str.replace("a","abc"); str.replaceAll("支持正则", "abc"); str.replaceFirst("a","abc");
|
将字符串使用指定的正则表达式进行分割(返回值是String[]类型)
1 2
| str.split("a"); str.split("a",2)
|
截取部分字符串内容(返回值是String类型)
1 2 3
| str.substring(1,3); str.substring(str.indexOf("xxx"),str.lastIndexOf("xxx"));
|
转换为大小写(返回值是String类型)
1 2
| str.toUpperCase(); str.toLowerCase();
|
去掉字符串左右两边空格(返回值是String类型)
去掉中间空格
1 2
| str.trim.replace(" ",""); str.trim.replaceAll(" ","");
|
StringBuffer/StringBuilder(字符串变量类)
值可以改变。线程安全(StringBuffer所有的方法都是同步的synchronized) 效率慢
值可以改变 线程不安全(不同步的),效率最快,(绝对不能作为成员变量进行使用)
- 创建初始化对象
1
| StringBuffer buffer = new StringBuffer("hello");
|
追加字符串
1 2
| buffer.append("123"); buffer.insert(索引值,"追加的内容");
|
删除字符串
1 2
| buffer.delete(开始索引, 结束索引); buffer.deleteCharAt(删除指定索引位置);
|
反转字符串
修改某个索引字符内容
1
| buffer.setCharAt(索引位置,'要修改的内容');
|
StringBuilder功能方法
创建初始化对象
1 2
| StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder("hello");
|
String/StringBuffer/StringBuilder区别
- 从数据:
String: 数据不可变
StringBuffer/StringBuilder:值可以改变
- 从内容
String: 浪费内存
StringBuffer/StringBuilder;始终都是同一个对象
- 从线程安全
String/StringBuffer 线程安全(同步)
StringBuilder 线程不安全(不同步)
- 效率
StringBuilder最快,其次是String,最后是StringBuffer
System
System类不能手动创建对象,因为构造方法被private修饰
方法:
1 2 3 4 5 6
| 获取系统当前毫秒值,可以测试程序执行时间 long start = System.currentTimeMillis(); for(int i = 0; i < 1000; i++){ } long end = System.currentTimeMillis(); System.out.println(end - start);
|
1 2
| 退出虚拟机,所有程序停止 System.exit(0);
|
1 2
| 获取当前系统的属性 System.getProperties();
|
1 2
| 复制数组 System.arraycopy(源数组,源数组的起始索引,目标数组,目标数组的起始索引,复制的个数);
|
util包常用类
Date
Date类对象用来表示时间和日期
该类提供一系列操纵日期和时间各组成部分的方法
构造方法重载
Calendar
Calendar类也是用来操作日期和时间的类,但它可以以整
数形式检索类似于年、月、日之类的信息
Calendar类是抽象类,无法实例化,要得到该类对象只能
通过调用getInstance方法来获得
Insatnt
JDK8的应用,推荐使用 Instant 代替 Date,LocalDateTime 代替 Calendar
LocalDate/LocalTime/LocalDateTime
LocalDate 获得当前系统的时间 2007-12-03
LocalTime 获得当前系统的时间 10:15:30
LocalDateTime 获得当前系统的时间 2007-12-03T10:15:30
此类也是不可变且线程安全
1 2 3 4 5 6
| public static String formatDate(Date now,String pattern){ SimpleDateFormat sdf = new SimpleDateFormat(pattern); String result = sdf.format(now); return result; }
|
1 2 3 4 5 6
| public static Date formateString(String str, String pattern){ SimpleDateFormat sdf = new SimpleDateFormat(pattern); Date date = sdf.parse(str); return date; }
|
数字的格式化
1 2 3 4 5
|
DecimalFormat df = new DecimalFormat("#.##"); String result = df.format(3.1415926);
|
Random(伪随机数类)
在多线程中是不安全的
创建实例
1 2
| Random random = new Random(); Random random = new Random(10);
|
取一个随机整数值
1 2
| random.nextInt(); random.nextInt(10);
|
ThreadLocalRandom(随机数类)
在多线程中是安全的
1 2
| ThreadLocalRandom localRandom =ThreadLocalRandom.current(); System.out.println(localRandom.nextInt(40, 100));
|
加密解密
Base64
jdk1.8可正常使用
Base64.Encoder(加密),Base64.Decoder(解密)
该类使用RFC 4648和RFC 2045中规定的Base64编码方案来实现用于解码字节数据的解(编)码器。
1 2 3 4 5 6 7 8 9
| '加密' String pass = "1234"; Encoder encoder = Base64.getEncoder(); String encodePass = encoder.encodeToString(pass.getBytes());
'解密' Decoder decoder = Base64.getDecoder(); byte[] by = decoder.decode(encodePass); String str = new String(by);
|
MessageDigest
MessageDigest类为应用程序提供消息摘要算法的
功能,如SHA-1或SHA-256或MD5。 消息摘要是采用
任意大小的数据并输出固定长度散列值的安全单向
散列函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(pass.getBytes());
byte[] encodeBy = messageDigest.digest(); System.out.println(Arrays.toString(encodeBy));
BigInteger bigInteger = new BigInteger(1, encodeBy); String pass1 = bigInteger.toString(16); System.out.println(pass1); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
|
泛型
意义:与形式参数作用一样,限定数据类型
作用:隐式帮助进行类型转换
功能:
- 修饰类–>泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13
| '泛型类的字母常用:E,T,K,V' public class Hello<E>{ '泛型可以充当数据类型,也可以有setter和getter方法' private E e; '泛型充当形式参数' public void a(E e1){ System.out.println(e1); } '泛型充当返回值,加上<E>代表这个方法是一个泛型方法' public <E> E b(){ System.out.println(b); } }
|
- 修饰接口–>泛型接口
1 2 3 4 5 6 7 8 9
| public interface World<E,T>{ '泛型充当形参' void add(E e); '泛型充当返回值' T delete(int id); '泛型修饰方法' <T> T test(); }
|
- 泛型擦除概念:泛型是在编译的时候起作用,但在代码运行期间是没有作用的
- 泛型上限
- 让泛型继承一个类
1 2 3
| public class Test<E extends Number>{ '传入的参数只能是Number中的数据类型' }
|
- 泛型通配符:**?**
1 2 3 4 5
| public class test<E,T>{ public void add(Hello<?,?> hello){ '?统配任意数据类型,不需要和类中的E和T保持一致' } }
|
集合
集合作用和数组作用一致,用于存储多个元素数据
理论上可以存储任意引用数据类型的数据(开发中都存储相同类型的数据–>避免出现类型准换问题)
在类/接口中出现 <A>这个,代表这个类为泛型的标志–>参数化类型(形参)
代表集合里面只能存储泛型所规定的的类型的数据(限定集合元素数据类型)
?代表的是泛型的通配符
? extends 父类,限制父类,不限制子类
? super 子类,限制子类,不限制父类
集合的接口
Collection(是List和Set的父类)
特征:
- 用于存放单值元素
- 元素是无序的(没有索引位置)
- 元素是否可以重复要看使用的是哪个类实现的
创建集合对象
1
| Collection<指定泛型的变量> collection = new ArrayList<指定泛型的变量>();
|
增加元素
1 2
| collection.add(E e); collection.addAll(Collection<? extends E> c);
|
删除元素
1 2 3 4 5
| collection.remove(Object o); collection.removeAll(Collection<?> c); collection.removeIf(Predicate<? super E> filter) 使用(迭代器)Iteator<T>中的 iterator()删除 remove();
|
查询元素
清除集合中所有的元素
判断元素是否存在
1 2
| collection.clear(); collection.clear();
|
lambda语法:**(参数类型 参数名,参数类型 参数名)->{需要进行的操作}**
遍历集合元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| foreach方法 for(Object obj:collection) { System.out.println(obj); } 迭代器 Iterator it = collection.iterator(); while(it.hasNext()) { Object obj = it.next(); if(obj.equals("hello")) { it.remove(); } }
jdk1.8 forEach+lambda新方法 collection.forEach(obj->{ System.out.println(obj); });
|
集合中存储任意类型的对象
1 2
| Collection coll = new ArrayList(); coll.add("aa");
|
迭代器
1 2 3 4 5
| Iterator it = coll.iterator(); while(it.hasNext()){ Object obj = it.next(); String i = (String)obj; }
|
集合转数组
1 2 3 4 5 6
| 第一种方法 Object[] objs = collection.toArray();
第二种方法 (推荐使用) Object[] objects = new Object[collection.size()]; collection.toArray(objects);
|
List<T>
特征
- 存储单值元素
- 元素有序的(有索引位置)
- 元素可以重复的
包括三个子类:ArrayList<E>(重要),LinkedList<E>,Vector
E代表的是:Element 元素,实际就是一个变量
三者之间的区别:
- 底层的数据结构
ArrayList/Vector 是由动态数组进行维护。
LinkedList 是由双向链表进行维护。
- 添加 删除 查询效率
ArrayList: 查询最快
LinkedList:添加删除最快 查询较慢
Vector: 都慢
- 线程安全
ArrayList/LinkedList 都是线程不安全的
Vector 线程安全的
ArrayList
1 2
| 初始化容量10 List<Integer> list = new ArrayList<>();
|
1 2
| 获取 list.get(list.size()-1)
|
1 2 3
| 删除 list.remove(1); list.remove(new Integer(1));
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 遍历 1. for(int index = 0,size = list.size();index<size;index++) { System.out.println(list.get(index)); } 2. for(Integer num:list) { System.out.println(num); }
3. Iterator<Integer> it = list.iterator(); while(it.hasNext()) { Integer num1 = it.next(); System.out.println(num1); it.remove(); }
4. ListIterator<Integer> listIt = list.listIterator(); while(listIt.hasNext() ){ System.out.println(listIt.next()); }
5. list.forEach(num->{ System.out.println(num); });
|
linkedList
1 2
| 初始化对象 LinkedList<String> linkedList = new LinkedList<>();
|
1 2 3 4
| 添加元素 linkedList.add(0, "abc"); linkedList.addFirst("a"); linkedList.addLast("d")
|
1 2 3 4 5 6 7 8
| 获取元素 linkedList.get(0); linkedList.getFirst(); linkedList.getLast();
linkedList.peek(); linkedList.peekFirst(); linkedList.peekLast();
|
1 2 3 4 5 6 7 8 9
| 删除元素 linkedList.remove(); linkedList.removeFirst(); linkedList.removeLast(); linkedList.remove("hello");
linkedList.poll(); linkedList.pollFirst(); linkedList.pollLast();
|
Set
特征
- 存储单值元素
- 元素无序(没有索引位置)
- 元素不可以重复的,值必须唯一(前提: 一定要重写 equals和hashcode),默认初始容量16
包含三个子类:HashSet<T>,LinkedHashSet<T>,TreeSet<T>
区别:
- 底层的数据结构
HashSet 是哈希表(哈希算法)维护,存储取出快,元素无序
LinkedHashSet 是由哈希表+双向链表维护,继承HashSet,元素是有序的 (插入顺序和 输出顺序是一致的)
TreeSet 是由二叉树(红黑树)进行维护 元素是有序的(按照自然顺序进行排列 要求集合元素数据类型必须有比较器 (实现 Comparable))
- 元素是否可以为null
HashSet/LinkedHashSet 元素可以为null
TreeSet 元素不允许为null
- 线程是否安全
HashSet<T>/LinkedHashSet<T>/TreeSet<T> 都不安全
哈希表存储对象的依据是对象的哈希值和equals方法
实现方法和Collection一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 初始化对象 Set<Integer> set = new HashSet<>();
添加元素 set.add(10);
Set<User> userSet = new HashSet<>(); userSet.add(new User()); userSet.add(new User()); userSet.add(new User());
遍历集合元素 set.forEach(num->{ if(num==10) { System.out.println(num); } });
|
Map
存储的是一组元素数据,有key和value
Map中的key是不能重复的,value可以重复
实现类和子类:HashMap<K,V>(元素无序),LinkedHashMap<K,V>(元素有序),TreeMap<K,V>,HashTable<K,V>,CouncurrentHashMap<K,V>
区别:
- 从底层数据结构
HashMap/HashTable 哈希表维护
LinkedHashMap 哈希表和链表维护,是HashMap的子类
TreeMap 红黑树维护,元素有序的,会按照key的自然顺序进行排序
CouncurrentHashMap CAS(比较并交换) 乐观锁 + Redis
- 线程安全
HashMap/LinkedHashMap/TreeMap 线程不安全
HashTable/CouncurrentHashMap 线程安全
- key和value是否可以为null
HashMap/LinkedHashMap key/value都可以为null
TreeMap key不能为null value是可以为null
HashTable/CouncurrentHashMap key/value都不能为null
HashMap,TreeMap,HashTable,LinkedHashMap
1 2 3 4 5
| 创建对象 Map<String, Integer> map = new HashMap<>(); ConcurrentHashMap<User, Integer> userMap = new ConcurrentHashMap<>(); TreeMap<User, Integer> userMap = new TreeMap<>(); Map<Integer, Integer> map = new LinkedHashMap<>(16);
|
1 2
| 新增元素 map.put("key",value);
|
1 2 3 4
| 查询元素 map.get("key"); map.containsKey("key"); map.containsValue(value);
|
1 2 3
| 删除元素 map.remove("key"); map.remove("key", value);
|
1 2 3
| 替换元素 map.replace("key", value); map.replace("key", value, 替换的value);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 遍历集合元素 map.forEach((key,value)->{ System.out.println("key:"+key+"----value:"+value); });
JDK8的新方法 Set<Entry<String, Integer>> entrySet = map.entrySet(); entrySet.forEach((Entry<String, Integer> entry)->{ System.out.println("key:"+entry.getKey()+"----value:"+entry.getValue()); });
增强for循环 for(Map.Entry<String, Integer> entry:map.entrySet()){ System.out.println("key:"+entry.getKey()+"----value:"+entry.getValue()); }
迭代器 Iterator<Entry<String, Integer>> it = entrySet.iterator(); while(it.hasNext()) { Entry<String, Integer> entry = it.next(); System.out.println("key:"+entry.getKey()+"----value:"+entry.getValue()); }
|
Collections
集合操作工具类
1 2 3
| 对 List集合 进行二分搜索,参数传递 List集合 和 被查找的元素,集合必须是有序的 Collections.binarySearch(list,5); 找不到指定的元素内容返回值是 插入点-1
|
1 2
| 对 List集合 随机排列 Collections.shuffle(list);
|
1 2 3
| List本身是线程不安全,用这个可以让它变成线程安全类 List<Integer> list = new ArrayList<>(); list = Collections.synchronizedList(list);
|
1 2 3 4 5 6 7 8 9
| 使用sort()方法对 list集合 进行升序排列,lambad替换 接口/抽象类 Collections.sort(list); 重写 Collections.sort(stuList, new Comparator<Student>() { @Override public int compare(Student stu1, Student stu2) { return stu1.getScore().compareTo(stu2.getScore()); } });
|
IO
File操作
File类构造方法
1 2 3 4
| File file = new File("文件路径"); File file = new File("父路径","子路径"); File file = new File(File类型的路径, "子路径");
|
显示与系统有关的路径分隔符
1 2
| String separator = File.pathSeparator; 打印是一个分号,在Linux下打印是一个冒号
|
显示与系统有关的名称分隔符
1 2
| String separator = File.separator; 打印一个向右的斜线 \ Linux下是左斜线 /
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| "判断路径中是否有这个文件" + file.exists(); "判断路径中是否是一个文件夹" + file.isDirectory(); "判断路径中是否是一个文件" + file.isFile(); "判断文件是否可读:" + file.canWrite();
"创建一个文件" + file.createNewFile(); "创建一个一级目录文件夹" + file.mkdir(); "创建多级目录文件夹" + file.mkdirs(); "删除文件" + file.delete(); "剪切/重命名文件" + file.renameTo(路径,"重命名");
"获得文件最后部分的名字:" + file.getName(); "获得文件大小字节数:" + file.length(); "获得目录名:" + file.getName(); "获取文件的绝对路径:" + file.getAbsolutePath(); "获取文件的绝对路径:" + file.getAbsoluteFile(); "获取文件的相对路径:" + file.getPath(); "获取路径中文件和文件夹名" + file.list(); "获取路径中文件和文件夹名" + file.listFiles(); "获取修改的时间:" + file.lastModified();
|
递归
注意事项:
- 递归一定要有出口
- 递归次数不能过多
- 构造方法禁止递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public static void main(String[] args) { File dir = new File("d:\\eclipse"); getAllDir(dir); } 定义方法,实现目录的全遍历 public static void getAllDir(File dir){ System.out.println(dir); File[] fileArr = dir.listFiles(); for(File f : fileArr){ if(f.isDirectory()){ getAllDir(f); }else{ System.out.println(f); } } }
计算斐波那契数列 public static int getFBNQ(int month){ if( month == 1) return 1; if( month == 2) return 1; return getFBNQ(month-1)+getFBNQ(month-2); }
|
字节操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public static void test2(File file) {
jdk1.7 提供一种更加优雅的方式 去关闭流对象 try(流对象)...catch...resources
try (InputStream inputStream = new FileInputStream(file);) { byte[] by = new byte[(int)file.length()]; int result = inputStream.read(by); int num = inputStream.read(); "off 从字节数组的第几个元素开始写入 ,len: 写入多少个元素到字节数组" int result = inputStream.read(by, 0, 4); System.out.println(Arrays.toString(by)); for(byte b:by) { System.out.print((char)b); } System.out.println(new String(by)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}
|
fileOutputStream
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static void test1(File file) {
try ( "文件不存在可以自定去创建,后面为true表示追加文件后面写,不会删除文件之前已经有的内容" OutputStream outputStream = new FileOutputStream(file,true); ) { outputStream.write('\n'); "换行" outputStream.write('c');"一次写一个字节内容"
byte[] by = {97,97,97,'a'}; outputStream.write(by); "依次写入byte中的字节"
outputStream.write("单价".getBytes()); "在文件中写中文" outputStream.write(by, 0, by.length);"off从第几个元素开始写入文件 len:写多少个" outputStream } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
|
字符操作
FileReader
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static void test3(File file) { try (Reader reader = new FileReader(file); ) { int result = 0; char[] ch = new char[10]; while ((result = reader.read(ch, 0, ch.length)) != -1) { System.out.print(new String(ch)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static void test1(File file) { try ( Writer writer = new FileWriter(file);) { writer.write('我'); writer.write("我们".toCharArray()); writer.write("abc".toCharArray(), 0, 2); writer.write("\n"); writer.append('a');
writer.flush(); "必须要刷新,不刷新就没有文件,有close()就不用刷新" } catch (IOException e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public static void testCopy3(File sourceFile, File targetFile) { System.out.println("COPY文件"); long start = System.currentTimeMillis(); try ( 创建高效的字节输入流对象 BufferedInputStream bufferedInputStream = new BufferedInputStream( new FileInputStream(sourceFile)); 创建高效输出流对象 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( new FileOutputStream(targetFile));) {
int len = 0; byte[] by = new byte[1024]; while ((len = bufferedInputStream.read(by)) != -1) { bufferedOutputStream.write(by, 0, len); } long end = System.currentTimeMillis(); System.out.println("copy结束。。。。。。。。。。。"+(end-start)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
|
输入输出流
DataInputStream/DataOutputStream
实现了一个DataInput接口,一般配合Socket使用
必须先写入文件,才能读取文件
读的顺序要和写的顺序一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| "先Write" public static void test1(File file) { try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(file));
) { dataOutputStream.writeUTF("jim"); "写入用户名" dataOutputStream.writeInt(1234); "写入密码" dataOutputStream.writeByte(20); "写入年龄"
} catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
"再Read" public static void test(File file) {
try (DataInputStream dataInput = new DataInputStream(new FileInputStream(file));) {
String name = dataInput.readUTF(); "读取UTF内容" int id = dataInput.readInt(); "读取Int内容" byte age = dataInput.readByte(); "读取字节内容"
} catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}
|
Properties
特点:
- 存储**键值对(一组数据)*,属性名—>属性值*
- 读取配置文件内容,*properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| "构造方法" Properties properties = new Properties();
"存储元素" properties.put("key","value"); properties.setProperty("key","value");
"字节输入流对象的创建的两种方法" InputStream inStream = PropertiesDemo.class.getResourceAsStream("user.properties"); InputStream inStream = PropertiesDemo.class.getClassLoader().getResourceAsStream("com/javasm/io/user.properties");
"以.properties结尾的文件书写格式中间不能有空格!" name=zhangSan age=20
"流对象读取文件中的键值对,保存到集合" properties.load(inStream);
"重写往文件里写入" properties.store(文件写入器,"原因");
"获取元素" String trueName = properties.getProperty("key"); "转成ISO8859-1读取,再转成utf-8输出" trueName = new String(trueName.getBytes("ISO8859-1"), "utf-8");
"遍历" Set<Entry<Object, Object>> set = properties.entrySet(); set.forEach(entry->{ System.out.println(entry.getKey()+"--------"+entry.getValue()); });
|
序列化
ObjectOutputStream 序列化流 写入
ObjectInputStream 反序列化流 读取
必须先写入文件,才能读取文件,类必须要实现Serializable接口
静态的成员变量不能序列化
transient(瞬态)修饰的成员变量不能被序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| "构造方法" ObjectInput objectInput = new ObjectInputStream(ObjectInputDemo.class.getClassLoader().getResourceAsStream("bin目录下配置文件名称")) ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream(new File("配置文件路径")))
"将指定的对象写入到文件中" objectOutput.writeObject(user); "从ObjectInputStream读取一个对象" objectInput.readObject();
"字节转字符的桥" : InputStreamReader(); "字符转字节的桥" : OutputStreamWriter();
"接收用户输入的字符,并指定的编码格式" BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); "将用户的输入写入到文件中" BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("src/b.txt")));
"指定读取的文件" BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("src/IO.txt"))); "将读取到文件的内容输出" BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
"写入固定的序列号": private static final long serialVersionUID = 1L "一次读取一行" :bufferedReader.readLine(); "写一个换行" :bufferedWriter.newLine(); "将缓冲区的内容刷新到文件" :bufferedWriter.flush(); "将内容输出/输入":bufferedWriter.write(content);
|
相关文章
JDBC
JAVA多线程
JUC