JavaSE阶段笔记

JavaSE

一.Java编程基础

①.数据类型
  • 基本数据类型

    数值型(int,long)

    字符型(char)

    布尔型(boolean)

  • 引用数据类型

    类(class)

    接口(interface)

    数组

    枚举(enum)

    注解(Annotation)

英文音标汉语数据类型
integer[ˈɪntɪdʒə®]整数数值型
long[lɒŋ]长的数值型
char[tʃɑː®]字符型
class[klɑːs]引用数据类型
interface[ˈɪntəfeɪs]接口引用数据类型
enum枚举引用数据类型
Annotation[ˌænəˈteɪʃn]注解引用数据类型
  • 变量的类型转换
    • 自动类型转换 :
    • 强制类型转换 :目标类型 变量名 = (目标类型)值
②.变量和常量
  1. 变量:在栈内存中开辟一个内存空间,存储数据。数据可变

  2. 常量:在程序中固定不变的值,是不能改变的数据,存储在常量池中

    语法:Java常量定义必须用final关键字修饰

    final 数据类型 常量名 = 值;

③.运算符
  1. 算数运算符

    运算符运算范例结果
    +正号a=3; +a;3
    -负号a=3; -a;-3
    +2+13
    _5-23
    *1*33
    /6/23
    %取模(求余数)8%53
    ++自增(前)a=2; b=++a;a=3,b=3
    ++自增(后)a=2; b=a++;a=3,b=2
    自减(前)a=2; b=–a;a=1,b=1
    自减(后)a=2; b=a–;a=1,b=2

    如果在进行自减或自加运算时,如果运算符(++或–)放在操作数的前面,则是先自增或自减,在进行其他运算。反之,如果运算符放在后面,先进行其他运算然后自加或自减。

  2. 赋值运算符

    运算符运算范例结果
    =赋值a=3;b=2;a=3;b=2;
    +=加等于a=3;b=2;a+=b;a=5;b=2;
    -=减等于a=3;b=2;a-=b;a=1;b=2;
    *=乘等于a=3;b=2;a*=b;a=6;b=2;
    /=除等于a=3;b=2;a/=b;a=1;b=2;
    %=模等于a=3;b=2;a&=b;a=1;b=2;
  3. 比较运算符

    表格中的实例整数变量A的值为10,变量B的值为20

    描述例子
    ==检查如果两个操作数的值是否相等,如果相等则条件为真(A == B)为假。
    !=检查如果两个操作数的值是否相等,如果值不相等则条件为真。(A != B) 为真。
    >检查左操作数的值是否大于右操作数的值,如果是那么条件为真。(A> B)为假。
    <检查左操作数的值是否小于右操作数的值,如果是那么条件为真。(A <B)为真。
    >=检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。(A> = B)为假
    <=检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。(A <= B)为真。
  4. 逻辑运算符

    下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假

    操作符描述例子
    &&称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真(A&&B)为假。
    ||称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真(A||B)为真。
    !称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false!B为真
  5. 位运算符

    操作符描述
    &相对应位都是1,结果为1,否则为1
    |相对应位都是0,结果为 0,否则为 1
    ^相对应位值相同,则结果为0,否则为1
    ~按位取反运算符翻转操作数的每一位,即0变成1,1变成0
    <<按位左移运算符。左操作数按位左移右操作数指定的位数
    >>按位右移运算符。左操作数按位右移右操作数指定的位数
    >>>按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充
④.选择结构语句
  1. if条件语句

    语法:

    if(判断条件){
    	执行语句;
    }
    
  2. if…else…

    语法:

    if(判断条件){
    	执行语句;
    }else{
    	执行语句;
    }
    
  3. switch

    语法:

    switch(控制表达式){
    	case:目标1:
    	执行语句1
    	break;
    	...
    	case:目标n:
    	执行语句n
    	break;
    	
    	default:
    	执行语句n+1
    }
    如果 case 语句块中没有 break 语句时,JVM 并不会顺序输出每一个 case 对应的返回值,而是继续匹配,匹配不成功则返回默认 case
⑤.循环结构语句
  1. while 循环

    语法:

    while(循环条件){
    	执行语句;
    }
    
  2. do…while 循环

    语法:

    do{
    	执行语句;
    }while(循环条件);
    do...while 循环中的执行语句至少执行一次
    
  3. for 循环

    语法:

    for(初始化表达式;循环条件;操作表达式){
    	执行语句;
    }
    
  4. 循环嵌套:一个循环语句的循环体中,在定义一个循环语句

    三种循环语句可以彼此嵌套

  5. 跳转语句

    • break 语句
      • 作用:在switch 语句中用于终止某个case,在循环语句用来跳出整个语句块
    • continue 语句
      • 作用:终止本次循环,执行下一次循环
⑥.数组
  1. 数组的定义

    共三种方式
    数组类型[] 数组名 = new 数组类型[数组长度]
    数组类型[] 数组名 = new 数组类型[]{数组元素};
    数组类型[] 数组名 = {数组元素};
    栗子:
    int[] arr = new int(10);
    int[] arr = new int(){1,2,3,4};
    int[] arr = {1,2,3,4};
    
  2. 数组的本质

    1.数组是一种引用类型
    2.数组是一个简单的数据结构,线性结构。
    3.数组是一个容器,可以用来存储其他元素。数组是可以存储任意数据类型的元素。
    4.数组分为:一维数组,二维数组,三维数组,多维数组…
    5.数组中存储的元素类型是统一的
    6.数组的长度不可改变。数组一旦创建长度是不可变的,固定的。

  3. 内存图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-74ZzrF0N-1603158679418)(C:\Users\谜语菌\Documents\img\数组.jpg)]

  4. 数组的遍历

    String[] arr = {"张三","李四","王五"};
    for(int i =0;i<arr.length;i++){
    	System.out.println(arr[i]);
    }
    
  5. 冒泡排序

    int[] arr = {5,4,9,2,16,43,7,4};
    for(int i =1;i < arr.length;i++){
    	for(int j =0;j<arr.length-1;j++){
    		if(arr[j]>arr[j+1]){
    			int num = arr[j];
    			arr[j] = arr[j+1];
    			arr[j+1] = num;
    			}
    		}
    	}
    for(int i=0;i<arr.length;i++){
    	System.out.println(arr[i]);
    }
    //输出结果:2,4,4,5,7,9,16,43,
    
  6. 多维数组

    1. 二维数组特点
      1、二维数组是一个特殊的一维数组。
      2、特殊的一维数组,特殊在这个一位数组中每一个元素都是"一维数组"。

    2. 二维数组静态初始化:
      Int [][] a = { {} , {} , {} };

    3. 二维数组动态初始化:
      Int[][] a = new int[4][4];

    4. 遍历

      int[][] arr = {{1,2,3},{3,4,5},{6,7,8,}};
      for(int i =0;i<arr.length;i++){
      	for(int j =0;j<arr.length;j++){
      		System.out.print(arr[i][j]+",");
      	}
      }
      //输出结果:1,2,3,3,4,5,6,7,8,
      

二.面向对象

①.面向对象概述
  1. 面向对象的三大特征

    • 封装
    • 继承
    • 多态
  2. 什么是类?

    • 类代表了一类事物,是一个抽象的概念
    • 在现实世界中,对象A与对象B之间有共用特征,进行抽象后总结出一个模板,这个模板称为类
  3. 什么是对象?

    • 对象是实际存在的个体,现实中实际存在
    程序开发过程
    程序员先观察现实世界,在现实世界中寻找对象
    发现所有对象共同的特征
    程序员在大脑中形成一个模板【类】
    java程序员可以通过代码表述一个类
    通过类就可以创建对象
    
  4. 类和对象的关系

    • 类–实例化–>对象(对象又称为实例)
    • 对象–抽象–>类
  5. 举例(加深理解)

    类描述的是对象的共同特征
    共同特征例如:身高特征
    这个身高特征在访问时必须创建对象,通过对象访问这个特征,特征具体到不同的对象值不同.

  6. 一个类主要描述什么信息呢?

    一个类主要描述 状态+行为
    状态信息:姓名,性别,年龄,升高…
    行为信息:吃,喝,玩,乐…
    状态—属性 行为—方法
    类{
    属性:描述对象的状态信息
    方法:描述对象的行为信息
    }

  7. 类的定义

    语法:

    [修饰符列表] class 类名{
    
    }
    
②.方法
  1. 方法的定义

    语法:

    [修饰符]返回值类型 方法名(参数){
    	方法体;
    }
    
    • 修饰符
      可选项,不是必须的。方法的修饰符列表中有static关键字的话,被称为实例变量,可以使用类名.方法名(实参列表)调用
    • 返回值类型
      方法结束后返回的值的类型,如果返回值类型不是void,表示方法结束后必须返回一个具体的值。
    • 方法名
      方法的名称,遵循驼峰命名法
    • 形参列表
      形参是局部变量,形参的个数可以是0-n个,形参之间使用逗号进行分隔,形参中真正起决定作用的是形参的数据类型,方法调用时实际上是给方法传递一个真实的数据,称为实际参数,简称实参。
      实参和形参必须满足,数量相同,数据类型相同,两个条件
  2. 方法的调用
    方法只有调用后才会执行,方法的调用不一定在main方法中,只要是程序执行到的位置,都可以调用其他方法

    静态方法(有static关键字的)
    类名.方法名(实参);
    成员方法
    引用.方法名(实参);
    
  3. 方法重载

    • 定义
      在一个程序中方法名相同,但是参数类型或者参数个数不同的方法,这就是方法重载
    • 使用场景
      当在同一个类中,方法完成的功能相似,建议方法名相同,方便编程,就像调用同一个方法似的
    • 方法重载的条件
      1. 在同一个类中
      2. 方法名不同
      3. 参数列表不同
        • 数量不同
        • 顺序不同
        • 类型不同

    栗子:

    public class Math{
    	public static int add(int x,int y){
    		return x+y;
    	}
    	public static int add(int x,int y,int a){
    		return x+y+a;
    	}
    	public static int add(double x,double y){
    		return x+y;
    	}
    }
    
  4. 方法递归

    • 定义
      方法内部自身调用自身

    • 递归的分类

      1. 直接递归
        方法自身调用自身
      2. 间接递归
        A方法调用B方法,B方法调用C方法,C方法调用A方法
    • 注意事项

      1. 递归一定要有条件限定,保证递归可以停止,否则会发生栈内存溢出
      2. 递归中虽然有限定条件但是递归的次数不能太多。否则也会发生栈内存溢出
      3. 构造方法禁止递归
    • 栗子

    public class Demo{
    	public static void main(String[] args){
    		//1~4的和
    		Demo.sum(4);
    	}
    	
    	public static int sum(int n){
    		if(n==1){
    			return 1;
    		}
    		return n + sum(n-1);
    	}
    }
    
③.对象
  1. 对象的创建和使用
    语法:

    new 类名();
    通过一个类可以实例化N个对象
    Student s = new Student();
    Student是一个引用数据类型
    s是一个变量名(引用)
    Student是一个引用数据类型
    new是运算符 作用是,在JVM堆内存中开辟一个新的内存空间
    
  2. 访问对象的语法

    读取数据:引用.变量名
    修改数据:引用.变量名 = 值;
    
  3. 对象栗子即JVM工作原理

    public class User {
    	int id = 1001;
    	String name = jack;
    	Addr add = new Addr(); 
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iva8fHPS-1603158679422)(C:\Users\谜语菌\Documents\img\无标题.jpg)]

  4. 构造方法

    • 语法:
    【修饰符】构造方法名(形参列表){
    	方法体:
    }
    返回值类型不需要指定
    构造方法名必须与类名保持一致
    如果不定义构造方法,程序会自动默认提供一个缺省构造
    如果定义了构造方法,则系统不再默认提供缺省构造
    
    • 构造方法的作用

      1. 创建对象
      2. 创建对象的同时初始化实例变量的内存空间
    • 构造方法的调用

      new 构造方法名(实参);
      构造方法有返回值,返回值是他自己
      构造方法支持重载机制
      
  5. 对象和引用的概念

    1. 对象:使用new运算符在堆内存中开辟的内存空间成为变量
      2. 引用:是一个变量,保存了内存地址,指向堆内存中的对象
      3. 所有访问实例相关的数据,都要使用"引用."的方式访问
      4. 只有一个空的引用,访问对象相关数据时会出现空指针异常
  6. this关键字

    • 定义
      this是一个引用,this的内存地址指向自身,this存储在JVM堆内存java对象的内部。每一个对象都有一个this

    • this的使用

      1. this可以出现在实例方法中,this指向当前正在执行这个行为的对象。
      2. this不能出现在静态方法中
      3. "this."大多情况下可以省略,但是在区分局部变量和实例变量时不可以省略。
    • 使用场景

      1. 可以使用在实例方法中,代表当前对象
      this.
      
      1. 可以使用在构造方法中,通过当前构造方法调用其他构造方法
      this(实参)
      只能出现在方法的第一行
      
  7. static关键字

    • 定义

      1. static 修饰的方法为静态方法
      2. static 修饰的变量为静态变量
      3. static 修饰的元素 都可以使用"类名."的方式访问
    • 变量
      在变量中使用 static 为静态变量,静态变量在类加载时初始化,不需要创建对象,内存就开辟了,存储在方法区中。

    • 变量声明

      1. 声明实例变量:所有对象都有这个属性,但是值会随着对象的不同而不同
      2. 声明静态变量:所有对象都有这个属性,并且所有对象值相同
    • 静态代码块

      1. 语法
      static{
      		java代码;
      }
      静态代码块在类加载时执行,并且只执行一次
      静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行
      
    • 使用场景

      1. 与具体的需求有关,例如项目中要求在类加载时刻执行代码完成日志的记录
      2. 静态代码块时java为程序员准备的特殊时刻,被称为类加载时刻
      3. 通常在静态代码块总完成预备工作,先完成数据的准备工具,例如:初始化连接池,解析XML配置文件
  8. final关键字

    • 特点

      1. final 关键字表示最终的,不可变的
      2. final 修饰的类无法被继承
      3. final 修饰的方法无法被重写
      4. final 修饰的变量赋值之后,不可重新赋值
      5. final 修饰的实例变量,必须手动赋值,不能使用系统默认值
      6. final 修饰的引用,一旦指向某个对象,不能指向其他对象,并且指向的对象无法被垃圾回收器回收
      7. final 修饰的变量不可变,与static联用,称作常量
      8. 抽象类和抽象方法,不能被 final 修饰
    • 常量

    public static final 类型 常量名 =;
    Java规范中要求常量名必须大写
    
