文章目录
1. 初识java
1. 变量
计算机内存中的一块存储区域,是存储数据的基本单元0
0 酒店的房间----变量
房间的类型 变量的类型
房间的门牌号 变量名
房间的住客 变量的值
声明变量的方法
-
先声明,后赋值
-
申明的同时赋值
-
多个同类型的变量一次性声明并赋值
int a=10,b,c;
2. 数据类型
- 基本数据类型
- 整数类型
- byte (1个字节) -128—127
- short (2)
- int (4)
- long (8)
- 小数类型
- float (4)
- double (8)
- 逻辑类型/boolean
- true
- flase
- 字符型,两个字节
- 单个字符
- 可以存放单个字符、数字、转义字符以及汉字,也可以放汉字对应的ASCII码
- 可以存放空格,但是只能放一个空格
- 整数类型
- 引用数据类型
- 字符串
- 数组类型(以及基本的数组类型)
- 对象类型
-
类型转换
-
自动类型转换
byte——>short——>int——>long——>float——>double
char——>int——>long
-
-
强制类型转换
- 目标类型数据小于原始数据类型
- 强制转换: 小类型 小变量 = (小类型)大数值;
- 会丢失精度
-
进制转换
- 20转换为2进制
- 8进制的56转换为10进制
3. 运算符
-
println与print的区别:print打印完指定内容之后结束; println,ln=line,打印完指定内容后换行,将光标定位在下一行
-
main方法的四要素:
- public :公共的
- static :静态的
- void :无返回值
- String[] args :变量,args可以是任意合法的变量
-
常用转义字符
转义字符 意义 \t 水平制表符 \n 换行 -
运算符:
-
运算符 描述 & 两个表达式都成立时,表达式才成立 | 表示链接条件有一个成立,表达式就成立 ^ 异或:相同为0,不同为1 ! 取反 && 短路与:当判断一个条件为true时就不判断第二个表达式,结果与&相同 || 短路或:当判断一个表达式为true式不在判断第二个
-
-
位运算符:
运算符 描述 & 按位与 | 按位或 ~ 取反 ^ 按位异或:相同为true,不同为false << 左移 >> 右移 >>> 无符号右移 -
三目运算符
结果 = <布尔类型表达式> ? <表达式1> : <表达式2>;
4. 进制转换
将10进制的39转换为2进制、8进制、16进制
分别将十六进制和八进制转换成十进制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ng6YQysz-1660055903780)(https://s2.loli.net/2022/07/29/Ck7DyqAzM5d4XS8.png)]
5. ASCII码表:
A:65
a:97
0:48
2. 分支语句
1. 循环结构
循环:
-
do循环
-
do while循环
-
字符串的.equalsIgnoreCase( )方法:忽略大小写的比较
-
跳转语句
-
continue 适用于跳出循环
- break适用于跳出循环与switch case
- return终止某个方法
-
for( ; ; )的三个表达式问题——只适用于循环次数确定😊
for(循环变量初始化;循环条件;迭代语句){ 循环体; } 注意:for循环会出现溢出
跳转语句: 标签名:循环结构{ break 标签名; }
3. 数组
❤️❤️Arrays.toString(int[] a):打印数组的值
1. 一维数组
-
数组的定义
- int[] arr={10,20} int arr[]={10,20}
- int arr[] =new int[10]
-
数组遍历:
- for循环遍历 (itar)
- 增强for循环 (iter)
-
Scanner获取参数的方法:
- sc.next( ) 获取字符串
- sc.nextInt(8) 转换为8进制输出
- sc.nextLine( )自动屏蔽空格
-
索引越界:ArrayIndexOutofBoundsException💜💜
2. 二维数组
-
二维数组的声明:
int[][] array int array[][] int[] array[]
-
二维数组的初始化:
- 动态初始化
array=new int[3][2] array.length=3 栈内存 堆内存 array[0]={1,2} array[0].leght=2 ... ..=2 array[2]={5,6}
- 静态初始化
array=new int[][]{ {1},{2,3},{4} }
-
二维数组的遍历
int[][] arr=new int[][]{ {1,2},{2,3}{1,2,3} }
- for循环嵌套
for (int i = 0; i < arr.length; i++) { for (int j = 0; j < arr[i].length; j++) { System.out.print(arr[i][j]+"\t"); } System.out.println(); }
- foreach循环
for (int[] ints : arr) { for (int anInt : ints) { System.out.print(anInt+"\t"); } System.out.println(); }
-
二维数组的操作:俄罗斯方块的变换、输出(3层循环)
for (int i = 0; i < types.length; i++) {
for (int j = 0; j < types.length; j++) {
boolean fla=false;
for (int k = 0; k < types.length; k++) {
if (types[k][0]==i&&types[k][1]==j){
fla=true;
break;
}
}
if (fla){
System.out.print("▪\t");
}else{
System.out.print("▫\t");
}
}
//一行打印完换行
System.out.println();
}
3. 数组拷贝(扩容)
1. System.arraycopy(原数组,原数组的起始位置,新数组,新数组起始位置,长度);
2. java.util.Arrays.copyOf(原数组,新长度);//返回带有原值的新数组 可以任意截取
int[] arr1={1,2,3,4};
int[] arr2=new int[5];
//固定长度数组复制
System.arraycopy(arr1,3,arr2,0,1);
for (int i : arr2) {
System.out.print(i+"\t");
}
//变长数组复制 java.util.Arrays.copyOf(原数组,新长度);
int[] arr3= Arrays.copyOf(arr1,2);
for (int i : arr3) {
System.out.print(i+"\t");
}
4. 数组练习题
-
//键盘输入5位同学本次java的成绩,输出最大值和最小值 public class TestArray01 { public static void main(String[] args) { //键盘输入 Scanner sc = new Scanner(System.in); int[] scores = new int[5]; for (int i = 0; i < scores.length-1; i++) { System.out.println("请输入第" + (i + 1) + "位同学的成绩:"); scores[i] = sc.nextInt(); } //输出最大与最小值 int min=scores[0]; int max=scores[0]; for (int i = 1; i < scores.length-1; i++) { if (min>scores[i]){ min=scores[i]; } if (max<scores[i]){ max=scores[i]; } } System.out.println("最低成绩为:"+min); System.out.println("最高成绩为:"+max); } }
-
冒泡排序与选择排序
冒泡排序:将相邻位置的元素比较大小,大的与小的换位置
选择排序:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。
//键盘输入数据,冒泡排序 //选择排序 import java.util.Arrays; import java.util.Scanner; public class TestArray02 { public static void main(String[] args) { //键盘输入 Scanner sc = new Scanner(System.in); int[] scores = {25, 62, 12, 10, 28}; System.out.println("请使用方法:\n1.冒泡排序\n2.选择排序"); int num = sc.nextInt(); switch (num) { case 1: System.out.println("请选择排序方式:\n1.升序\n2.降序"); int nu = sc.nextInt(); switch (nu) { case 1: //冒泡排序的升序 bulAsc(scores); break; case 2: //冒泡排序的降序 bulDesc(scores); break; } //冒泡排序 break; case 2: //选择排序 System.out.println("请选择排序方式:\n1.升序\n2.降序"); nu = sc.nextInt(); switch (nu) { case 1: //选择排序的降序排列 selAsc(scores); break; case 2://选择排序的升序排列 selDesc(scores); break; } } } //排序前为: public static void qian(int[] scores) { System.out.print("排序前为:"); for (int i = 0; i < scores.length; i++) { System.out.print(scores[i] + "\t"); } System.out.println(); } // 冒泡排序的升序 public static void bulAsc(int[] scores) { qian(scores); //冒泡排序 for (int j = 0; j < scores.length - 1; j++) { for (int i = 0; i < scores.length - 1 - j; i++) { if (scores[i] > scores[i + 1]) { int temp = scores[i]; scores[i] = scores[i + 1]; scores[i + 1] = temp; } } System.out.print("第"+ (j+1) +"趟排序后:\t"); for (int k = 0; k < scores.length; k++) { System.out.print(scores[k]+"\t"); } System.out.println(); } later(scores); } // 冒泡排序的降序 public static void bulDesc(int[] scores) { qian(scores); for (int j = 0; j < scores.length - 1; j++) { for (int i = 0; i < scores.length - 1 - j; i++) { if (scores[i] < scores[i + 1]) { int temp = scores[i]; scores[i] = scores[i + 1]; scores[i + 1] = temp; } } } later(scores); } // 选择排序的升序 public static void selAsc(int[] scores) { qian(scores); for (int i = 0; i < scores.length - 1; i++) { int tempMin = i; for (int j = i; j < scores.length; j++) { if (scores[tempMin] > scores[j]) { tempMin = j;//找到本轮的最小值的下标 } //将最小值的下标换到最前面 int tem = scores[i]; scores[i] = scores[tempMin]; scores[tempMin] = tem; } } later(scores); } // 选择排序的降序 public static void selDesc(int[] scores) { qian(scores); //选择排序 5 2 6 1 for (int i = 0; i < scores.length - 1; i++) { int tempMax = i; for (int j = i + 1; j < scores.length; j++) { if (scores[tempMax] < scores[j]) { tempMax = j;//循环找到本次最大值的下标 } } //将本轮最大的和前面的换 int temp = scores[i]; scores[i] = scores[tempMax]; scores[tempMax] = temp; } later(scores); } // 排序后 public static void later(int[] scores) { System.out.print("排序后为:"); for (int score : scores) { System.out.print(score+"\t"); } } }
4. 方法
方法的定义
-
方法的定义
public static void 方法名(){ 方法体; }
-
定义方法的位置:类的内部,与main并列
-
调用方法时优先执行方法内部代码,结束后返回到调用处
-
定义方法需要关注的两点:
- 返回值类型
- 参数
-
方法的运行区:栈内存
-
方法的好处:
- 提高代码复用性
- 提高代码可读性
- 维护性、升级成本
-
方法递归:(递归的出口)
- 斐波那契数列
- n的阶乘
可变长参数
-
可变长参数 JDk1.5之后
public static void main(String[] args) { printHobbies(125,"sleep","book","java"); } public static void printHobbies(int number, String... hobbies) { if (hobbies.length==0){ System.out.println(number+"无爱好"); } System.out.print(number+" , i like "); for (String hobby : hobbies) { System.out.print(hobby+" "); } }
1.可适配>=0个同类型的参数
2.一个方法中有且仅只能有一个可变长参数,在参数列表的最后一个
3. 若同时定义了定长方法与变长方法——优先调用定长参数方法
5. 面向对象
1. 类和对象
类:具有相同属性和行为的一组对象的集合(共同属性和行为的事件抽象)——对象的模板
类 = 成员变量 + 成员方法
public class 类名{
成员变量;
成员方法;//无static
}
//成员方法:代表对象能做什么
修饰符 返回值类型 方法名(形参列表){
方法体;
}
对象:类的实例
- 类的定义步骤:
- 定义类
- 编写类的成员变量
- 编写类的成员方法(无static)
- 创建对象: 类名 对象名 = new 构造方法();
- 使用对象:使用成员变量: 对象名.成员变量名;
使用成员方法: 对象名.方法名();
- 成员变量与局部变量的区别
局部变量 | 成员变量 | |
---|---|---|
定义位置 | 方法或者方法内的结构中 | 类中方法外的变量 |
默认值 | 无默认值。先初始化后使用 | 与数组相同,有0值 |
使用范围 | 从定义行到包含其结构结束 | 对象存在则存在 |
命名冲突 | 不能与局部变量重名 | 不能与成员变量重名,可与局部变量重名,局部变量优先 |
- this关键字://解决局部变量隐藏成员变量
方法的形参与成员变量同名时,不带this的为局部变量(形参)
不同名时,不带this的为成员变量
- 方法重载:一个类中定义的多个方法之间的关系
- 同一个类中的多个方法的方法名相同,参数列表不同(个数、顺序、类型)
- 与访问修饰符、返回值类型无关
public static void printddf(){
System.out.println("jnid");
}
public static void printddf(int n){
System.out.println("jnid");
}
public static void printddf(String n){
System.out.println("jnid");
}
public static void printddf(int n,String num){
System.out.println("jnid");
}
- 构造方法:用于对象的初始化
- 名称与类名完全相同
- 没有返回值类型❤️
- 创建对象时触发构造方法的调用,不可通过句点手动调用
若没有定义带参方法,编译器默认提供无参构造方法
一旦定义了带参构造方法必须定义无参构造方法
-
构造方法的重载
多个构造方法的方法名与类名相同,无返回值类型,方法参数列表不同(个数、顺序、类型)
-
this两种使用
- this.name: 对象的属性
- this(形参): 调用构造方法 —— 要注意构造递归
public class Student {
//成员变量
String name;
int id;
int score;
//构造方法
public Student() {
System.out.println("无参构造方法");
}
public Student(String name) {
this(); //调用无参构造方法
this.name=name; // this.name为成员变量 name为局部变量
System.out.println("1参构造方法");
}
public Student(String name, int id) {
this(name); // 调用1参构造方法 --9 *this()只能放在首行 要注意构造调用❤️
this.id=id;
System.out.println("2参构造方法");
}
public Student(String name, int id, int score) {
this(name,id);
this.score=score;
System.out.println("3参构造方法");
}
2. 标准类
成员变量:private修饰
构造方法:提供无参、带参
成员方法:get/set方法 、 其他成员方法
3. 封装
避免数据漏洞,提高编码安全性
私有、get/set
-
实现方法:
私有化(private)成员变量,提供公共的getter\setter方法
私有化(private)成员变量,提供公共的带参构造方法
public class Point {
private int a;
private int b;
private int c;
//get/set方法:
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
//构造方法
public Point(int a, int b, int c) { //💙 无返回类型
this.a = a;
this.b = b;
this.c = c;
}
public void show() {
System.out.println(this.a + " " + this.b + " " + this.c);
}
💜💜💜💜💜💜💜 Boolean类型的setter为:
public void isSex(boolean sex){
this.sex=sex;
}
封装好处:过滤有效数据,提高代码复用性
公共方法中可以编写大量的代码,进行逻辑控制处理参数漏洞(分支语句)
封装的缺点:
代码量增大
class Student{
String name;
private int age;
public void setAge(int age){
if(age>0 && age <120){ // 有效数据
this.age=age;
}else{ // 无效数据
System.out.print("无效数据");
}
}
}
4. 继承
将相同的部分抽取出来定义在父类,实现重用
1.语法:
class 子类 extends 父类{ }
子类继承父类后,子类可以使用父类的属性和方法,也可以定义子类独有的属性和方法
好处:他提高代码复用性、可扩展性、维护性
弊端:削弱子类的独立性
💜💜java只支持单继承,多级继承 属性和方法逐级叠加💜💜
2. 不可继承:
1. 类中的构造方法
2. private修饰的属性和方法
3.父子类不在同一个包时,default修饰的属性和方法
访问修饰符
本类 | 同包子类 | 非同包子类 | 其他 | |
---|---|---|---|---|
private | ✔️ | ❌ | ❌ | ❌ |
default (默认) | ✔️ | ✔️ | ❌ | ❌ |
protected | ✔️ | ✔️ | ✔️ | ❌ |
public | ✔️ | ✔️ | ✔️ | ✔️ |
3. 继承中的方法重写
当父类中的方法无法满足子类的需求时,可在子类中定义和父类相同的方法
- 父类中的私有方法子类不可重写
- 子类访问权限不能更低(public>默认>私有)
- 构造方法不可重写——不可继承
super():调用父类的无参构造方法,必须在方法体的首行(显式书写/隐式书写)
super | this |
---|---|
super.属性 :调用父类成员变量 | this.属性:本类成员变量 |
super.方法 :调用父类成员方法 | this.方法:子类方法 |
super()/super(参数) :调用父类构造方法 | this()/this(参数):调用本类构造方法 |
❤️❤️this()/this(实参)与super()/super(参数)在同一个子类的构造方法中不能同时书写
4.访问特点
子类局部范围查找——>子类成员范围——>父类查找——>报错(不考虑父类的父类…)
5. 多态
——父类引用指向子类对象
1. 多态的的前提
- 有继承/实现关系(直接/间接)
- 有方法重写
- 有父类引用指向子类对象
2.多态中成员访问的特点
- 成员变量:编译看左边,执行看左边
- 成员方法:编译看左边,执行看右边——有重写
3. 多态中的方法重写
方法重写在子父类之间,方法签名完全相同(方法名、参数列表),重写后的方法的访问修饰符要>=父类的访问修饰符
❤️❤️构造方法不可重写
4. 构造方法
- 一个类无法继承他本身——构造递归
- 一个类可以继承他不同包的同名类,要写全路径
- 构造方法无法继承——>构造方法无法重写
5. 转型
-
向上转型:从子——>父 //父类引用指向子类对象
Animal a=new Cat();
向下转型:从父——>子(强转) //
Cat cat=(Cat)a; //可能会出现 类型转换异常 ClassCastException💜💜 //Dog dog=(Dog)a; java默认a为Cat类型,不可转换 //
6. 多态的应用
- 使用父类作为方法的形参实现多态,使方法参数的类型更为宽泛
- 使父类作为方法的返回值实现多态,使方法可以返回不同子类对象
-
避免类型转换异常:instanceof关键字,保证类型转换的正确性
语法: 父类引用 instanceof 类型 //返回boolean类型结果 if ( a instanceof Fish){ Fish ff=(Fish)a; ff.eat(); }else if (a instanceof Cat){ Cat cat=(Cat)a; } }
7.多态的好处
屏蔽子类间的差异
灵活、耦合度低
6. 接口
公共的规范标准,能力的具体要求
1. 接口特点
-
接口用关键字 interface 修饰
-
implements:类实现接口
public class 类名 implements 接口名{ }
-
接口不可实例化。接口多态✔️
-
接口的实现类:
- 实现接口中的所有抽象方法
- 本身就是抽象类
2. 接口的成员特点
-
成员变量:只能是常量,默认为final修饰 公开的
public static final int age=10;
-
构造方法:无
-
成员方法:只能为公开的抽象方法
3. 类和接口
类可实现多个接口
4. 接口和接口
继承关系,可继承多个接口
5.接口引用(多态)
接口引用指向是实现类的对象
✔️注意:
1. 仅可调用接口中所申明的方法————不可调用实现类中独有的方法
2. 可强转回实现类的本身————独有方法实现
6. 抽象类与接口的异同
-
相同点:
- 可编译为字节码文件
- 不能创建对象
- 可作为引用类型
- 具备object类中所定义的方法
-
不同点:
-
成员区别:
- 抽象类:变量、常量、构造方法、抽象方法、非抽象方法
- 接口:常量、抽象方法
-
关系区别:
- 类-类:单继承
- 类-接口:实现、多实现
- 接口-接口:继承、多继承
-
设计理念:
- 抽象类:对类抽象,包括属性、行为
- 接口:对行为抽象,主要是行为
-
7.接口的好处
- 降低程序的耦合度
- 更自然的使用多态
- 设计与实现完全分离
- 更容易搭建程序的框架
- 更容易更换具体实现
7. 抽象类
一个没有方法体的方法——应该定义为抽象方法
类中有抽象方法——应该定义为抽象类
1.特点
-
抽象类与抽象方法必须使用abstract修饰
public abstract class 类名{ } public abstract void 方法名(){ }
-
抽象类中不一定有抽象方法,但有抽象方法的一定是抽象类
-
抽象类不可实例化——多态
-
抽象类的子类——* 重写抽象类中的所有抽象方法
*是抽象类
2. 抽象类成员特点
-
成员变量:可常量可变量
-
构造方法:有 但不可实例化,用与子类访问父类数据的初始化
-
成员方法:*抽象方法:限定子类必须完成的动作
*非抽象方法
3. 抽象类的作用
- 被子类继承–子类必须重写父类的抽象方法or子类仍然是抽象类
- 声明为引用–多态
//抽象类的实现
public class Test01 {
Demo01 d1=new Demo01() {//相当于Demo01的匿子类
@Override
void eat() {
}
};
}
8. 修饰符
1. static
共享的
1. 定义
- 静态属性:一个类共同拥有的共享空间(一份),任何改变都会影响改变
public class StaticDemo {
static int a;
public static void main(String[] args) {
StaticDemo demo = new StaticDemo();
demo.a = 100;
StaticDemo demo02 = new StaticDemo();
demo02.a = 200;
System.out.println(demo02.a);
}
}
//结果为200
- 静态可以修饰属性和方法称为静态属性、静态方法
- 静态成员是全类所有对象共享的成员
- 全类中只有一份,不会随着创建多个对象而产生多份
- 通过类名/对象名调用
2. 静态特点
- 静态方法允许直接访问静态成员
- 静态方法不可直接访问非静态成员
- 静态方法中不可使用this和super
- 静态方法可继承,不可重写,无多态
- 在类加载时,静态代码块只执行一次
3. 静态代码块
可为静态属性赋值或初始行为
静态代码块在创建时被加载,只执行一次
package com.qfedu.Ststic;
//静态代码块
public class StaticDemo02 {
//非静态代码块
{
System.out.println("这是非静态代码块01");
}
{
System.out.println("这是非静态代码块02");
System.out.println("这是非静态代码块03");
}
static {
System.out.println("这是静态代码块");
}
public void sum(){
System.out.println(1+5);
}
}
package com.qfedu.Ststic;
public class TestDemo02 {
public static void main(String[] args) {
//创建对象
StaticDemo02 st=new StaticDemo02();
System.out.println("--------------");
StaticDemo02 st2 = new StaticDemo02();
}
}
/*
结果:
这是静态代码块
这是非静态代码块01
这是非静态代码块02
这是非静态代码块03
--------------
这是非静态代码块01
这是非静态代码块02
这是非静态代码块03
*/
创建对象的过程
如果一个类中同时定义了静态代码块和非静态代码块
2. final
最终态
1. 修饰类
表示为最终类,不可被继承
system、math、String
2. 修饰方法
表示此方法为最终方法,不可重写
3. 修饰常量
-
基本类型:值不能变
实例常量:可以直接赋初值、在非静态代码块中、构造方法中初始化值
package com.qfedu.Ststic; public class StaticDemo03 { /*{ a=10; }*/ public StaticDemo03(){ a=12; } final int a; //final int a=10; public static void main(String[] args) { StaticDemo03 s3=new StaticDemo03(); System.out.println(s3.a); } } /* 结果: 12 */
-
引用类型:地址不可变,值可以变
package com.qfedu.Final; public class FinalDemo01 { public static void main(String[] args) { final int[] arr={1,2,3}; //arr=new int[]{4,5,6};//报错 arr[0]=23; final Student student = new Student(); // student=new Student();//Cannot assign a value to final variable 'student' } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1KeeudvF-1660055903783)(https://s2.loli.net/2022/07/29/ePAEYDvMtx6RS1K.png)]
9. 常用类
1. 内部类
一个类的内部又定义了一个完整的类
内部类可以直接访问外部类的私有成员,不破坏封装
1. 1 成员内部类与静态内部类
-
在类的内部定义与变量并列
-
外部类的实例,创建时必须依赖外部类对象
package com.qfedu; public class Outer { int a=12; public class Inner { int a=13; public void sum(){ System.out.println(1+2); } } public static void main(String[] args) { Inner inner = new Outer().new Inner();//创建内部类对象 System.out.println(inner.a); inner.sum(); } }
-
当内外部类有重名属性时,优先访问内部类属性
-
成员内部类:
- 非静态内部类:不能定义静态成员方法和变量
- 静态内部类:非静态方法和静态方法都不可访问外部的非静态方法
//内部类 package com.qfedu.Inner; public class Outter01 { int num; private String name; private static double score; static boolean sex; class Inner01{ public void test(){ System.out.println(num); System.out.println(name); System.out.println(sex); } /* 非静态内部类中不能定义静态方法 */ /*public static void test02(){ }*/ } /* 静态内部类的静态和非静态方法都不可调用非静态成员 */ static class Inner02{ public static void test03(){ // System.out.println(name); System.out.println(score); System.out.println(sex); } public void test04(){ /* System.out.println(name); System.out.println(num);*/ System.out.println(score); System.out.println(sex); } } }
//内部类的测试类 package com.qfedu.Inner; public class TestOutter01 { public static void main(String[] args) { Outter01.Inner01 inner01 = new Outter01().new Inner01(); inner01.test(); System.out.println("------------"); // Outter01.Inner02 inner02 = new Outter01.Inner02(); Outter01.Inner02.test03(); } }
1.2 局部内部类
定义在外部类的方法中,作用范围和创建对象范围仅限于当前方法
局部内部类访问当前外部类的方法中的局部变量时,因为无法保障变量的生命周期与自生相同,变量必须修饰为final jdk1.7后可以不写
3. 匿名内部类
没有类名的局部内部类(特征与局部内部类相同)
-
拥有继承或实现
-
优点:减少代码量
-
缺点:可读性差
-
定义类、实现类、创建对象的语法合并,只能创建一个该类的对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9n08wPR-1660055903785)(https://s2.loli.net/2022/07/29/5SYkAoPfMNn3GJO.png)]
2. Object
-
public final Class<?> getClass():返回引用中存储的实际对象类型
通常用于判断两个引用中世纪存储对象类型是否一致
-
public int hashCode( ):返回该对象的十进制哈希值 (根据对象的地址、字符、数字计算的int类型的数值)
哈希码不唯一,可保证相同对象的哈希码相同
-
public String toString():返回该对象的字符串表现形式
-
public boolean equals(Object obj):默认实现(this==obj),比较两个对象地址是否相同,进行覆盖比较对象的内容是否相同
-
finalize():当对象被判断为垃圾对象时,JVM自动调用此方法,用来标记垃圾对象进入回收队列
垃圾对象:没有有效引用指向此对象,为垃圾对象
垃圾回收:由GC销毁垃圾对象,释放数据存储空间
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象
手动回收机制:使用System.gc()方法通知jvm回收垃圾
package com.qfedu.Object;
public class Object01 {
public static void main(String[] args) {
Student s1=new Student();
Student s2=new Student();
//getclasss 得到实际类型
System.out.println(s1.getClass());
System.out.println(s2.getClass());
//判断两个变量是否相同
System.out.println(s1.getClass().equals(s2.getClass()));
System.out.println("-----------------------------");
//hashcode
Object o1=s1;
System.out.println(s1.hashCode());
System.out.println(o1.hashCode());
System.out.println(s2.hashCode());
System.out.println("-------------------------------");
System.out.println(s1.toString());
System.out.println(s2.toString());
System.out.println("-------------------------------");
}
}
//结果:
class com.qfedu.Object.Student
class com.qfedu.Object.Student
true
-----------------------------
460141958
460141958
1163157884
-------------------------------
com.qfedu.Object.Student@1b6d3586
com.qfedu.Object.Student@4554617c
-------------------------------
3. 包装类
基本数据类型的引用类型
❤️有了类的特点,就可以调用类中的方法
包装类的默认值为NULL
3.1 包装类的分类
基本类型:boolean char byte short int long float double
包装类: Boolean Character Byte Short integer Long Float Double
--------------------- -----------------------------------------------------------------------
父类 object Number
3.2 包装类和基本数据的转换
jdk5以前需要手动装箱和拆箱 jdk5后提供自动装箱和拆箱
- 装箱:基本类型——>包装类型 底层调用valueOf( )方法 如Integer.valueOf()
- 拆箱:包装类型——>基本类型 底层调用intValue( )
package com.Test.API;
//包装类和基本类的转换
public class IntegerTest {
public static void main(String[] args) {
//装箱 int->integer
//使用valueOf()方法
//手动装箱
int i=2;
Integer i1 = new Integer(i);
Integer i2 = Integer.valueOf(i1);
//手动拆箱————>intValue()
Integer integer = new Integer(17);
int i3 = integer.intValue();
System.out.println("______________");
//jdk5之后的方法
int s=2;
//装箱
Integer s1=s;
Integer s2 = new Integer(99);
//拆箱
int s3=s2;
}
}
测试题
//判断下面的代码是否正确,为什么?
Double d=100d; // 对,自动装箱 Double.vlaueOf(100d);
Float f=1.5f; // 对,自动装箱 Float.valueOf(1.5f);
Integer i=2;
Double s=i;//错误,包装类型不能相互转换
//范围:-128~127
Integer i1=128;
Integer i2=128;
System.out.println(i1==i2);//错误,超出范围 在堆中创建对象
//下面的两个题目输出结果相同吗?为什么?
Object obj1=true?new Integer(1):new Double(2.0);
System.out.println(obj1); //输出1.0 三目运算符是一个整体,类型提升
Object obj2;
if (true){
obj2=new Integer(1);
}else{
obj2=new Double(2.0);
}
System.out.println(obj2); //if语句是独立的,不会自动类型提升,输出1
3.3 包装类与String类的转换
-
Integer——>String
方法一:字符串拼接
方法二:toString()方法
方法三:String.valueOf()方法
public static void main(String[] args) { Integer i = 90; //方法一:拼接字符串 String s = i + ""; //方法二:toString() String s1 = i.toString(); //方法三:String.valueOf()方法 String s2 = String.valueOf(i); }
-
String——>int
方法一:Integer.parseInt()
方法二:使用装箱
String ss="12345"; //方法一: int s3 = Integer.parseInt(ss); //方法二: int s4 = new Integer(ss);
3.4 Integer和Character的常用方法
System.out.println(Integer.MIN_VALUE);//返回最小值 -2147483648
System.out.println(Integer.MAX_VALUE);//返回最大值 2147483647
System.out.println(Character.isDigit('a'));//判断是不是数字
System.out.println(Character.isLetter('a'));//判断是不是字母
System.out.println(Character.isUpperCase('a'));//判断是不是大写
System.out.println(Character.isLowerCase('a'));//判断是不是小写
System.out.println(Character.isWhitespace('a'));//判断是不是空格
System.out.println(Character.toUpperCase('a'));//转成大写
System.out.println(Character.toLowerCase('A'));//转成小写
3.5 包装类面试题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RrSuuWCh-1660055903787)(https://s2.loli.net/2022/07/30/Da6sHVpfhvCJo5Z.png)]
4. String类
字符串是常量值,创建后不能改变
String 对象用于保存字符串——一组字符序列
字符串的字符使用Unicode编码,一个字符占两个字节
4.1 String常用方法
public char charAt(int index); //返回指定索引处的 char 值。索引范围为从 0 到 length() - 1
public int compareTo(String anotherString); //按字典顺序比较两个字符串。如果这两个字符串相等,则结果为 0;否则返回前一个 字符串-后一个字符串的大小
public int compareToIgnoreCase(String str); //按字典顺序比较两个字符串,不考虑大小写。
public String concat(String str); //将指定字符串连接到此字符串的结尾。
public boolean contains(CharSequence s); //当且仅当此字符串包含指定的 char 值序列时,返回 true。
public boolean equals(Object anObject); //将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。
public boolean equalsIgnoreCase(String anotherString); //将此 String 与另一个 String 比较,不考虑大小写。
public char[] toCharArray(); //将此字符串转换为一个新的字符数组。
public byte[] getBytes(); //使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
public int indexOf(int ch); //返回指定字符在此字符串中第一次出现处的索引。
public int lastIndexOf(int ch); //返回指定字符在此字符串中最后一次出现处的索引。
public boolean isEmpty()当且仅当 length(); // 为 0 时返回 true。
public int length(); //返回此字符串的长度。
public String replace(char oldChar, char newChar); //返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
public String replaceAll(String regex,String replacement);//使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
public String[] split(String regex); //根据给定正则表达式的匹配拆分此字符串。
public boolean startsWith(String prefix); //测试此字符串是否以指定的前缀开始。
public boolean endsWith(String suffix); //测试此字符串是否以指定的后缀结束。
public String substring(int beginIndex); //返回一个新的字符串,它是此字符串的一个子字符串。该子字符串从指定索引处的字符开始,直到此字符串末尾。
public String substring(int beginIndex,int endIndex); //返回一个新字符串,它是此字符串的一个子字符串。
public String toLowerCase(); //使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
public String toUpperCase(); //使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
public String trim(); //返回字符串的副本,忽略前导空白和尾部空白。
public String intern(); //返回字符串对象的规范化表示形式。
4.2 两种创建String对象的区别
方法一:直接赋值 String s="nihao";
方法二:调用构造器 String s2=new String("nihao");
方法一先在常量池找是否有“nihao”的数据空间,如果没有就创建然后指向它,如果有就直接指向,最终s指向常量池
方法二先在堆中创建空间,里面维护了value属性,指向常量池的“nihao“空间。如果常量池中没有,重新创建,如果有,直接指向,最终指向堆中空间地址
4.3 String类面试题
源码:
-
String a="abc"; String b="abc"; System.out.println(a.equals(b)); //True 值相同 System.out.println(a==b); //true 指向常量池
-
String a="jack"; String b=new String("jack"); System.out.println(a.equals(b)); System.out.println(a==b); System.out.println(a==b.intern()); System.out.println(b==b.intern());//b.intern()返回常量池地址(对象) //画出内存布局图? //答案: 常量池 堆 true false true false
-
String s1="nihao"; String s2="java"; String s4="java"; String s3=new String("java"); System.out.println(s2==s3);//F System.out.println(s2==s4);//T System.out.println(s2.equals(s3));//T System.out.println(s1==s2);//F
-
Person p1=new Person(); p1.name="ly"; Person p2=new Person(); p2.name="ly"; System.out.println(p1.name.equals(p2.name));//内容 T System.out.println(p1.name==p2.name);//堆 F System.out.println(p1.name=="ly");//❤️❤️❤️ String s1=new String("bcde"); String s2=new String("bsde"); System.out.println(s1==s2);//堆 F
-
字符串特性
String a="hello"+"abc"; 创建了几个对象?1个 String a="hello"+"abc";==>等价于String a=helloabc;
-
String a="hello"; String b="abc"; String c=a+b; 创建了及格对象?画出内存图 //底层是StringBuilder sb=new StringBuilder(); // sb.append(a); // sb.append(b); //sb在中,并且append是在原来的字符串基础上追加的。 // 重要规则:String c1="ax"+"sa";常量相加,看的是池。 // String c2=a+b,变量相加,看堆
-
//下面代码结果是?说明原因 String s1="nihao";//s1指向池 String s2="java";//s2指向池 String s5="nihaojava";//指向池 String s6=(s1+s2).intern();//指向池 System.out.println(s5==s6);//T System.out.println(s5.equlas(s6);//T
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sWQqlOvv-1660055903788)(https://s2.loli.net/2022/07/29/Wmr2np5E1BSPh7X.png)]
4.4 StringBuffer类 -fianl类 线程安全–适用于多线程
StringBuffer 与StringBuilder 是可变字符串,可对字符内容进行增删
继承AbstractStringBuilder AbstractStringBuilder属性char[] value,存放字符序列
-
常见方法:
增加:
public StringBuilder append(boolean b);
删除:
public StringBuilder delete(int start,int end);//移除此序列的子字符串中的字符。该子字符串从指定的 start 处开始,一直到索引 end - 1 处的字符,如果不存在这种字符,则一直到序列尾部。如果 start 等于 end,则不发生任何更改。
改:
public StringBuilder replace(int start,int end,String str);//使用给定 String 中的字符替换此序列的子字符串中的字符。
查询:
public int indexOf(String str);//返回第一次出现的指定子字符串在该字符串中的索引。
插入:
public StringBuilder insert(int offset,boolean b);//将 boolean 参数的字符串表示形式插入此序列中。 第二个参数将被转换成字符串,就好象使用了 String.valueOf 方法一样。
长度:
public int length();//返回长度(字符数)。
反转:
public StringBuilder reverse();//将此字符序列用其反转形式取代。
4.5 StringBuffer 练习题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XS4R4vXu-1660055903792)(https://s2.loli.net/2022/07/29/RaikTbl1ZosexcP.png)]
4.6 StringBuilder——单线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ha5yCSAq-1660055903792)(https://s2.loli.net/2022/07/29/TLGVi2OCXRHuoKS.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Xavka5M-1660055903793)(https://s2.loli.net/2022/07/29/MIgX7jVKytabJBe.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OIO1irnN-1660055903793)(https://s2.loli.net/2022/07/29/IfnSvQRAh1zVwTq.png)]
邮箱验证:
import jdk.nashorn.internal.runtime.regexp.RegExp;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//邮箱检测
public class Test01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("欢迎进入邮箱注册\n1、正则表达式检测\t2、普通方法检测");
int i = sc.nextInt();
System.out.print("请输入将要申请的邮箱:");
String myStr = sc.next();
switch (i) {
case 1:
isTrueSimple(myStr);
break;
case 2:
isTrue(myStr);
break;
default:
System.out.println("输入有误");
System.exit(0);
}
}
}
public static void isTrueSimple(String myStr) {
String regEx = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
Pattern p = Pattern.compile(regEx);
Matcher matcher = p.matcher(myStr);
boolean b = matcher.matches();
System.out.println(b);
System.out.println("注册成功!!");
}
public static boolean isTrue(String myStr) {
//@之前为数字、字母、下划线 第一位不为0
if (myStr.isEmpty()) {
System.err.println("不能为空");
return false;
}
//@
int c = myStr.indexOf("@");
if (c == myStr.length() - 1) {
System.err.println("@不能在末尾");
return false;
}
if (c != myStr.lastIndexOf("@")) {
System.err.println("不能存在两个@");
return false;
}
if (myStr.charAt(0) == '0' && myStr.charAt(0) == '@') {
System.err.println("首位不能为0与@");
return false;
}
for (int i = 0; i < c; i++) {
Character c1 = myStr.charAt(i);
if (!(Character.isDigit(c1) || Character.isLetter(c1) || c1 == '_')) {
System.err.println("@前请输入数字、字母、下划线");
return false;
}
}
int i = myStr.indexOf('.');
int i2 = myStr.lastIndexOf('.');
// .在@之后且不相邻
if (i - c < 2 || i == myStr.length() - 1 || i2 == myStr.length() - 1) {
System.err.println(".在@之后不可相邻,.不可在末尾");
return false;
}
//@之后的s数据判断
for (int j = c + 1; j < myStr.length(); j++) {
Character c1 = myStr.charAt(i);
if (!(Character.isDigit(c1) || Character.isLetter(c1) || c1 == '_' || c1 == '.')) {
System.err.println("@后请输入数字、字母、下划线、.");
return false;
}
}
System.out.println("注册成功!!");
return true;
}
}
5.BigDecimal
位置:java.math包
作用:精确计算浮点数
创建方式:BigDecimal bd=new BigDecimal(“1.0”);
方法:
加 BigDdecimal add(BigDecimal bd);
减 BigDdecimal subtract(BigDecimal bd);
乘 BigDdecimal multiply(BigDecimal bd);
除 BigDdecimal divide(BigDecimal bd);
6. 日期类Date
构造方法:
- Date()
- Date(long date)
常用方法:
- public long getTime( ) ; 返回当前时间到1970年1月1日的毫秒数
- public void setTime( ); 设置时间
7. Calendar日历类
protect Calendar()构造方法为protect修饰,无法直接创建该对象
常用方法:
public static Calendar getInstance();//使用默认时区和语言环境获得一个日历。返回的 Calendar 基于当前时间,使用了默认时区和默认语言环境。
public final void set(int year,
int month,
int date,
int hourOfDay,
int minute,
int second);//设置字段 YEAR、MONTH、DAY_OF_MONTH、HOUR、MINUTE 和 SECOND 的值。保留其他字段以前的
public int get(int field);//返回给定日历字段的值。在 lenient 模式下,所有日历字段都被标准化。
public final void setTime(Date date)使用给定的 Date 设置此 Calendar 的时间。
public final Date getTime()返回一个表示此 Calendar 时间值(从历元至现在的毫秒偏移量)的 Date 对象。
public abstract void add(int field,
int amount)根据日历的规则,为给定的日历字段添加或减去指定的时间量。例如,要从当前日历时间减去 5 天,可以通过调用以下方法做到这一点:
add(Calendar.DAY_OF_MONTH, -5)。
public long getTimeInMillis()返回此 Calendar 的时间值,以毫秒为单位。
7.1 SimpleDateFormat类
字母 | 日期或时间 | 示例 |
---|---|---|
y | 年 | 2019 |
M | 年中的月份 | 08 |
d | 月中的天数 | 12 |
H/h | 小时 24小时/12小时 | 22/03 |
m | 分钟 | 59 |
s | 秒 | 56 |
S | 毫秒 | 368 |
格式化:Date——>String
使用.format()
public static void main(String[] args) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy MM dd HH:mm:ss");
String format = sdf.format(new Date());
System.out.println(format);
}
//2022 07 27 19:46:30
解析:String——>Date
使用.parse( )
package com.qfedu;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatTest01 {
public static void main(String[] args) throws ParseException {
//格式化
SimpleDateFormat sdf=new SimpleDateFormat("yyyy MM dd HH:mm:ss");
String format = sdf.format(new Date());
System.out.println(format);
System.out.println("________________");
//解析
String s="2022-07-05 14:12:56";
SimpleDateFormat ss=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = ss.parse(s);
System.out.println(parse);
}
}
//2022 07 27 19:52:43
//________________
//Tue Jul 05 14:12:56 CST 2022
8. System类
static void arraycopy(..);//复制数组
static long currentTimeMillis(...);//获取当前系统时间,返回毫秒值
static void gc();//建议jvm启动垃圾回收器回收垃圾
static void exit(int status);//退出jvm,如果参数是0表示正常退出,非0表示异常退出
10. 集合
对象的容器,放不了基本数据类型
可实现数组的功能
和数组的区别:
- 数组长度固定,集合长度不固定
- 数组可以存放基本数据类型和引用类型
1. Collection父接口
特点:代表一组任意类型的对象,无序、无下标
方法:
boolean add(Object o); //添加一个对象
boolean addAll(Collection c); //将一个集合中的所有对象添加到此集合中
void clear(); //清空此集合的所有对象
boolean contains(Object o); //检查此集合中是否包含o对象
boolean equals(Object o); //比较此集合是否与指定集合相等
boolean isEmpty(); //判断集合为空
boolean remove(Object o); //在此集合中移除o对象
int size(); //返回此集合中的元素个数
Object[] toArray(); //将此集合转换成数组
2. List子接口
特点:有序、有下标、元素可重复
方法:
void add(int index,Object o); //在index位置插入对象O
boolean addAll(int index,Collection c); //将一个集合中的元素添加到此集合中的index位置
Object get(int index); //返回集合中指定位置的元素
List subList(int fromIndex,int toIndex); //返回fromIndex和toIndex之间的集合元素
E set(int index,E element); //用指定元素替换列表中指定位置的元素(可选操作)。
3. List实现类
3.1 ArrayList–继承AbstractList–继承AbstractCollection
数组结构实现,查询快、增上慢 必须开辟连续空间
jdk1.2版本,运行效率快,线程不安全
3.2 Vector
数组结构实现,查询快、增上慢
jdk10.版本,运行效率慢,线程安全
3.3LinkedList --继承 AbstractSequentialList
链表结构,增删快、查询慢 无须开辟连续空间
3. 泛型
泛型默认为上限
//泛型的上限
public static void printCollection01(Collection<? extends Studenet> c){}
//泛型的下限
printCollection02(Collection<? super Studenet> c){}
//泛型的上下限不是重载
4. Collections工具类
集合工具类,定义了除了存取之外的集合常用方法
方法:
public static void reverse(List<?> list);//反转集合中元素的顺序
public static void shuffle(List<?> list);//随机重置集合元素的顺序
public static void sort(List<?> list);//升序排序(集合必须实现Comporable接口)
5. Set接口
无序、无下标、不可重复
全部继承Collection的方法
遍历:
-
foreach
-
迭代器
Set set=new HashSet(); set.add("1"); set.add("2"); set.add("3"); //set集合遍历: 1. 迭代器 Iterator iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //2. 增强for循环 for (Object o : set) { System.out.println(o); }
5.1 HashSet❤️
基于HashCode实现元素不重复
❤️底层是HashMap
不保证存放与取出顺序一致
方法:
Set set=new HashSet();
//boolean add(Obj e); 添加成功返回true,否则返回false
System.out.println(set.add("1"));
//boolean remove(Obj e); 返回删除的boolean值
System.out.println(set.remove("2"));
练习题
package Com.qfedu;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
//定义-个Employee类,该类包含: private成员属性name,age 要求:
//1.创建3个Employee对象放入HashSet中
//2.当name和age的值相同时,认为是相同员工,不能添加到HashSet集合中
public class SetTest03 {
public static void main(String[] args) {
Set set=new HashSet();
set.add(new Employee("张三",45));//ok
set.add(new Employee("张四",15));//pk
set.add(new Employee("小三",41));//ok
set.add(new Employee("张三",45));//No
System.out.println(set);
}
}
class Employee{
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && name.equals(employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
//结果:
[Employee{name='小三', age=41}, Employee{name='张四', age=15}, Employee{name='张三', age=45}]
- 定义一一个Employee类,该类包含: private成员属性name,sal,birthday(MyDate类
.型),其中birthday为MyDate类型(属性包括: year, month, day),要求:
1.创建3个Employee放入HashSet中
2.当name和birthday的值相同时,认为是相同员工,不能添加到HashSet集合中
5.2 LinkedHashSet
底层为LinkedHashMAp,为双向列表,有序
练习题:
Car类(属性:name,price),
如果name和price一样,
则认为是相同元素,就不能添加。
package Com.qfedu;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
public class SetTest05 {
public static void main(String[] args) {
/*
Car类(属性:name,price),
如果name和price一样,
则认为是相同元素,就不能添加。
*/
Set set=new LinkedHashSet();
set.add(new Car("比亚迪",500000));
set.add(new Car("比亚迪",452000));
set.add(new Car("比亚迪",500000));
set.add(new Car("五零",500000));
System.out.println(set);
}
}
class Car{
private String name;
private long privace;
public Car(String name, long privace) {
this.name = name;
this.privace = privace;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getPrivace() {
return privace;
}
public void setPrivace(long privace) {
this.privace = privace;
}
@Override
public String toString() {
return "\nCar{" +
"name='" + name + '\'' +
", privace=" + privace +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return privace == car.privace && Objects.equals(name, car.name);
}
@Override
public int hashCode() {
return Objects.hash(name, privace);
}
}
//结果:
[
Car{name='比亚迪', privace=500000},
Car{name='比亚迪', privace=452000},
Car{name='五零', privace=500000}]
5.3 TreeSet
实现自动排序
手动排序:
-
实现Comporable接口,重写ComparTo方法
public class homework01 { public static void main(String[] args) { //Set Set<Person> personSet = new TreeSet<>(); //当pid与anme相同时,认为时同一个人 //按照年龄升序排序,当年龄相同时按照sallary升序排序 personSet.add(new Person(01, "张三", 45, '男', 1000)); personSet.add(new Person(02, "张杰", 35, '男', 40000)); personSet.add(new Person(03, "小艾", 12, '女', 3500)); personSet.add(new Person(01, "张三", 78, '女', 1000)); personSet.add(new Person(05, "赵小花", 12, '女', 6000)); System.out.println(personSet); System.out.println("-------------------------------"); } } /* class Person implements Comparable<Person> { //✔️equals和hashCode实现去重 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return pid == person.pid && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(pid, name); } //✔️compareTo实现排序 @Override public int compareTo(Person o) { int num1 = this.age - o.age; int num2 = num1 == 0 ? this.sallary - o.sallary : num1; return num2; } } */
-
继承Compartor类
实现排序
6. Map接口
Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
key与value存在一对一的关系,key不可重复,value可重复
key与value都可为null
方法:
V put(K key,V value); //添加,key重复就覆盖
V remove(Object o); //根据键删除键值对
void clean(); //清空
boolean containskey(Object key); //判断集合是否包含指定的键
boolean containsValue(Object value); //判断集合是否包含指定的值
boolean isEmpty(); //是否为空
int size(); //集合长度
获取:
V get(Object key); //根据键获取值
set<k> keySet(); //获取所有键的集合
Collection<v> values(); //获取所有值的集合
set<Map.Enty<k,v>>entrySet();//获取所有键值对对象的集合
Map集合的实现类:
HashMap、LInkedeHashMap、TreeMap
Map遍历:
package Com.qfedu;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest02 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("天运","lf");
map.put("nc","lf");
map.put(null,"lf");
System.out.println(map);
//map集合的遍历
//1、先找到键的集合,在找值
Set set = map.keySet();
//1、增强for
for (Object o : set) {//找到键
System.out.println(o+"-"+map.get(o));
}
System.out.println("------------");
//2、迭代器
Iterator iterator1 = set.iterator();
while (iterator1.hasNext()){
Object key = iterator1.next();
System.out.println(key+":"+map.get(key));
}
System.out.println("-----------");
//方法二:直接找到键值对
Set entryset = map.entrySet();
//1、增强for
for (Object entry : entryset) {
Map.Entry m=(Map.Entry)entry;
System.out.println(m.getKey()+":"+m.getValue());
}
System.out.println("-----------");
//2、迭代器
Iterator iterator = entryset.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
Map.Entry m=(Map.Entry)next;
System.out.println(m.getKey()+":"+m.getValue());
}
}
}
Map的put方法的返回值
public class MapTest03 {
public static void main(String[] args) {
Map<String,String> map=new HashMap();
//put方法的返回值为key上次的value,若没有上次的value就返回null
System.out.println(map.put("rede", "花朵"));
System.out.println(map.put("rede", "祖国的花朵"));
}
}
//结果
null
花朵
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urEIgBhY-1660055903804)(https://s2.loli.net/2022/08/07/CT84kxEUcsFYeKv.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ra8P1nP-1660055903805)(https://s2.loli.net/2022/07/29/QFVik17fTMC9XLE.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6nqdg6d-1660055903806)(https://s2.loli.net/2022/08/07/pLUtYZFDlRCEPiQ.png)]
11. 异常
1. 异常的概念:
-
java语言中,将程序执行中发生的不正常情况称为“异常”(开发中的语法和逻辑错误不算)
-
执行的异常:
-
error:JVM无法解决的严重问题。例如栈溢出
-
exception:编程错误或偶然的外在因素导致的一般性问题,可处理
*运行时异常
*编译时异常
-
2. 异常的体系图
-
NullPointException:空指针异常
-
ArithmeticException:算术异常
-
ArrayIndexOfBoundsException:数组下标越界异常
-
ClassCastException:类型转换异常
-
NumberFormatException:数字格式不正确异常
-
InputMismatchException:表明获取的标记与期望类型的模式不匹配,或者该标记超出期望类型的范围。
while (true) { Scanner sc=new Scanner(System.in); System.out.println("请输入一个整数"); try { int i = sc.nextInt(); System.out.println(i); break; } catch (InputMismatchException e) { System.out.println("输入有误,请输入一个整数"); } }
结果:
编译时异常(必须处理 throws或try-catch-finally)
编译期间就必须处理,否则代码不能通过编译
常见编译型异常
- SQLException //操作数据库时,查询表发生异常
- IOEXCEPTION//操作文件时发生异常
- FileNotFoundException//操作一个不存在的文件,发生异常
- ClassNotFoundException//加载类,类不存在,发生异常
- EOFException//操作文件,达到文件末尾时发生异常
- IIlegalArguementException//非法参数异常
3. 异常的处理
一般使用try-catch-(finslly)机制解决异常
try{
可能会出现错误的的代码
}catch(异常的名称 异常变量){
对异常进行处理
}finally{
不管是否出现异常,都会执行,且优先执行
}
-
try-catch异常处理
package com.Test.Exception; import java.util.Scanner; //如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止 public class TryCatchException { public static void main(String[] args) { while (true) { Scanner sc=new Scanner(System.in); System.out.println("请输入一个整数"); try { int i = sc.nextInt(); System.out.println(i); break; } catch (java.lang.Exception e) { System.out.println("输入有误,请输入一个整数"); } } } }
-
throws异常处理
格式:
method() throws 异常名{ 方法体; }
public class Person { public void sum() throws java.lang.Exception { int a=10,b=0; int s=a/b; } }
注意:
- 子类重写父类的方法时,子类抛出的异常类型要么和父类一样,要么是父类类型异常的子类型
- 在throws过程中,如果有try-catch,就相当于处理异常,不必throws
4. Throwable的成员方法
public Strng getMessage();//返回throwable的详细信息
public String toString();//返回可抛出的简短描述
public void printStackTrace();//把异常错误信息输出在控制台
5. 自定义异常
步骤:
- 定义类:自定义异常类名继承Exception 或RuntimeException
- 如果继承了Exception ,属于编译异常
- 如果继承了RuntimeException,属于运行异常
//要求范围在18-120之间,否则抛出自定义异常
public static void main(String[] args) {
int age = 156;
if (age > 120 || age < 18) {
throw new AgeException("年龄需要在18-120之间");
}
System.out.println("你的输入正确");
}
}
//自定义异常
class AgeException extends RuntimeException{
public AgeException(String message){
super(message);
}
}
//结果:
Exception in thread "main" com.Test.Exception.AgeException: 年龄需要在18-120之间
at com.Test.Exception.Person.main(Person.java:13)
❤️❤️一般情况下,自定义异常继承RuntimeException,把自定义异常做成运行异常,好处是可以使用默认的处理机制,比较方便
💜当捕获有多层捕获时,越向下异常类型越大💜
throw和throws的区别
意义 | 位置 | 后面跟的东西 | 使用场景 | |
---|---|---|---|---|
throws | 异常处理的一种方式 | 方法头部 | 异常类型 | 所有异常的申明 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 | 具体异常的处理 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JucxdnSj-1660055903807)(https://s2.loli.net/2022/08/01/HPbeIDLVugdrBsY.png)]
注意:子类重写父类带有throws申明的函数时,throws抛出的异常要在父类的可控范围内
方法中遇到throw,当前方法结束
总结:
练习题
- 接收命令行的两个参数(整数),计算两数相除cal(int n1,int n2),对数据格式不正确(NumberFormatException)、缺少命令行参数(ArrayIndexOfBoundsException)
÷0进行异常处理(ArithmeticException)
package com.Test.Exception;
import java.util.Scanner;
public class Demo01 {
//接收命令行的两个参数(整数),计算两数相除cal(in n1,int n2)
//对数据格式不正确(NumberFormatException)、缺少命令行参数(ArrayIndexOfBoundsException)
// 、÷0进行异常处理(ArithmeticException)
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入:");
String string = sc.nextLine();
String[] s = string.split(" ");
int[] a = new int[s.length];
//判断个数是否正确
try {
if (a.length != 2) {
throw new ArrayIndexOutOfBoundsException("参数不够");
}
//将接收到的数转换为整数
int n1 = Integer.parseInt(s[0]);
int n2 = Integer.parseInt(s[1]);
System.out.println("最终结果为:"+cal(n1, n2));
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
} catch (NumberFormatException e) {
System.out.println("数据不是整数");
} catch (ArithmeticException e) {
System.out.println("分母不能为0");
}
//当捕获有多层捕获时,越向下异常类型越大
}
}
public static int cal(int n1, int n2) {
return n1 / n2;
}
}
-
写出下面代码的结果
package com.Test.Exception; public class Demo02 { public static void func(){ try { throw new RuntimeException(); } finally { System.out.println("B"); //¹ } } public static void main(String[] args) { try { func(); //进入方法 System.out.println("A"); //方法有错误,不在执行此行 } catch (java.lang.Exception e) { System.out.println("C"); //² } System.out.println("D"); //³ } }
结果: B C D
-
写出下面代码的结果
package com.Test.Exception;
public class Demo03 {
public static void main(String[] args) {
try {
showExce();
System.out.println("A");
} catch (java.lang.Exception e) {
System.out.println("B"); //1
}finally {
System.out.println("C"); //2
}
System.out.println("D"); //3
}
public static void showExce() throws java.lang.Exception {
throw new java.lang.Exception();
}
}
结果:
B
C
D
- 下面题的结果
public class TestException02 {
public static void main(String[] args) {
System.out.println(a());
}
public static int a() {
try {
System.out.println("000");
return -1;
} catch (java.lang.Exception e) {
return 1;
} finally {
System.out.println("finally");
return 0;
}
}
结果:
000
finally
0
- 下面代码的结果
public static void main(String[] args) {
System.out.println(a());
}
public static int a() {
try {
int a=12;
System.out.println("try");
System.out.println(a/0);
return -1;
} catch (Exception e) {
System.out.println("catch");
return 1;
} finally {
System.out.println("finally");
return 0;
}
}
//结果
000
catch
finally
0
- 下面代码的结果
package com.qfedu;
public class TestException03 {
public static void main(String[] args) {
System.out.println(getNum());
}
public static int getNum() {
int a=12;
try {
System.out.println("try");
System.out.println(a/0);
return -1;
} catch (Exception e) {
System.out.println("catch");
System.out.println(a);
return 0;
} finally {
System.out.println("finally");
System.out.println(a+=10);
}
}
}
//结果
try
catch
12
finally
22
0
12. 线程
程序:指令的集合
进程:运行的程序
线程:由进程创建,是进程的实体。一个进程可以有多个线程,cpu的基本调度单位。例如:迅雷是一个进程,当中的多个下载任务是多个线程
进程之间不能共享资源,同进程的线程可以共享资源。
并发:单核cpu同时执行多个线程,来回切换
并行:多核cup同时执行多个线程
1. 创建线程的两(3)种方式
- 继承Thread类,重写run( )方法;创建Tread对象,调用start()方法。
- 实现Runable接口,重写run( )方;创建Runnbale对象,调用start()方法
- (线程池)
2. 线程优先级——IllegalArgumentException(超出范围)
线程优先级高,cpu时间片多
当设置的优先级超出(1-10)的范围,运行时异常-IllegalArgumentException
三个常量,10个值;MAX_PRIORITY=10、MINORITY=1,NORMALPRITY=5
设置获取优先级:
public final int getPriority( );
public final int setPriority(int newPriority ); //1~10
3.守护线程
线程对象的setDeamon(true)
设置当前线程为守护线程
-
位置:当前线程的start()之前
-
作用:被守护的线程结束后,守护线程可以不必执行完毕,提前结束。提高程序的效率
-
只能守护主线程
4. 线程名
setName(String name);
//构造方法设置名称
public Thread(Runnable target,String name);
public Thread(String name);
5. 线程状态
6. 常用方法
6.1 sleep休眠 interruptionException-中断异常(不释放线程锁)
- 线程的静态方法
- wait()是object的方法
public static void sleep(long millis);//使正在执行的线程停留指定的ms
public static void sleep(long millis,Long 纳秒);//使正在执行的线程停留指定的毫秒+纳秒
6.2 线程让步(放弃)
public static void yield();//线程主动放弃cpu的执行资源,让其他线程与自己抢占cpu,可能出现其他线程没有抢到cpu资源
6.3 插队线程 interruptionException
public final void join();//等待这个线程执行完之后再执行
7.线程同步
lock
sychnorixed:
- 同步代码块 ——任何非空对象
- 同步方法 —— this
- 静态同步方法——当前类对象
Synchorized使用:会自动释放锁
- 同步代码块
synchorized(对象){ //得到对象的锁,才能操作代码块
//需要被同步的代码
}
- synchorized可以放在方法的申明处,表示整个方法为同步方法
public synchorized void m(String name){//当前对象this
//需要被同步的代码
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIBk0aOz-1660055903808)(https://s2.loli.net/2022/08/03/l2cjaAgUdpeODYH.png)]
锁:任意的非空对象
同步方法:this
静态同步方法:锁的对象为类
8. 死锁
9. 线程通信
10. 线程池
避免频繁的创建和销毁线程
10.1 获取线程池
常用的线程池接口和类(java.util.concurrent)
- Executor:线程池的顶级接口
- ExecutorService:线程池的接口,可通过submit(Runnable task)提交任务代码
- Excutors工厂类:通过此类可以获得一个线程池
- 通过newFixedThreadPool(int nThreads)获取固定数量的线程池
- 通过newCachedThreadPool)获得动态数量的线程池,如不够则创建新的,无上限。
10.2 Callable接口
public interface Callable{
public V call( ) ;//与run( )类似
}
10.3 Future接口
异步接收ExecutorService.submit( )所返回的状态结果,包含了call( )的返回值
方法: V get ()以阻塞形式等待Future中的异步处理结果(call ()的返回值)
10.4 线程池举例
- callable:
package com.qfedu.pool;
import java.util.concurrent.*;
public class Test01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
//以callable接口方式创建匿名内部类
Callable<Integer> callable = new Callable<Integer>() {
@Override
//重写callable接口的call()方法,与run()方法类似
public Integer call() throws Exception {
int count=0;
for (int i = 0; i <=100; i++) {
count+=i;
}
return count;
}
};
//创建任务,将实现callable接口的类传入
FutureTask<Integer> task = new FutureTask<>(callable);
// Thread thread = new Thread(task);
//将任务加入到线程池中去运行
executorService.submit(task);
//submit会返回一个值
Integer sum = task.get();
System.out.println(sum);
//关闭线程池
executorService.shutdown();
}
}
- Runnable:
package com.qfedu.pool;
import java.util.concurrent.*;
//卖票
public class Test03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//创建Runnable的匿名内部类
Runnable runnable = new Runnable() {
int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket <= 0) {
break;
}
System.out.println(Thread.currentThread().getName() + "卖了" + (ticket--) + "张票");
}
}
};
for (int i = 0; i <= 5; i++) {
pool.execute(runnable);
}
//关闭线程池
pool.shutdown();
}
}
11. lock 接口
比synchorized结构更灵活。显式定义
常用方法:
void lock( ):获得锁,如果锁被占用,就等待
boolean tryLock( ):尝试获得锁
void unlock( ):释放锁
实现类:
-
重入锁:
lock锁的实现类,与synchorized都有互斥功能
ReentrantLock:
package com.qfedu.pool; import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; public class LockTest { //实现重入锁 public static void main(String[] args) { //创建线程池 ExecutorService executorService = Executors.newFixedThreadPool(4); //创建重入锁 ReentrantLock lock = new ReentrantLock(); //创建callable接口的匿名内部类 Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { int a = 10; int b = 20; try { lock.lock(); a+=b; }finally { lock.unlock(); } return a; } }; //创建任务 FutureTask<Integer> task = new FutureTask<>(callable); //将任务加载到线程池 executorService.submit(task); //得到返回值 try { System.out.println(task.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //关闭线程池 } }
-
读写锁
ReentrantReadWriteLock:
一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。
支持多次分配读锁,使多个读操作可以并发执行。
12. 生产者消费者
-
送奶工——牛奶——消费者
package com.qfedu; public class Costumer_Poductor { public static void main(String[] args) { Container container = new Container(); new poductor(container).start(); new custormer(container).start(); } } //生产者 class poductor extends Thread { Container container; public poductor(Container container) { this.container = container; } @Override public void run() { for (int i = 1; i <= 100; i++) { container.put(new Milk(i)); System.out.println("产生了第" + i); } } } //消费者 class custormer extends Thread { Container container; public custormer(Container container) { this.container = container; } @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("消费了第--->" + container.pop().id); } } } //产品--- 牛奶 class Milk { int id; public Milk(int id) { this.id = id; } } //容器---奶箱 class Container { Milk[] milks = new Milk[10]; int count = 0; //送奶工放牛奶 //通知消费者等待 public synchronized void put(Milk m) { //如果产品数量等于容器大小,就让生产者停止生产 if (count == milks.length) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //让生产者生产 milks[count] = m; count++; //做好就通知消费者消费 this.notifyAll(); } //消费者消费牛奶 //通知生产者生产牛奶 public synchronized Milk pop() { //判断是否可以消费 //容器中没有产品就等待 if (count == 0) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //消费者消费 count--; Milk milk = milks[count]; //使用完就通知生产 this.notifyAll(); return milk; } }
-
面包厂生产、消费者
package com.qfedu; public class Customer_Poductor02 { public static void main(String[] args) { BreadContioner breadContioner = new BreadContioner(); breadContioner.setCurrentNum(100); new Poductor(breadContioner, 50).start(); new Poductor(breadContioner, 40).start(); new Poductor(breadContioner, 10).start(); new Customer(breadContioner, 78).start(); new Customer(breadContioner, 20).start(); new Customer(breadContioner, 5).start(); } } //生产者 class Poductor extends Thread { BreadContioner breadContioner; private int num; public Poductor(BreadContioner breadContioner, int num) { this.breadContioner = breadContioner; this.num = num; } @Override public void run() { breadContioner.put(num); } } //消费者 class Customer extends Thread { BreadContioner breadContioner; private int num; public Customer(BreadContioner breadContioner, int num) { this.breadContioner = breadContioner; this.num = num; } @Override public void run() { breadContioner.pop(num); } } //商品 //面包厂 class BreadContioner { final int MAX_NUM = 500;//仓库容量 int currentNum;//现存个数 public int getCurrentNum() { return currentNum; } public void setCurrentNum(int currentNum) { this.currentNum = currentNum; } //生产者生产面包 public synchronized void put(int num) { //当需要生产的数+现存的数>容量 停止生产 等待消费 if ((num + currentNum) > MAX_NUM) { //等待消费 try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //生产面包 currentNum += num; System.out.printf("生产了%d个面包,仓库有%d个面包\n", num, currentNum); //生产完毕,释放,通知消费者 可以消费了 notifyAll(); } //消费者消费面包 public synchronized void pop(int num) { //当需要消费的个数<现存个数 停止消费,去生产 if (num > currentNum) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //消费者消费面包 currentNum -= num; System.out.printf("消费者消费了%d个面包,还剩%d个面包\n", num, currentNum); notifyAll(); } }
-
13.死锁
-
死锁生成的原因:
?
13. IO流
1. File
一个文件或文件夹
-
file的构造方法
File(String pathname)
通过将给定的路径名字符串转换为抽象路径名来创建新的File
实例File(File parent, String child)
从父抽象路径名和子路径名字符串创建新的File
实例。File(String parent, String child)
从父路径名字符串和子路径名字符串创建新的File
实例
-
file.separator
:windows为反斜杠,unix为斜杠 :可实现跨平台 -
字节流
-
字节节点流
-
字节过滤流
- 字符流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9ZbLVvo-1660055903814)(C:/Users/骆天运/AppData/Roaming/Typora/typora-user-images/image-20220809222954644.png)]
-
字符过滤流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J4Q7exNj-1660055903815)(https://s2.loli.net/2022/08/09/7TablZR31Q5iCG8.png)]
空接口:标记Java类拥有某种能力
tcp/ip模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-05UnnFkz-1660055903817)(https://s2.loli.net/2022/08/09/98g2VrLwd3y7fkz.png)]
InetAddress类
14.网络编程
长连接、短连接
tcp:
Udp
三次握手
四次挥手
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nPunJMgU-1660055903818)(https://s2.loli.net/2022/08/09/n3Qx94HzPfOrpbM.png)]
开发步骤:
建立通信连接(会话) :
●创建ServerSocket,指定端口号
●调用accept等待客户端接入
●客户端请求服务器:
创建Socket,指定服务器IP +端口号
●使用输出流,发送请求数据给服务器
使用输入流,接收响应数据到客户端(等待)
●服务器响应客户端:
●使用输入流,接收请求数据到服务器(等待)
●使用输出流,发送响应数据给客户端
15.注解与反射
1.注解:可被程序读取
-
内置注解
- @override:定义在java.lang.Override中,用于子类 重写父类的属性或者方法
- @Deprecated:定义在java.lang.Deprecated中,表示此方法已经过时,不推荐使用
- @SuppressWarnings():定义在java.lang.SuppresWarings中,用来一致编译使得额警告信息
- 参数:all、unchecked、value={“unchecked”,“deprecation”}
-
元注解:用来注解其他注解,java定义了4个标准的meta-annotation类型
@Target:描述注解的使用范围
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期
@Document:说明该注解被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
-
定义注解:使用@interface关键字,注解中只能包含属性
2. 反射机制:传统的方式不能创建对象
3. 类对象
类加载的产物,封装了一个类的所有的信息(类名、父类、接口、属性、方法、构造方法)
3.1 获取类对象
-
通过类的对象获取类对象
Student s=new Student();
Class c=s.getClass();
-
通过类名获取类对象
class c=Student.Class;
-
通过静态方法获取类对象
Class c=Class.forNAme(包名.类名);
public class TestClass {
public static void main(String[] args) {
//获取类对象
//new对象
Student student = new Student();
Class<? extends Student> c1 = student.getClass();
//类名.class
Class<Student> c2 = Student.class;
//Class.forName(包名.类名)
try {
Class<?> c3 = Class.forName("com.ltyedu.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3.2 常用方法
3.2.1 属性
package com.ltyedu;
import java.lang.reflect.Field;
import java.util.Arrays;
public class TestGetFileds {
public static void main(String[] args) {
//创建类对象
Class<Student> c = Student.class;
//获得类对象的名称
String name = c.getName();
System.out.println(name);
//com.ltyedu.Student
//获取类对象的名不要包名
String simpleName = c.getSimpleName();
System.out.println(simpleName);
//Student
//获取类对象的包名
Package aPackage = c.getPackage();
System.out.println(aPackage);
//package com.ltyedu
//获取类对象的父类的class
Class<? super Student> superclass = c.getSuperclass();
System.out.println(superclass);
//class com.ltyedu.person
//获取类对象接口的class数组
Class<?>[] interfaces = c.getInterfaces();
System.out.println(Arrays.toString(interfaces));
//[interface java.io.Serializable, interface java.util.RandomAccess]
System.out.println("_____________________");
//获取本类以及父类的所有public修饰的属性
Field[] fields = c.getFields();
System.out.println(Arrays.toString(fields));
//[public int com.ltyedu.Student.sid, public java.lang.String com.ltyedu.person.pass]
System.out.println("______________________");
//获取本类以及父类指定public修饰的属性
Field name1 = null;
try {
name1 = c.getField("pass");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
System.out.println(name1);
//public int com.ltyedu.Student.sid
System.out.println("❤️❤️❤️❤️❤️❤️");
//获取本类的所有的属性 包括private
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//public int com.ltyedu.Student.sid
//private java.lang.String com.ltyedu.Student.name
//int com.ltyedu.Student.age
//java.lang.String com.ltyedu.Student.school
//protected char com.ltyedu.Student.sex
//获取本类的指定属性,可以为private
Field name2 = null;
try {
name2 = c.getDeclaredField("name");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
System.out.println(name2);
//private java.lang.String com.ltyedu.Student.name
}
}
student:
package com.ltyedu;
import javax.imageio.plugins.jpeg.JPEGImageReadParam;
import java.io.Serializable;
import java.util.RandomAccess;
class Student extends person implements Serializable, RandomAccess {
public int sid;
private String name;
int age;
String school;
protected char sex;
public Student() {
}
public Student(String name, int age, String school, char sex) {
this.name = name;
this.age = age;
this.school = school;
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", school='" + school + '\'' +
", sex=" + sex +
'}';
}
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 String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
person:
package com.ltyedu;
public class person {
private int id;
public String pass;
}
3.2.2 方法:
public class TestGetMethods {
public static void main(String[] args) {
//创建类对象
Class<Student> c = Student.class;
//获取本类对象以及父类对象的所有public修饰的方法
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("❤️❤️❤️❤️❤️❤️");
//获取本类以及父类指定方法名与参数类型的public对象
try {
Method setName = c.getMethod("setName", String.class);
System.out.println(setName);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println("❤️❤️❤️❤️");
//获取本类的所有方法,包括private修饰的方法
Method[] declaredMethods = c.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
//public void com.ltyedu.Student.setSex(char)
//public void com.ltyedu.Student.setAge(int)
//public int com.ltyedu.Student.getAge()
//public void com.ltyedu.Student.setSchool(java.lang.String)
//public java.lang.String com.ltyedu.Student.getSchool()
//public char com.ltyedu.Student.getSex()
//private void com.ltyedu.Student.say()
//public java.lang.String com.ltyedu.Student.toString()
//public java.lang.String com.ltyedu.Student.getName()
//public void com.ltyedu.Student.setName(java.lang.String)
System.out.println("❤️❤️❤️❤️❤️");
//获取本类的指定方法名与参数类型的方法,包括private修饰的方法
Method say = null;
try {
say = c.getDeclaredMethod("say");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println(say);
//private void com.ltyedu.Student.say()
}
3.2.3 类对象方法的调用
public class TsetMethod_invoke {
public static void main(String[] args) {
//类对象的调用
//1. 获取类对象
//2. 通过m= c.getDeclaredMethod(String name,Class<?>... parameterTypes>获取类对象的方法
//3. 使用Method对象的invoke()方法,invoke就是调用的意思,代表使用类对象调用该方法 m.invoke();
Class<Student> c = Student.class;
try {
Method w = c.getDeclaredMethod("writeeer", String.class, String.class, int.class);
// 方法对象的setAccessible(boolean)使用反射修改方法的访问权限级别
// 原因是调用的private方法jvm找不到,设置为true就可以修改可访问
w.setAccessible(true);
Object invoke = w.invoke((new Student()), "helo", "java", 200);
System.out.println(invoke);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
/**
* private String writeeer(String a,String b,int c){
* return a+b+c;
* }
*/
}
}
注意:存在精确匹配问题
public void setAge(int age) {
this.age = age;
}
public void setAge(Integer age) {
this.age = age;
}
//两者可以同时存在
c.getDeclaredMethod("setAge",int.Class);//调用的是int
c.getDeclaredMethod("setAge",Integer.Class);//调用的是Integer
3.2.4 修饰符编码与解码
package com.ltyedu;
//修饰符编码问题
import javax.management.monitor.Monitor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class TestModification {
public static void main(String[] args) {
Class<Student> c = Student.class;
Field[] declaredFields = c.getDeclaredFields();
for (Field f : declaredFields) {
// 属性名 属性的修饰符编码 属性的修饰符解码
System.out.println(f.getName()+"\t"+f.getModifiers()+"\t"+ Modifier.toString(f.getModifiers()));
}
}
}
java中默认的构造器是pulic
原因:
- 被非同包的类new()创建
- 反射获取
- 获取16进制的数值
每一个数字只会有一种情况