javaSE基础

文章目录

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. 循环结构

循环:

  1. do循环

  2. do while循环

  3. 字符串的.equalsIgnoreCase( )方法:忽略大小写的比较

  4. 跳转语句

  5. continue 适用于跳出循环

    • break适用于跳出循环与switch case
    • return终止某个方法
  6. for( ; ; )的三个表达式问题——只适用于循环次数确定😊

    for(循环变量初始化;循环条件;迭代语句){
        循环体;
    } 
    注意:for循环会出现溢出
    
    跳转语句:
    标签名:循环结构{
            break 标签名;
    }
    

3. 数组

❤️❤️Arrays.toString(int[] a):打印数组的值

1. 一维数组

  • 数组的定义

    1. int[] arr={10,20} int arr[]={10,20}
    2. int arr[] =new int[10]
  • 数组遍历:

    1. for循环遍历 (itar)
    2. 增强for循环 (iter)
  • Scanner获取参数的方法:

    1. sc.next( ) 获取字符串
    2. sc.nextInt(8) 转换为8进制输出
    3. sc.nextLine( )自动屏蔽空格
  • 索引越界:ArrayIndexOutofBoundsException💜💜

2. 二维数组

  1. 二维数组的声明:
    int[][] array
    int array[][]
    int[] array[]
    
  2. 二维数组的初始化:

    • 动态初始化
    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}
    }
    
  3. 二维数组的遍历

    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();
            }
    
  4. 二维数组的操作:俄罗斯方块的变换、输出(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. 数组练习题

  1. //键盘输入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);
    
        }
    }
    
    
  2. 冒泡排序与选择排序

    冒泡排序:将相邻位置的元素比较大小,大的与小的换位置

    选择排序:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。

    //键盘输入数据,冒泡排序
    //选择排序
    
    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并列

  • 调用方法时优先执行方法内部代码,结束后返回到调用处

  • 定义方法需要关注的两点:

    1. 返回值类型
    2. 参数
  • 方法的运行区:栈内存

  • 方法的好处:

    • 提高代码复用性
    • 提高代码可读性
    • 维护性、升级成本
  • 方法递归:(递归的出口)

    1. 斐波那契数列
    2. n的阶乘

可变长参数

  1. 可变长参数 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 构造方法();
  • 使用对象:使用成员变量: 对象名.成员变量名;

​ 使用成员方法: 对象名.方法名();

  1. 成员变量与局部变量的区别
局部变量成员变量
定义位置方法或者方法内的结构中类中方法外的变量
默认值无默认值。先初始化后使用与数组相同,有0值
使用范围从定义行到包含其结构结束对象存在则存在
命名冲突不能与局部变量重名不能与成员变量重名,可与局部变量重名,局部变量优先
  1. this关键字://解决局部变量隐藏成员变量

方法的形参与成员变量同名时,不带this的为局部变量(形参)

不同名时,不带this的为成员变量

  1. 方法重载:一个类中定义的多个方法之间的关系
  • 同一个类中的多个方法的方法名相同,参数列表不同(个数、顺序、类型)
  • 与访问修饰符、返回值类型无关
    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");
    }
  1. 构造方法:用于对象的初始化
  • 名称与类名完全相同
  • 没有返回值类型❤️
  • 创建对象时触发构造方法的调用,不可通过句点手动调用