④.封装
  • 封装的作用

    1. 复杂性封装,对外提供简单的操作入口
    2. 封装就意味着程序可以随意使用,并且适应性强
    3. 封装之后,提高了安全性
  • 封装的步骤

    1. 所有属性私有化
    2. 对外提供简单的操作入口(get,set方法)
⑤.继承
  1. 定义

    继承就是子类继承父类的特征和行为,使其子类对象拥有父类对象的实例域和方法,使其子类具有父类的相同行为

  2. 作用

    代码复用,继承最重要的作用是,有了继承才有了,方法覆盖和多态机制。

  3. 语法

    【修饰符】class 类名 extends 父类名{
    	方法体;
    }
    java语言中只支持单继承,一个类只能继承一个类
    父类的构造方法和私有元素,子类不能继承
    类之间可以实现间接继承
    A extends B
    B extends C
    C extends D
    A类间接继承C,D
    
  4. 方法重写(方法覆盖)

    • 定义
      重写是子类对父类继承过来的方法进行重新编写,返回值和形参不能改变。即外壳不变,核心重写。

    • 重写的条件

      1. 方法重写发生在具有继承关系的父子类之间
      2. 方法重写时,返回值类型相同,方法名相同,形参列表相同
      3. 访问权限不能底可以高
      4. 抛出异常不能多只能少
    • 注意

      1. 私有方法不能继承,所以不能重写
      2. 构造方法不能继承,所以不能重写
      3. 静态方法不存在重写
      4. 重写只针对方法,不涉及属性
  5. super关键字

    • 定义

      子类重写父类方法后,无法直接访问父类被重写的方法,为了解决这个问题,java提供了super关键字访问父类的成员变量。

    • 使用

      1. 使用super关键字调用父类的成员变量和成员方法
      super.成员变量
      super.成员方法(实参)
      
      1. 使用super关键字调用父类构造方法
      super(实参);
      必须位于子类构造方法的第一行,并且只能出现一次
      
⑥.多态
  1. 定义

    多态是同一个行为具有多个不同表现形式或形态的能力,
    多态就是同一个接口,使用不同的对象而执行不同的操作
    栗子:
    狗叫—汪汪汪
    猫叫—喵喵喵
    猪叫—哼哼哼
    用一个事件反映在不同对象上,就会有不同的结果

  2. 多态存在的三个必要条件

    • 继承
    • 重写
    • 父类的引用指向子类的对象
  3. 多态基础语法

    • 向上转型
      子类型转父类型(自动类型转换)
    • 向下转型
      父类型转子类型(强制类型转换)
    package js;
    
    public class Demo{
        public static void main(String[] args){
            //向上转型
            Animal cat = new Cat();
            Animal dog = new Dog();
            cat.eat();
            dog.eat();
            //向下转型
            if (cat1 instanceof Cat) {
                Cat cat1 = (Cat)cat;
                cat1.animal();
            }
        }
    }
    class Animal {
        public void eat(){
            System.out.println("吃...");
        }
    }
    
    class Cat extends Animal {
        public  void eat(){
            System.out.println("猫吃老鼠");
        }
    
        public void animal(){
            System.out.println("猫咪在抓老鼠");
        }
    }
    
    class Dog extends Animal {
        public void eat(){
            System.out.println("狗吃骨头");
        }
    }
    
⑦.抽象类
  1. 定义

    在面向对象的概念中,所有的对象都是通过类来描述的,但是反过来不是所有的类都是用来描述对象的,如果一个类没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

  2. 语法

    public abstract class 抽象类{
    public abstract void 抽象方法();
    }
    抽象类:在class关键字前面加 abstract
    抽象方法:在方法的修饰符列表中加 abstract 抽象方法以 ; 结束,不能加{}
    
  3. 抽象类特征

    • 抽象类无法被实例化,所以抽象类必须要被继承才能使用
    • 抽象类中不一定有抽象方法,但抽象方法必须出现在抽象类中
    • 抽象类除了不能实例化对象以外,类的其他功能依然存在,成员变量,成员方法,和构造方法的访问方式和普通类一样
⑧.接口
  1. 定义

    接口在Java编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

  2. 语法

    【修饰符】interface 接口名 {}
    实现
    【修饰符】class 类名 implements 接口名{}
    接口中只能出现,常量,抽象方法,默认方法(default 修饰)
    接口不能被实例化,所以需要被实现
    一个类可以实现多个接口。一个非抽象的类实现接口,需要将接口中的所有方法"实现/重写/覆盖"
    
  3. 接口的特征

    • 接口是隐式抽象的,声明接口时可以不使用 abstract
    • 接口中的方法也是隐式抽象的,声明时同样不需要 abstract
    • 接口中的方法都是公有的
  4. 接口的作用

    • 可是使项目分层,所有层面面向接口开发,开发效率
    • 接口使代码和代码之间耦合度降低,就像内存条和主板的关系,变得可插拔。可以随意切换
⑨.Object类
  1. toString

    • 设计 toString 方法的目的
      返回java对象中的字符串表示类型
      在现实开发中,Object里面的toString方法已经不够用,所以需要进行重写。

    • Object中的toString方法

    public String toString(){
    	return getClass().getName()+"@"+lnteger.toHexString(hashCode());
    }
      Object中的toString方法返回:类名@Java对象的内存地址经过哈希算法得出的int类型值再转换为十六进制。
     这个输出结果可以等同看做Java对象在堆内存中的内存地址。
    
  2. equals

    • 作用:比较内存地址

    • Object中的equals方法:

    public boolean equals(Object obj){
    	return(this==obj);
    }
    == 判断对象内存地址是否相同,相同是true,不同则是false
    目的:判断两个对象是否相等
    
  3. finalize

    • 什么时候调用
      1. finalize方法每个对象都有
      2. finalize方法不需要程序员调用,系统自动调用
      3. java对象如果没有更多的引用指向它,则成为垃圾数据,等待垃圾回收器的回收,垃圾回收器在回收这个对象之前会自动调用该对象的finalize方法。
⑩.内部类
  1. 成员内部类

    • 特点

      1. 成员内部类可以等同看作成员变量
      2. 成员内部类中不能有静态声明
      3. 成员内部类可以访问外部类中所有的数据
    • 语法:

      public class 外部类名{
      	class 外部类名{
      		方法体
      	}
      }
      //创建内部类对象
      外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
      
  2. 局部内部类

    • 特点
      1. 局部内部类可以等同看作局部变量,都是在方法中定义的,有效范围只限于方法内部
      2. 局部内部类在访问局部变量时,局部变量必须使用final修饰

    = 语法

    public class 类名{
    	public void 方法名{
    		//不能用访问控制符修饰
    		class 内部类名{
    		//不能有静态声明
    		}
    		//调用
    		内部类名 变量名 = new 内部类名();
    	}
    }
    
  3. 静态内部类

    • 特点

      1. 静态内部类可以等同看作静态变量
      2. 可以直接访问外部类中私有的数据
      3. 无法直接访问成员数据
    • 语法

    public class 外部类名{
    	static class 内部类名{
    	
    	}
    }
    //创建内部类对象
    内部类名 变量名 = new 外部类名.内部类名();
    
  4. 匿名内部类

    没有名字的类,可以少定义一个类,但无法重复使用

    • 语法
    public class 外部类{
    	//静态方法
    	public static void m1(接口名 变量){
    		变量.抽象方法名;
    	}
    	//主方法
    	public static void main(String[] args){
    	m1(new 接口名(){
    		public void 抽象方法名(){
    			方法体;
    		}
    	})
    	}
    }
    //接口
    public interface 接口名{
    	void 抽象方法名();
    }
    
异常
  1. 异常处理机制

    • 定义

      1. 异常模拟的是现实世界中“不正常”的事件
      2. Java中采用“类”来模拟异常
      3. 类是可以创造对象的
        NullpointerException e = 0x2213;
        e是一个变量,其中保存着内存地址,指向堆中的对象
        NullpointerException就表示一类异常
        “抢劫”—表示一类异常
        “张三被抢劫”—表示一个异常事件
    • 作用
      程序发生异常后,为我们输出详细的提示信息,程序员可以通过这个信息,对程序进行处理,使程序更加健壮

    • 本质
      程序执行过程中发生异常事件,JVM为我们创建了一个XXX(对应着异常事件)类型的对象。并且这个对象包含详细的异常信息,并且JVM将这个对象中的信息输出到控制台。

    • 异常继承结构

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1qSSP7kN-1603158679425)(C:\Users\谜语菌\Documents\img\hvuweg.JPG)]

  2. 异常处理

    • 异常抛出 throws
      在方法声明的位置上使用throws关键字向上抛出异常。不是真正的处理异常,谁调用抛给谁

    • 异常捕捉 try…catch…

    • throws和throw的区别

      1. throws 出现在方法头,throw 出现在函数体
      2. throws 表示出现函数的一中可能,并不一定发生异常,throw 则是抛出了异常,执行throw则一定抛出了某种异常。
    • 语法

    public int m1() throws Exception{
    	if(age < \0){
    		throw new Exception("年龄不能为负数");
    	}
    }
    //捕捉
    try{
    	可能出现异常的代码
    }catch(异常类型1 变量){
    	处理异常的代码
    }...
    1.catch 语句块可以写多个
    2.从上到下,catch 必须从小类型到大类型进行捕捉
    3.try...catch...中最多执行一个语句块。执行结束后,try...catch...就结束了
    
    • finally 语句块
    try{
    	可能出现异常的代码
    }catch(异常类型1 变量){
    	处理异常的代码
    }finally{
    	一定执行的代码
    }
    1. finally语句块可以直接和try语句块连用
    2.finally语句块中的代码一定会执行,除非在执行finally语句之前退出了JVM
    
    • 打印异常堆栈信息

    一般情况下都会使用printStackTrace方法去调试程序

    try{
    	FileInputstream fis = new FileInputstream("c:acd.txt");
    }catch(FileNotFoundException e){
    	e.printStackTrace();
    	String msg = e.getMessage();
    	System.out.println(msg);
    }
    
  3. 自定义异常类

    • 编译时异常,直接继承Exception

    • 运行时异常,直接继承RuntimeException

    • 自定义构造方法

    • 栗子

    public class MyException extends Exception {
    	public MyException(){
    		//调用父类的无参构造
    		super();
    	}
    	public MyException(String msg){
    		//调用父类构造方法
    		super(msg);
    	}
    }
    
    public void use{
    	public void zhuCe(String name) throws {
    		if(name.length()<6){
    			throw new MyException("账号长度小于6位");
    		}else{
    			System.out.println("注册成功");
    		}
    	}
    }
    

三.常用类

String

