public class HelloWorld{
public static void main(String[] args){
System.out.println("helloworld");
}
}
注意:
1.java所有的标点符号必须是英文半角
2.java严格区分大小写
3.编码不一致会中文乱码
4.所有的语句以分号结束
5.括号和引号是成对出现的
6.一个java文件内可以存在多个类 编译后有几个类就会生成几个.class文件
7.被public 修饰的类 类名必须与源文件的名字保持一致
//单行注释
/*
多行注释
*/
/**
*文档注释
*/
1.字母数字 下划线_ 美元符$组成
2.数字不能开头
3.不能是java中的关键字和保留字
关键字: 在java中赋予了特殊含义的字符串(单词) class void static
保留字: 当前版本无意义以后可能使用 goto
4.严格区分大小写 String string
5.标点符号必须是英文半角
1.见名之意
2.对类进行命名时要求每一个单词的首字母都大写
HelloWorld PrintTest IdentifierTest
3.对变量,方法命名时 第一个单词首字母小写从第二个单词开始首字母大小
userName
passWord
getSumResult
4.对包进行命名时 每一个单词所有的字母都小写
com.wu.oop
com.wu.thread
com.wu.io
5.对常量命名时 每一个单词所有的字母都大写 如果是多个单词组成 单词与单词之间使用下划线连接
整形 | 默认值 | 字节(1字节8位) | 取值范围 |
---|---|---|---|
byte | 0 | 1 | -128~128 |
short | 0 | 2 | -32768 ~ 32767 |
int | 0 | 4 | -2147483648~2147483647 |
long | 0 | 8 | |
字符形 | |||
char | \u0000 | 1 | |
浮点型 | 存储的数据最多 | ||
float(单精度) | 0.0 | 4 | |
double(双精度) | 0.0 | 8 | |
布尔型 | |||
boolean | false | 1 |
8.1.1、自定义常量:用 final 修饰哦
8.1.2、字面量:即编程语言中表示固定值或数据的直接文本形式(eg:10)
8.2.1、变量的声明和赋值
方式一:先声明再赋值 ------> int i; i = 10;
方式二:声明时赋值 ---------> int i = 10;
注意:
1、局部变量(局部变量:方法内的变量)使用前必须进行初始化(赋值就是初始化)
2、同一个方法内不能存在同名的变量
3、声明变量的本质:申请内存
& : 与
| : 或
^ : 异或
! : 取反
&& : 短路与
|| : 短路或
& : 雨
| : 或
^ : 异或
- : 非
<< : 左移
>> : 右移
>>> : 无符号右移
//创建键盘输入对象
Scanner input = new Scanner(System.in);
//给出提示语句
System.out.println("请输入");
//获取一个整形的数据,并赋值给 num
int num = intput.nextInt();
/*
获取其他类型的基本数据
nextByte()
nextShort()
nextInt()
nextFloat()
nextDouble()
nextBoolean()
获取字符串数据
next() ---> 遇到空格就结束输入
nextLine()
获取字符类型的数据
使用next()或者nextLine()获取数据后使用charAt(0)方法,来获取输入数据的第一个字符
*/
//单分支
if(布尔表达式){
}
//双分支
if(布尔表达式){
} else {
}
//多分支
if(布尔表达式){
} else if (布尔表达式) {
} ......{
} else {
}
switch(表达式){
case 常量值:
break; //结束循环
case 常量值:
break; //结束当前循环,进行下一次循环
case 常量值:
break;
[default]: //可有可无,如果条件都不满足的话,默认执行default中的语句
break;
}
for(初始变量;循环条件;迭代条件){
循环体
}
for(int i = 0;i < 5;i++){
System.out.println(i);
}
5.1.1:嵌套循环:将 一个循环作为另一个循环的循环体
外层循环控制行数
内层循环控制列数
外层他循环执行一次,内层循环需要执行一遍
//冒泡排序及优化
//arr.length-1,一个长度为arr.length的数组只需要执行 arr.length-1次即可有序
for(int i = 0; i < arr.length-1;i++){
boolean flag = true;
for(int j = 0;j < arr.length-i-1;j++){ //arr.length-i-1-->让排序只注重于无序部分
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;
}
}
if(flag){
berak;//如果提前排序完,就提前退出
}
}
Arrays.toString(arr);
while(循环条件(布尔表达式)){
}
do{
循环体 //无论条件是否满足,都会执行一次do方法体中的内容
}while(循环条件);
数据类型[] 数组名; eg: int[] arr;
数据类型 数组名[] ; eg: int arr[];
6.2.1、静态初始化:完成初始化后知道数组的元素内容
形式一:数据类型 数据名[] = {值1,值2};
eg:int arr[] = {1,2,3,4,5};
形式二:数据类型 数据名[] = new 数据类型[]{值1,值2};
eg; int arr[] = new int[]{1,2,3,4,5};
6.2.2、动态初始化:完成初始化后知道数组的长度和默认值,但不知道具体的值
数据类型 数据名[] = new 数据类型[数组长度];
eg:int arr[] = new int[10];//创建一个长度为10的一维数组
//普通for循环:需要使用到数组下标
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
//foreach循环(增强for循环,本质也是普通for循环):不需要数组的下标
for(数组元素类型 变量名:数组名){
System.out.println(变量名)
}
//eg:
for(int i :arr){
System.out.println(i);
}
注意
1.、获取指定下标的元素 数组名[下标]
2、修改指定下标的值 数组名[下标]=值;
3、获取数组的长度 数组名.length,数组的长度一旦完成初始化 则不可改变
4、下标的范围[0,length-1]
5、一旦下标超过范围 报 java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常6、数组也可以存引用数据类型
//数组的反转
int arr[] ={1,3,10,21,12,26,15};
for (int i=0,j=arr.length-1;i<j;i++,j--){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
System.out.println("Arrays.toString(arr) = " + Arrays.toString(arr));
6.4.1、二维数组的声明
数据类型[][] [] [] 数据名
数据类型[][] [] 数据名[]
数据类型[][] 数据名[][] [] []
6.4.2、二维数组的初始化
静态初始化
形式一:数据类型 数据名[] [] ={{1,2},{2},{12,3,3}}; 声明和赋值必须一起
形式二:数据类型 数据名[] [] = new 数据类型[] [] {{1,2,3},{1,2},{2,3}}; 声明和赋值必须分开
动态初始化
形式一:数据类型 数据名[] [] = new 数据类型[值1] [值2];
值1:二维数组中一维数组的个数
值2:二维数组中,一维数组元素的个数
形式二:数据类型 数据名[] [] = new 数据类型[值1] [];
值1:二维数组中一维数组的个数
声明了一维数组的数量,具体的一维数组数据需要进行单独赋值来完成初始化
注意
1、二维数组的长度 数组内一维数组的个数
2、获取二维数组元素 数组名[一维数组的下标] [一维数组内元素的下标]
3、二维数组的元素是一维数组 一维数组不是基本数据类型所以 默认值为nul
6.4.3、二维数组的遍历
//普通for
for(int i = 0;i < 二维数据的长度;i++){
for(int j = 0;j < 二维数组中一维数组的长度;j++){
System.out.println(arr[i][j]);
}
}
//增强for
for(二维数组元素类型 变量名1:数组名){
for(一维数组的元素类型 变量名2:变量名1){
System.out.println(变量名2);
}
}
//声明
[权限修饰符] static 返回值类型 方法名([形参列表]){
方法体
}
//调用
方法名();
注意:
1.方法调用才会执行
2.方法与方法时兄弟姐妹关系 地位相同 在类中声明
3.方法执行完毕回到方法调用处 (如果方法没有返回值 则回到调用方法的下一行)
public void test(String...args){
}
注意:
1.数据类型…形参名 声明可变参数
2.可变参数底层使用数组进行数据存储
3.可变参数接收的实参数量[0,n]
4.可变参数必须位于参 数列表的最后 因此一个方法只能有一个可变参数
1.5、成员变量(属性/实例变量) 和 局部变量的区别
public class Student {
private String name;
private int age;
//get set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//无参构造
public Student() {
}
//有参构造
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
class 子类 extends 父类{
}
1、实现继承后可以复用父类的资源(属性和方法)
2、java是单继承的,一个类只能继承另一个类,但是一个类可以有多个子类(但是可以多实现,或者使用内部类来实现需要多继承的资源)
重写注意点
1、权限修饰符 必须 大于等于 父类的权限修饰符
2、void和基本数据类型必须和父类保持一致,引用数据类型可以和父类保持一致,也可以是父类的子类
3、方法名和形参列表必须和父类保持一致
4、编译时异常,子类不能抛出别父类更大的异常
3.1.1、重写toString
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
this:代指当前对象
调用属性
调用方法
调用构造器
super:代指当前对象从父类继承的资源
调用父类的属性
调用父类的方法
调用父类的构造器
变量:就近一致
方法:追根溯源
Student stu1 = new Student();
Student stu2 = new Student();
Student stu3 = new Student();
Student stu[] = {stu1,stu2,stu3};
4.1.1、向上转型
1、有继承关系
2、有方法重写
//父类类型 对象名 = new 子类类型();
Person p = new Student();
完成向上转型后 对象 调用方法的判断
编译看父亲,运行看孩子
1、如果子类重写了父类的方法,则执行子类重写的方法
2、如果没有重写,则执行从父类继承的方法
应用:
1、数组,父类类型做数组类型,可以接收任意子类的对象
2、形参,父类类型做形参,可接收任意子类对象
3、返回值,父类类型做返回值,可以返回任意子类对象
缺点:完成向上转型后,无法使用子类独有的方法
4.1.2、向下转型
- 场景:在完成向上转型后,还想使用子类独有的方法
- 前提:完成了向上转型
- 语法:子类类型 变量名 = (子类类型) 父类类型的值;
- 可能的遇见问题:ClassCastException(类型转换异常)
- 解决方法:使用instanceof来进行判断
- 语法: 对象名 instanceof 类型名 —> 判断左边的对象是否属于右边的类型
- 只要类型在对象的继承的关系上,就会返回true
多态方法的调用问题:
虚方法:可以重写的方法
静态分配:编译时 形参和实参最匹配
动态绑定:运行时是否有重写
非虚方法:不可以重写的方法
内存位置 | 修饰符 | 调用方法 | 内存空间 | 生命周期 | |
---|---|---|---|---|---|
静态 | 方法区 | 有static修饰 | 类名.属性名 | 所有静态共有一份空间 | 类加载是创建,类销毁时销毁 |
非静态 | 堆 | 无static修饰 | 对象名.属性名 | 每创建一个对象,开辟一个空间 | 对象创建时创建,当没有对象指向堆中的内存时,由GC回收 |
调用方式 | 调用资源 | this和super | 方法重写 | 绑定 | |
---|---|---|---|---|---|
静态方法 | 类名.方法名 | 不能直接使用非静态资源,可以在静态方法内创建对象来调用 | 不可以使用 | 没有重写 | 编译时绑定 |
实例方法 | 对象名.方法名 | 可以使用所以资源 | 可以使用 | 可以重写 | 运行时绑定 |
被abstract修饰的方法 — > abstract 返回值 方法名();
如果一个类继承了抽象类
抽象方法必须在抽象类中
//接口中的方法全部为抽象方法
public interface Person{
//抽象方法
void eat();
//接口中可以用默认方法
default void sleep(){
System.out.println("睡觉");
}
}
//实现接口,接口可以多实现
public class Student implements Person{
//实现接口后必须重写接口中的抽象方法
@Override
void eat(){
}
}
注意:
1、如果一个类实现了接口,可以看过这个接口的孩子
2、一个类可以实现多个接口
3、如果实现了多个接口,这些接口中含有相同方法名的默认方法,实现类必须重写该默认方法
调用接口内同名的默认方法,接口名.super.默认方法名(); eg: Person.super.sleep();
4、如果既要实现接口,也要继承类,必须先继承再实现
5、如果继承类和实现类中有同名的方法,则执行继承类中的方法
6、如果一个类实现了接口,必须重写接口中的所有抽象方法,否则该就变成抽象类
7.3.1、cloneable
7.3.2、Comparable
7.3.3、Comparator
使用:
- 实现接口
- 重写方法(多次使用多态)
- 调用方法
1、外部类只能被public和缺省修饰,内部类可以被所有修饰符修饰
2、内部类中可以存在静态或者非静态资源
3、内部类中的非静态方法内,可以直接使用外部内的所有资源
静态方法内,只能使用外部类中的静态资源
4、外部内使用内部类资源
内部类非静态资源 -----> 创建内部类对象.资源名
内部类静态资源 -------> 内部类名.资源名
5、打破了java单继承的限制,外部类和内部类都可以单独的继承其他类
6、在外部类使用内部类资源(和普通类调用对象一致)
非静态资源 —> 创建内部类对象
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
内部类对象.资源名
静态资源 -----> 内部类对象.静态资源名
7、内部类会产生独立的字节码文件(命名格式:外部类名$内部类名.class)
8、如果内部类和外部类有相同的非静态属性
this.属性名:调用内部类的资源
外部类名.this.属性名:调用外部类的资源
8.1.1、普通成员内部类
8.1.2、静态成员内部类
注意:
- 静态成员内部类可以直接使用外部类的静态资源
- 非静态资源需要创建外部类对象来调用
- 外部类可以使用内部类资源
- 非静态资源 —> 内部类对象名.资源名
- 静态资源 -----> 内部类名.资源名
- 在外部类中直接使用内部类资源
- 内部类静态资源 外部类名.内部类名.资源名
- 内部类非静态资源 创建静态内部类对象
- 外部类名.内部类名 对象名 = new 外部类名.内部类名();
- 对象名.资源名
注意:
1、局部内部类使用外部类资源是有所在方法决定的
如果在普通方法内,那么可以直接使用外部类所有资源
如果在静态方法内,那么只能直接使用外部类静态资源
2、局部内部类也会产生独立的字节码文件
命令格式:外部类名$序号内部类名.class (序号从1开始)
3、局部内部类 使用了所在方法的局部变量,那么这个变量会默认被final修饰
8.3.1、声明方式
interface Student{
void eat();
}
public class Person {
public static void main(String[] args) {
Person person = new Person();
person.show();
}
public void show(){
//匿名内部类
Student student=()->{
System.out.println("bbb");
};
student.eat();
}
public void show(){
//lombda表达式
((Student) () -> System.out.println("aaa")).eat();
}
}
8.3.2、匿名内部类的意义
8.3.3、应用
注意:
1、代码块优先与构造器执行
2、普通成员代码块只要创建一次对象,就会执行一次
3、代码有作用域访问
int i =10;
{
int i = 21;
System.out.println(i);//21
}
注意:
1、无论对象创建几次,都只会执行一次
2、静态成员代码块会优先与普通成员代码块执行
3、静态成员代码块也有作用域范围限制
- 静态成员变量显示赋值语句
- 静态代码块内容
执行顺序和代码编写顺序有关
- 使用了类中的静态资源(属性和方法)
- 创建对象
注意:
1、类的初始化只会执行一次
2、如果有继承关系,会优先对父类进行初始化,然后再对子类进行初始化
3、父类和子类进行初始化时,会公用一个< clinit > 方法
4、子类使用了从父类经常的静态资源,那么只会先对父类进行初始化,不会导致子类进行初始化
:
1 super()
2 实例变量显示赋值语句
3 代码块内容
4 构造器内
混合初始化:
先父再子
先类再实例
public class Person {
{
System.out.println("1");
}
static {
System.out.println(2);
}
String name = getName();
public String getName() {
System.out.println(4);
return null;
}
static int age = getAge();
public static int getAge(){
System.out.println(5);
return 10;
}
Person(){
super();
System.out.println(3);
}
}
public class Student extends Person{
{
System.out.println("6");
}
static {
System.out.println(7);
}
String name = getName();
public String getName() {
System.out.println(8);
return null;
}
static int age = getAge();
public static int getAge(){
System.out.println(9);
return 10;
}
Student(){
super();
System.out.println("A");
}
}
@Test
public void test01(){
new Student();
//2 5 7 9 1 8 3 6 8 A
}
/*
1、先进入构造器调用super先父类先进行实例化,
2、先进行父类的静态内容(静态代码块和静态变量和方法)初始化,再进行子类静态内容初始化,
3、再进行父类代码块进行初始化,进行子类代码块初始化
4、执行父类方法初始化,如果子类重写了父类的方法,就执行子类重写的方法进行初始化,
5、执行父类构造器初始化,最后执行子类构造器初始化
*/
枚举对象.ordinal()
枚举对象.name()
枚举类型.values()
枚举类型.valueOf();
1.自定义枚举类型 默认继承自Enum类
2.枚举类中的属性值必须在枚举对象的下面
3.编译器生成 values() valueOf();
4.枚举类可以实现接口 既可以统一处理 也可以每一个枚举对象单独处理
5.枚举可以在switch中使用
Throwable
error : 程序员无法解决的问题,eg:堆内存溢出
exception:为编译时异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nf7XYGcm-1692363825584)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230729095452126.png)]
1、产生异常对象 发生异常的位置会产生异常对象
2、如果没有对异常对象处理 则会沿着调用关系逐级向上抛出,直到抛到jvm
3、抛到jvm后会终止程序运行,并打印异常信息
异常信息:异常类型,触发异常的原因,异常抛出的位置(轨迹,从哪开始抛出)
public static void main(String[] args) throws InvalidValueException {
}
if (line <= 0 || column <= 0){
throw new InvalidValueException("矩形的长宽必须是正整数");
}
try{
//可能发生异常的代码
} catch 异常类型 异常名{
//对异常的处理
} finally {
//无论是否发生异常,都会执行
//如果不想执行finally,可以使用System.exit(0) 0:正常退出,非0:非正常退出----> 强制 退出jvm
}
注意:
1、只能捕获catch中声明的异常类型
2、可以进行多重catch()
3、进行多重异常时,父类在后,子类在前
4、try中声明的变量,只能在try的语句块内使用,如果想要在其他位置使用需要进行作用域提示,还需要注意初始化问题
public class InvalidValueException extends Exception{
public InvalidValueException(){
}
public InvalidValueException(String message) {
super(message);
}
}
长度 | 线程安全 | 效率 | |
---|---|---|---|
String | 不可变 | 不安全 | |
StringBuilder | 可变 | 不安全 | 快 |
StringBuffer | 可变 | 安全 | 中(待定) |
5.1.1、创建字符串对象
1、字面量
2、构造器
3、拼接
4、方法
1、位于java.lang包下,不需要导包
2、在java内,只要是使用双引号包裹起来的都可以看错String类型
3、String类的对象是不可变对象,不能修改原始值
4、数据存储在字符串常量池内,相同的数据只会开辟一块内存空间
5、底层被final修饰,所以无法修改
6、实现了Comparable接口,可以进行字符串比较
.isEmpty() //判断字符串是否为空
.length() //获取字符串长度
.toUpperCase() //将小写字母换成大写
.toLowerCase() //将大写字母换成小写
.equals(param) //比较字符串内容是否相同
.equalsIgnoreCase(param) //忽略大小写比较字符串内容
.compareTo(param) //按照下标进行比较,逐个字符比较ASCII码值,
.compareToIgnoreCase(parm) //忽略大小写比较大小
.concat(param) //把param拼接到字符串后
.trim() //去空格
.contains(param) //查看字符串是否包含某些连续字符
.indexOf(param) //获取指定元素第一次出现的下标(没有就返回-1)
.lastIndexOf(param) //获取指定元素最后一次出现的下标(没有就返回-1)
.chatAt(param) //获取指定下标的字符
.toCharArray() //将字符串变为char数组
.substring(param1,param2) //一个参数时,从参数一直截取到最后,两个参数就是从param1截取到param2,但不包括怕param2
.startsWith(param) //判断是否以指定内容开始
.startsEnd(param) //判断是否一指定内容结束
.replace(param1,param2) //将字符串中的param1内容换成param2
.split(param) //将字符串切割为几部分,以param为切割点,
//获取字符串中字符出现的次数
//方式1
public void test01(){
String str = "abfffafdasfgtwdds";
char c[] = str.toCharArray();
Arrays.sort(c);
String s = new String(c);
System.out.println("s = " + s);
for (int start = 0; start <s.length();) {
char at = s.charAt(start);
int i = s.lastIndexOf(at);
System.out.println(at+" ------> " + (i-start+1));
start = i +1;
}
}
//方式2
@Test
public void test01(){
String s = "ABCDABCDABCDAB";
//todo 1.将不重复字符组成字符串 ABCD
//1.1创建一个空字符串用于存储不重复的字符
String newStr = "";
//1.2遍历旧的字符串将不重复字符添加到新的字符串内
for (int i = 0; i <s.length() ; i++) {
//获取指定下标的字符
char e = s.charAt(i);
//如果没有出现过 进行添加
if(newStr.indexOf(e)==-1){
newStr+=e;
}
}
// System.out.println("newStr = " + newStr);//ABCD
//todo 2.再让不重复字符串内的每一个字符与原始字符串进行比较
for(int i = 0;i<newStr.length();i++){
//定义变量统计数量
int count = 0;
char nc = newStr.charAt(i);
for(int j = 0;j<s.length();j++){
char oc = s.charAt(j);
if(nc==oc){
count++;
}
}
System.out.println(nc+" --> "+count);
}
}
1.0就有了
和StringBuffer一样,通过传入的参数来返回底层代码的coder的值来判断传入的数据类型来决定字符串的长度
.setlength() //设置长度
.append(param) //在字符串后拼接内容
.delete(param1,param2) //删除范围(左闭右开)
.insert(param1,param2) //在下标param1之前插入param2内容
.replace(param1.param2,param3) //把下标param1~param2直接的内容替换成param3
.reverse() //反转字符串
static int binarySearch(int[] a, int key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数
static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组
static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
static void fill(int[] a, int val) :用val填充整个a数组
static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val
static void sort(int[] a) :将a数组按照从小到大进行排序
static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
static String toString(int[] a) :把a数组的元素,拼接为一个字符串,形式为:[param1,param2…]
基本数据类型 | 包装类(java.lang包) | 缓存对象 |
---|---|---|
byte | Byte | -128~127 |
short | Short | -128~127 |
int | Integer | -128~127 |
long | Long | -128~127 |
float | Float | 没有 |
double | Double | 没有 |
char | Character | 0~127 |
boolean | Boolean | true和false |
//手动装箱
int i = 10;
Integer inte = Integer.valueOf(i)
//自动装箱(底层包装类对象自己去调.valueOf())
int i = 10;
Integer inte = i;
//手动拆箱
Integer inte = new Integer(1021);
int i = inte.intvalue()
//自动拆箱(底层包装类对象自己去调用自己类型的Value()--->intVaule(),doubleValue() .......)
Integer inte = new Integer(1021);
int i = inte;
1、字符串拼接
2、String.valueOf(基本数据类型)
包装类型.parse基本数据类型(字符串对象) Integer.parseInt(s)
.MAX_VALUE //获取包装类能存储的最大数值
.MIN_VALUE //获取包装类能存储的最小数值
.max(param1,param2) //获取两数最大值
.min(param1,param2) //获取两数最小值
.sum(param1,param2) //求两数和
.compare(param1,param2) //判断两数大小
.toBinaryString(param) //十进制转换为2进制,
1、赋值问题
2、缓存问题
3、不可以变对象
.abs() //绝对值
.sqrt() //开平方
.pow(param1,param2) //param1的param2次方
.floor(param) //向下取整
.ceil(param) //向上取整
.random() //随机数
.round(param) //四舍五入
.max(param1,param2) //比较大小
@Test
public void test01(){
// long bigNum = 123456789123456789123456789L;
BigInteger b1 = new BigInteger("123456789123456789123456789");
BigInteger b2 = new BigInteger("78923456789123456789123456789");
//System.out.println("和:" + (b1+b2));//错误的,无法直接使用+进行求和
System.out.println("和:" + b1.add(b2));
System.out.println("减:" + b1.subtract(b2));
System.out.println("乘:" + b1.multiply(b2));
System.out.println("除:" + b2.divide(b1));
System.out.println("余:" + b2.remainder(b1));
}
@Test
public void test02(){
/*double big = 12.123456789123456789123456789;
System.out.println("big = " + big);*/
BigDecimal b1 = new BigDecimal("123.45678912345678912345678912345678");
BigDecimal b2 = new BigDecimal("7.8923456789123456789123456789998898888");
//System.out.println("和:" + (b1+b2));//错误的,无法直接使用+进行求和
System.out.println("和:" + b1.add(b2));
System.out.println("减:" + b1.subtract(b2));
System.out.println("乘:" + b1.multiply(b2));
System.out.println("除:" + b1.divide(b2,20,RoundingMode.UP));
//divide(BigDecimal divisor, int scale, int roundingMode)
System.out.println("除:" + b1.divide(b2,20,RoundingMode.DOWN));
//divide(BigDecimal divisor, int scale, int roundingMode)
System.out.println("余:" + b1.remainder(b2));
}
//保留两位小数的方式:
@Test
public void test02(){
double f = 111231.5585;
BigDecimal bg = new BigDecimal(f);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println(f1);
}
@Test
public void test5(){
long time = Long.MAX_VALUE;
Date d = new Date(time);
System.out.println(d);
}
@Test
public void test4(){
long time = 1559807047979L;
Date d = new Date(time);
System.out.println(d);
}
@Test
public void test3(){
Date d = new Date();
long time = d.getTime();//获取当前时间的毫秒值
System.out.println(time);//1559807047979
}
@Test
public void test2(){
long time = System.currentTimeMillis();
System.out.println(time);//1559806982971
//当前系统时间距离1970-1-1 0:0:0 0毫秒的时间差,毫秒为单位
}
@Test
public void test1(){
Date d = new Date();
System.out.println(d);
}
@Test
public void test10() throws ParseException{
String str = "2023年10月21日 16时03分14秒 545毫秒 星期六 +0800";
SimpleDateFormat sf =
new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒 E Z");
Date d = sf.parse(str);
System.out.println(d);
}
@Test
public void test9(){
Date d = new Date();
SimpleDateFormat sf =
new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒 E Z");
//把Date日期转成字符串,按照指定的格式转
String str = sf.format(d);
System.out.println(str);
}
该类提供了三种格式化方法:
预定义的标准格式。如:DateTimeFormatter.ISO_DATE_TIME;
ISO_DATE
本地化相关的格式。如:DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
自定义的格式。如:DateTimeFormatter.ofPattern(“yyyy-MM-dd hh:mm:ss”)
@Test
public void test(){
LocalDateTime now = LocalDateTime.now();
//预定义的标准格式
DateTimeFormatter df = DateTimeFormatter.ISO_DATE_TIME;//2021-10-21T10:21:23.211
//格式化操作
String str = df.format(now);
System.out.println(str);
}
@Test
public void test1(){
LocalDateTime now = LocalDateTime.now();
//本地化相关的格式
//DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);//2021年10月21日 上午10时21分03秒
DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);//21-10-21 下午10:21
//格式化操作
String str = df.format(now);
System.out.println(str);
}
@Test
public void test2(){
LocalDateTime now = LocalDateTime.now();
//自定义的格式
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒 E 是这一年的D天");
//格式化操作
String str = df.format(now);
System.out.println(str);
}
//把字符串解析为日期对象
public void test3(){
//自定义的格式
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy.MM.dd");
//解析操作
LocalDate parse = LocalDate.parse("2021.12.12", pattern);
System.out.println(parse);
}
方法 | 描述 |
---|---|
now() / now(ZoneId zone) | 静态方法,根据当前时间创建对象/指定时区的对象 |
of() | 静态方法,根据指定日期/时间创建对象 |
getDayOfMonth()/getDayOfYear() | 获得月份天数(1-31) /获得年份天数(1-366) |
getDayOfWeek() | 获得星期几(返回一个 DayOfWeek 枚举值) |
getMonth() | 获得月份, 返回一个 Month 枚举值 |
getMonthValue() / getYear() | 获得月份(1-12) /获得年份 |
getHours()/getMinute()/getSecond() | 获得当前对象对应的小时、分钟、秒 |
withDayOfMonth()/withDayOfYear()/withMonth()/withYear() | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象 |
with(TemporalAdjuster t) | 将当前日期时间设置为校对器指定的日期时间 |
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours() | 向当前对象添加几天、几周、几个月、几年、几小时 |
minusMonths() / minusWeeks()/minusDays()/minusYears()/minusHours() | 从当前对象减去几月、几周、几天、几年、几小时 |
plus(TemporalAmount t)/minus(TemporalAmount t) | 添加或减少一个 Duration 或 Period |
isBefore()/isAfter() | 比较两个 LocalDate |
isLeapYear() | 判断是否是闰年(在LocalDate类中声明) |
format(DateTimeFormatter t) | 格式化本地日期、时间,返回一个字符串 |
parse(Charsequence text) | 将指定格式的字符串解析为日期、时间 |
static long currentTimeMillis() :返回当前系统时间距离1970-1-1 0:0:0的毫秒值
static void exit(int status) :退出当前系统
static void gc() :运行垃圾回收器。
static String getProperty(String key):获取某个系统属性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wC6arvQc-1692363825585)(F:\Typora\images\JavaSE\image-20230804183012783.png)]
集合和数组既然都是容器,它们有啥区别呢?
数组的长度是固定的。集合的长度是可变的。
数组中可以存储基本数据类型值,也可以存储对象,而集合中只能存储对象
//1、添加元素**
add(E obj)://添加元素对象到当前集合中
addAll(Collection<? extends E> other)://添加other集合中的所有元素对象到当前集合中,即this = this ∪ other
//2、删除元素**
boolean remove(Object obj) ://从当前集合中删除第一个找到的与obj对象equals返回true的元素。
boolean removeAll(Collection<?> coll)://从当前集合中删除所有与coll集合中相同的元素。即this = this - this ∩ coll
boolean retainAll(Collection<?> coll)://从当前集合中删除两个集合中不同的元素,使得当前集合仅保留与c集合中的元素相同的元素,即当前集合中仅保留两个集合的交集;
//3、查询与获取元素**
boolean isEmpty()://判断当前集合是否为空集合。
boolean contains(Object obj)://判断当前集合中是否存在一个与obj对象equals返回true的元素。
boolean containsAll(Collection<?> c)://判断c集合中的元素是否在当前集合中都存在。即c集合是否是当前集合的“子集”。
int size()://获取当前集合中实际存储的元素个数
Object[] toArray()://返回包含当前集合中所有元素的数组
Iterator<Integer> iterator = collection.iterator();
while (iterator.hasNext()){
Integer next = iterator.next();
if (next%10 ==3){
iterator.remove(); //遍历时必须使用迭代器对象删除,不能使用集合对象删除
} else {
System.out.print(next + " ");
}
}
@Test
public void test02(){
Collection<String> c = new ArrayList<>();
c.add("张三");
c.add("李四");
c.add("王五");
c.add("赵六");
//增强for循环(本质也是迭代器)
for (String s : c) {
System.out.println("s = " + s);
}
Iterator<String> iterator = c.iterator();
//迭代器
while (iterator.hasNext()){
String ele = iterator.next();
System.out.println("ele = " + ele);
}
}
相同:
1、底层都是数组
2、都继承了AbstractList类
不同:
1、初始化长度时间不同:
ArrayList第一次创建对象是,数组长度为0,第一次添加数据是,数组长度为10
Vector第一次创建对象是,数组长度就为10
2、扩容方式不同
ArrayList扩容0.5倍
Vector看底层的capacityIncrement=0是,扩容到2倍(为旧数组长度+旧数组长度)
capacityIncrement>0是,为(capacityIncrement+就数组长度)
3、线程安全和效率不同
ArrayList线程不安全,效率高
Vector线程安全,效率低
无序,唯一
底层使用HashMap的key去存储(因为key是唯一的)
有序(插入顺序),唯一
底层使用LinkedHashMap的key去存储
//方式一
Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key+","+value);
}
//方式二
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer, String>> iterator = entrySet.iterator();
while (iterator.hasNext()){
Map.Entry<Integer, String> entry = iterator.next();
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key+" "+value);
}
key无序,不重复
底层采用数组加链表存储,当节点数量大于8时,且数组长度不小于64时,采用数组加红黑树
底层双向链表加哈希表
key有序(添加顺序),唯一
如果存储自定义类型数据 必须要重新 hashCode() equals()
底层哈希表加红黑树
key有序(自然排序),唯一
线程安全
相同:
1、都实现了Map接口
2、底层都是用了哈希表
不同:
1、对null值的处理
HashMap的key和value都可以为null
Hashtable的key和value都不能为null
2、底层数组开辟空间的时间不同
HashMap在第一添加数据时开辟空间,数组长度为16
Hashtable在创建对象时开辟空间,数组长度为11
3、线程安全和效率
HashMap线程不安全,效率高
Hashtable线程安全,效率低
定义:参数化类型
1、输入输入的类型
2、减少类型的转换
泛型的位置:
类: 定义在类上 泛型类型
接口: 泛型接口
方法:
泛型方法:方法执行时才确定泛型类型的方法
自定义泛型方法:
将泛型的声明放到返回值前
public void cc(){}
public static void show(){}
定义泛型的上限:
T extends 类型:
T 未知类型 可以是指定类型也可以是它的孩子
T extends Animal: T 既可以是Animal 也可以是Animal的孩子
T extends Number & Comparable:指定多个上限
泛型的擦除:
1.需要泛型却没有指定泛型则采用最高类型Object
2.泛型存在于编译时
泛型的通配符:
?: 代表未知类型
通配符的下限: ? super T 最小类型
? super Dog : 未知类型可以是Dog 也可以是Dog的父亲
通配符的上限: ? extends T 最高类型
? extends Comparable: 未知类型可以是Comparable 也可以是Comparable的孩子
getName() //获取文件名
length() //获取文件大小(不能获取文件夹大小,要获取文件夹大小就获取文件夹中所有文件大小的和)
lastModified() //获取文件最后修改日期(返回毫秒值)
.isFile() //是否为文件
isDirectory() //是否为文件夹
exists() //是否存在
.createNewFile() //创建文件
.delete() //删除文件(只能删除空文件夹,直接删除,不放入回收站,但不能删除文件夹)
.mkdir() //创建文件夹
.mkdirs() //创建多级文件夹
注意:
1.NotSerializableException:没有序列化异常
需要存储对象所在的类 必须实现 Serializable 接口
2.如果某些属性不想被序列化
属性前+ transient
属性前+ static
3.序列化和反序列化版本号要一致4.可以使用对象流写出基本类型的数据
读取顺序要和写出顺序一致
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.11.0version>
dependency>
1、实现Thread类
2、重新run方法
3、创建Thread对象,调用start方法
public class CreateThread extends Thread{
@Override
public void run() {
while (true){
System.out.println("thread run...................");
}
}
}
public static void main(String[] args) {
CreateThread createThread = new CreateThread();
createThread.start();
}
//匿名类创建
new Thread(){
@Override
public void run() {
System.out.println("Thread.............");
}
}.start();
1、实现Runnable接口
2、重新run方法
3、创建实现了Runnable接口类的对象
4、创建Thread对象,传入实现了Runnable接口类的对象
5、调用start方法
public class CreateRunnable implements Runnable{
@Override
public void run() {
while (true){
System.out.println("runnable run................");
}
}
}
public static void main(String[] args) {
new Thread(new CreateRunnable()).start();
}
//匿名类创建
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runnable..........");
}
}).start();
1、实现Callable接口,可以使用泛型
2、重写call方法
3、创建FutureTask对象,传入Callable对象
4、创建Thread对象,传入FuturTask对象
5、调用Thread对象的start方法
public class CreateCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("Callable实现多线程");
return "Callable实现多线程";
}
}
public static void main(String[] args) {
FutureTask futureTask = new FutureTask<>(new CreateCallable());
new Thread(futureTask).start();
}
//固定大小的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
fixedThreadPool.execute(() -> System.out.println("Hello, world!"));
fixedThreadPool.shutdown(); // 必须调用 shutdown() 才能关闭线程池。否则会导致内存泄漏。
//可缓存的线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(() -> System.out.println("Hello, world!"));
cachedThreadPool.shutdown(); // 必须调用 shutdown() 才能关闭线程池。否则会导致内存泄漏。
//单个线程的线池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(() -> System.out.println("Hello, world!"));
singleThreadExecutor.shutdown(); // 必须调用 shutdown() 才能关闭线程池。否则会导致内存泄漏。
//可执行延迟任务的线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
scheduledThreadPool.scheduleAtFixedRate(() -> System.out.println("Hello, world!"), 0, 5, TimeUnit.SECONDS);
scheduledThreadPool.shutdown(); // 必须调用 shutdown() 才能关闭线程池。否则会导致内存泄漏。
public void run() :此线程要执行的任务在此处定义代码。
public String getName() :获取当前线程名称。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
public final int getPriority() :返回线程优先级
public final void setPriority(int newPriority) :改变线程的优先级
public static void main(String[] args) {
Thread t = new Thread(){
public void run(){
System.out.println(getName() + "的优先级:" + getPriority());
}
};
t.setPriority(Thread.MAX_PRIORITY);
t.start();
System.out.println(Thread.currentThread().getName() +"的优先级:" + Thread.currentThread().getPriority());
}
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public static void sleep(long millis) :线程睡眠,使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
void join() :加入线程,当前线程中加入一个新线程,等待加入的线程终止后再继续执行当前线程。
void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。如果millis时间到,将不再等待。
void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
public final void stop():强迫线程停止执行。 该方法具有不安全性,已被弃用,最好不要使用。
public void interrupt():中断线程,实际上是给线程打上一个中断的标记,并不会真正使线程停止执行。
public static boolean interrupted():检查线程的中断状态,调用此方法会清除中断状态(标记)。
public boolean isInterrupted():检查线程中断状态,不会清除中断状态(标记)
public synchronized void method(){
}
同步方法的锁对象
普通同步方法:this
静态普通同步方法:类型.class
//普通同步方法
public synchronized void a(){}
//静态普通同步方法
public synchronized static void b(){}
synchronized(同步锁){
}
wait():等待,会释放锁
notify():唤醒等待的线程
notifyAll():唤醒所有的等待的线程
线程通信的方法只能在同步代码块或同步方法中使用
当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
当线程对象调用start()方法后,线程就从新建状态转为就绪状态
如果就绪的线程获得了CPU资源,开始执行run()方法的线程,则该线程处于运行状态
当运行的线程遇到某些特殊的情况导致线程临时放弃CPU的资源,不在继续执行,此时线程进入阻塞状态
线程完成任务或者意外终止后,线程处于死亡状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lbfBMRx7-1692363825585)(F:\Typora\images\JavaSE\image-20230808095550958.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kCkVNRHx-1692363825585)(F:\Typora\images\JavaSE\image-20230809095640422.png)]
sleep不会释放锁,wait会释放锁
sleep可指定休眠时间,时间结束后将自动继续执行,wait需要可以指定时间也可以无限等待,直到notify或者notifyALll
sleep在Thread类中,是静态方法,wait属于Object类中
调用wait方法是由锁对象调用,而锁对象的类型是任意类型的对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ejBd8z6a-1692363825585)(F:\Typora\images\JavaSE\image-20230808110021342.png)]
UDP:用户数据协议
TCP
a、加载 load
b、链接 link
c、初始化 initialize
a、那些操作会导致类的初始化
a、引导类加载器(Bootstrap Classloader) 又称为根类加载器
jdk8前
它负责加载jre/rt.jar核心库
它本身不是Java代码实现的,也不是ClassLoader的子类,获取它的对象时往往返回null
jdk8后
"jdk.management.jfr"
"java.rmi"
"java.logging"
"java.xml"
"jdk.jfr"
"java.datatransfer"
"jdk.net"
"java.naming"
"java.desktop"
"java.prefs"
"java.security.sasl"
"jdk.naming.rmi"
"java.base"
"jdk.management.agent"
"jdk.sctp"
"java.management"
"jdk.unsupported"
"java.instrument"
"jdk.management"
"jdk.nio.mapmode"
"java.management.rmi"
b、扩展加载器(jdk8前(Extension ClassLoader),jdk8后叫平台类加载器(PlatformClassLoader))
jdk8
它负责加载jre/lib/ext扩展库
它是ClassLoader的子类
jdk8后 平台类加载器
"java.sql"
"jdk.charsets"
"java.transaction.xa"
"java.xml.crypto"
"jdk.xml.dom"
"jdk.httpserver"
"jdk.crypto.cryptoki"
"java.net.http"
"jdk.zipfs"
"jdk.crypto.ec"
"jdk.crypto.mscapi"
"jdk.jsobject"
"java.sql.rowset"
"java.smartcardio"
"java.security.jgss"
"jdk.security.auth"
"java.compiler"
"java.scripting"
"jdk.dynalink"
"jdk.accessibility"
"jdk.security.jgss"
"jdk.naming.dns"
"jdk.localedata"
c、应用程序类加载器(APplication ClassLoader)
加载如下内容
"jdk.jdi"
"jdk.jstatd"
"jdk.random"
"jdk.internal.ed"
"jdk.compiler"
"jdk.internal.opt"
"jdk.jconsole"
"jdk.attach"
"jdk.javadoc"
"jdk.jshell"
"jdk.editpad"
"jdk.internal.le"
"jdk.jlink"
"jdk.jdwp.agent"
"jdk.internal.jvmstat"
"jdk.unsupported.desktop"
"jdk.jdeps"
"jdk.jartool"
"jdk.jpackage"
d、自定义类加载器
当你的程序需要加载“特定”目录下的类,可以自定义类加载器;
当你的程序的字节码文件需要加密时,那么往往会提供一个自定义类加载器对其进行解码
后面会见到的自定义类加载器:tomcat中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZdDhC9k2-1692363825586)(F:\Typora\images\JavaSE\image-20230809103726176.png)]
简述
下一级的类加载器,如果接到任务时,会先搜索是否加载过,如果没有,会先把任务往上传,如果都没有加载过,一直到根加载器,如果根加载器在它负责的路径下没有找到,会往回传,如果一路回传到最后一级都没有找到,那么会报ClassNotFoundException或NoClassDefError,如果在某一级找到了,就直接返回Class对象。
优点
1、采用双亲委派模式的好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关系可以避免类的重复加载,当父亲已经加载了该类,就没有必要让子类加载器再加载一次
2、安全,java核心api中定义类型不会被随意替换。假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
注意:
应用程序类加载器 把 扩展类加载器视为父加载器,
扩展类加载器 把 引导类加载器视为父加载器。
1、该类的所有实例偶读已经被回收,也就是java堆中不存在该类的任何实例
2、加载该类的ClassLoader已经被回收
3、该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法
如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了
//(1)基本数据类型和void
例如:int.class
void.class
//(2)类和接口
例如:String.class
Comparable.class
//(3)枚举
例如:ElementType.class
//(4)注解
例如:Override.class
//(5)数组
例如:int[].class
Class<String> stringClass = String.class;
String s = new String();
s.getClass();
Class<?> aClass = Class.forName("java.lang.String");
//用其他的类加载对象去调用getClassLoader().loadClass()方法
Class<Person> personClass = Person.class;
Class<?> aClass1 = personClass.getClassLoader().loadClass("java.lang.String");
System.out.println("aClass1 = " + aClass1);
public class TestClassInfo {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
//1、先得到某个类型的Class对象
Class clazz = String.class;
//比喻clazz好比是镜子中的影子
//2、获取类信息
//(1)获取包对象,即所有java的包,都是Package的对象
Package pkg = clazz.getPackage();
System.out.println("包名:" + pkg.getName());
//(2)获取修饰符
//其实修饰符是Modifier,里面有很多常量值
/*
* 0x是十六进制
* PUBLIC = 0x00000001; 1 1
* PRIVATE = 0x00000002; 2 10
* PROTECTED = 0x00000004; 4 100
* STATIC = 0x00000008; 8 1000
* FINAL = 0x00000010; 16 10000
* ...
*
* 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
*
* mod = 17 0x00000011
* if ((mod & PUBLIC) != 0) 说明修饰符中有public
* if ((mod & FINAL) != 0) 说明修饰符中有final
*/
int mod = clazz.getModifiers();
System.out.println(Modifier.toString(mod));
//(3)类型名
String name = clazz.getName();
System.out.println(name);
//(4)父类,父类也有父类对应的Class对象
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
//(5)父接口们
Class[] interfaces = clazz.getInterfaces();
for (Class class1 : interfaces) {
System.out.println(class1);
}
//(6)类的属性, 你声明的一个属性,它是Field的对象
/* Field clazz.getField(name) 根据属性名获取一个属性对象,但是只能得到公共的
Field[] clazz.getFields(); 获取所有公共的属性
Field clazz.getDeclaredField(name) 根据属性名获取一个属性对象,可以获取已声明的
Field[] clazz.getDeclaredFields() 获取所有已声明的属性
*/
Field valueField = clazz.getDeclaredField("value");
// System.out.println("valueField = " +valueField);
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
//修饰符、数据类型、属性名
int modifiers = field.getModifiers();
System.out.println("属性的修饰符:" + Modifier.toString(modifiers));
String name2 = field.getName();
System.out.println("属性名:" + name2);
Class<?> type = field.getType();
System.out.println("属性的数据类型:" + type);
}
System.out.println("-------------------------");
//(7)构造器们
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//修饰符、构造器名称、构造器形参列表 、抛出异常列表
int modifiers = constructor.getModifiers();
System.out.println("构造器的修饰符:" + Modifier.toString(modifiers));
String name2 = constructor.getName();
System.out.println("构造器名:" + name2);
//形参列表
System.out.println("形参列表:");
Class[] parameterTypes = constructor.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println(parameterType);
}
//异常列表
System.out.println("异常列表:");
Class<?>[] exceptionTypes = constructor.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
}
System.out.println("=--------------------------------");
//(8)方法们
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
//修饰符、返回值类型、方法名、形参列表 、异常列表
int modifiers = method.getModifiers();
System.out.println("方法的修饰符:" + Modifier.toString(modifiers));
Class<?> returnType = method.getReturnType();
System.out.println("返回值类型:" + returnType);
String name2 = method.getName();
System.out.println("方法名:" + name2);
//形参列表
System.out.println("形参列表:");
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println(parameterType);
}
//异常列表
System.out.println("异常列表:");
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
}
}
}
两种方式:
1、直接通过Class对象来实例化(要求必须有无参构造)
2、通过获取构造器对象来进行实例化
方式一的步骤:
(1)获取该类型的Class对象(2)创建对象
@Test
public void test2()throws Exception{
Class<?> clazz = Class.forName("com.atguigu.test.Student");
//Caused by: java.lang.NoSuchMethodException: com.atguigu.test.Student.()
//即说明Student没有无参构造,就没有无参实例初始化方法
Object stu = clazz.newInstance();
System.out.println(stu);
}
@Test
public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
// AtGuigu obj = new AtGuigu();//编译期间无法创建
Class<?> clazz = Class.forName("com.atguigu.test.AtGuigu");
//clazz代表com.atguigu.test.AtGuigu类型
//clazz.newInstance()创建的就是AtGuigu的对象
Object obj = clazz.newInstance();
System.out.println(obj);
}
方式二的步骤:
(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象
如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
示例代码:
public class TestNewInstance {
@Test
public void test3()throws Exception{
//(1)获取Class对象
Class<?> clazz = Class.forName("com.atguigu.test.Student");
/*
* 获取Student类型中的有参构造
* 如果构造器有多个,我们通常是根据形参【类型】列表来获取指定的一个构造器的
* 例如:public Student(int id, String name)
*/
//(2)获取构造器对象
Constructor<?> constructor = clazz.getDeclaredConstructor(int.class,String.class);
//(3)创建实例对象
// T newInstance(Object... initargs) 这个Object...是在创建对象时,给有参构造的实参列表
Object obj = constructor.newInstance(2,"张三");
System.out.println(obj);
}
}
1、获取该类的Class对象
2、获取属性对象
3、设置属性可访问 field.setAccessible(true);
4、创建实例对象:如果操作的是非静态属性,需要创建实例对象
5、设置属性值
6、获取属性值
注意
如果操作静态变量,那么实例对象可以省略,用null表示
public class TestField {
public static void main(String[] args)throws Exception {
//1、获取Student的Class对象
Class clazz = Class.forName("com.atguigu.test.Student");
//2、获取属性对象,例如:id属性
Field idField = clazz.getDeclaredField("id");
//3、如果id是私有的等在当前类中不可访问access的,我们需要做如下操作
idField.setAccessible(true);
//4、创建实例对象,即,创建Student对象
Object stu = clazz.newInstance();
//5、获取属性值
/*
* 以前:int 变量= 学生对象.getId()
* 现在:Object id属性对象.get(学生对象)
*/
Object value = idField.get(stu);
System.out.println("id = "+ value);
//6、设置属性值
/*
* 以前:学生对象.setId(值)
* 现在:id属性对象.set(学生对象,值)
*/
idField.set(stu, 2);
value = idField.get(stu);
System.out.println("id = "+ value);
}
}
1、获取该类型的Class对象
2、获取方法对象
3、创建实例对象
4、调用方法
注意
如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
如果方法是静态方法,实例对象也可以省略,用null代替
public class Person {
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public void show(){
System.out.println("Person show()");
}
private boolean isEven(int num){
return num%2==0;
}
public static int getSum(int a,int b){
return a+b;
}
private static String concat(String a,String b,int c){
return a+b+c;
}
}
public class PersonTest {
@Test
public void test05() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//todo 私有的静态方法
//1.创建Class对象
Class<Person> personClass = Person.class;
//2.获取指定的方法
Method concat = personClass.getDeclaredMethod("concat", String.class, String.class, int.class);
//3.设置私有方法可以操作
concat.setAccessible(true);
//4.执行方法 获取结果
Object result = concat.invoke(null, "貂蝉", "妲己", 666);
//5.展示结果
System.out.println("result = " + result);
}
@Test
public void test04() throws Exception{
//todo isEven
//1.创建Class对象
Class<?> aClass = Class.forName("com.atguigu.reflect01.method05.Person");
//2.获取指定的方法
Method isEven = aClass.getDeclaredMethod("isEven", int.class);
isEven.setAccessible(true);
//3.创建对象
Object o = aClass.newInstance();
//4.执行方法
Object result = isEven.invoke(o, 19);
System.out.println("result = " + result);
}
@Test
public void test03() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
//todo 反射调用 show()
//1.创建Class对象
Class<?> aClass = Class.forName("com.atguigu.reflect01.method05.Person");
//2.获取指定的方法
Method show = aClass.getMethod("show");
//3.创建对象
Object o = aClass.newInstance();
//4.执行方法
show.invoke(o);
}
@Test
public void test02(){
Person p = new Person("张三");
p.show();
int sum = Person.getSum(10, 39);
System.out.println("sum = " + sum);
}
@Test
public void test01(){
//1.创建Class对象
Class<Person> personClass = Person.class;
//2.获取所有的方法
//2.1获取父子类内所有公共的方法
//Method[] methods = personClass.getMethods();
//2.2本类中所有的方法
Method[] methods = personClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println("method = " + method);
}
}
}
public class ListTest {
@Test
public void test01() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//1.创建集合对象
ArrayList<String> list = new ArrayList();
list.add("张三");
//1.创建Class对象
Class aClass = list.getClass();
//2.获取方法
Method addMethod = aClass.getDeclaredMethod("add", Object.class);
//3.执行方法
addMethod.invoke(list,1021);
System.out.println(list);
}
}
@interface 注解名{
数据类型 属性名() [default 值];
数据类型 属性名() [default 值];
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V7CLHqVy-1692363825586)(F:\Typora\images\JavaSE\image-20230809180135902.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FOGqxGQ-1692363825586)(F:\Typora\images\JavaSE\image-20230809180119272.png)]
内置函数式接口
1、消费型函数式接口 有形参没有返回值
2、供给型函数式接口 没有形参没有返回值
3、判断型函数式接口 有形参有返回值,但返回值为布尔型
4、功能型函数式接口 有形参有返回值
1、形参类型可以省略
2、如果只有一个形参 () 可以省略
3、如果方法体只有一条语句,可以省略{}
4、带返回值方法的,只有一条返回语句可以省略 return
public interface Student {
void show();
}
interface A{
int sum(int a,int b);
}
public class StudentTest {
@Test
public void test01(){
//Student s = StudentTest::show;
Student s = ()-> System.out.println("show.....");
s.show();
}
@Test
public void test02(){
//A a = (int a1,int b)-> a1 + b;
/*A a = (int a1,int b)-> {
return a1 + b
};*/
//A a = (a1, b) -> a1+b;
A a = Integer::sum;
System.out.println("a.sum(10,21) = " + a.sum(10, 21));
}
}
/*
描述:猴子吃桃子问题,
猴子第一天摘下若干个桃子,
当即吃了所有桃子的一半,还不过瘾,又多吃了一个。
第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。
以后每天都吃了前一天剩下的一半多一个。到第十天,只剩下一个桃子。
试求第一天共摘了多少桃子?
1
4
10
22
*/
public class MonkeyTest {
public static void main(String[] args) {
System.out.println(monkey(1));
}
public static int monkey(int day){
if (day==10){
return 1;
}
return (monkey(day+1)+1)*2;
}
}
//斐波那契数列 1 1 2 3 5 8
public class FeiBo {
public static void main(String[] args) {
System.out.println("getFeiBo(5) = " + getFeiBo(6));
}
public static int getFeiBo(int num){
if (num == 1 || num == 2){
return 1;
}
return getFeiBo(num-1)+getFeiBo(num-2);
}
}
public class BinarySearch {
public static void main(String[] args) {
int arr[] = {1,2,3,4,5,6,7,8};
System.out.println("binarySearch(arr,1) = " + binarySearch(arr, 1));
}
public static int binarySearch(int arr[],int num){
//定义开始
int start = 0;
//定义结束
int end = arr.length-1;
while (start <= end){
int mid = (start+end)/2;
int midValue = arr[mid];
if (midValue < num){
start = mid+1;
} else if(midValue > num){
end = mid -1;
} else {
return mid;
}
}
return -1;
}
}
public class SelectSort {
public static void main(String[] args) {
int arr[] = {5,7,12,10,21,26,9};
System.out.println("排序前");
System.out.println(Arrays.toString(arr));
//需要进行几次排序
for (int i = 0; i < arr.length-1; i++) {
int minIndex = i;
//需要和后面的几个元素依次对比
for (int j = i+1; j <arr.length ; j++) {
if (arr[j]<arr[minIndex]){
minIndex = j;
}
}
//如果最小元素下标不是i,那么就进行元素
if (i!=minIndex){
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
System.out.println("排序后");
System.out.println(Arrays.toString(arr));
}
}
//冒泡排序及优化
//arr.length-1,一个长度为arr.length的数组只需要执行 arr.length-1次即可有序
for(int i = 0; i < arr.length-1;i++){
boolean flag = true;
for(int j = 0;j < arr.length-i-1;j++){ //arr.length-i-1-->让排序只注重于无序部分
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;
}
}
if(flag){
berak;//如果提前排序完,就提前退出
}
}
Arrays.toString(arr);