若没有定义带参方法,编译器默认提供无参构造方法
一旦定义了带参构造方法必须定义无参构造方法
  1. 构造方法的重载

    多个构造方法的方法名与类名相同,无返回值类型,方法参数列表不同(个数、顺序、类型)

  2. this两种使用

    1. this.name: 对象的属性
    2. 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

  1. 实现方法:

    ​ 私有化(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():调用父类的无参构造方法,必须在方法体的首行(显式书写/隐式书写)

superthis
super.属性 :调用父类成员变量this.属性:本类成员变量
super.方法 :调用父类成员方法this.方法:子类方法
super()/super(参数) :调用父类构造方法this()/this(参数):调用本类构造方法

❤️❤️this()/this(实参)与super()/super(参数)在同一个子类的构造方法中不能同时书写

4.访问特点

​ 子类局部范围查找——>子类成员范围——>父类查找——>报错(不考虑父类的父类…)

5. 多态

——父类引用指向子类对象

1. 多态的的前提

  1. 有继承/实现关系(直接/间接)
  2. 有方法重写
  3. 有父类引用指向子类对象

2.多态中成员访问的特点

  1. 成员变量:编译看左边,执行看左边
  2. 成员方法:编译看左边,执行看右边——有重写

3. 多态中的方法重写

方法重写在子父类之间,方法签名完全相同(方法名、参数列表),重写后的方法的访问修饰符要>=父类的访问修饰符

❤️❤️构造方法不可重写

4. 构造方法

  1. 一个类无法继承他本身——构造递归
  2. 一个类可以继承他不同包的同名类,要写全路径
  3. 构造方法无法继承——>构造方法无法重写

5. 转型

  1. 向上转型:从子——>父 //父类引用指向子类对象

    Animal a=new Cat();
    

    向下转型:从父——>子(强转) //

    Cat cat=(Cat)a;
    
    //可能会出现 类型转换异常   ClassCastException💜💜
    //Dog dog=(Dog)a;   java默认a为Cat类型,不可转换
    //
    

6. 多态的应用

  • 使用父类作为方法的形参实现多态,使方法参数的类型更为宽泛
  • 使父类作为方法的返回值实现多态,使方法可以返回不同子类对象
  1. 避免类型转换异常: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.特点

  1. 抽象类与抽象方法必须使用abstract修饰

    public abstract class  类名{ }
    public abstract void 方法名(){ }
    
  2. 抽象类中不一定有抽象方法,但有抽象方法的一定是抽象类

  3. 抽象类不可实例化——多态

  4. 抽象类的子类——* 重写抽象类中的所有抽象方法

    ​ *是抽象类

2. 抽象类成员特点

  1. 成员变量:可常量可变量

  2. 构造方法:有 但不可实例化,用与子类访问父类数据的初始化

  3. 成员方法:*抽象方法:限定子类必须完成的动作

    ​ *非抽象方法

3. 抽象类的作用

  1. 被子类继承–子类必须重写父类的抽象方法or子类仍然是抽象类
  2. 声明为引用–多态
image-20220725170335309
//抽象类的实现

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

*/

创建对象的过程

​ 如果一个类中同时定义了静态代码块和非静态代码块

image-20220726093048099

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)]

image-20220721073954616

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 局部内部类

  1. 定义在外部类的方法中,作用范围和创建对象范围仅限于当前方法

  2. 局部内部类访问当前外部类的方法中的局部变量时,因为无法保障变量的生命周期与自生相同,变量必须修饰为final jdk1.7后可以不写

3. 匿名内部类

没有类名的局部内部类(特征与局部内部类相同)

  • 拥有继承或实现

  • 优点:减少代码量

  • 缺点:可读性差

  • 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9n08wPR-1660055903785)(https://s2.loli.net/2022/07/29/5SYkAoPfMNn3GJO.png)]

image-20220726120054740

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类的转换

  1. 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);
        }
    
  2. 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 包装类面试题

image-20220726192819712

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RrSuuWCh-1660055903787)(https://s2.loli.net/2022/07/30/Da6sHVpfhvCJo5Z.png)]

4. String类

字符串是常量值,创建后不能改变

String 对象用于保存字符串——一组字符序列

字符串的字符使用Unicode编码,一个字符占两个字节

image-20220727173616342

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();				//返回字符串对象的规范化表示形式。 
image-20220726193324403 image-20220726194535287

4.2 两种创建String对象的区别

方法一:直接赋值 String s="nihao";
方法二:调用构造器 String s2=new String("nihao");

方法一先在常量池找是否有“nihao”的数据空间,如果没有就创建然后指向它,如果有就直接指向,最终s指向常量池
方法二先在堆中创建空间,里面维护了value属性,指向常量池的“nihao“空间。如果常量池中没有,重新创建,如果有,直接指向,最终指向堆中空间地址

4.3 String类面试题

在这里插入图片描述
源码:
在这里插入图片描述

  1. String a="abc";
    String b="abc";
    System.out.println(a.equals(b));	//True  值相同
    System.out.println(a==b);			//true  指向常量池
    
  2. 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
    
  3. 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
    
  4. 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
    
    
  5. 字符串特性

    String a="hello"+"abc";
    创建了几个对象?1String a="hello"+"abc";==>等价于String a=helloabc;
    
  6. 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,变量相加,看堆
    
  7. //下面代码结果是?说明原因
    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)]

image-20220727105753163

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();//将此字符序列用其反转形式取代。
    
image-20220726210359474 image-20220726210643530 image-20220726211100922 image-20220726210643530 image-20220726211100922 image-20220726211237757 image-20220726211237757 image-20220726211434965

4.5 StringBuffer 练习题

image-20220726211948342

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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)]

image-20220727101549788 image-20220727101838872

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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);
image-20220727144641712

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类

字母日期或时间示例
y2019
M年中的月份08
d月中的天数12
H/h小时 24小时/12小时22/03
m分钟59
s56
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

image-20220727154728250

8. System类

		static void arraycopy(..);//复制数组
        static long currentTimeMillis(...);//获取当前系统时间,返回毫秒值
        static void gc();//建议jvm启动垃圾回收器回收垃圾
        static void exit(int status);//退出jvm,如果参数是0表示正常退出,非0表示异常退出

10. 集合

对象的容器,放不了基本数据类型

可实现数组的功能

和数组的区别

  • 数组长度固定,集合长度不固定
  • 数组可以存放基本数据类型和引用类型