java.lang.String 字符串类型

  1. 概述

    • 特点
      1. 字符串一旦被创建不可再改变
      2. 提升字符串的访问效率, 在程序中使用缓存技术,所以在Java中所有用"双引号"括起来的字符串都会在"字符串常量池"中创建一份,在方法区中被储存。
      3. 在程序执行过程中,如果程序用到某个字符串,例如"ABC",那么程序会在字符串常量池中去搜索该字符,如果没有找到该字符,则在字符串常量池中新建一个"ABC"字符串,如果找到就直接引用(字符串常量池就是一个缓存区,为了提高访问字符串的效率)
  2. String 构造方法=

       public String():空构造
       public String(byte[] bytes):把字节数组转成字符串
       public String(byte[] bytes,int index,int length):把字节数组的一部分转成字符串
       public String(char[] value):把字符数组转成字符串
       public String(char[] value,int index,int count):把字符数组的一部分转成字符串
       public String(String original):把字符串常量值转成字符串
    
  3. String 常用方法

    返回值类型方法名作用
    charcharAt(int index)返回指定索引处的字符
    intindexOf(char a,int index)返回指定字符在字符串中第一次出现处的索引
    intlastIndexOf返回指定字符在字符串中最后一次出现处的索引
    intlength()返回字符串的长度
    booleanstartsWith(String prefix)判断此字符串是否以指定字符串开始
    booleanendsWith(String suffix)判断此字符串是否以指定的字符串结尾
    booleanequals(Object obj)将此字符串与指定的字符串比较
    booleanisEmpty()判断此字符串是否为空
    booleancontains(Char arquence)判断此字符串是否包含指定的字符
    StringtoLowerCase()将字符串中的所有字符转换为小写
    StringtoUpperCase()将字符串中的所有字符转换为大写
    Stringreplace(char oldChar,char newChar)用 newChar 字符替换字符串中出现的所有 oldChar 字符,并返回替换后的新字符串
    StringSubstring(int eginlndexb,int enfindex)截取字符串,从beginIndex直到最后,从beginIndex直到索引enfIndex-1
    Stringtrim()去除原字符串首尾的空格
    Char[]toCharArray()将字符串转换为一个字符数组
    String[]split(String regex)将字符串分割,分割标准为refex
StringBuffer
  1. 作用

    当对字符串进行修改时,需要用到StringBuffer和StringBuilder类

    和String类不同的是,StringBuffer和StringBuilder的对象能够被多次修改,并且不产生新的未使用对象

  2. 定义和原理

    • StringBuffer和StringBuilder是什么?

      是一个字符串缓冲区

    • 工作原理
      预先在内存中申请一块空间,以容纳字符序列,如果预留空间不够,则进行自动扩容,以容纳更多的字符序列

  3. StringBuffer,StringBuilder和String的区别

    • String是不可变的字符序列,存储在字符串常量池中
    • StringBuffer底层是一个char数组,初始容量是16,该char数组是可变的。并且可以自动扩容
  4. StringBuffer和StringBuilder的区别

    • StringBuffer是线程安全的
    • StringBuilder是非线程安全的
  5. 如何进行优化?

    • 最好在创建StringBuffer之前,预测StringBuffer的存储字符数量,然后在创建String Buffer的时候采用指定初始化容量的方式创建String Buffer,为了减少底层数组的拷贝,提高效率。

6.常用方法

|返回值类型|方法名|作用|
|---|---|---|
|String|append(char c)|添加字符到字符串的末尾|
|String|insert(int offset,String str)|在offset位置插入字符串str|
|String|delete(int start,int ent)|删除指定范围的字符串|
|String|replace(int start,int ent,String s)|对指定范围的字符串用新字符串s替换|
|void|setCharAt(int index,char ch)|修改指定位置index处的字符|
|String|reverse()|将此字符串颠倒|
System

System 类定义了一些与系统相关的属性和方法,它所提供的属性和方法都是静态的。

  • 常用方法
返回值类型方法名作用
properpiesgetProperpies()获取当前系统的属性
properpiesgetProperpies(key)获取当前指定键描述的系统属性
longcurrentYimeMillis()返回以毫秒为单位的系统时间
voidArraycopy(…)用于将一个数组中的元素快速拷贝到另一个数组
voidgc()运行垃圾回收站,并对垃圾回收
arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
① src:表示源数组
② dest:表示目标数组
③ srcPos:表示源数组中拷贝元素的起始位置
④ destPos:表示拷贝的目标数组的起始位置
⑥ length:表示拷贝元素的个数
注意:在进行数组拷贝时,目标数组必须要有足够的空间来存放拷贝的元素,否则会发生角标越界异常。
Math
  • Math是一个工具类,主要用于完成复杂的数学运算。如:求绝对值,三角函数,指数运算等。

  • Math类中的方法都是静态方法,可以直接调用。Math类中有两个静态常量PI和E,代表数学中的Π和e

    方法名作用
    abs()计算绝对值
    sin()计算正弦
    cos()计算余弦
    tan()计算正切
    sqre()计算平方根
    cbrt()计算立方根
    pow()计算乘方
    ceil()求大于参数的最小整数
    floor()求小于参数的最大整数
    round()对小数进行四舍五入后的结果
    max()求两个数的较大值
    min()求两个数的较小值
    random()生成一个大于等于0.0小于0.1的随机值
    public class Test {
        public static void main(String[] args){
            System.out.println("计算绝对值的结果"+Math.abs(-10));//        计算绝对值的结果10
            System.out.println("计算正弦的结果"+Math.sin(2.1));//        计算正弦的结果0.8632093666488737
            System.out.println("计算余弦的结果"+Math.cos(3.4));//        计算余弦的结果-0.9667981925794611
            System.out.println("计算正切的结果"+Math.tan(5.7));//        计算正切的结果-0.6597305715207762
            System.out.println("计算平方根的结果"+Math.sqrt(8.5));//        计算平方根的结果2.9154759474226504
            System.out.println("计算立方根的结果"+Math.cbrt(6));//        计算立方根的结果1.8171205928321397
            System.out.println("计算的乘方结果"+Math.pow(2,3));//        计算的乘方结果8.0
            System.out.println("求大于参数的最小整数"+Math.ceil(2.3));//        求大于参数的最小整数3.0
            System.out.println("求小于参数的最大整数"+Math.floor(2.3));//        求小于参数的最大整数2.0
            System.out.println("对小数进行四舍五入的结果"+Math.round(2.3));//        对小数进行四舍五入的结果2
            System.out.println("求两个数的较大值"+Math.max(10,39));//                求两个数的较大值39
            System.out.println("求两个数的较小值"+Math.min(10,39));//        求两个数的较小值10
            System.out.println("生成一个大于等于0.0小于0.1的随机值"+Math.random());//        生成一个大于等于0.0小于0.1的随机值0.8174336488567913
        }
    }
    
    
Random

​ 在JDK的java.util包中,有一个Random类,它可以在指定取值范围内产生随机数字

public class Test {
    public static void main(String[] args){
        Random random = new Random();
        System.out.println("生成boolean类型的随机数"+random.nextBoolean());//        生成boolean类型的随机数false
        System.out.println("生成double类型的随机数"+random.nextDouble());//        生成double类型的随机数0.2783710213582392
        System.out.println("生成float类型的随机数"+random.nextFloat());//        生成float类型的随机数0.9605354
        System.out.println("生成int类型的随机数"+random.nextInt());//        生成int类型的随机数-749075235
        System.out.println("生成0-10之间的随机数"+random.nextInt(10));//        生成0-10之间的随机数0
        System.out.println("生成long类型的随机数"+random.nextLong());//        生成long类型的随机数1352877345433554247
    }
}
包装类
  1. 八种基本数据类型对应的包装类
基本数据类型包装类型
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter
  • 自动装箱:将基本数据类型的变量赋给对应的包装类变量
  • 自动拆箱:将包装类对象类型的变量直接赋给对应的基本数据类型变量
  1. 基本数据类型,包装类以及字符串之间的转换

    Java中除了支持基本数据类型与对应包装类的转换外,还提供了其他方法来支持基本数据类型,基本数据包装类以及字符串之间的转换。

    通过引用数据类型字符串String类的valueOf(),可以将8种基本数据类型转化为对应的字符串类型
    通过8中包装类的静态方法valueOf()既可以将对应的基本数据类型转换为包装类,也可以将变量内容匹配的字符串转换为包装类(Character除外)
    通过八种包装类的有参构造方法同样既可以将对应的基本数据类型转换为包装类,也可以将变量内容匹配的字符串转换为包装类(Character除外)
    通过八种包装类的静态方法parseXxx()可以将变量内容匹配的字符串转换为基本数据类型
    包装类都重写了Object类中的toString()方法,以字符串的形式返回被包装的基本数据类型的值
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aEiC5y8Y-1603158679430)(C:\Users\谜语菌\Documents\img\saf.jpg)]

时间和日期类
  1. Date

    • 构造方法
      1.Date():用来创建当前时间
      2.Date(lang date):用来创建指定时间的Date对象,其中date参数表示1970年1月1日0时0分0秒以来的毫秒数
  2. Calendar

    • 定义

      1. Calendar类是一个抽象类,不可以被实例化,使用静态方法getInstance()来得到一个Calendar对象
      2. Calendar类的功能比Date类强大,但是实现方式复杂一些
    • 创建一个代表系统当前日期的Calendar对象

      Calendar c = Calendar.getInstance();
      
    • 方法

    方法名功能
    int get(int field)获取时间
    void add(int field,int amount)增加
    void set()修改时间
    Calendar类对象字段类型列1
    Calendar.YEAR年份
    Calendar.MONTH月份
    Calendar.DATE日期
    Calendar.DAY_OF_MONTH日期,和上面的字段意义完全相同
    Calendar.HOUR12小时制的小时
    Calendar.HOUR_OF_DAY24小时制的小时
    Calendar.MINUTE分钟
    Calendar.SECOND
    Calendar.DAY_OF_WEEK星期几
  3. DateFormat

    时间对象与字符串之间的相互转换(格式化日期)
    使用 SimpleDateFormat 格式化日期

    public class DateDemo {
    public static void main(String args[]) {
    Date dNow = new Date( );
       SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
       System.out.println("当前时间为: " + ft.format(dNow));
    }
    //2018-09-06 10:16:34
    

四.集合

①.概述
  1. 什么是集合

    集合是Java中提供的一种容器,可以用来存储多个数据

  2. 集合和数组的区别

    • 数组的长度是固定的,集合长度可变
    • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多时,使用集合进行存储。
  3. 集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-usbcCXIW-1603158679432)(C:\Users\谜语菌\Documents\img\集合.png)]

②.Collection
  1. 是什么?

    是所有单列集合的根接口

  2. 方法

    返回值方法名作用
    booleanadd(E e)把给定的对应的对象添加到集合中
    voidclear()清空集合中的所有元素
    booleanremove(E e)把给定的对象在当前集合中删除
    booleancontains(E e)判断当前集合中是否包含给定的对象
    booleanisEmpty()判断当前集合是否为空
    intsize()返回集合中的元素个数
    Object[]toArray()把集合中的元素,存储到数组中
③.List
  • 特点

    1. 有序的集合,存储元素和取出元素的顺序是一致的(存储123,取出123)
    2. 有索引,包含一些带索引的方法
    3. 允许存储重复的元素
    4. 底层是数组结构,查询快,增删慢
  • List接口中带索引的方法

    返回值方法名作用
    voidadd(int index,E element)将指定的元素,添加到该集合中的指定位置上
    Eget(int index)返回指定元素替换集合中指定位置的元素
    Eremove(int index)溢出列表中指定位置的元素并返回
    Eset(int index)用指定元素替换集合中指定位置的元素,返回被替换的元素
④.ArrayList 集合
  1. 特点:

    • 长度可变
    • 大小可变的数组实现
  2. 方法

    返回值类型方法名作用
    booleanadd(E e)添加元素
    voidadd(int index,E e)在指定的索引出添加一个元素
    Eget(int index)返回指定索引处的元素
    intsize()返回集合中的元素个数
    booleanremove(Object o)删除指定元素,返回删除是否成功
    Eremove(int index)删除指定索引处的元素,返回被删除的元素
    Eset(int index,E element)修改指定索引处的元素,返回被修改的元素
  3. ArrayList 集合的遍历

    • for循环遍历
    public class Demo{
    	public static void main(String[] args){
    	ArrayList<String> arr = new ArrayList()<String>;
    	arr.add("1sa");
    	arr.add("2sa");
    	arr.add("3sa");
    	for(int i = 0;i<arr.size();i++){
    		String str = arr.get(i);
    		System.out.println(str);
    		}
    	}
    }
    
    • 迭代器遍历ArrayList 集合

      1. 迭代器
        • 使用集合中 iterator() 获取迭代器的实现类对象,使用 Iterator 接口接收
        • 注意:Iterative有泛型,迭代器的泛型跟着集合设置,集合什么泛型,迭代器什么泛型
        • 语法
          Iterative it = 集合.iterator();
      2. 遍历
      //hasNext() 判断集合还有没有下一个元素
      while(it.hasNext()){
      	//next() 取出下一个元素,然后将指针向后移动一位
      	String str = it.next();
      	System.out.println(e);
      }
      
    • 增强for循环

      1. 前提
        • 只能用来遍历集合和数组
        • Collectionextends Ierable:所有的单列集合都可以使用增强for循环
        • public interface Iterable实现这个接口允许对象成为"foreach"语句的目标。
      2. 增强for遍历ArrayList 集合
      for(数据类型 变量名:集合名/数组名){
      	System.out.println(变量名);
      }
      
    • 练习:

      /**
       * 将集合中姓张的姓名打印到控制台
       */
      public class ListDemo01 {
          public static void main(String[] args) {
              String[] arr = {"张无忌","张三","王老五","李四八","张天雷","胡八一"};
              ArrayList<String> list = new ArrayList<>(Arrays.asList(arr));
              for(String name:list){
                  if(name.startsWith("张")){
                      System.out.println(name);
                  }
              }
              System.out.println(list);
          }
      }
      
      /**
       * 斗地主发牌案例
       */
      public class Demo02 {
          public static void main(String[] args) {
              String[] hua = {"♥","♠","♣","♦"};
              String[] dian = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
              //创建牌库集合
              ArrayList<String> pai = new ArrayList<>();
              pai.add("大王");
              pai.add("小王");
              //将花和点结合存储到牌库中
              for(String d:dian){
                  for(String h:hua){
                      pai.add(h+d);
                  }
              }
              //打乱顺序
              Collections.shuffle(pai);
              //加入玩家
              ArrayList<String> zhangsan = new ArrayList<>();
              ArrayList<String> lisi = new ArrayList<>();
              ArrayList<String> wangwu = new ArrayList<>();
              ArrayList<String> dipai = new ArrayList<>();
              //打印扑克牌数量
              System.out.println(pai.size());
              //开始发牌
              for(int i = 0;i<pai.size();i++){
                  if(i>=51){
                      dipai.add(pai.get(i));
                  }else if(i%3==0){
                      zhangsan.add(pai.get(i));
                  }else if(i%3==1){
                      lisi.add(pai.get(i));
                  }else if(i%3==2){
                      wangwu.add(pai.get(i));
                  }
              }
              System.out.println("底牌---"+dipai+"---"+dipai.size());
              System.out.println("张三---"+zhangsan+"---"+zhangsan.size());
              System.out.println("李四---"+lisi+"---"+lisi.size());
              System.out.println("王五---"+wangwu+"---"+wangwu.size());
          }
      }
      54
      底牌---[8, 大王,6]---3
      张三---[♣J,2, ♥J,5,3,7,4,2, ♠A,10,9,3,5, ♦K, ♦A,3,3]---17
      李四---[10, 小王,5,8,4,10, ♥A,6,2, ♣A,10,4, ♣Q,8,7,9,7]---17
      王五---[8, ♠J, ♦Q, ♠K,9,2, ♥K,6, ♣K,6,4,9, ♦J,7, ♠Q, ♥Q,5]---17
      
⑤.LinkedList
  1. 特点
  • 底层是链表结构,查询慢,增删快
  1. 特有方法

    返回值类型方法名作用
    voidaddFirst(E e)将元素添加到开头位置
    voidaddLast(E e)将元素添加到最末尾
    EgetFirst()获取第一个元素
    EgetLast()获取最后一个元素
    EremoveFirst()删除第一个元素
    EremoveLast()删除最后一个元素
    Epop()从此列表所表示的堆栈处弹出一个元素
    booleanisEmpty()如果集合为空,则返回true
⑥.Set和Hashset
  • set接口的特点

    1. 不允许存储重复的元素
    2. 没有索引,也不能使用普通for循环遍历
  • HashSet特点

    1. 不允许存储重复的元素
    2. 没有索引
    3. 是一个无序的集合,存储元素和取出元素的顺序有可能不一样
    4. 底层是一个哈希表结构(查询速度快)
  • HashSet存储自定义类型元素

  • Set集合保证元素的唯一,存储的元素必须重写hashCode()和equals()

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tyCMKb5q-1603158679433)(C:\Users\谜语菌\Documents\img\tianruo_2020-6-15-637278061033090177.jpg)]

  • LinkedHashSet集合特点

    • 底层是一个哈希表(数组+链表/红黑树)+链表(记录元素的存储顺序),保证元素有序。
⑦.Collections
  • java.utils.Collections 是集合工具类,用来对集合进行操作。

    返回值方法名作用
    booleanaddAll(Collection c,T…elements)向集合中添加一些元素
    voidshuffle(list<?> list)打乱集合中元素顺序
    voidsort(List list)将集合中的元素按照默认规则排序
    • sort(List list)使用前提
      • 排序集合元素,必须实现Comparable或CompareTo,重写接口中的方法
⑧.Map
  1. 举例子

    • 需求实现学号与姓名之间村子对应关系
    • 一对一
  2. 定义和特点

    • 为了体现有一对一对应关系的数据,java提供了一种专门用于存储对应关系的集合。
    • 将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。
  3. Map和Collection的区别

    • Map是一个双列集合,常用于处理存在对应关系的数据。key不可以重复
    • Collection是一个单列集合,Collection有不同的子体系,有的允许重复,有索引,有序。有的不允许重复,无序。
  4. 常用方法

返回值类型方法名作用
Vput(K key,V value)存储键值对到集合中
Vremove(Object key)把指定的键所对应的键值对,在集合中删除
Vget(Object key)根据指定的键,在Map集合中获取对应的值
booleancontainsKey(Object key)判断集合中是否包含指定的键
SetkeySet()获取Map集合中所有的键,存储到Set集合中
Set<Map.Entry<K,V>>entrySet()获取到Map集合中所有的键值对对象的集合
/**
 * 遍历Map集合
 */
public class Demo03 {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("1001","张无忌");
        map.put("1002","黎恬然");
        map.put("1003","王昌龄");
        //获取map集合中的键
        Set<String> set = map.keySet();
        //遍历set集合,获取map中的键值对数据
        for(String key:set){
            String value = map.get(key);
            System.out.println(key+"---"+value);
        }
    }
}
/**
 * 第二种遍历方法
 */
public class MapDemo04 {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("1001","张无忌");
        map.put("1002","黎恬然");
        map.put("1003","王昌龄");
        //获取键值对集合
        Set<Map.Entry<String, String>> sets = map.entrySet();
        for(Map.Entry<String,String> set:sets){
            String key = set.getKey();
            String value = set.getValue();
            System.out.println(key+"---"+value);
        }
    }
}

⑨.HashMap和LinkedHashMap

  • HashMap集合的特点

    1. HashMap集合底层是哈希表:查询速度特别快

      JDK1.8以前:数组+单向链表

      JDK1.8之后:数组+单向链表/红黑树(链表的长度超过八):提高查询速度

    2. HashMap集合是一个无序的集合,存储元素和取出元素顺序可能不一致

  • LinkedHashMap特点

    1. LinkedHashMap集合底层是一个哈希表+链表(保证迭代顺序)
    2. linkedHashMap集合是一个有序的集合,存储元素和取出元素顺序一致
⑩.Hashtable和Properties
  • java.util.Hashtable<K,V> 集合 implements Map<K,V>接口

  • 与HashMap的区别:

    1. Hashtable:
      • 底层是一个哈希表,是一个线程安全的集合,是单线程的,速度慢
      • 可以存储null键,null值
      • 被(HashMap和ArrayList)取代
      • 子类Properties依旧存活
    2. HashMap
      • 底层是一个哈希表,是一个线程不安全的集合,是多线程集合,速度快
      • 不能存储null键,null值
  • properties

    1. java.util.Properties集合

    2. 定义

      表示了一个持久的属性集。properties可保存在流中或从流中加载。

      properties集合是一个唯一和IO流相结合的集合

      • 可以使用store(),把集合中的临时数据,持久化写入到硬盘中存储
      • 可以使用load(),把硬盘中保存的文件(键值对),读取到集合中使用
      • properties是一个双列集合,key和value默认都是字符串
    3. 方法

      返回值方法名作用
      Objectsetproperty(String key,String value)调用父类方法中的put
      StringgetProperty(String key)通过key找到value值
      SetstringPropertyNames()相当于keySet方法
    4. store()

      • 可以使用store(),把集合中的数据,写入到硬盘
      void store(OutputStream out,String comments)
      void store(Writer writer,String comments)
      参数:
      OutputStream out  字节输出流,不能写中文
      Writer writer     字符输出流,可以写中文
      String comments   注释,用来解释说明保存的文件做什么的,一般使用空字符null,使用中文会出现乱码
      
    5. load()

      • 可以使用load(),把硬盘中保存的键值对,读取到集合中使用
      void load(InputStream inStream)
      voud load(Reader reader)
      参数
      InptStream inStream  字节输入流,不能含有中文
      Reader reader        字符输入流,可以包含中文
      
    6. 配置文件注意事项

      • 存储键值对的文件中,键与值默认的连接符号可以使用=,空格
      • 存储键值对的文件中,可以使用#进行注释
      • 存储键值对的文件中,键与值默认字符串,不用加引号

五.IO流

Ⅰ.File类

Java.IO.File 类是文件和目录路径名的抽象表示,主要用于对文件和目录操作
我们可以使用File类的方法
- 创建一个文件/文件夹
- 删除文件/文件夹
- 获取文件/文件夹
- 判断文件/文件夹是否存在
- 对文件夹进行遍历
- 获取文件的大小

  1. 路径

    • 绝对路径:是一个完整的路径,以盘符开始的路径
    • 相对路径:是一个简化的路径
      • 相对只的是相对于当前项目的根目录,如果使用当前项目的根目录,路径可以简化书写
    • 注意:
      1. 路径不区分大小写
      2. 路径中的文件名称分隔符 windows 使用两个反斜杠
  2. 构造方法

    • public File(String pathname):通过将给定的路径名转换为抽象路径名来创建新的实例
    • public File(String parent,String Child):父路径名和子路径名创建新的实例
    • public File(File parent,String child):从父抽象路径名和子路径名创建新的实例
  3. 方法

    • 获取功能的方法

      1. String getAbsolutePath():返回此File的绝对路径名字符串,无论路径是绝对相对,都会返回绝对路径
      2. String getPath():将File转换为路径名字符串,获取构造方法中传递的路径
      3. String getName():返回由此File表示的文件或目录的名称,获取的是构造方法结尾的部分
      4. long length():返回由此File表示的文件大小,以子节为单位,文件夹无大小概念,如果构造方法给出的路径不存在,返回0
    • 判断功能的方法

      1. boolean exists():此File表示的文件或目录是否真实存在
      2. boolean isDirectory():此File表示的是否为目录
      3. boolean isFile():此File表示的是否是文件
    • 创建和删除功能方法

      1. boolean mkdir():创建由此FIle表示的单级空文件夹
      2. boolean mkdirs():创建由此File表示的单级空文件夹,也可以创建多级文件夹
      3. boolean createNewFile():当具有该名称的文件不存在时创建一个新的文件,此方法只能创建文件,且路径不存在会抛出异常
      4. boolean delete():删除由此File表示的文件/目录
    • 遍历数组的方法

      1. String[] list():返回一个String数组,表示该File目录中所有子文件或目录
      2. File[] listFile():返回一个File数组,表示该File目录中所有子文件或目录
    • 递归目录

    public class Demo {
     public static void main(String[] args) {
         File file = new File("D:\\Test\\");
         bianli(file);
     }
      public static void bianli(File f){
         File[] arr = f.listFiles();
         for(File file:arr){
             if(file.isDirectory()){
                 bianli(file);
             }else{
                 System.out.println(file);
             }
         }
      } 
    }
    
    • FileFilter过滤器
    public class Demo {
     public static void main(String[] args) {
         File file = new File("D:\\Test");
         guolu(file);
     }
    
     public static void guolu(File f){
         File[] files = f.listFiles(new FileFilter(){
    
    		@Override
    		public boolean accept(File pathname) {
    			// TODO Auto-generated method stub
    			return pathname.isDirectory()||pathname.getName().toLowerCase().contains("html");
             }
         });
             for(File file:files){
                 if(file.isDirectory()){
                     guolu(file);
                 }else{
                     System.out.println(file);
                 }
             }
     } 
    }
    
Ⅱ.IO流简介
  1. 归纳图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fqNpMKcA-1603158679435)(C:\Users\谜语菌\Documents\img\IO流.jpg)]

  2. IO原理图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOkESxOj-1603158679437)(C:\Users\谜语菌\Documents\img\未命名图片.jpg)]