image-20220730110703800

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❤️

image-20220728191836851

基于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}]
  1. 定义一一个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

实现自动排序

手动排序:

  1. 实现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;
        }
    }
    */
    
    
  2. 继承Compartor类

实现排序

image-20220730111326212

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
花朵

image-20220728234103576

image-20220729141018357

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urEIgBhY-1660055903804)(https://s2.loli.net/2022/08/07/CT84kxEUcsFYeKv.png)]

image-20220728230624822

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ra8P1nP-1660055903805)(https://s2.loli.net/2022/07/29/QFVik17fTMC9XLE.png)]

image-20220807210718047

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6nqdg6d-1660055903806)(https://s2.loli.net/2022/08/07/pLUtYZFDlRCEPiQ.png)]

11. 异常

1. 异常的概念:

  • java语言中,将程序执行中发生的不正常情况称为“异常”(开发中的语法和逻辑错误不算)

  • 执行的异常:

    • error:JVM无法解决的严重问题。例如栈溢出

    • exception:编程错误或偶然的外在因素导致的一般性问题,可处理

      *运行时异常

      *编译时异常

2. 异常的体系图

image-20220801141407859
  • 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("输入有误,请输入一个整数");
                }
            }
    

    结果:

    image-20220801114616767 image-20220801140419573

编译时异常(必须处理 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;
        }
    }
    

    注意:

    1. 子类重写父类的方法时,子类抛出的异常类型要么和父类一样,要么是父类类型异常的子类型
    2. 在throws过程中,如果有try-catch,就相当于处理异常,不必throws

4. Throwable的成员方法

public Strng getMessage();//返回throwable的详细信息
public String toString();//返回可抛出的简短描述
public void printStackTrace();//把异常错误信息输出在控制台

image-20220725223849969

image-20220725223849969 image-20220725223849969

5. 自定义异常

步骤:

  1. 定义类:自定义异常类名继承Exception 或RuntimeException
  2. 如果继承了Exception ,属于编译异常
  3. 如果继承了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,当前方法结束

总结:

image-20220802082813493

练习题

  1. 接收命令行的两个参数(整数),计算两数相除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;

    }
}
  1. 写出下面代码的结果

    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
    
    
  2. 写出下面代码的结果

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

  1. 下面题的结果
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
  1. 下面代码的结果
  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
  1. 下面代码的结果
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同时执行多个线程

image-20220802103447232

1. 创建线程的两(3)种方式

  1. 继承Thread类,重写run( )方法;创建Tread对象,调用start()方法。
  2. 实现Runable接口,重写run( )方;创建Runnbale对象,调用start()方法
  3. (线程池)

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. 线程状态

image-20220802165330298

6. 常用方法

6.1 sleep休眠 interruptionException-中断异常(不释放线程锁)

  1. 线程的静态方法
  2. 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使用:会自动释放锁

  1. 同步代码块
synchorized(对象){  //得到对象的锁,才能操作代码块
   //需要被同步的代码
}

  1. synchorized可以放在方法的申明处,表示整个方法为同步方法
public synchorized void m(String name){//当前对象this
    //需要被同步的代码
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIBk0aOz-1660055903808)(https://s2.loli.net/2022/08/03/l2cjaAgUdpeODYH.png)]

锁:任意的非空对象

同步方法:this

静态同步方法:锁的对象为类

8. 死锁

9. 线程通信

image-20220803112015547

image-20220803112410051

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 线程池举例

  1. 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();

    }
}

  1. 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. 生产者消费者

  1. 送奶工——牛奶——消费者

    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;
        }
    }
    
    
    1. 面包厂生产、消费者

      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.死锁

  1. 死锁生成的原因:

    ?

13. IO流

image-20220809101232125

image-20220804092316290

image-20220804092336803

image-20220804092441083

image-20220804093702319

1. File

一个文件或文件夹

  1. file的构造方法

    • File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
    • File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
    • File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
  2. file.separator:windows为反斜杠,unix为斜杠 :可实现跨平台

  3. 字节流

    image-20220809222735788

  4. 字节节点流

image-20220809222842036

  1. 字节过滤流

    image-20220809222914857

image-20220809223112054

  1. 字符流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9ZbLVvo-1660055903814)(C:/Users/骆天运/AppData/Roaming/Typora/typora-user-images/image-20220809222954644.png)]

  1. 字符过滤流

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J4Q7exNj-1660055903815)(https://s2.loli.net/2022/08/09/7TablZR31Q5iCG8.png)]

空接口:标记Java类拥有某种能力

image-20220806092027025

image-20220806094051383

tcp/ip模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-05UnnFkz-1660055903817)(https://s2.loli.net/2022/08/09/98g2VrLwd3y7fkz.png)]image-20220806100027620
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进制的数值

每一个数字只会有一种情况
在这里插入图片描述

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值