Ⅲ.字节输出流OutputStream
  1. 概述
    把内存中的数据写入到硬盘文件中
    Java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。定义了字节输出流基本共性功能方法。

  2. 方法:

    • write(byte[] b):将b.length字节匆匆指定的字节数组写入输出流中
    • write(byte[] b,int off,int len):从指定字节数组写入len字节,从偏移量off开始输出到此输出流
    • flush():刷新此输出流
    • close():关闭此输出流,当流完成时释放系统资源
  3. 程序写入工作原理

  • Java程序———>JVM——->OS——->硬盘存储
  1. FileoutputStream

    • FileoutputStream(String url):创建一个具有执行名称的文件写出数据

    • FileoutputStream(File file):创建一个指定File路径的对象写入数据

    • 参数:

      1. String name:文件的路径
      2. File file:文件
    • 代码实例:

    public class IODemo {
     public static void main(String[] args) throws IOException {
         FileOutputStream fos = new FileOutputStream("a.txt");
         fos.write("s".getBytes());
         fos.close();
     }
    }
    
  2. 一次写入多个字节

    public class Test {
        public static void main(String[] args) throws IOException{
            FileOutputStream fos = new FileOutputStream("out.text");
            byte[] bytes = {65,66,67,68,69};
            fos.write(bytes, 1, 2);
            fos.close();
        }
    }
    //BC
    
Ⅳ.字节输入流InputStream
  1. 概述
    读取字节信息到内存中
    Java.io.InputStream抽象类时表示字节输入流的所有类的超类。

  2. 方法

    • read() :从输入流中读取数据的下一个字节
    • read(byte[] b):从输入流中读取一些字节数,并存储带字节数组b中。
    • read(byte[] b,int off,int len):从输入流中读取一些字节,并存储带字节数组b中,off指定数组字节的下标,len表示读取的字节数目
    • close():关闭此字节流,并释放系统资源
  3. FileInputStream

    • FileInputStream(String name)
    • FileInputStream(File file)
    • 参数:读取文件的数据源
      • String name:文件的路径
      • File file:文件
    • 构造方法的作用
      1. 会创建一个FileInputStream对象
      2. 会把FileInputStream对象指定构造方法中要读取的文件
  4. 代码示例

    //单个字节读取
    public class Test {
        public static void main(String[] args) throws IOException{
            //创建字节输入流
            FileInputStream in = new FileInputStream("out.text");
            //记录读取到的字节
            int len = 0;
            //把读取到的字节赋值给变量len
            while((len=in.read())!=-1){
                System.out.print((char)len);
            }
        }
    }
    //多个字节读取
    public class Test {
        public static void main(String[] args) throws IOException{
            FileInputStream in = new FileInputStream("out.text");
            byte[] bytes = new byte[1024];
            int len = 0;
            while((len=in.read(bytes))!=-1){
                System.out.print(new String(bytes,0, len));
            }
        }
    }
    
Ⅴ.IO流拷贝文件
public class Test {
    public static void main(String[] args) throws IOException{
       //创建字节输入流
       FileInputStream in = new FileInputStream("out.text");
       //创建字节输出流
       FileOutputStream out = new FileOutputStream("in.txt");
       //创建字节数组用于记录字节信息
       byte[] bytes = new byte[1024];
       //创建变量len用于记录字节数
       int len = 0;
       //读取文件字节信息
       while((len=in.read(bytes))!=-1){
           //写入文件信息
            out.write(bytes, 0, len);
       }
       //关闭流
       in.close();
       out.close();
    }
}
Ⅵ.字符输出流 Writer

java.io.Writer抽象类是表示用于写出字符流的所有类的超类

  1. 共性的成员方法

    • void write(int c):写入单个字符
    • void write(char[] char):写入字符数组
    • abstract void write(char[] char,int off,int len):写入字符数组的某一部分,off数组的开始索引,len写的字符个数
    • void write(String str):写入字符串
    • void write(String str,int off,int len):写入字符串的某一部分,off字符串开始的索引,len写入的字符个数
    • void flush():刷新该流的缓冲
    • void close():关闭此流,关闭前刷新
  2. FileWriter 文件字符输出流
    java.io.FileWriter extends OutputStreamWriter extends Writer

    • 构造方法:
      FileWriter(File file):根据给定的File对象构造一个File Writer对象
      FileWriter(String filename):根据给定的文件名构造一个FilrWriter对象
      参数:String filename:文件的路径
      File file:文件

    • 构造方法的作用

      1. 创建一个FileWriter对象
      2. 根据构造方法中传递的文件/文件的路径,创建文件
      3. 把FileWriter对象指向创建好的文件
    • 案例

      public class Test {
          public static void main(String[] args) throws IOException{
             //创建字符输出流
             FileWriter fw = new FileWriter("fw.txt");
             //写入字符串
             fw.write("nihaoshijie");
             //关闭流
             fw.close();
          }
      }
      
Ⅶ.字符输入流 Reader

java.io.Reader:字符输入流,是字符输入流最顶层的父类,定义一些共性的成员方法,是一个抽象类

  1. 共性的成员方法

    • int read():读取单个字符并返回
    • int read(char[] char):读取字符数组
    • void close():关闭流
  2. 文件字符输入流:FileReader
    java.io.FileReader extends InputStreamReader extends Reader

    • 构造方法
      FileReader(String fileName)
      FileReader(File file)
      参数:读取文件的数据源
      String fileName:文件的路径
      File file:一个文件

    • 作用:

      1. 创建一个FileReader对象
      2. 会把FileReader对象指向要读取的文件
    • 案例:

      public class Test {
          public static void main(String[] args) throws IOException{
             //创建字符输入流
             FileReader fr = new FileReader("fw.txt");
             //创建字符数组记录数据信息
             char[] chars = new char[1024];
      	  //创建变量len记录字符数
             int len = 0;
             //输入字符
             while((len=fr.read(chars))!=-1){
                 System.out.print(new String(chars,0,len));
             }
          }
      }
      
Ⅷ.缓冲流
  1. 概述

    • 缓冲流,也叫高效流,是对4个基本的FileXXX流的增强,所以也是4个流
      • 字节缓冲流:BufferedInputStream,BufferedOutputStream
      • 字符缓冲流:BufferedReader,BufferedWriter
    • 缓冲流的基本原理,在创建流对象时,会创建一个内置默认大小的缓冲区数组,通过缓冲区读写,减少系统的IO次数,从而提高读写的效率
    • 原理图
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-42ekjLI6-1603158679438)(C:\Users\谜语菌\Documents\img\缓冲流.jpg)]
  2. 流的使用

    • 构造方法
      BufferedOutputStream(OutputString out):创建一个新的缓冲输出流
      BufferedOutputStream(OutputString out,int size):创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
      参数:
      OutputStream out:字节输出流,我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率
      int size:指定缓冲流内部缓冲区的大小,不指定默认

    • 拷贝文件案例

    //字节缓冲流
    public class Test {
        public static void main(String[] args) throws IOException{
           //创建字节缓冲输入流
           BufferedInputStream buffIn = new BufferedInputStream(new FileInputStream("out.text"));
           //创建字节缓冲输出流
           BufferedOutputStream buffOut = new BufferedOutputStream(new FileOutputStream("out.txt"));
           //创建变量len记录字节信息
           int len = 0;
           //拷贝文件
           while((len=buffIn.read())!=-1){
                buffOut.write(len);
           }
           buffIn.close();
           buffOut.close();
        }
    }
    
    //字符缓冲流
    public class Test {
        public static void main(String[] args) throws IOException{
           //创建字符缓冲输入流
           BufferedReader br = new BufferedReader(new FileReader("bug.txt"));
           //创建字符缓冲输出流
           BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
           //创建字符串记录一行数据
           String str = null;
           //循环时每次读取一行字符
           while((str=br.readLine())!=null){
                bw.write(str);
               //换行
               bw.newLine();
           }
           br.close();
           bw.close();
        }
    }
    
    • 文本排序案例
    /**
     * 文本排序
     */
    public class Test {
        public static void main(String[] args) throws IOException{
           //创建字符缓冲流
           BufferedReader br = new BufferedReader(new FileReader("pai.txt"));
           BufferedWriter bw = new BufferedWriter(new FileWriter("xu.txt"));
           //创建map集合
           HashMap<Integer,String> hashMap = new HashMap<>();
           //创建字符串,记录一行字符
           String str = null;
           //读取一行字符
           while((str=br.readLine())!=null){
               //进行拆分存储
                String[] arr = str.split("\\.");
                //将数据存储在集合中
                hashMap.put(Integer.parseInt(arr[0]),"."+arr[1]);
           }
           //获取key存储到Set集合中
           Set<Integer> sets = hashMap.keySet();
           //遍历集合
           for(int key:sets){
               //获取value
                String value = hashMap.get(key);
                //写入到文件中
                bw.write(key+value);
                bw.newLine();
           }
           br.close();
           bw.close();
        }
    }
    
Ⅸ.转换流
  1. 字符转换流 OutputStreamWriter
    java.io.OutputStreamWriter extends Writer
    OutputStreamWriter:是字符流通向字节流的桥梁,可使用指定的 charset将要写入流中的字符编码成字节。

    • 继承自父类的共性成员方法
      • void writer(int c):写入单个字符
      • void writer(char[] char):写入字符数组
      • abstract void write(char[] char,int off,int len):写入字符数组的某一部分,off数组的开始索引,len写的字符个数
      • void write(String str):写入字符串
      • void write(String str,int off,int len):写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
      • void flush():刷新该缓冲
      • void close():关闭该流
    • 构造方法
      OutputStreamWiter(OutputStream out):创建使用默认字符编码的OutputStreamWriter。
      OutputStreamWriter(OutputStream out,String charsetName):创建使用指定字符集的OutputStreamWriter
      参数:
      OutputStream out:字节输出流,可以用来写转换之后的字节到文件中
      String charsetName:指定的编码表名称,不区分大小写,可以是utf-8/gbk…默认utf-8
    • 案例
    /**
     * 转换流
     * 将字节输出流转换为字符输出流,并更改字符集
     */
    public class Test {
        public static void main(String[] args) throws IOException{
            FileOutputStream out = new FileOutputStream("a.txt");
            OutputStreamWriter osw = new OutputStreamWriter(out,"GBK");
            osw.write("a我是你爸爸fa");
            osw.flush();
            osw.close();
            out.close();
        }
    }
    
  2. InputStreamReader
    java.io.inputStreamReader extends Reader
    InputStreamReader:是字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。

    • 继承自父类的共性成员方法

      • int read():读取单个资源并返回
      • int read(char[] char):一次读取多个字符,将字符读入数组
      • void close():关闭流
    • 构造方法

      InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader
      InputStreamReader(InputStream in,String charsetName):创建使用指定字符集的InputStreamReader
      参数:
      InputStream in:字节输入流,用来读取文件中保存的字节
      String charsetName:指定的编码方式,默认utf-8

    • 案例

    /**
     * 转换流
     */
    public class Test {
        public static void main(String[] args) throws IOException{
            FileInputStream in = new FileInputStream("a.txt");
            InputStreamReader isr = new InputStreamReader(in,"GBK");
            int len = 0;
            while((len=isr.read())!=-1){
                System.out.print((char)len);
            }
            isr.close();
            in.close();
        }
    }
    
Ⅹ.对象的序列化流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fDDyqeR5-1603158679440)(C:\Users\谜语菌\Documents\img\序列化.jpg)]

  1. 序列化流

java.io.ObjectOutputStream extends OutputStream
ObjectOutputStream:对象的序列化流
作用:把对象以流的方式写入到文件中保存

  • 构造方法:
    ObjectOutputStream(OutputStream out)创建写入指定OutputStream的ObjectOutputStream.
    参数:OutputStream out:字节输出流

  • 特有的成员方法
    void writeObject(Object obj):将指定的对象写入ObjectOutputStream

  • 案例

public class Student implements Serializable{
 private static final long serialVersionUID = 1l;
 private String name;
 private int age;
 public Student(){

 }
 public Student(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() {
     // TODO Auto-generated method stub
     return name+age;
 }
}

public class Test {
 public static void main(String[] args) throws IOException{
     ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
     Student s = new Student("张一凡",11);
     oos.writeObject(s);
     oos.flush();
     oos.close();
 }
}
  1. 对象反序列化流

java.io.ObjectInputStream extends InputStream
ObjectInputStream:对象的反序列化流
作用:把文件中保存的对象以流的方式读取出来使用

  • 构造方法
    ObjectInputStream(InputStream in):创建从指定InputStream 读取的OBjectInputStream
    参数:InputStream in:字节输入流

  • 特有成员方法
    Object readObject():从ObjectInputStream读取对象

  • 注意:
    readObject方法声明抛出了ClassNotFoundException(class文件找不到异常)
    当不存在对象的class文件时抛出此异常
    反序列化的前提

    1. 类必须实现Serializable
    2. 必须存在类对象的class文件
  • 案例:

public class Test {
public static void main(String[] args) throws IOException,ClassNotFoundException{
     ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
     Object o = ois.readObject();
     ois.close();
     System.out.println(o);
 }
}
  1. 序列化原理图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R05lWCg9-1603158679442)(C:\Users\谜语菌\Documents\img\序列化原理.jpg)]

  1. 集合的序列化和反序列化案例

    public class Test {
        public static void main(String[] args) throws IOException,ClassNotFoundException{
            //创建集合
            ArrayList<String> list = new ArrayList<>();
            //创建对象序列化流
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
            //存入数据
            list.add("张三丰");
            list.add("李春雷");
            list.add("张三四");
            list.add("五六七");
            oos.writeObject(list);
            oos.flush();
            oos.close();
            //创建对象反序列化流
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
            //读取对象
            Object o = ois.readObject();
            System.out.println(o);
            ois.close();
        }
    }
    

六.多线程

Ⅰ.线程概述
  1. 进程

    点击应用,程序执行,进入到内存中占用一些空间,程序执行,这些进入到内存的程序叫做进程
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmGWO6ys-1603158679443)(C:\Users\谜语菌\Documents\img\进程.jpg)]

  2. 线程

    线程属于进程,是进程中的一个执行单元,负责程序的执行
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v0xc4WDM-1603158679444)(C:\Users\谜语菌\Documents\img\线程.jpg)]

  3. 并发并行

    • 并发:指两个或多个事件在同一时间段内发生
    • 并行:指两个或多个事件在同一时刻发生(同时发生)
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2PXgfxo5-1603158679445)(C:\Users\谜语菌\Documents\img\并发并行.jpg)]
  4. 主线程

    主线程:执行主(main)方法的线程
    单线程程序:java程序中只有一个线程
    执行从main方法开始,从上到下依次执行
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DjL03ENz-1603158679446)(C:\Users\谜语菌\Documents\img\主线程.jpg)]

  5. 多线程

    1. 基础的多线程

      public class MyThread extends Thread{
          public void run(){
              int i = 0;
              while(i++<5){
              System.out.println("run方法在运行...");
              }
          }
      }
      
       public class Test {
           public static void main(String[] args){
               MyThread mt = new MyThread();
               mt.start();
               new MyThread().start();
               for(int i = 0;i<5;i++){
                   System.out.println("main在执行...");
               }
           }
       }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5oryIxsD-1603158679447)(C:\Users\谜语菌\Documents\img\多线程.jpg)]

Ⅱ.线程概述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QiUYB77O-1603158679449)(C:\Users\谜语菌\Documents\img\多线程.png)]

Ⅲ.线程生命周期
1. NEW(新建状态):仅由JVM分配了内存,不能运行
2. RUNNABLE(可运行状态):分为就绪状态和运行状态两种,线程可以在两种状态之间互相转换
3. BLOCKD(阻塞状态):处于运行状态的线程可能会因为某些原因失去CPU的执行权,暂时进入阻塞状态
4. WAITING(等待状态):处于运行状态的线程,调用无限期的方法[wait()、join()]就会进入等待状态
5. TIMED_WAITING(定时等待状态):调用了有时间参数限制的方法
6. TERMINATED(终止状态):线程执行完毕,退出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPXj34fR-1603158679452)(C:\Users\谜语菌\Documents\img\线程状态.jpg)]

Ⅲ.线程的创建
  1. Thread实现多线程

    public class MyThread extends Thread{
        public void run(){
            int i = 0;
            while(i++<5){
            System.out.println("run方法在运行...");
            }
        }
    }
    public class Test {
        public static void main(String[] args){
            MyThread mt = new MyThread();
            mt.start();
            new MyThread().start();
            for(int i = 0;i<5;i++){
                System.out.println("main在执行...");
            }
        }
    }
    
  2. Runnable接口实现多线程

    public class Test {
        public static void main(String[] args){
            new Thread(new Runnable(){
            
                @Override
                public void run() {
                    int i = 0;
                    while(i++<5){
                        System.out.println("run...");
                    }
                }
            }).start();;;
            for(int i = 0;i<5;i++){
                System.out.println("main...");
            }
        }
    }
    
Ⅳ.Thread

java.lang.Thread

  • 构造方法
    Thread(Runnable target):分配新的Thread对象
    Thread(String name):设置Thread名称
    Thread(Runnable target,String name):分配新的Thread对象
  1. 设置线程名称

    • 创建一个带参数的构造方法,参数传递线程的名称,调用父类的带参构造方法,把线程名称传递给父类,让父类给子线程起一个名字
    • 使用Thread类中的方法setName(String name)改变线程名称
    public class MyThread extends Thread{
        //无参构造
        public MyThread(){
        }
        //有参构造
        public MyThread(String name){
            //调用父类有参构造
            super(name);
        }
        //编写run()循环5次
        public void run(){
            int i = 0;
            while(i++<5){
            //获取线程名称
            System.out.println(Thread.currentThread().getName()+"的run方法在运行...");
            }
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            //使用参数设置线程名称
            MyThread mt = new MyThread("张大仙");
            mt.start();
            //使用setName()设置线程名称
            MyThread mt1 = new MyThread();
            mt1.setName("张无忌");
            mt1.start();
        }
    }
    
  2. 获取线程的名称

    • 使用Thread类中的方法getName()返回该线程名称
    • 先使用currentThread()获取当前正在执行的线程,使用线程中的方法,getName()获取线程的名称,static Thread currentThread()返回对当前执行的线程对象的引用。
  3. 睡眠

    • static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),毫秒数结束之后,线程继续执行
    //倒计时案例
    public class Demo {
        public static void main(String[] args) {
            for(int i = 60;i>=0;i--) {
    			System.out.println(i);
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
            }
        }
    }
    
Ⅴ.Runnable

java.lang.Runnable
Runnable接口应该由那些打算通过某一线程执行起实例的类来实现。类必须定义一个称为run的无参方法,也可以使用匿名内部类实现

public class MyThread implements Runnable{
    //创建run方法
    public void run(){
        int i = 0;
        while(i++<5){
        System.out.println(Thread.currentThread().getName()+"的run方法在运行...");
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        Thread t = new Thread(mt,"Mt1");
        t.start();
        //匿名内部类实现多线程
        new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i = 0;i<=5;i++){
                    System.out.println(Thread.currentThread().getName()+"的run()...");
                }
            }
        },"Mt2").start();;
    }
}
  • Runnable和Thread的区别
    实现Runnable接口创建多线程程序的优点
    1.避免了单线程的局限性。一个类只能继承一个类,类继承了Thread类无法继承其他类实现了Runnable接口还可以继承其他类,实现其他接口
    2.增强了程序的扩展性,降低了程序的耦合度。实现Runnable接口的方式,把设置线程任务和开启新线程进行分离。实现类中,重写了run():用来设置线程任务。创建Thread类对象,调用start方法:用来开启新线程
Ⅵ.多线程同步
  1. 线程安全问题

    • 模拟线程安全问题
    public class MyThread implements Runnable{
        private int piao = 20;
        public void run(){
            while(piao>0){
                System.out.println(Thread.currentThread().getName()+"卖出第"+piao+"张票");
                try{
                    Thread.sleep(1000);
                }catch(Exception e){
                    e.getMessage();
                }
                piao--;
            }
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            MyThread mt = new MyThread();
            new Thread(mt,"窗口1").start();;
            new Thread(mt,"窗口2").start();;
            new Thread(mt,"窗口3").start();;
        }
    }
    //打印:
    窗口1卖出第20张票
    窗口3卖出第20张票
    窗口2卖出第20张票
    窗口2卖出第17张票
    窗口3卖出第17张票
    窗口1卖出第17张票
    窗口2卖出第16张票
    窗口3卖出第16张票
    窗口1卖出第15张票
    窗口2卖出第13张票
    窗口3卖出第12张票
    窗口1卖出第12张票
    窗口2卖出第10张票
    窗口1卖出第10张票
    窗口3卖出第10张票
    窗口2卖出第9张票
    窗口1卖出第7张票
    窗口3卖出第7张票
    窗口1卖出第5张票
    窗口2卖出第4张票
    窗口3卖出第5张票
    窗口2卖出第1张票
    窗口1卖出第1张票
    窗口3卖出第1张票
    
  2. 解决方式1:同步代码块

    • 格式:
    synchroized(锁对象){
       可能出现安全问题的代码(访问了共享数据的代码)
       ...
    }
    
    • 注意:

      1. 通过代码块中的锁对象可以是任意对象
      2. 保证多个线程使用的锁对象是同一个
      3. 锁对象作用是将同步代码块锁住,只让一个线程在同步代码块中执行
    • 案例

      public class MyThread implements Runnable{
          //票数
          private int piao = 20;
          //锁对象
          Object lock = new Object();
          public void run(){
              //同步代码块
              synchronized(lock){
              while(piao>0){
                  System.out.println(Thread.currentThread().getName()+"卖出第"+piao+"张票");
                  try{
                      Thread.sleep(1000);
                  }catch(Exception e){
                      e.getMessage();
                  }
                  piao--;
              }
              }
          }
      }
      public class Demo {
          public static void main(String[] args) {
              MyThread mt = new MyThread();
              new Thread(mt,"窗口1").start();;
              new Thread(mt,"窗口2").start();;
              new Thread(mt,"窗口3").start();;
          }
      }
      
  3. 解决方法2:同步方法

    • 格式(定义方法的格式)

      修饰符 synchronized 返回值类型 方法名(参数列表){
      可能出现线程安全问题的代码(访问了共享数据的代码)
      }
      
    • 案例

       public class MyThread implements Runnable{
          //票数
          private int piao = 20;
          //同步方法
          public synchronized void lock(){
              while(piao>0){
                  System.out.println(Thread.currentThread().getName()+"卖出第"+piao+"张票");
                  try{
                      Thread.sleep(1000);
                  }catch(Exception e){
                      e.getMessage();
                  }
                  piao--;
              }
          }
          public void run(){
              this.lock();
          }
      }
      
      public class Demo {
          public static void main(String[] args) {
              MyThread mt = new MyThread();
              new Thread(mt,"窗口3").start();;
              new Thread(mt,"窗口1").start();;
              new Thread(mt,"窗口2").start();;
          }
      }
      
  4. 解决方法3:Lock锁
    java.util.concurrent.locks.lock接口
    lock实现提供了比使用synchronized()和语句更广泛的锁定操作

    • lock接口的方法

      1. void lock():获得锁
      2. void unlock():释放锁
    • 案例

      public class MyThread implements Runnable{
          //票数
          private int piao = 20;
          //定义一个Lock锁
          Lock lock = new ReentrantLock();
          public void run(){
              //获得锁
              lock.lock();
              while(piao>0){
                  System.out.println(Thread.currentThread().getName()+"卖出第"+piao+"张票");
                  try{
                      Thread.sleep(1000);
                  }catch(Exception e){
                      e.getMessage();
                  }
                  piao--;
              }
              //释放锁
              lock.unlock();
          }
      }
      public class Demo {
          public static void main(String[] args) {
              MyThread mt = new MyThread();
              new Thread(mt,"窗口3").start();;
              new Thread(mt,"窗口1").start();;
              new Thread(mt,"窗口2").start();;
          }
      }
      
Ⅶ.线程间通讯
  1. 线程间通讯的方法

    方法声明功能
    void wait()使当前线程放弃同步锁进入等待状态
    void notify()唤醒同步锁上等待的,第一个调用wait()的线程
    void notifyAll()唤醒此同步锁上所有等待的线程
  2. 案例1

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urwPN0Cr-1603158679452)(C:\Users\谜语菌\Documents\img\通讯.jpg)]

    public class Demo {
     public static void main(String[] args) {
    	//创建锁对象
    	Object obj = new Object();
    	//创建线程类
    	new Thread() {
    		public void run() {
    			//创建锁对象
    			while (true) {
    				synchronized (obj) {
    			System.out.println("老板来俩包子");
    			try {
    				obj.wait();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			System.out.println("吃完了,再来俩");
    			}
    			}
    			
    		}
    	}.start();;
    	new Thread() {
    		public void run() {
    			while (true) {
    				synchronized (obj) {
    				try {
    					Thread.sleep(2000);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				System.out.println("做好了包子");
    				obj.notify();
    			}
    			}
    		}
    	}.start();;
     }
    }
    
  3. 案例2
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZAa2KooJ-1603158679454)(C:\Users\谜语菌\Documents\img\包子.jpg)]

    public class baozi{
        String pi;
        String xian;
        Boolean cun = false;
    }
    
    public class baozipu implements Runnable{
        //包子变量
        baozi bz;
        //无参构造
        public baozipu(){}
        //有参构造
        public baozipu(baozi bz){
            this.bz=bz;
        }
        @Override
        public void run() {
            while (true) {
                int zhong = 0;
               //如果有包子 
               synchronized(bz){
               if(bz.cun==true){
                   try {
                    bz.wait(); 
                   } catch (Exception e) {
                       //TODO: handle exception
                   }
                }else{
                    if(zhong%2==0){
                        bz.pi="厚皮";
                        bz.xian="猪肉";
                    }else{
                        bz.pi="薄皮";
                        bz.xian="羊肉";
                    }
                    zhong++;
                    System.out.println("正在生产");
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        //TODO: handle exception
                    }
                    bz.cun=true;
                    //唤醒吃货线程
                    bz.notify();
                    System.out.println("生产了"+bz.pi+bz.xian+"的包子");
                }
               }
            }
        }
    }
    
    public class chihuo implements Runnable{
        baozi bz;
        //无参构造
        public chihuo(){}
        //有参构造
        public chihuo(baozi bz){
            this.bz=bz;
        }
        @Override
        public void run() {
            while(true){
                //如果没有包子
                synchronized(bz){
                    if(bz.cun==false){
                        try {
                            bz.wait();
                        } catch (Exception e) {
                            //TODO: handle exception
                        }
                    }else{
                        System.out.println("吃货在吃"+bz.pi+bz.xian+"的饺子");
                        try {
                            Thread.sleep(3000);
                        } catch (Exception e) {
                            //TODO: handle exception
                        }
                        System.out.println("吃货吃完了");
                        bz.cun=false;
                        bz.notify();
                    }
                }
            }
        }
    }
    
    public class Demo{
        public static void main(String[] args) {
            baozi bz = new baozi();
            baozipu bzp = new baozipu(bz);
            chihuo ch = new chihuo(bz);
            new Thread(bzp).start();;
            new Thread(ch).start();;
        }
    }
    
Ⅷ.线程池
  1. java.util.concurrent.Executors

    • static ExecutorService newFixedThreadPool(int nTreads):创建一个可重用固定线程数的线程池
    • 参数:int nTreads:创建线程池中包含的线程数量
    • 返回值:ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收(面向接口编程)
  2. java.util.concurrent.ExecutorService:线程池接口

    • 作用:用来从线程池中获取线程,调用start(),执行线程任务

    • 方法

      1. submit(Runnable task):提交一个Runnable任务用于执行
    1. shutdown():关闭线程池
    • 使用步骤
    使用线程工厂类Executors里提供的静态方法newFixedThreadPool生产一个指定线程数的线程池
    创建一个类,实现Runnable接口重写run方法,设置线程任务
    调用ExecutorService中的方法submit,传递线程任务,开启线程,执行run方法
    调用ExecutorService中的方法shutdown销毁线程池。
    
    • 案例

      public class MyThread implements Runnable{
          //票数
          private int piao = 20;
          //定义一个Lock锁
          Lock lock = new ReentrantLock();
          public void run(){
              //获得锁
              lock.lock();
              while(piao>0){
                  System.out.println(Thread.currentThread().getName()+"卖出第"+piao+"张票");
                  try{
                      Thread.sleep(1000);
                  }catch(Exception e){
                      e.getMessage();
                  }
                  piao--;
              }
              //释放锁
              lock.unlock();
          }
      }
      public class Demo {
          public static void main(String[] args) {
              MyThread mt = new MyThread();
              ExecutorService es = Executors.newCachedThreadPool();
              es.submit(mt);
              es.shutdown();
          }
      }
      
    • 原理图

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Sltg9bM-1603158679455)(C:\Users\谜语菌\Documents\img\线程池.jpg)]

七.网络编程

Ⅰ.软件结构
  1. C/S结构:全称Client/Server结构,是客户端和服务器结构
     ![软件结构](C:\Users\谜语菌\Documents\img\CS.jpg)
  2. B/S结构:全程Browser/Server结构,是浏览器金和服务器结构
     ![软件结构](C:\Users\谜语菌\Documents\img\BS.jpg)
  3. 注意
     两种架构各有优势,但无论是哪种架构,都离不开网络的支持。**网络编程**,就是在一定协议下,实现两台计算机的通讯的程序
Ⅱ.网络通信协议
  1. 网络通信协议
    通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则网络传输协议,它对数据的传输格式,传输速率,传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换

  2. TCP/IP协议
    传输控制协议/因特网互联协议,是Internet最基本,最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通讯的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议完善自己的需求
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jipl9pw3-1603158679457)(C:\Users\谜语菌\Documents\img\传输.jpg)]

  3. UDP于TCP协议
    java.net包中提供了两种常见的网络协议支持

    • UDP概述
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rwiZMeso-1603158679459)(C:\Users\谜语菌\Documents\img\UDP.jpg)]
      ​ 用户数据协议(User Datagram Protocol)。UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时也不会向发送端反馈是否接收到数据。
      ​ UDP协议消耗资源小,通信效率高,所以通常都会用于音频,视频和普通数据的传输例如视频会议都使用UDP协议。
      ​ 使用UDP协议传送数据时,不能保证数据的完整性,因此传输重要数据时不建议使用UDP协议

    • UDP特点和单位

      1. 特点:数据被限制在64kb以内,超出范围就不能发送了
      2. 数据报(Datagram):网络传输的基本单位
    • TCP概述

      传输控制协议(Transmission Control Protocol).TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
      在TCP连接中必须要明确客户端与服务器端,由客户端向服务器端发送连接请求,每次连接的创建都要经过"三次握手"
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H32X9ElM-1603158679459)(C:\Users\谜语菌\Documents\img\TCP.jpg)]

Ⅲ.ip地址和端口号
  1. ip地址

    • 定义:
      指互联网协议地址(Internet Protocol Address),ip地址用来给一个网络中的计算机设备做唯一的编号。假如把PC比作手机,那么ip地址就相当于电话号码

    • 分类

      • IPv4:一个32位的2进制数,通常分为4个字节,表示成a.b.c.d的形式,例如192.168.65.100.
      • IPv6:采用128位地址长度,每16个字节位一组,分为8组16进制数。
    • 常用命令

      • 查看本机ip地址
      ipconfig
      
      • 检查网络是否连通
      ping 空格 ip地址
      ping 220.181.57.216
      
      • 特殊的ip地址
      本机的IP地址:127.0.0.1、localhost
      
  2. 端口号

    • 定义
      如果说ip地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程。用两个字节表示整数,取值范围065535,其中01023以占用。
      利用协议+IP地址+端口号三元组合就可以标识网络中的进程了。
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wiI9PmwX-1603158679461)(C:\Users\谜语菌\Documents\img\端口.jpg)]
Ⅳ.TCP通信程序
  1. 概述
    TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分客户端与服务端

    • 两端通信的步骤
      1. 服务端程序需要事先启动,等待客户端连接
      2. 客户端主动连接服务器端,连接成功才能通信。服务器端不可以主动连接客户端

    在java中提供两个类用于实现TCP通信程序:

    • 客户端:java.net.Socket类表示。创建Socket对象,向服务端发出连接请求,两者建立连接开始通信
    • 服务端:java.net.SeryerSocket类表示。创建SeryerSocket对象,相当于开启一个服务并等待客户端连接。
  2. Socket类

    • TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器回写的数据

    • 表示客户端的类
      java.net.Socket:此类实现客户端套接字。套接字是两台机器间通信的端点。套接字:包含IP地址和端口号的网络单位

    • 构造方法:
      Socket(String host,int port):创建一个流套接字并将其连接到指定主机的指定端口号。
      参数: String host:服务器主机的IP地址
      int port:服务器的端口号

    • 成员方法

    方法功能
    OutputStream getOutputStream()返回此套接字的输出流
    InputStream getInputStream()返回此套接字的输入流
    void close()关闭此套接字
  3. SeryerSocket类
    TCP通信的服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据

    • 表示服务器的类:
      java.net.SeryerSocket:此类实现服务器套接字

    • 构造方法
      SeryerSocket(int port):创建绑定到特定端口的服务器套接字
      参数:int port:端口号

    • 成员方法:
      Socket accept():监听并接收到此套接字的连接,并返回Socket对象

  4. 案例

    • 基本案例

      public class TCPServer {
          public static void main(String[] args) throws IOException {
              //创建服务器ServerSocket对象和系统要指定的端口号
              ServerSocket serverSocket = new ServerSocket(8865);
      
              while (true){
                  //开启多线程
                  new Thread(new Runnable() {
                      Socket socket = null;
                      @Override
                      public void run() {
                          try {
                              //调用accept()获取网络流对象
                              socket = serverSocket.accept();
                              //创建网络字节输入流读取客户端信息
                              InputStream in = socket.getInputStream();
                              byte[] bytes = new byte[1024];
                              int len = 0;
                              len = in.read(bytes);
                              System.out.println(new String(bytes,0,len));
      
                              //获取网络字节输出流向客户端回传数据
                              OutputStream out = socket.getOutputStream();
                              out.write("你好,客户端!".getBytes());
                          }catch (Exception e){
                              System.out.println("失败");
                          }finally {
                              //关闭资源
                              try {
                                  serverSocket.close();
                                  socket.close();
                              } catch (IOException e) {
                                  e.printStackTrace();
                              }
                          }
                      }
                  }).start();
              }
          }
      }
      
      public class TCPClient {
          public static void main(String[] args) throws IOException {
              //创建Socket对象,并连接到指定的服务器端
              Socket socket = new Socket("127.0.0.1",8865);
              //获取网络字节输出流
              OutputStream out = socket.getOutputStream();
              //向服务器端输出信息
              out.write("你好,服务器!".getBytes());
              //获取网络字节输入流
              InputStream in = socket.getInputStream();
              //读取服务器端传来的信息
              byte[] bytes = new byte[1024];
              int len = 0;
              len=in.read(bytes);
              System.out.println(new String(bytes,0,len));
              //释放资源
              socket.close();
          }
      }
      
    • 文件上传案例

      public class TCPServer {
          public static void main(String[] args) {
            try {
                  //创建ServerSocket对象
                  ServerSocket serverSocket = new ServerSocket(6786);
      
                  while (true) {
                      //开启多线程
                      new Thread(new Runnable() {
                          @Override
                          public void run() {
                              try {
                                  //文件上传保存目录
                                  File file = new File("E:\\img");
                                  if (!file.exists()) {
                                      file.mkdir();
                                  }
                                  Socket socket = serverSocket.accept();
                                  //获取网络文件输入流
                                  InputStream in = socket.getInputStream();
                                  //创建本地文件输出流
                                  String fileName = System.currentTimeMillis() + new Random().nextInt(99999) + ".jpg";
                                  FileOutputStream fos = new FileOutputStream(file +"\\"+ fileName);
                                  byte[] bytes = new byte[1024];
                                  int len = 0;
                                  while ((len=in.read(bytes))!=-1){
                                      fos.write(bytes,0,len);
                                  }
                                  //创建网络字节输出流,回传数据
                                  OutputStream out = socket.getOutputStream();
                                  out.write("上传成功".getBytes());
                                  System.out.println("0000");
                                  out.flush();
                                  //关闭资源
                                  serverSocket.close();
                                  socket.close();
                                  fos.close();
                              } catch (IOException e) {
                                  e.printStackTrace();
                              }
                          }
                      }).start();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      
      public class TCPClient {
          public static void main(String[] args) throws IOException {
              //创建Socket对象
              Socket socket = new Socket("127.0.0.1",6786);
              //创建本地文件输入流
              FileInputStream fis = new FileInputStream("C:\\Users\\谜语菌\\Documents\\img\\sanjiao.jpg");
              //创建网络字节输出流
              OutputStream out = socket.getOutputStream();
              byte[] bytes = new byte[1024];
              int len = 0;
              while ((len = fis.read(bytes))!=-1){
                  out.write(bytes,0,len);
              }
              //添加结束标记
              socket.isOutputShutdown();
              //创建网络字节输入流
              InputStream in = socket.getInputStream();
              while ((len = in.read(bytes))!=-1){
                  System.out.println(new String(bytes,0,len));
              }
              System.out.println("000");
              //关闭资源
              socket.close();
              fis.close();
          }
      }
      
      

八.Juit单元测试

  1. 测试的分类

    • 黑盒测试:不需要写代码,给输入值,看程序是否输出期望的值
    • 白盒测试:需要写代码。关注程序具体的执行流程
  2. 白盒测试

    • 步骤:

      1. 定义一个测试类(测试用例)
        包名:xxx.xxx.test
        测试类名:被测试类名+Test
      2. 定义一个测试方法:可以独立运行
        方法名:test+测试的方法名
        返回值:void
        参数列表:空参
      3. 给测试方法加@Test注解
      4. 添加依赖
    • 结果判定

      1. 绿色成功
      2. 红色失败
      • 一般使用断言操作:Assert.assertEquals(期望的值,实际的值)
    • 补充

      • @Before
        修饰的方法,在所有测试方法开始之前执行
      • @After
        修饰的方法,在所有测试方法结束之后执行
    • 案例

    public class Math {
        public int add(int a,int b){
            return a+b;
        }
    }
    public class MathTest {
        @Before
        public void init(){
            System.out.println("测试方法执行之前执行");
        }
        @After
        public void closure(){
            System.out.println("测试方法执行结束执行");
        }
        @Test
        public void testAdd(){
            Math math = new Math();
            int i = math.add(3,2);
            System.out.println("testAdd()执行...");
            Assert.assertEquals(5,i);
        }
    }
    

Ⅱ.反射:框架设计的灵魂

①什么是反射

反射

​ 将类的各个组成部分封装为其他对象,这就是反射机制。

好处

​ 1.可以在程序运行过程中操作这些对象。

​ 2.可以降低程序的耦合度,提高程序的可扩展性。

②什么是框架

框架:

​ 半成品的软件。可以在框架的基础上进行软甲开发,简化代码。

③获取Class对象的方式

**1.Class.forName(“全类名”):**将字节码文件加载进内存,返回Class对象

  • 多用于配置文件,将类名定义在配置文件中。读取文件加载类

**2.类名.Class:**通过类名的属性Class获取

  • 多用于参数的传递

**3.对象.getClass():**getClass()方法在Object类中定义着

  • 多用于对象的获取字节码的方式
public class ReflectDom01 {
    /**
     获取Class对象的方式:
     */
    public static void main(String[] args) throws Exception {
        //1.Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
        Class aClass = Class.forName("com.zixi.wed.domian.person");
        System.out.println(aClass);
        //2.类名.Class:通过类名的属性Class获取
        Class<person> bClass = person.class;
        System.out.println(bClass);
        //3.对象.getClass():getClass()方法在Object类中定义着
        person p = new person();
        Class<? extends person> cClass = p.getClass();
        System.out.println(cClass);

        //比较三个对象
        System.out.println(aClass == bClass);  //true
        System.out.println(aClass == cClass);  //true
    }
}

结论:

​ 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。

④Class对象的功能

1.获取成员变量们

返回值类型方法名作用
Field[]getFields()获取所有public修饰的成员变量
FieldgetField(String name)获取指定名称的 public修饰的成员变量
Field[]getDeclaredFields()获取所有的成员变量
FieldgetDeclaredField(String name)获取指定名称的成员变量

代码示例:

public class ReflectDeom02 {

    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException {
        //Field[]   getFields()  
        person p = new person();
        Class<person> personClass = person.class;
        Field[] fields = personClass.getFields();
        for(Field f:fields){
            System.out.println(f);
            //public int com.zixi.wed.domian.person.a
        }
        //Field  getField(String name)
        Field a = personClass.getField("a");
        a.set(p,12);
        System.out.println(a.get(p));//12
        //Field[] 	getDeclaredFields()
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field f:declaredFields){
            System.out.println(f);
            //private java.lang.String com.zixi.wed.domian.person.name
            //private int com.zixi.wed.domian.person.age
            //public int com.zixi.wed.domian.person.a
        }
        //Field 	getDeclaredField(String name)
        Field name = personClass.getDeclaredField("name");
        name.setAccessible(true);//暴力反射:无视安全性,访问person中的私有变量
        name.set(p,"张三");
        System.out.println(name.get(p));//张三
    }
}

2.获取构造方法们

返回值类型方法名作用
Constructor<?>[]getConstructors()获取所有public修饰的构造方法
ConstructorgetConstructor(Class<?>…parameterTypes)获取指定public修饰的构造方法
Constructor<?>[]getDeclaredConstructors()获取所有的构造方法
ConstructorgetDeclaredConstructor(Class<?>… parameterTypes)获取指定参数的构造方法

代码示例:

    public static void main(String[] args) throws Exception {
        Class<person> personClass = person.class;
        //Constructor<?>[] getConstructors()
        Constructor<person> constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        //public com.zixi.wed.domian.person(java.lang.String,int)
        
        //创建对象
        person person = constructor.newInstance("张三", 21);
        System.out.println(person);
        //person{name='张三', age=21}
        
        //创建空参对象
        person person1 = personClass.newInstance();
        System.out.println(person1);//person{name='null', age=0}
    }

3.获取成员方法们

返回值类型方法名作用
Method[]getMethods()获取所有public修饰的方法
MethodgetMethod(String name, Class<?>… parameterTypes)获取指定public修饰的方法
Method[]getDeclaredMethods()获取所有的方法
MethodgetDeclaredMethod(String name, Class<?>… parameterTypes)获取指定的方法

代码示例:

public class ReflectDeom04 {
    public static void main(String[] args) throws Exception {
        //获取全部方法 getMethods()
        Class<person> personClass = person.class;
        Method[] methods = personClass.getMethods();
        for(Method method:methods){
            System.out.println(method);
            System.out.println(method.getName());
        }
        //获取指定方法  getMethod(String name, Class<?>... parameterTypes)
        Method chi_method = personClass.getMethod("chi");
        person p = new person();
        chi_method.invoke(p);//吃馒头...
        //获取有参方法
        Method chi = personClass.getMethod("chi", String.class);
        chi.invoke(p,"米饭");//吃米饭...
    }
}

4.获取类名

        //获取类名
        String name = personClass.getName();
        System.out.println(name);  //com.zixi.wed.domian.person

Field:成员变量

操作:

​ 1.设置值

​ void set(Object obj,Object value)

​ 2.获取值

​ void get(Object obj)

​ 3.忽略访问权限修饰符的安全检查

​ setAccessible(true):暴力反射

Constructor:构造方法

​ 创建对象:

​ T newInstance(Object…initargs)

​ 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

Method:方法对象

​ 执行方法:

​ Object invoke(Object obj,Obj…args)

​ 获取方法名:

​ String getName():获取方法名

⑤反射案例
//配置文件
className=com.zixi.wed.domian.Student
methodName=sleep
/**
 * 学生类
 */
public class Student {
    public void sleep(){
        System.out.println("sleep...");
    }
}

/**
 * 框架类
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //1.加载配置文件
        //1.2创建Properties对象
        Properties properties = new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        properties.load(is);
        //获取配置文件中定义的数据
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        //获取Class对象
        Class aClass = Class.forName(className);
        //获取无参构造方法
        Constructor<?> constructor = aClass.getConstructor();
        //创建对象
        Object o = constructor.newInstance();
        //获取方法
        Method method = aClass.getMethod(methodName);
        //执行方法
        method.invoke(o);
        //sleep...
    }
}

Ⅲ.注解

概念

概念:说明程序,给计算机看

注释:用文字描述程序,给程序员看

定义

从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。

作用分类
  1. 编写文档:通过代码里标识的注解生成文档【生成doc文档】
  2. 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
  3. 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
学习内容
①JDK中预定义的一些注解

@Override:检测被该注解标注的方法是否是继承自父类(接口)的(是否是重写的)

@Deprecated:该注解标注的内容,表示已过时

@SuppressWarnings:压制警告

代码示例:

@SuppressWarnings("all")
public class AnnoDemo02 {
    @Override
    public String toString() {
        return super.toString();
    }

    @Deprecated
    public void show1(){
        //有缺陷
    }

    public void show2(){
        //缺陷弥补,替代show1方法
    }

    public void demo(){
        show1();
    }
}

②自定义注解

格式:

元注解
public @interface 注解名称{

}

本质:注解本质上就是一个接口,该接口默认继承.Annotation接口

​ public interface MyAnno extend java.lang.annotation.Annotation{}

**属性:**接口中的抽象方法

  1. 属性的返回值类型
  • 基本数据类型

  • String

  • 枚举

  • 注解

  • 以上类型的数组

    定义了属性,在使用时需要给属性赋值

    public @interface myAnn {
        String name();
        int age();
        String sex() default "男";
        //如果的定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不进行赋值
    }
    @myAnn(name = "张三",age = 12)
    public class AnnDemo {
    }
    //value属性单独存在,赋值时可以省略value
    public @interface myAnn {
        String value();
    }
    @myAnn("张三")
    public class AnnDemo {
    }
    //数组赋值时使用{}包裹,数组中只有一个数据时{}可以省略
    public @interface myAnn {
        String name();
        int age();
        String sex() default "男";
        String[] arr();
    }
    @myAnn(name = "张三",age = 12,arr = {"张三","李四"})
    public class AnnDemo {
    }
    @myAnn(name = "张三",age = 12,arr = "张三")
    public class AnnDemo {
    }
    

元注解:用于描述注解的注解

  1. @Target:描述注解能够作用的位置

    @Target(value = {ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
    public @interface myAnn {
    }
    TYPE:可以作用于类上
    METHOD:可以作用于方法上
    FIELD:可以作用于成员变量上
    
  2. @Retention:描述注解被保留的阶段

    SOURCE
    CLASS
    RUNTIME
    @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
    
  3. @Documented:描述注解是否被抽取到api文档中

  4. @Inherited:描述注解是否被子类继承

③在程序中使用(解析)注解:获取注解中定义的属性值
  1. 获取注解定义的位置的对象 (Class,Method,Field)
  2. 获取注解的对象 getAnnotation(注解.class)
  3. 调用注解中的抽象方法获取配置的属性值
//配置文件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
    String className() default "com.zixi.wed.domian.Student";
    String methodName() default "sleep";
}

//学生类
public class Student {
    public void sleep(){
        System.out.println("sleep...");
    }
}
//框架类
@MyAnno
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //1.解析注解
        //1.1获取该类的字节码文件
        Class reflectTestClass = ReflectTest.class;
        //2.获取注解对象
        //其实就是在内存中生成了一个该注解接口的实现类对象
        MyAnno annotation = reflectTestClass.getAnnotation(MyAnno.class);
       //3.调用注解对象中发定义的抽象方法,获取返回值
        String className = annotation.className();
        String methodName = annotation.methodName();
        //3.创建class对象
        Class aClass = Class.forName(className);
        //4.获取构造器并创建对象
        Constructor constructor = aClass.getConstructor();
        Object o = constructor.newInstance();
        //5.获取方法
        Method method = aClass.getMethod(methodName);
        method.invoke(o);

    }
}

案例
/**
*计算器类
*/
public class Calculator {
    //加法
    @MyAnno1
    public int add(){
        return 1+0;
    }
    //减法
    @MyAnno1
    public int red(){
        return 1-0;
    }
    //乘法
    @MyAnno1
    public int ride(){
        return 1*0;
    }
    //除法
    @MyAnno1
    public int exc(){
        return 1/0;
    }
    private void show(){
        System.out.println("show...");
    }
}
/**
*注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno1 {
}
**
 * 简单的测试框架
 *
 *当主方法执行后,会自动自行检测被检测的所有方法(加了Check注解的方法),判断方法是否异常,记录到文件中
 */
public class TestCheck {
    public static void main(String[] args) throws IOException {
        //1.创建计算器对象
        Calculator c = new Calculator();
        //2.获取c的字节码文件对象
        Class aClass = c.getClass();
        //3.获取所有方法
        Method[] methods = aClass.getMethods();

        int number = 0;//出现异常的次数
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));

        for(Method method:methods){
            //4.判断方法上是否有Check注解
            // 5.有,执行
            if(method.isAnnotationPresent(MyAnno1.class)){
                try {
                    Object invoke = method.invoke(c);
                } catch (Exception e) {
                    //6.捕获异常
                    number++;

                    bw.write(method.getName()+"方法发生异常了");
                    bw.newLine();
                    bw.write("异常的名称:"+e.getCause().getClass().getSimpleName());
                    bw.newLine();
                    bw.write("异常的原因:"+e.getCause().getMessage());
                    bw.newLine();
                    bw.write("--------------------");
                }
            }
        }
        bw.newLine();
        bw.write("本次测试一共出现"+number+"次异常");
        bw.flush();
        bw.close();
    }
}
/**
*运行展示
*/
exc方法发生异常了
异常的名称:ArithmeticException
异常的原因:/ by zero
--------------------
本次测试一共出现1次异常

小结
  1. 以后大多时候,我们会使用注解而不是自定义注解
  2. 注解给谁用?
  • 编译器
  • 解析程序用
  1. 注解不是程序的一部分,可以理解为注解是一个标签
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值