JavaSE复习笔记

第一章 Java概述

一、计算机语言

  1. 机器语言
  2. 汇编语言
  3. 高级语言

二、跨平台原理

Java可以在一处开发到处运行,即在一类操作系统上开发的程序,可以在任何操作系统上运行。

不同的操作系统有不同的JVM,java是运行在JVM上,从而实现了跨平台。

  1. JVM:Java虚拟机
  2. JRE:Java运行时环境=JVM+核心类库
  3. JDK:Java开发工具集=JRE+开发工具
  4. 三者关系:JDK包含JRE,JRE包含JVM

三、JDK安装与配置环境变量

安装时建议不要单独再安装公共jre。

配置环境变量:

  1. 目的:更方便的在任意目录下使用开发工具
  2. 电脑-》右键属性-》高级-》系统环境变量-》新建变量名JAVA_HOME,变量值java安装目录-》编辑path变量,添加变量值:%JAVA_HOME%\bin;

四、入门程序

  1. 开发程序的步骤
    1. 编写源代码
    2. 使用javac命令编译源代码,产生对应的.class字节码文件
    3. 使用java命令运行字节码文件,产生结果
  2. 注意事项:
    1. 源码中使用的字符,严格区分大小写,
    2. 必须是英文状态下的标点符号等
    3. 括号必须成对出现
    4. 创建类时,建议使用public修饰符,如果有public,类名必须与文件名一致
    5. 可以创建多个类,只能有一个public的
    6. 编码要一致

第二章 基础语法

一、注释

给程序员开的说明性文字

  1. 单行注释 //注释内容
  2. 多行注释 /*注释内容 */
  3. 文档注释 /**注释内容 */

二、关键字

Java赋予了特殊含义的字符序列(单词),比如:public class static void

保留字:const ,goto

特殊值:true ,false,null

三、标识符

用于给类,方法,变量等起名字的字符序列。

  1. 命名规则:必须遵守的
    1. 由英文字母、数组、下划线_,美元符号组成
    2. 不能是数字开头
    3. 不能使用关键字
    4. 严格区分大小写
  2. 建议遵守的命名规范:
    1. 见名知意
    2. 类名,接口名:大驼峰发则 XxxYyy
    3. 方法名,变量名:小驼峰 xxxYyy
    4. 包名:全小写 com.atguigu.test
    5. 常量名:全大写 ,多个单词下划线隔开。 MAX_VALUE

四、常量

程序运行过程中,其值不可改变的量

  1. 字面量。比如:字符串"hello",整数100,浮点数12.3,布尔值true或false,字符‘a’,空值null

  2. 自定义常量,使用关键字final

    final double PI = 3.1415926

五、变量

程序运行过程中,其值可以改变的量

  1. 声明格式

    数据类型 变量名; 示例:int age;

  2. 初始化值

    开辟内存空间并给赋值,示例:age=18;

  3. 声明并初始化

    格式:数据类型 变量名 = 初始值;

    示例:int age = 18;

    示例:int a=1,b=2,c=3;

六、二进制存储

二进制存储数据

  1. 整数的存储,底层按照补码形式存储

    1. 原码:最高位是符号位,0是正,1是负数,其他为数值位。
    2. 反码:原码基础上,符号位不变,数值位按位取反,0变1,1变0
    3. 补码:反码基础上加1

    正数的原码,反码,补码都相同,负数按照以上规则得出。

  2. 小数的存储

    1. java浮点数无法精确存储小数
    2. 同样字节大小的存储小数的范围远大于存储整数的范围
  3. 字符的存储

    编码表:每个字符都有唯一对应的二进制数值

    ASCII码表:英文字符,其他编码表都向下兼容此编码方式

    GBK:中国编码表

    Unicode的:万国码,统一码,Java本身支持的编码表

    UTF-8:编码方式

七、数据类型

1.分类

  1. 基本数据类型

    1. 整数
      1. byte 1 -128~127
      2. short 2
      3. int 4
      4. long 8
    2. 浮点数
      1. float 4
      2. double 8
    3. 字符型 2 0~65535
    4. 布尔型 1 true/false
  2. 引用数据类型

    String,数组,类,接口等

2.类型转换

基本数据类型中,七种数值类型(除布尔类型外)可以相互转换类型。
byte、short、int、long、double、float、boolean

  1. 自动转换:数值范围小的类型转为数值范围大的类型

    1. 多个类型混合运算,自动提升为最大的类型
    2. byte,short,char之间进行运算,全部提升为int
  2. 强制转换:数值范围大的类型转为数值范围小的类型,容易损失精度

    1. 可以强制提升某个类型

      int a=1,b=2;
      double c=(double)a/b;
      

八、运算符

  1. 算数运算符

    加+ 减- 乘* 除/ 取余% 自增++ 自减–

    自增++,自减–

    1. 单独使用时,前置后置效果一样

      int a=10;
      a++;//自增1
      ++a;//自增1
      System.out.println(a);
      
    2. 复合使用时

      • 后置:先使用,再自增自减。

        int a = 10;
        int b = a++;//后置
        System.out.println(a);//11
        System.out.println(b);//10
        
      • 前置:先自增自减,在使用。

        int a = 10;
        int b = ++a;//前置
        System.out.println(a);//11
        System.out.println(b);//11
        
  2. 赋值运算符

    = += -= *= /= %=

    byte a = 10;
    a += 10;//可以,相当于a=a+10;
    a = a + 10;//编译不通过
    
  3. 关系运算符

    结果一定是布尔类型

    < > <= >= == !=

  4. 逻辑运算符

    操作数都是布尔类型的,结果也是布尔类型

    逻辑与& :两边都为真,才为真

    逻辑或|:一边为真,就为真

    逻辑非!:取反

    异或^, :两边相同为假,两边不同为真。

    短路与&&,:同单与

    短路或||:同单或

    为什么推荐使用短路与、短路或?

    短路与,短路或,当通过操作符左边的表达式结果,可以直接判断出最终结果时,右边不再执行,效率高。

  5. 条件运算符(三目运算符)

    格式:条件表示?结果1:结果2;

    注意:结果是一个数据(不能是输出语句)。

    int age=18;
    String s = age>=18?"可以开车了":"好好学习";
    
  6. 位运算符

    按照二进制位进行运算的运算符,运算效率高

    &,|,~,^ ,

    左移<< :左移n位,等于乘以2的n次幂。

    右移>> :右移n为,等于除以2的n次幂,除不尽时,向下取整。

    无符号右移>>> :底层二进制数据移动时,左边始终补0

  7. 运算符的优先级

    大体的排序:算术 > 位 > 比较 > 逻辑 > 三元 > 赋值

    第三章 流程控制

    1. 顺序结构:代码自上而下逐行执行
  8. 选择结构:根据条件不同,选择性的执行某些特定代码

    1. 循环结构:根据条件,重复执行特定代码

一、键盘录入

键盘扫描器 java.util.Scanner;

import java.util.Scanner;//导入
//....
//创建一个键盘扫描器
Scanner in = new Scanner(System.in);
//提示信息
System.out.println("请输入数据:");
//接收数据
int n = in.nextInt();//接收整数
char ch = in.next().charAt(0);//接收一个字符
String s = in.next();//接收字符串,遇到空白字符结束
String line = in.nextLine();//接收一个行字符串,遇到enter键结束。

二、分支结构

1.if语句

  1. 格式一:

    if(关系表达式){
    	语句块
    }
    
  2. 格式二:

    if(关系表达式){
    	语句块1
    }else{	语句块2
    
    }
    
    
  3. 格式三:

    if(关系表达式1){
    	语句块1
    }else if(关系表达式2){
    	语句块2
    }else if(关系表达式3){
    	语句块3
    }else{
    	语句块n
    }
    
    
  4. if语句嵌套

    if(年龄大18){
        
        if(男性){
           // 开车
        }else{
          //  
        }
        
    }
    
    

2.switch语句

  1. 格式:

    switch(常量表达式){
        case 常量值1:
            语句块1break;
        case 常量值2:
            语句块2break;
        case 常量值3:
            语句块3break;
        default :
            语句块
            break;
    }
    
    
  2. 格式说明

    1. 常量表达式的值跟case后面的常量值相等时,执行case后对应的语句块。
    2. 常量表达式值的类型,限定为6种:byte,short,int,char,String,枚举
    3. break关键字,用于跳出switch语句,如果没有会穿透执行下一个case语句块。
    4. case后面的常量值不能重复。

3.if与switch比较

  1. if语句的条件是布尔类型,更方便使用范围作为条件
  2. switch语句条件,只能是常量值,而且类型有限制
  3. 如果添加时固定的几个常量值时,可以使用if或switch,如果固定值的个数较多时,推荐使用switch语句。

三、循环语句

1.for循环

  1. 格式

       for(初始化语句①; 循环条件语句②; 迭代语句④){
       		循环体语句③
       }
    
       for(;;){
           循环体语句块;//如果循环体中没有跳出循环体的语句,那么就是死循环
       }
    
    
  2. 执行流程:①②③④②③④②③④…②

  3. 示例

    for(int i=0;i<5;i++){
        System.out.println(i);
    }
    
    

2.while循环

  1. 格式

    while (循环条件语句①) {
        循环体语句②;
    }
    
    while(true){
         循环体语句;//如果此时循环体中没有跳出循环的语句,也是死循环
    }
    
    
  2. 执行顺序:①②①②①②…①

  3. 示例

    int i=0;
    while(i<5){
        System.out.println(i);
        i++;
    }
    
    

3.do…while循环

  1. 格式

    do {
        循环体语句①;
    } while (循环条件语句②)
  2. 执行顺序:① ②①②①②…②

4.循环语句比较

  1. 如果循环次数确定,使用for循环
  2. 循环次数不确定,使用while
  3. 只是执行一次循环体,使用do…while
  4. for(;{循环体},除循环体外不需要执行其他语句,性能略高
  5. while(true){ 循环体},除循环体外还需要执行小括号里的表达式

四、关键字break

应用场景与作用

  1. switch语句中,用于跳出switch语句

  2. 循环语句中,跳出当前循环体

    for(int i=0;i<5;i++){
        if(i==2)
            break;
        System.out.println(i);
    }
    //结果:0 1
    
    

五、关键字continue

用于循环语句中,跳出当次循环,继续下一次循环

for(int i=0;i<5;i++){
    if(i==2)
        continue;
    System.out.println(i);
}
//结果:0 1 3 4

六、嵌套循环

//打印5行5列的*
//外循环控制行数
for(int i=0;i<5;i++){
    //内循环控制列数
    for(int j=0;j<5;j++){
        System.out.print("*");
    }
    System.out.println();//换行
}

第四章 数组

一、相关概念

  1. 数组:一个存储相同类型数据的容器

  2. 数组名:数组的名字,是个变量名,遵循标识符规则,规范

  3. 元素:数组中的每个数据

  4. 索引:脚标或下标,用于访问元素的编号。0 ,1,2…

  5. 长度:数组存放的元素个数。数组的length属性

二、特点:

  1. 数组一旦创建不可改变,长度不可变。
  2. 数组的元素都是同一种数据类型
  3. 内存中开辟的一块连续的内存空间
  4. 通过索引可以快速访问元素

三、数组的声明与初始化

  1. 声明

    格式:数据类型[] 数组名;

int[] arr;

  1. 初始化

    开辟内存空间,并给初始化值

    1. 静态初始化:程序员给出初始值,系统决定数组长度
    int[] arr = new int[]{1,2,3,4,5};
    //简化
    int[] arr = {1,2,3,4,5};
    
    
    1. 动态初始化:程序给出数组长度,初始值系统给出默认值
    //先声明,再初始化
    int[] arr;
    arr = new int[5];
    //声明并同时初始化
    int[] arr = new int[5];
    
    
    

四、数组元素的访问

int[] arr = new int[]{1,2,3,4,5};
System.out.println(arr[0]);//获取0位置的元素
arr[0] = 11;//修改0位置的元素
int x = arr[0];

数组的遍历

int[] arr = new int[]{1,2,3,4,5};
for(int i=0;i<arr.length;i++){
    System.out.println(arr[i]);
}


五、数组元素的默认初始值

动态初始化数组后,系统给出元素的默认初始值

  1. 整数(byte ,short,int,long):0
  2. 浮点数(float,double):0.0
  3. 字符型(char):0,\u0000,表现出来时空白
  4. 布尔(boolean):false
  5. 引用数据类型:null

六、数组的内存分析

数组是引用数据类型

	堆
		存放new的对象和数组
		可以被所有的线程共享,不会存放别的对象引用
	栈
		存放变量基本类型(包含这个基本类型的具体数值)
		引用对象的变量(会存放这个引用再堆里面的具体地址)
	方法区
		可以被所有线程共享
		包含了所有static和class变量

七、数组的相关算法

  1. 统计相关,求总和,求均值,统计个数

  2. 查找指定元素及其位置(顺序查找,二分查找);查找最值及其位置。

  3. 冒泡排序,排序原理掌握:每轮两两比较大小,大的交换到后面,每轮比较完后最大的移动到最后位置,依次比较多轮

    int[] arr = {11,2,3,44,5,66,7};
    //外循环控制轮数
    for(int i=0;i<arr.length-1;i++){
        //内循环控制每轮比较的次数
        for(int j=0;j<arr.length-1-i;j++){
            //比较并交换
            if(arr[j]>arr[j+1]){
                int temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
           
        }
    }
    
    
  4. 数组的反转:前后元素倒置

  5. 数组的扩容:数组空间不足时,进行扩容。通常情况扩容为原来的1.5倍或2倍。创建新数组,效率低,要减少扩容操作

  6. 数组元素的插入:通常首先需要扩容。插入元素后,保证原来元素有序性。把插入位置之后的每个元素后移一位。

  7. 数组元素的删除:把删除位置之后的每个元素前移一位,以保证原数据的有序性和连续性。

  8. 直接选择排序:每轮的第一个元素与后面的每个元素比较。把最小的与每轮的第一个交换位置。依次多轮比较。

八、数组工具类Arrays

Java提供的一个工具,里面封装一些方便操作数组的方法

  1. 排序:Arrays.sort(arr);
  2. 二分查找:int index = Arrays.binarySearch(数组,目标元素);//如果返回负数表示没找到
  3. 把数组元素变成字符串: String s = Arrays.toString(数组);

九、二维数组

本质上是一个元素是一维数组的数组

  1. 声明格式:

    //声明
    数据类型[][]  数组名;
    
    

    示例:

    int[][] arr;
    
    
  2. 初始化

    1. 静态初始化

      int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};
      //简化
      int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
      
      
    2. 动态初始化

      //规则二维表
      int[][] arr = new int[2][3];//2行3列
      
      
      //不规则二维表
      int[][] arr = new int[3][];
      arr[0] = new int[]{1};
      arr[1] = new int[]{2,3};
      arr[2] = new int[]{4,5,6};
      
      
  3. 二维数组元素的访问与遍历

    int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
    
    for(int i=0;i<arr.length;i++){
        //遍历每个一维数组
        for(int j=0;j<arr[i].length;j++){
            System.out.print(arr[i][j]+" ")}
        System.out.println();
    }
    
    

第五章 面向对象(上)

一、概念理解

  1. 面向对象:是一种编程思想,就在程序设计过程中,参照现实中事物,把事物的静态特征和动态特征抽象描述为计算机中的事件。

  2. 对象:是一个具有属性和行为具体的事物。

  3. 类:是一类具有相同属性和行为的事物的抽象。

  4. 类与对象的关系:

    类是对象的模板,对象是类的实例

    类是抽象的,对象是具体的

二、类和对象的定义与创建

  1. 类的定义格式

    【修饰符】 class 类名{
        //类的成员
        //属性-静态特征-成员变量
        //动态特征-成员方法
    }
    
    

    示例

    public class Student{
        //成员变量
        String name;
        int age;
        //成员方法
        public void study(){
            System.out.println("学习....");
        }
    }
    
    
  2. 通过类来创建对象

    类名 对象名 = new 类名();//类名,可以看做是一种自定义的数据类型,是引用数据类型
    
    

    示例

    Student s = new Student();
    //对象的使用
    //使用属性
    s.name = "tom";
    s.age = 18;
    //使用方法
    s.study();
    
    

三、包

包名:com.atguigu.test 。当前类必须在第一行使用关键字package声明所在的包

  1. 可以避免类重名:有了包之后,类的全名称就变为:包.类名

  2. 分类组织管理众多的类

    使用不同包下的类需要导入,使用关键字import 包名.类名。java.lang包下不需导入

  3. 配合权限修饰符实现权限管理

四、成员变量

  1. 变量的分类

    1. 成员变量:定义在类的成员位置,作用范围是整个类内部
      1. 类变量:静态变量,有static修饰的
      2. 实例变量:没有static修饰
    2. 局部变量:定义在方法或其他局部区域内,作用访问局部区域
  2. 成员变量的声明

    1. 格式

      【修饰符】 数据类型 变量名;//常用修饰符有权限修饰符,static ,final
      
      
    2. 示例

      public class Student{
      	public String name;
      	public static int x=10;//属于类变量
      }
      
      
  3. 成员变量的访问

    1. 实例变量访问,必须使用对象来访问

      Student s = new Student();
      s.name = "tom";//通过对象名.属性名 访问
      
      
    2. 类变量的访问,可以使用对象访问或类名访问(推荐方式)

      Student s = new Student();
      System.out.println(Student.x);//通过类名.属性名来访问
      
      
  4. 成员变量的特点

    1. 实例变量:每个对象独有一份
    2. 类变量:类的所有对象公用的一份数据
    3. 所有的成员变量都有默认初始值。类似数组元素的默认初始值
  5. 成员变量的内存分析

    实例变量在堆中,静态变量在方法区中

  6. 成员变量与局部变量

    成员变量 局部变量
    声明的位置 直接声明在类的成员位置 声明在方法体中或其他局部区域内(方法声明上,构造方法,代码块等)
    修饰符 public、private、static、final等 不能使用访问权限修饰符,可以使用final
    内存加载位置 堆或方法区(static修饰时)
    初始化值 有默认初始化值 无默认初始化值
    生命周期 同对象或类(static时)的生命周期 随着方法的调用而存在,方法调用完毕即消失

五、方法

  1. 概念

    方法是功能代码块,为了提高代码的复用性,可以简化代码,用于描述对象的行为特征。

  2. 方法的分类

    1. 静态方法:有static修饰,可以使用类名或对象名调用,推荐使用类名调用
    2. 实例方法:没有static修饰,使用对象名调用
  3. 方法的声明

    1. 格式
    【修饰符】 返回值类型 方法名(【数据类型1 变量1,数据类型2 变量2...){
        //方法体
        return 【返回值】;
    }
    
    
    1. 格式说明

      修饰符:可以是权限修饰符,static等

      返回值类型:如果方法有返回值类型必须与返回值的类型一致,没有返回值是void

      方法名:标识符,xxxYyy

      参数列表:可有可无,参数是局部变量

      return语句:作用①返回值,②结束方法。如果没有返回值,方法体最后可以有return;

    2. 示例

      public class Student{
          //成员方法
          public String show(){
              System.out.prrintln("hello");
              return "hello";
          }
          
          public static void hello(String name){
              //return;
              System.out.println("hello "+name);
             // return;
          }
          
      }
      
      
  4. 方法的调用

    1. 类的外部

      1. 实例方法:对象名.方法名(实参);

        Student s = new Student();
        String str = s.show();//因为此方法有返回值,可以使用变量接收
        s.hello("tom");//静态方法,不推荐这种方式调用
        
        
      2. 静态方法:类名.方法名(实参);

        Student.hello("tom");//推荐
        
        
    2. 同一个类内部

      可以直接调用本类内的其他方法。注意:静态的不能访问非静态

      public class Chinese{
          String name;//实例变量
          static String country="China";//类变量,静态变量
      
          public void testInstanceMethod(){}//实例方法
          
          public static void testStaticMethod(){//静态方法
              //注意:这里不能访问非静态成员
          }
          
          //实例方法
          public void test(){
              sout(name+"--"+country)//可以直接方法类的成员变量
              testInstanceMethod();//直接访问成员方法
              testStaticMethod();//实例方法中直接访问静态方法
          } 
      }
      
      
    3. 方法调用的注意事项:

      1. 形参是方法声明上的参数列表,调用方法时传入的任意匹配的数据
      2. 实参是调用方法时实际传入的数据
      3. 调用方法时,实参列表必须跟形参列表完全匹配。参数的个数,类型,顺序都必须一致
      4. 返回值类型必须与实际的返回数据类型匹配。
  5. 方法参数的值传递机制

    Java中,方法传参只有值传递。

    方法参数是基本数据类型:形参的改变不会影响实参

    方法参数是引用数据类型:形参的改变会影响实参

  6. 方法重载Overload

    在同一个类中,方法名相同,参数列表不同的情况。

    参数列表不同指的是:参数个数不同或类型不同或类型顺序不同。

  7. 可变参数

    相同类型的任意个参数。任意个参数会被封装到一个数组中,可变参数的变量实际是一个数组。

    public int add(String s,int i,int...a){//表示调用方法时可以传入的参数个数任意
        
    }
    
    

    注意:一个方法中只能有一个可变参数,并且必须在最后一个。

六、递归

  1. 概念:方法调用自己的情况

    //求n!
    public int testRecursion(int n){
        if(n==1)
            return 1;
        return  testRecursion(n-1)*n;
    }
    
    
  2. 分类

    1. 直接递归:方法自己直接调用自己
    2. 间接递归:方法A调用方法B,方法B调用方法A
  3. 注意事项:

    1. 递归一定要有出口(终止条件),否则是无穷递归(类似死循环),会导致栈内存溢出
    2. 即使递归有终止条件,递归次数也不宜太多,否则还会造成栈内存溢出

七、对象数组

元素是引用数据类型的数组

public class Student{
    private String name;
    private int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    
    public void printInfo(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

//主方法
//创建对象数组
Student[] stus = new Student[3];
//存储对象
stus[0] = new Student("tom",18);
stus[1] = new Student("jack",19);
stus[2] = new Student("rose",20);
//遍历数组
for(int i=0;i<stus.lenght;i++){
    stus[i].printInfo();
}

第六章 面向对象(中)

一、封装

  1. 概念理解:把事物内部隐藏起来,与外界隔离,对外提供安全的公共访问途径,总之,隐藏该隐藏的,暴露该暴露的。

  2. 使用权限修饰符可以实现类的封装

    权限修饰符 本类内 本包内 其他包子类中 任意位置
    private Y
    缺省的 Y Y
    protected Y Y Y
    public Y Y Y Y

    可以修饰外部类的是public、缺省修饰符

    4种修饰符可以修饰内部类、方法、成员变量、构造器

  3. 类的封装

    属性私有化,提供公共的方法用于外界访问属性

    public class Student{
        //属性私有化
        private String name;
        private int age;
        
        //公共的getter/setter
        public void setName(String name){
            this.name = name;//this表示对象的引用,谁调用此方法,代表谁
        }
        
        public String getName(){
            return name;
        }
    }
    
    

二、构造器

  1. 构造器的作用

    初始化对象的数据

  2. 语法格式:

    权限修饰符 类名(【参数列表】){
        //构造器
    }
    
    
  3. 格式说明

    1. 构造器的名字必须与本类类名相同
    2. 构造器与普通方法类似,但是没有返回值,也没有void
    3. 构造器也可以重载
    4. 系统会默认给出无参构造器,如果显示写出一个构造器,隐藏的无参构造器不再存在
  4. 示例:

    public class Student{
        private String name;
        private int age;
        //空参构造器
        public Student(){}
        //带参构造器
        public Student(String name){
            this.name = name;
        }
        
        public Student(String name,int age){
            this(name);//调用本类的其他构造器,注意这句必须在构造体内第一行
            this.age = age;
        }
    }
    
    

三、标准Javabean

满足特定标准规范的Java类

  1. 类必须是具体的(非抽象)和公共的,
  2. 并且具有无参数的构造方法,
  3. 成员变量私有化,并提供用来操作成员变量的setget 方法。
  4. 实现序列化接口

四、继承

  1. 理解:类似生活中的继承,Java类也有父子关系,子类继承父类的属性和方法。

  2. 格式:使用关键字extends使两个类产生父子关系

    //父类
    public class Animal{}
    //子类
    public class  Cat extends Animal{
        
    }
    
    
  3. 继承中成员变量的特点

    1. 父类私有的属性,不能被子类直接使用(不能被继承),如果非要访问,可以通过公共的方法
    2. 父子类中定义了同名的属性,要访问父类中的属性,可以使用super.属性来访问
  4. 方法重写Override

    1. 概念理解:继承关系中,子类声明了与父类相同的方法,一般方法体不同
    2. 具体要求:
      • 方法名和参数列表必须相同
      • 修饰符:子类的不能小于父类的
      • 返回值类型:子类的不能大于父类的
      • 异常声明:子类的不能大于父类的
    3. 不属于方法重写的情况
      • 静态方法不能重写,方法重写指的是实例方法
      • private修饰的方法不能被重写,子类中不可见
      • final修饰的方法不能被重写
    4. 面试题:Override与Overload的区别?
  5. 继承中的构造方法

    1. 构造器不能继承的,构造器名称与本类名相同
    2. 子类构造器中默认隐藏super()语句,用于调用父类中的无参构造器。所以子类使用构造器来创建对象一定会先初始化父类数据。
    3. 总之:子类实例化一定会通过super关键来调用父类的某个构造器实现父类数据的初始化。
  6. Java单继承限制

    1. 每个Java类只能有一个父类,但是可以有多个子类
    2. Java支持多重继承,A类可以继承自B类,B类可以继承自C类
    3. 父子类是一种相对概念

五、this和super关键字

  1. this关键字

    • 当前对象的引用,表示一个对象

    • 应用位置:

      • 构造器中,this(参数),表示调用本类的其他构造器,
      • 实例方法中,this.成员,this表示当前正在创建的对象

      注意:静态域中不能使用this关键字

  2. super关键字

    • 用于在子类中方法父类的特殊关键字,不能单独使用,区别this

    • 应用

      • 构造器中,super(参数),表示调用父类的构造器
      • 实例方法中,super.成员,表示调用父类的成员变量或方法

      注意:不能再静态域中使用

    1. 就近原则和追根溯源原则

      在继承关系中,访问变量或方法时,首先从本类中查找调用,如果没有再去父类中查找,如果有则正常使用。

六、成员变量的初始化

  1. 初始化方式

    1. 默认初始化值
    2. 直接显示赋值
    3. 代码块初始化值
    4. 构造器初始化值
  2. 代码块

    1. 静态代码块,通常用于给静态变量初始值,只执行一次

      class A{
          static int x;
          //静态代码块
          static{
      		x=10;
          }
      }
      
      
    2. 构造器代码块,通常用于给实例变量初始值,每次实例化都会执行

      class A{
           int x;
          //构造代码块
          {
      		x=10;
          }
      }
      
      
  3. 类变量的初始化

    类初始化的目的主要是为类变量初始化值。类的加载过程大致分为3个阶段:加载-》链接-》初始化

    其中链接阶段,执行类变量的默认值初始化

    在初始化阶段,执行直接显示赋值语句静态代码块中的语句,这两部分按照代码书写的先后顺序执行

    一个类的要初始化,一定会先初始化其父类,类的初始化只执行一次

  4. 实例变量的初始化

    实例化的目的主要是给实例变量进行初始化值

    1. 默认初始值
    2. 直接显示赋值
    3. 构造代码块初始化值
    4. 构造器初始值

    其中2.3 根据代码的书写先后顺序来执行。

    实例化语句每次创建对象都执行

七、多态

  1. 概念理解:Java多态在编译期的一个类型,在运行期间表现出来的是另外一种类型的形态。

  2. 格式:

    父类型引用指向子类类型的对象或接口类型引用指向实现类对象

    Animal a = new Cat();//Cat是Animal的子类
    //编译看左边,运行看右边
    
    
  3. 前提:

    有继承关系或接口与实现类关系

    有方法重写,多态才有意义

  4. 好处:

    1. 提高了代码的扩展性

      public void feed(Animal a){
          a.eat();
      }
      
      
    2. 降低了类与类之间的耦合

  5. 多态的应用

    1. 应用在方法参数

      public static void feed(Animal a){
          a.eat();
      }
      //-------------------
      main(){
      	Animal a = new Cat();
          feed(a);
      }
      
      
      
    2. 用在数组

      Animal[] as = new Animal[3];
      as[0] = new Cat();
      as[1] = new Animal();
      
      
    3. 用在方法的返回值类型

      public Animal buy(String name){
          if("cat".equals(name))
              return new Cat();
      }
      
      
  6. 向上转型&向下转型

    1. 向上转型:把子类类型转换为父类类型,自动向上转型

      Cat cat = new Cat();
      Animal a = cat;//自动向上转型
      
      
    2. 向下转型:把父类类型转换为子类类型,强制向下转型

      Animal animal = new Cat();
      Cat cat = (Cat)animal;//强制向下转型
      
      
    3. instanceof关键字:检查类的运行时类型。强制转换要保证知道原本的类型,才能强制转换,否则发生类转换异常。

      Animal animal = new Cat();
      if(animal instanceof Cat){
      	Cat cat = (Cat)animal;//强制向下转型
      }
      
      
  7. 多态引用时成员的引用原则

    1. 成员变量

      编译看左边,运行也看左边

    2. 虚方法:可能被重写的方法

      编译看左边,运行看右边

      1)静态分派:在左边父类中找到最匹配的方法

      2)动态绑定:在子类中找到上一步中最匹配的方法的重写方法

    3. 非虚方法

      静态方法、私有方法、final修饰的方法,编译运行都看左边

八、final关键字

表示最终的,不可改变的

  1. 修饰的类,不能被继承

  2. 修饰的方法,不能被重写

  3. 修饰的变量,是个常量

    //此类不能被继承
    final class A{
        public static final VALUE = 123;//静态常量
        final void test(){
            final int a = 10;//final修饰局部变量
            //a = 20;//不可以
        }
    }
    
    

九、Object类

Java中的根类、父类。包括数组都实现了其方法

常用方法:

  1. hashCode();

    得到对象的哈希码值。默认是内存地址转换而来的一个整数。

    建议子类都重写此方法,让返回值与类的成员相关,而不是与内存地址相关。

  2. getClass();

    返回对象的运行时类

    new Student().getClass().getName();//返回运行时类的名称。com.atguigu.Student
    
    
  3. toString();

    返回对象的字符串表示形式。默认返回的是:”运行时类名称“+”@“+”哈希值的16进制“

    建议子类都重写此方法。建议返回类的所有属性信息。

    Student s = new Student();
    System.out.println(s);//等同于下句
    System.out.println(s.toString());
    
    
  4. equals(Object obj);

    判断两个对象是否相等,返回布尔类型。默认按照“==”进行比较,比较的是内存地址。

    建议子类都重写此方法,建议用于比较对象的所有内容是否相同。

  5. finalize()

    当垃圾回收器来回收一个对象时,会调用此对象的finalize方法。

第七章 面向对象(下)

一、抽象类

  1. 引入:如果一个类是一个更抽象的概念,可以定义为抽象类。如果类中有抽象方法,必须为抽象类。

  2. 语法格式:

    //抽象类,使用关键字abstract
    public abstract class Animal{
        //抽象方法,使用abstract修饰
        public abstract void eat();//没有方法体
    }
    
    
  3. 特点:

    1. 抽象类有构造器,但不能创建对象,用于子类调用初始化父类数据
    2. 抽象类可以有抽象方法,也可以没有
    3. 有抽象方法的类必须是抽象类
    4. 抽象类的子类必须重写所有的抽象方法,除非子类也是个抽象类。

二、接口

  1. 概念理解:本质上是一种标准规范。是静态常量与抽象方法的集合

  2. 定义格式:

    //接口,使用关键字interface定义
    public interface Jumpable{
        //接口的成员
        int VALUE = 1;//静态常量,默认修饰符public static final
        void jump();//抽象方法,默认修饰符 public abstract
        //jdk8之后:
        default void  testDefault(){//默认修饰符public,实现类可以选择是否重写缺省方法。
            System.out.println("缺省方法,默认方法,扩展方法");
        }
        
        static void testStatic(){//默认修饰符public,为本尽快服务的工具类方法
            System.out.println("静态方法");
        }
        
        //jdk9之后:
        private void testPrivate(){//为本接口缺省方法,静态方法提供服务
            System.out.println("私有方法");
        }
        
    }
    
    
  3. 特点:

    1. 接口没有构造器,不能创建对象
    2. 不能有变量,只有静态常量
    3. 接口可以多实现,一个类可以同时实现多个接口
    4. 接口支持多继承,一个接口可以同时继承自多个接口
    5. 接口的实现类必须重写所有的抽象方法,除非实现类也是个抽象类
  4. 接口的实现

    接口是用来被类实现的

    //定义实现类时候可以让类实现接口
    public class Cat implements Jumpable{
        //重写接口中的方法
        public void eat(){
            System.out.println("猫跳高");
        }
    } 
    
    
    

    接口的多实现

    public interface A{}
    public interface B{}
    //一个类同时实现多个接口
    public class C implements A,B{} 
    
    

    接口支持多继承

    public interface A{}
    public interface B{}
    //一个接口同时继承自多个接口
    public interface C extends A,B{} 
    
    
  5. 接口与实现类对象的多态引用

    //多态:接口类型引用指向其实现类对象
    Jumpable c = new Cat();
    //等同于下面两句
    Cat cat = new Cat();
    Jumpable c = cat; 
    
    //调用功能
    c.eat();//编译看左边,运行看右边
    
    

三、Java经典接口

  1. Comparable接口:用于比较任意的对象,前提任意的类必须实现此接口,并重写compareTo方法。
  2. Comparator接口:用于比较任意的对象,不修改任意类的情况,可以定义任意对象的比较器类实现此接口,并重写compare方法。
  3. Cloneable接口:一个类实现了此接口,表示这个类的对象可以被克隆。

四、内部类

定义在一个类的内部的类,内部的类就是内部类,这个外部的类称为外部类

  1. 成员内部类

    1. 静态内部类:是一个相对独立的类,主要服务于外部类

      public class Outer{
          //静态内部类
          static class Inner{
              //不能访问外部类的非静态成员
          }
          
      }
      
      

      创建对象:Outer.Inner inner = new Outer.Inner();

      不能访问外部类的非静态成员

      可以使用四种权限修饰符

    2. 非静态内部类:

      public class Outer{
          class Inner{
               //不能声明静态成员,但是可以声明静态常量
          }
      }
      
      

      创建对象:Outer.Inner inner = new Outer().new Inner();

      与外部类的耦合度高,可直接访问外部类的任何成员,包括私有的

      不能声明静态成员,但是可以声明静态常量

      可以使用四种权限修饰符

  2. 局部内部类:定义在外部类的局部区域(方法)内。

    public class Outer{
        public void test(){
            int a =10;//局部变量
            class Inner{
                //访问的外部类的局部变量,必须是个常量或等价常量
                System.out.println(a);//a不可修改    
            }
        }  
    }
    
    
  3. 匿名内部类

    没有名字的内部类,实际是一个局部内部类。

    当接口的实现类只使用一次时,可以使用匿名内部类。

    格式:new 类名或接口名(){ 子类或实现类的成员}

    //接口
    public interface Danceable{
        void dance();
    }
    
    //测试类
    public class Demo{
        //静态方法,参数是接口类型,表示实参应该是一个接口的实现类对象
        public static void invite(Danceable danceable){
            danceable.dance();
        }
        //主方法
        main(){
            //常规写法,先创建接口的实现,然后创建实现类对象,再作为实参传入invite方法。
            //invite(接口的实现类对象);
            //匿名内部类
           invite(new Danceable(){
               public void dance(){
                   System.out.println("跳舞");
               } 
           })
        } 
    }
    
    

五、关键字static

静态的,随着类的加载而加载

  1. 修饰成员变量,类变量或静态变量,表示此类的所有对象共享的一份数据

  2. 修饰成员方法,类方法或静态方法,可以使用类名直接调用,通常用于定义工具类方法

  3. 修饰代码块,静态代码块,主要用于初始化类变量,只在类加载过程中执行一次。

  4. 修饰内部类,静态内部类

  5. 静态导入,把不同包下的类的方法静态导入,可以像本类中一样使用导入的方法

    import static java.util.Arrays.*;

六、单例模式

设计模式:针对某种开发需求,总结的一套经验

单例模式:内存中只能有某个类的一个实例,不能出现第二个。

饿汉式:

public class Singleton{
    //私有的静态常量
    private static final Singleton instance = new Singleton();
    //私有构造器
    private Singleton(){}
    //公共的获取实例的方法
    public static Singleton getInstance(){
        return instance;
    } 
}

**懒汉式:**有线程安全问题,可能会得到多个实例

public class Singleton{
    //私有的静态
    private static Singleton instance = null;
    //私有构造器
    private Singleton(){}
    //公共的获取实例的方法
    public static Singleton getInstance(){
        if(instance == null)
            instance = new Singleton();
        return instance;
    } 
}

七、注解

  1. 概念理解:给程序看的一种注释。

  2. 常见注解:

    1. @Override 表示验证方法是否是重写的
    2. @Deprecated 表示过时的
    3. @SurpressWarning 抑制警告
  3. 自定义注解格式

    public @interface MyAnnotation{}
    
    
  4. 元注解:使用在注解上的注解

    * @Target 表示注解可以使用的位置
    * ElementType.METHOD 用在方法上
    * ElementType.FIELD 用在属性上
    * ElementType.TYPE 用在类上
    * @Retention  表示注解的有效范围,有效周期
    * RetentionPolicy.SOURCE  只在源码中有效
    * RetentionPolicy.CLASS  在字节码文件中有效
    * RetentionPolicy.RUNTIME 在运行期有效
    * @Inherited 表示加了此注解的类的子类同样有这个注解
    * @Documented 表示在生成的API文档中有此注解信息
    
    

    示例:

    @Target(ElementType.METHOD) //注解可以使用的目标位置,比如类、方法、成员变量等上面
    @Retention(RetentionPolicy.RUNTIME)//注解的有效周期,
    @Inherited
    @Documented
    public @interface MyAnnotation{}
    
    

第八章 异常

程序运行过程中发生的不正常情况,如果发生了异常不进行处理,虚拟机会终止运行。

一、Java程序中如何表示异常?都有什么异常?

  1. java中使用不同的Java类表示不同的异常

  2. 异常体系:

    所有的错误和异常都继承自Throwable类。

    1. **Error错误:**表示严重的问题,一旦发生,无法处理,虚拟机只能终止。

      StackOverflowError、OutOfMemoryError

    2. Exeption:通常所说的异常处理指的这类异常,一般性问题,可以通过预防措施处理发生的异常,以保证程序可以继续运行。

      • 编译异常:受检异常,如果此类异常没有进行处理,编译不通过

        除RuntimeException类及其子类外的Exception都是编译异常

      • 运行时异常:非受检异常,可以选择是否处理。

        RuntimeException类及其子类都是运行时异常

二、Java中异常如何产生?

**异常抛出机制:**当程序中发生异常时,虚拟机会抛出对应的异常类对象,从发生处逐层向方法的调用处抛出,直到主方法中还没处理,最后抛给JVM,JVM会打印异常对象中封装的异常信息,并终止运行。

异常的抛出方式:

  1. 自动抛出:异常发生后,JVM自动创建对应的异常类对象,并抛出

  2. 手动抛出:手动创建异常类对象,使用关键字throw抛出。

    throw  new RuntimeException("主动抛出的异常");
    
    

如果在此过程中,任何环节进行了此异常的处理,就可以保证程序的继续运行。

三、异常如何处理?

异常处理机制: 异常捕获

try{
    //可能发生异常的代码
}catch(可能发生的异常类型1  变量1){//捕获异常
    //异常1发生后的业务逻辑代码
    //通常输出异常的栈追踪信息到日志文件中
}catch(可能发生的异常类型2  变量2){//后面捕获的异常类不能小于前面的
    //异常1发生后的业务逻辑代码
}finally{
    //一定会执行的代码,通常用于释放资源
}

异常的声明:

通常当程序中可能发生编译期异常时,必须进行异常处理,那么此时可以进异常捕获处理或者在当前方法中声明异常,表示当前方法可能有某类型异常发生,谁来调用此方法谁来处理。

使用关键字throws来在方法上声明异常

public void test() throws FileNotFoundException{} 

四、异常处理注意事项

  • 编译期异常必须处理,要么捕获处理,要么声明在方法上,让调用者处理。
  • 运行时异常被抛出可以不处理。即不捕获也不声明抛出。
  • try语句范围要尽量小的包围在可能出现异常的一行或几行代码上,不要把大量无异常的代码一起包起来,虽然这样很省事。
  • catch语句捕获的异常类型要尽量小,尽量精准,好针对性的做处理。
  • 如果finally有return语句,永远返回finally中的结果,但要避免该情况.
  • 如果父类方法抛出了多个异常,子类重写父类方法时不能抛出更大异常,可以抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
  • 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。

第九章 常用类

一、String类

String类表示一个字符序列,字面量“abc”也是这个类一个实例

  1. 特点:

    1. 字符串一旦创建不可改变
    2. 内部使用char[] 来存储字符序列,jdk9之后使用byte[].
    3. 字符串字面量是个常量,存储在字符串常量池中,而且每个字符串只有一份。
    4. String类是final修饰,不能被继承。
  2. 创建字符串对象的方式

    1. String s = “abc”;
    2. public String() :初始化新创建的 String对象,以使其表示空字符序列。
    3. String(String original): 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
    4. public String(char[] value) :通过当前参数中的字符数组来构造新的String。
    5. public String(char[] value,int offset, int count) :通过字符数组的一部分来构造新的String。
    6. public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。
    7. public String(byte[] bytes,String charsetName) :通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
    8. String s = “” + 任意数据类型;
  3. 字符串常用方法

    (1)boolean isEmpty():字符串是否为空

    (2)int length():返回字符串的长度

    (3)String concat(xx):拼接,等价于+

    (4)boolean equals(Object obj):比较字符串是否相等,区分大小写

    (5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写

    (6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小

    (7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写

    (8)String toLowerCase():将字符串中大写字母转为小写

    (9)String toUpperCase():将字符串中小写字母转为大写

    (10)String trim():去掉字符串前后空白符

    (11)boolean contains(xx):是否包含xx

    (12)int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1

    (13)int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1

    (14)String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。

    (15)String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

    (16)char charAt(index):返回[index]位置的字符

    (17)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回

    (18)String(char[] value):返回指定数组中表示该字符序列的 String。

    (19)String(char[] value, int offset, int count):返回指定数组中表示该字符序列的 String。

    (20)static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String

    (21)static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String

    (22)static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String

    (23)static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String

    (24)byte[] getBytes():编码,把字符串变为字节数组,按照平台默认的字符编码进行编码

    ​ byte[] getBytes(字符编码方式):按照指定的编码方式进行编码

    (25)new String(byte[] ) 或 new String(byte[], int, int):解码,按照平台默认的字符编码进行解码

    ​ new String(byte[],字符编码方式 ) 或 new String(byte[], int, int,字符编码方式):解码,按照指定的编码方式进行解码

    (26)boolean startsWith(xx):是否以xx开头

    (27)boolean endsWith(xx):是否以xx结尾

    正则表达式:用字符串表示的一组规则。比如:“\d{11}”

    (28)boolean matchs(正则表达式):判断当前字符串是否匹配某个正则表达式

    (29)String replace(xx,xx):不支持正则

    (30)String replaceFirst(正则,value):替换第一个匹配部分

    (31)String repalceAll(正则, value):替换所有匹配部分

    (32)String[] split(正则):按照某种规则进行拆分

二、可变长字符序列

String类是不可变的,如果要频繁改变字符串,效率会降低,所以java提供了可变长字符序列

StringBuilder类:线程不安全,效率略高

StringBuffer类:线程安全,效率略低

  1. 常用方法

    常用的API,StringBuilder、StringBuffer的API是完全一致的

    (1)StringBuffer append(xx):拼接,追加

    (2)StringBuffer insert(int index, xx):在[index]位置插入xx

    (3)StringBuffer delete(int start, int end):删除[start,end)之间字符

    StringBuffer deleteCharAt(int index):删除[index]位置字符

    (4)void setCharAt(int index, xx):替换[index]位置字符

    (5)StringBuffer reverse():反转

    (6)void setLength(int newLength) :设置当前字符序列长度为newLength

    (7)StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str

    (8)int indexOf(String str):在当前字符序列中查询str的第一次出现下标

    ​ int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标

    ​ int lastIndexOf(String str):在当前字符序列中查询str的最后一次出现下标

    ​ int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标

    (9)String substring(int start):截取当前字符序列[start,最后]

    (10)String substring(int start, int end):截取当前字符序列[start,end)

    (11)String toString():返回此序列中数据的字符串表示形式

  2. 示例:

    //创建StringBuilder对象
    StringBuilder sb = new StringBuilder("hello");
    //追加
    sb.append(",").append("world").append(",").append("java");
    //转换为String对象
    String s = sb.toString();
    
    

三、数学相关类

  1. Math类

    • public static final double PI:返回圆周率
    • public static double abs(double a) :返回 double 值的绝对值。
    • public static double ceil(double a) :返回大于等于参数的最小的整数。
    • public static double floor(double a) :返回小于等于参数最大的整数。
    • public static long round(double a) :返回最接近参数的 long。(相当于四舍五入方法)
    • public static double pow(double a,double b):返回a的b幂次方法
    • public static double sqrt(double a):返回a的平方根
    • public static double random():返回[0,1)的随机值
    • public static double max(double x, double y):返回x,y中的最大值
    • public static double min(double x, double y):返回x,y中的最小值
  2. Random类:用于产生伪随机数

    1. public Random():创建一个新的随机数生成器。此构造方法将随机数生成器的种子设置为某个值,该值与此构造方法的所有其他调用所用的值完全不同。(没有真正的随机数,需要种子产生随机数,同一个种子产生的伪随机数序列相同)
    2. public Random(long seed):使用单个 long 种子创建一个新的随机数生成器。该种子是伪随机数生成器的内部状态的初始值,该生成器可通过方法 next(int) 维护。
    • boolean nextBoolean():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 boolean 值。
    • void nextBytes(byte[] bytes):生成随机字节并将其置于用户提供的 byte 数组中。
    • double nextDouble():返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 double 值。
    • float nextFloat():返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 float 值。
    • double nextGaussian():返回下一个伪随机数,它是取自此随机数生成器序列的、呈高斯(“正态”)分布的 double 值,其平均值是 0.0,标准差是 1.0。
    • int nextInt():返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。
    • int nextInt(int n):返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
    • long nextLong():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。
  3. BigInteger类:表示一个高精度的超大整数

    不可变的任意精度的整数。

    1. BigInteger(String val)
    2. BigInteger add(BigInteger val)
    3. BigInteger subtract(BigInteger val)
    4. BigInteger multiply(BigInteger val)
    5. BigInteger divide(BigInteger val)
    6. BigInteger remainder(BigInteger val)
    7. int intValue():将此 BigInteger 转换为 int。
    8. long longValue():将此 BigInteger 转换为 long。
    9. float floatValue():将此 BigInteger 转换为 float。
  4. BigDecimal类

    不可变的、任意精度的有符号十进制数。

    • BigDecimal(String val)
    • BigDecimal add(BigDecimal val)
    • BigDecimal subtract(BigDecimal val)
    • BigDecimal multiply(BigDecimal val)
    • BigDecimal divide(BigDecimal val)
    • BigDecimal divide(BigDecimal divisor, int roundingMode)
    • BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
    • BigDecimal remainder(BigDecimal val)
    • double doubleValue():将此 BigDecimal 转换为 double。

四、日期时间API

  1. Date类

    Date date = new Date();
    
    long time = date.getTime();//获取1970年1月1日 8:0:0 到现在毫秒值
    
    Date date1 = new Date(毫秒值)
    
    
  2. Calendar类

    //创建对象
    Calendar c = Calendar.getInstance();
    //常用方法get(int a);
    int year = c.get(Calendar.YEAR)
    
    
  3. SimpleDateFormat格式化类

    用于进行字符串与日期对象之间的转换。

    //创建格式化类对象,可以指定格式
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //格式化:把日期格式化为指定格式的字符串
    String strDate = sdf.format(new Date());
    //解析:把指定格式的字符串解析为日期对象
    Date  newDate = sdf.parse("1999-09-09 11:10:10");//注意有编译期异常
    
    
  4. JDK8的日期类

    1. LocalDate,LocalTime,LocalDateTime类

      //得到一个日期时间对象
      LocalDateTime now = LocalDateTime.now();//当前系统的日期时间对象
      LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));//指定时区
      LocalDateTime now = LocalDateTime.of(1999,9,9,10,10,10);//指定日期时间
      
      
    2. 日期,时间区间或间隔Period ,Duration

      //日期间隔
      Period period = Period.between(beforeDate,afterDate);
      //日期时间间隔
      Duration duration = Duration.between(beforeDateTime,afterDateTime);
      
      
    3. DateTimeFormatter格式化类

      该类提供了三种格式化方法:

      预定义的标准格式。如:DateTimeFormatter.ISO_DATE_TIME; ISO_DATE

      本地化相关的格式。如:DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)

      自定义的格式。如:DateTimeFormatter.ofPattern(“yyyy-MM-dd hh:mm:ss”)

      //自定义格式化类对象
      DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
      //格式化日期对象成为指定格式的字符串
      String strDateTime = dtf.format(LocalDateTime.now());
      //解析:把字符串解析为日期时间对象
      LocalDate parse = LocalDate.parse("2020-12-12", dtf);
      
      

五、系统相关类

  1. System系统类

    系统类中很多好用的方法,其中几个如下:

    • static long currentTimeMillis() :返回当前系统时间距离1970-1-1 8:0:0的毫秒值
    • static void exit(int status) :退出当前系统
    • static void gc() :运行垃圾回收器。
    • static String getProperty(String key):获取某个系统属性
    • static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
  2. Runtime运行时类

    单例模式的应用(饿汉式)

    • public static Runtime getRuntime(): 返回与当前 Java 应用程序相关的运行时对象。
    • public long totalMemory():返回 Java 虚拟机中的内存总量。此方法返回的值可能随时间的推移而变化,这取决于主机环境。
    • public long freeMemory():回 Java 虚拟机中的空闲内存量。调用 gc 方法可能导致 freeMemory 返回值的增加。
    • public long maxMemory(): 返回 Java 虚拟机试图使用的最大内存量。
    • Process exec(String command):在单独的进程中执行指定的字符串命令。

六、数组工具类

  • static int binarySearch(int[] a, int key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数
  • static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组
  • static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
  • static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
  • static void fill(int[] a, int val) :用val填充整个a数组
  • static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val
  • static void sort(int[] a) :将a数组按照从小到大进行排序
  • static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
  • static String toString(int[] a) :把a数组的元素,拼接为一个字符串,形式为:[元素1,元素2,元素3。。。]

七、包装类

  1. Java针对每种基本数据类型都提供了对应的引用数据类型,称为包装类

    序号 基本数据类型 包装类(java.lang包)
    1 byte Byte
    2 short Short
    3 int Integer
    4 long Long
    5 float Float
    6 double Double
    7 char Character
    8 boolean Boolean
    9 void Void
  2. 自动装箱\拆箱

    //自动装箱:把基本数据类型装箱为对应的引用数据类型
    Integer i = 10;
    //自动拆箱:把引用数据类型拆箱为对应的基本数据类型
    int a = i;
    
    
  3. 常用API

    Integer i = 10;
    Integer i2 = new Integer(100);
    
    //把字符串(数字组成)转为整数
    new Integer("123");
    Integer.parseInt("123");
    Integer.valueOf("123");
    //整数转为字符串
    String str = Integer.toString(123);
    String str2 = i.toString();
    String str3 = String.valueOf(123);
    String str4 = ""+123;
    
    
  4. 包装类的缓存

    包装类的数据在缓存数值范围内时,直接从内存中取出对象,超过范围会创建新的对象

    包装类 缓存对象
    Byte -128~127
    Short -128~127
    Integer -128~127
    Long -128~127
    Float 没有
    Double 没有
    Character 0~127
    Boolean true和false

    示例:

    Integer i1 = 10;
    Integer i2 = 10;
    System.out.println(i1==i2);//true 有缓存
    
    Integer i1 = 200;
    Integer i2 = 200;
    System.out.println(i1==i2);//false 没有缓存
    
    

八、枚举enum

  1. 概念:本质上是只有固定几个对象的Java类,继承自Enum类。JDK1.5后

  2. 定义格式:

    public enum Gender{
        FEMALE,MALE
    }
    
    

    枚举类的要求和特点:

    • 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。
    • 如果常量对象列表后面没有其他代码,那么“;”可以省略,否则不可以省略“;”。
    • 编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数,
    • 如果枚举类需要的是有参构造,需要手动定义private的有参构造,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。
    • 枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。
    • JDK1.5之后switch,提供支持枚举类型,case后面可以写枚举常量名。
    • 枚举类型如有其它属性,建议(不是必须)这些属性也声明为final的,因为常量对象在逻辑意义上应该不可变。
  3. 常用方法

    1.toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法!
    2.name():返回的是常量名(对象名) 【很少使用】
    3.ordinal():返回常量的次序号,默认从0开始
    4.values():返回该枚举类的所有的常量对象,返回类型是当前枚举的数组类型,是一个静态方法
    5.valueOf(String name):根据枚举常量对象名称获取枚举对象

第十章 集合

一、基本概念

  1. 装数据的容器跟数组类似。
  2. 与数组的区别:
    • 数组长度不可变,集合长度可变
    • 数组提供的属性和方法有限,集合提供了更丰富的API,用于对元素进行增删改查操作
    • 数组元素存储特点单一,有序可重复,集合有不同的存储特点
    • 数组可以存储基本数据类型和引用数据类型,集合只能存储引用数据类型。

二、Collection接口

表示一组对象的集合

  1. 常用方法

    1、添加元素

    (1)add(E obj):添加元素对象到当前集合中

    (2)addAll(Collection other):添加other集合中的所有元素对象到当前集合中,即this = this ∪ other

    2、删除元素

    (1) boolean remove(Object obj) :从当前集合中删除第一个找到的与obj对象equals返回true的元素。

    (2)boolean removeAll(Collection coll):从当前集合中删除所有与coll集合中相同的元素。即this = this - this ∩ coll

    3、判断

    (1)boolean isEmpty():判断当前集合是否为空集合。

    (2)boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素。

    (3)boolean containsAll(Collection c):判断c集合中的元素是否在当前集合中都存在。即c集合是否是当前集合的“子集”。

    4、获取元素个数

    (1)int size():获取当前集合中实际存储的元素个数

    5、交集

    (1)boolean retainAll(Collection coll):当前集合仅保留与c集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即this = this ∩ coll;

    6、转为数组

    (1)Object[] toArray():返回包含当前集合中所有元素的数组

三、Iterator迭代器

  1. 迭代器的使用

Iterator是一个接口,通过Collection集合的Iterator()方法可以得到一个迭代器对象。

Iterator接口中的方法主要有: hasNext(); next(); remove();

//创建集合
Collection c = new ArrayList();
//添加元素
c.add("hello");
c.add("java");
//获取迭代器
Iterator it = c.iterator();
//遍历集合
while(it.hasNext()){
    Object obj = it.next();//取出下一个元素
}

四、增强for循环

可以用来遍历Collection集合或数组。遍历Collection集合时,底层实际是通过迭代器Iterator实现的。

  1. 格式

    for(元素的类型 变量 : Collection集合或数组){
        
    }
    
    
  2. 示例

    Collection c = new ArrayList();
    //遍历集合
    for(Object obj : c){
        System.out.println(obj);//打印集合中的每个元素
    }
    
    
    int[] arr = {1,2,3,4,5};
    //遍历数组
    for(int i : arr){
        System.out.println(i);//打印数组中的每个元素
    }
    
    
  3. 增强for与Iterable接口的关系

    实现了Iterable接口的类都可以使用增强for进行遍历

    public interface Iterable<T> {
     	Iterator<T> iterator();
    }
    
    public interface Collection<E> extends Iterable<E> {
    	
    	//Iterator iterator();
    }
    
    public class ArrayList implements Collection{
    	//内部类
    	 private class Itr implements Iterator<E> {
    		 public boolean hasNext() {
                return cursor != size;
            }
    
            public E next() {
            }
    	 }
    	 
    	@Override
    	public Iterator<E> iterator() {
            return new Itr();
        }
    }
    
    
  4. 快速失败机制

    当使用迭代器遍历集合的同时,使用集合的方法对集合元素进行增删等操作,会导致concurrentModifactionException并发修改异常。因为此操作会导致数据的不准确,对以后使用集合数据存在隐患。所以Java不允许此操作。

    集合源码中每个实现类都有一个属性modCount,用于统计集合的修改次数,借助此属性实现快速失败机制。

五、List集合

  1. List是一个Collection的子接口

  2. 特点:

    1. 元素有序的(可预知的迭代顺序或说存取顺序一致)
    2. 可重复的
    3. 有索引,可以通过索引快速访问元素
  3. 特有方法:都跟索引有关

    1、添加元素

    • void add(int index, E ele)
    • boolean addAll(int index, Collection eles)

    2、获取元素

    • E get(int index)
    • List subList(int fromIndex, int toIndex)

    3、获取元素索引

    • int indexOf(Object obj)
    • int lastIndexOf(Object obj)

    4、删除和替换元素

    • E remove(int index)
    • E set(int index, E ele)
  4. 遍历方式

    1. 迭代器
    2. 增强for
    3. 普通for循环

六、ArrayList实现类

  1. List接口的典型实现类,有序的,可重复的

  2. 底层结构:数组

  3. 效率:(使用索引)查询快,增删慢

  4. Vector比较:ArrayList是线程不安全的,效率相对高。

  5. 源码分析:

    1. 使用空参创建ArrayList对象时,初始容量为0,(JDK7的新版本或JDK1.8之后)
    2. 添加第一个元素时,扩容初始容量为10,
    3. 之后每次再扩容时,扩为原来的1.5倍

七、LinkedList实现类

  1. 底层结构:双向链表

  2. 效率:增删快,查询慢

  3. 特有方法:(都跟首尾相关)

    • void addFirst(Object obj )
    • void addLast(Object obj )
    • Object getFirst()
    • Object getLast()
    • Object removeFirst()
    • Object removeLast ()

八、Set集合

特点:元素唯一,无序(有特例)

  1. HashSet实现类
    1. 底层结构:哈希表
    2. 效率:均衡提供
    3. 存储原理:如何去重?先比较元素的hashCode值,再通过equals比较,都相同则认为元素重复。
  2. LinkedHashSet实现类:有序的
    1. 继承自HashSet
    2. 底层结构:在哈希表基础上维护一个链表,用于保证元素的迭代顺序。
    3. 效率:相对于HashSet略低
  3. TreeSet实现类:实现了排序
    1. 底层结构:红黑树
    2. 效率:查询效率高于链表
    3. 存取原理:如何实现排序?元素必须可以比较大小,要求实现Comparable接口或Comparator接口来实现元素的大小比较。在添加元素时,跟已添加元素进行比较,小的放左边,大的放右边。遍历元素时,采用中序遍历,即左中右。

九、Map集合

  1. 概念理解:表示一组键值对key-value

  2. 特点:key唯一,(无序)

  3. 常用方法:

    1、添加操作

    • V put(K key,V value)
    • void putAll(Map m)

    2、删除

    • void clear()
    • V remove(Object key)

    3、元素查询的操作

    • V get(Object key)
    • boolean containsKey(Object key)
    • boolean containsValue(Object value)
    • boolean isEmpty()

    4、元视图操作的方法:

    • Set keySet()
    • Collection values()
    • Set> entrySet()

    5、其他方法

    • int size()
  4. Map集合遍历

    Map<Integer,String> map = new HashMap();
    map.put(101,"hello");
    //遍历方式一
    Set<Integer> keySet = map.keySet();
    for(Integer key : keySet){
        String value = map.get(key);
        sout(key+" = "+value);
    }
    
    //遍历方式二
    Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
    for(Map.Entry<Integer,String> entry : entrySet){
        Integer key = entry.getKey();
        String value = entry.getValue();
          sout(key+" = "+value);
    }
    
    
  5. HashMap实现类

    • 特点:key是唯一,无序,key和value都可以为null

    • 底层结构:哈希表=数组+链表+红黑树(jdk8之后)

    • 效率:增删改查综合效率高于单纯的数组、链表

    • 构造方法

      HashMap map = new HashMap();//空参构造,没有初始容量,第一次添加元素时初始容量为16
      HashMap map = new HashMap(int capacity);//指定初始容量,得到的初始容量一定是2的n次幂(比指定值大的最小的2的次幂)
      
      
    • 存储原理

      1. 计算元素的存储位置

        计算key的hashCode值,进行高低16位异或运算,再对底层数组长度取模运算,得到元素存储的索引位置。

      2. 判断是链表还是红黑树,没有重复则进行添加元素,如果是链表,在链表尾部插入。

      3. 通过equals比较key是否相同,如果相同则覆盖旧的value,并返回旧value。实现去重。

    • 扩容机制:

      1. 第一次添加元素时初始化容量为16
      2. 当元素个数超过扩容阈值threshold时=加载因子loadFactor(0.75)*容量capacity,进行扩容。扩容的新容量为旧容量的2倍
      3. 当桶中元素个数大于8时,并且容量小于64时,进行扩容,如果大于等64则链表转红黑树。当红黑树节点数<=6时,退化为链表。
  6. LinkedHashMap实现类

    • 特点:元素唯一,有序
    • 底层结构:哈希表基础上维护一个链表,用于保证元素的迭代顺序
    • 是HashMap的子类
  7. TreeMap实现类

    • 特点:元素唯一,无序,实现了排序,要求元素必须可以比较大小(实现Comparable或Comparator)
    • 底层结构:红黑树
    • 效率:查询效率高于链表
  8. Hashtable类

    • 特点:元素唯一,无序,key不能为null
    • 底层结构:哈希表
    • 对比HashMap:线程安全的效率相对低,HashMap是线程不安全的
  9. Properties类

    • 特点:key和value都是字符串

    • 是Hashtable的子类

    • 常用方法:

      String getPropertie(String key);

      void setProperty(String key , String value);

十、Collections工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:

  • public static boolean addAll(Collection c,T… elements)将所有指定元素添加到指定 collection 中。
  • public static int binarySearch(List> list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
  • public static int binarySearch(List list,T key,Comparator c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。
  • public static > T max(Collection coll)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
  • public static T max(Collection coll,Comparator comp)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
  • public static void reverse(List list)反转指定列表List中元素的顺序。
  • public static void shuffle(List list) List 集合元素进行随机排序,类似洗牌
  • public static > void sort(List list)根据元素的自然顺序对指定 List 集合元素按升序排序
  • public static void sort(List list,Comparator c)根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
  • public static void swap(List list,int i,int j)将指定 list 集合中的 i 处元素和 j 处元素进行交换
  • public static int frequency(Collection c,Object o)返回指定集合中指定元素的出现次数
  • public static void copy(List dest,List src)将src中的内容复制到dest中
  • public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值
  • Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
  • Collections类中提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx的不可修改的视图。

第十一章 泛型

一、泛型的概念理解

  1. 泛型:参数化类型
  2. 语法格式:<引用数据类型>,
  3. 好处:把运行期强制类型转换的安全隐患提前到编译期解决,并且简化了代码。
  4. 可以声明的位置:类、接口、方法

二、自定义泛型

  1. 泛型类

    public class GenericsClass<T>{
        T obj;
        public void setObj(T obj){
            this.obj = obj;
        }
        public T t getObj(){
            return obj;
        }
        //public static void test(T t){}//静态成员不能使用类型变量
    }
    
    

    泛型类的使用

    GenericsClass<String> gc1 = new GenericsClass<String>();
    gc1.setObj("abc");
    String s = gc1.getObj();
    //注意:
    //创建对象时,泛型类型参数左右两边的类型必须一致
    
    
  2. 泛型接口

    public interface GenericsInter<T>{
        void show(T t);
    }
    
    

    使用泛型接口:泛型接口不明确类型参数,实现类或子类仍然是一个泛型类

    public class ClassA<T> implements GenericsInter<T>{
        public void show(T t){
        }
    }
    
    

    使用泛型接口:泛型接口明确类型参数,实现类或子类仍然不是泛型类

    public class ClassAimplements GenericsInter<String>{
        public void show(String t){
        }
    }
    
    
  3. 泛型方法

    当类的成员中只有一个方法内部统一使用了一种不确定的类型时,可以把泛型声明在这个方法上,这就是泛型方法。

    public class MyClass{
        String a;
        int b;
        public void testA(String x){}
        //泛型方法
        public <T> T show(T t){} 
    }
    
    

三、通配符

  1. 表示任意类型

    使用场景:通常用于对数据进行反转,排序等不添加不取出数据的操作。

    List<?> list = new ArrayList<Object>();
    list = new ArrayList<String>();
    list = new ArrayList<Animal>();
    list = new ArrayList<Cat>();
    
    
  2. 设置通配符上限。表示上限为Animal的任意类型。

    使用场景:不能添加数据,适合获取数据

    List<? extends Animal> list = new ArrayList<>();
    //list = new ArrayList();//编译失败
    list = new ArrayList<Animal>();
    list = new ArrayList<Cat>();
    
      
       
  3. 设置通配符下限。表示下限为Animal的任意类型。

    使用场景:通常用于添加数据,不适合获取数据

    List<? super Animal> list = new ArrayList<>();
    list = new ArrayList<Object>();
    list = new ArrayList<Animal>();
    //list = new ArrayList();//编译失败
    
    
  4. 第十二章 IO流

    一、File文件类

    File类是系统中的文件或文件夹的一种抽象表示形式

    1. 构造方法

      File f1 = new File("D:/test/abc.txt");//表示一个文件
      File f2 = new File("D:/test/","abc.txt");//表示一个文件
      File f3 = new File("D:/test/");//表示一个目录
      File f4 = new File(f3,"abc.txt");//表示一个文件
      
      
    2. 常用方法

      • public String getName() :返回由此File表示的文件或目录的名称。
      • public long length() :返回由此File表示的文件的长度。
      • public String getPath() :将此File转换为路径名字符串。
      • public long lastModified():返回File对象对应的文件或目录的最后修改时间(毫秒值)
      • public boolean exists() :此File表示的文件或目录是否实际存在。
      • public boolean isDirectory() :此File表示的是否为目录。
      • public boolean isFile() :此File表示的是否为文件。
      • public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
      • public boolean delete() :删除由此File表示的文件或目录。 只能删除空目录。
      • public boolean mkdir() :创建由此File表示的目录。
      • public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
      • public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
      * `public File[] listFiles()` :返回一个File数组,表示该File目录中的所有的子文件或目录。  
      * `public File[] listFiles(FileFilter filter)`:返回所有满足指定过滤器的文件和目录。如果给定 filter 为 null,则接受所有路径名。否则,当且仅当在路径名上调用过滤器的 FileFilter.accept(java.io.File) 方法返回 true 时,该路径名才满足过滤器。如果当前File对象不表示一个目录,或者发生 I/O 错误,则返回 null。
    
    

    二、IO流

    1. 概念理解:

      数据传输的一种抽象表示,可以理解为数据传输管道,数据的流入Input指数据从其他介质中传输到内存中。数据流出Output指的是数据从内存中传输到其他介质。

    2. IO流的分类

      1. 根据流向分:输入流、输出流
      2. 数据单位大小分:字节流、字符流

    三、基本字节字符流的使用

    1. 字节输入流InputStream

      FileInputStream文件字节输入流

      FileIntputStream fis = new  FileInputStream("abc.txt");
      
      int ch = fis.read();//读一个字节
      
      byte[] bytes = new byte[1024];
      int len = fis.read(bytes);//读取数据到字节数组中,并返回读取的字节个数
      
      
    2. 字节输出流OutputStream

      FileOutputStream文件字节输出流

      FileOutputStream fos = new FileOutputStream("abc.txt"):
      FileOutputStream fos = new FileOutputStream("abc.txt",true);//追加写入
      
      fos.write(97);//写一个字节到文件中
      
      byte[] bytes = {97,98,99,100};
      fos.write(bytes,0,2);//写字节数组的一部分到文件中
      
      
      
    3. 字符输入流Reader

      FileReader文件字符输入流

      FileReader fr = new FileReader("abc.txt");
      //读取一个字符
      int ch = fr.read();
      //读取一个字符数组
      char[] chars = new char[1024];
      int len = fr.read(chars);//返回读取到的字符个数
      
      
    4. 字符输出流Writer

      FileWriter文件字符输出流

      FileWriter fw = new FileWriter("abc.txt");
      //写一个字符到文件中
      fw.write('a');
      //写一个字符数组的一部分到文件中
      char[] chars = {'a','b','中','国'};
      fw.wrtie(chars,0,3);//写入“ab中”
      
      //写入一个字符串
      fw.write("hello world");
      
      

    四、字符输出流的flush方法和close方法

    字符输出流默认自带缓冲区,默认大小为8k的字节数组,当缓冲满后自动把所有字符一次写入到文件中,否不会直接写入文件。

    flush方法:用于刷新缓冲区,将缓冲区中的数据写入文件中。

    close方法:先刷新缓冲区,再释放资源。在使用完IO流之后,一定注意调用此方法。

    五、缓冲流

    高效流,在创建流对象时,会创建一个8k大小的缓冲区,为了提升IO效率。

    1. 高效字节流

      1. BufferedInputStream
      2. BufferedOutputStream
    2. 高效字符流

      1. BufferedReader

        String readLine();//读取一行字符串

      2. BufferedWriter

        write(String s);//写入字符串

        newLine();//写入一个换行符

    六、转换流

    把字节流转换为字符流,本质上转换流是字符流,相当于字节流+编码方式

    1. InputStreamReader

      InputStreamReader isr = new InputStreamReader(new FileInputStream("abc.txt"),"GBK");//创建转换流,指定读取数据的编码方式
      int ch = isr.read();//读取一个字符
      
      
    2. OutputStreamWriter

      OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("abc2.txt"),"UTF-8");//创建输出转换流,指定写出字符的编码方式
      osw.write('中');
      
      

    七、对象流

    1. 序列化与反序列化

      • 序列化:把Java对象按照字节形式持久存储到磁盘等其他介质中。
      • 反序列化:把磁盘等介质中持久存储的对象,还原为JVM中的java对象。
      • 一个对象要被序列化,此对象类型必须实现Serializeble接口。
    2. 对象流

      1. ObjectOutputStream对象输出流

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
        //写出一个java对象
        oos.write(new Student());//Student类必须实现序列化接口
        
        
      2. ObjectInputStream

        ObjectInputStream ois =new ObjectInputStreawm(new FileInputStream("oos.txt"));
        //读取一个java对象
        Object obj = ois.readObject();
        
        

      八、打印流和标准输入输出流

      打印流没有输入流,只有输出流

      1. PrintStream字节打印流

        println(Object obj);//多个重载方法

        print(Object obj);//多个重载方法

      2. PrintWriter字符打印流

      3. System.in 标准输入流,从键盘读取数据

      4. System.out 标准输出流,输出到控制台

    第十三章 多线程

    一、相关概念

    1. 并行与并发

      • 并行:同一时刻(时间点),发生了多个事件。单核CUP不支持并行。
      • 并发:同一个微小时间片(时间区间)内,发生了多个事件。
    2. 线程与进程

      • 进程:一个程序运行过程的描述,系统以进程为单位来分配系统资源。
      • 线程:程序中的一条执行路径。一个进程中至少有一个线程。也可以有多个线程,这时候就是多线程程序。
    3. 多线程的应用场景与好处

      1. 多个线程同时执行一个大的任务。比如多线程下载文件。
      2. 多个线程分别执行不同的任务,共同完成一个大的任务。
      3. 多线程的好处:提高了CPU的利用率。
    4. 线程调度:

      CPU资源有限,系统以线程为单位,分配cpu资源,Java支持的抢占式调度方式,每个线程随机获得cpu资源。

    二、线程的创建方式

    Java提供了Thread线程类,此类的对象表示一个线程。

    1. 方式一:继承Thread类

      1. 创建Thread的子类,并重写run方法
      2. 创建子类对象,即线程类对象
      3. 调用start方法启动线程
    2. 方式二:实现Runnable接口

      1. 创建Runnable接口的实现类,即线程任务类,并重写run方法
      2. 创建线程任务类对象,
      3. 创建Thread线程类对象,通过构造器传入线程任务类对象。
      4. 调用start方法启动线程
    3. 两种创建方式的区别

      1. 方式一简单一些,但是有Java的单继承限制。
      2. 方式二打破了单继承限制,方便多个线程间共享数据。
    4. 匿名内部类方式创建线程

      //继承Thread类创建方式的匿名内部类方式。
      new Thread(){
          public void run(){
              System.out.println("线程任务...");  
          }
      }.start();
      
      
      //实现Runnable接口方式的匿名内部类方式
      new Thread(new Runnable(){
          public void run(){
      		System.out.println("线程任务...");  
          }  
      }).start();
      
      

    三、Thread类

    1. 构造方法
      • public Thread() :分配一个新的线程对象。
      • public Thread(String name) :分配一个指定名字的新的线程对象。
      • public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
      • public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
    2. 线程使用基础方法
    • public void run() :此线程要执行的任务在此处定义代码。

    • public String getName() :获取当前线程名称。

    • public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

    • public final boolean isAlive():测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。

    • public final int getPriority() :返回线程优先级

    • public final void setPriority(int newPriority) :改变线程的优先级

    • 每个线程都有一定的优先级,优先级高的线程将获得较多的执行机会。每个线程默认的优先级都与创建它的父线程具有相同的优先级。Thread类提供了setPriority(int newPriority)和getPriority()方法类设置和获取线程的优先级,其中setPriority方法需要一个整数,并且范围在[1,10]之间,通常推荐设置Thread类的三个优先级常量:

      MAX_PRIORITY(10):最高优先级

      MIN _PRIORITY (1):最低优先级

      NORM_PRIORITY (5):普通优先级,默认情况下main线程具有普通优先级。

    1. 线程控制常见方法
    • public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

    • public static void sleep(long millis) :线程睡眠,使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

    • public static void yield():线程礼让,yield只是让当前线程暂时失去执行权,让系统的线程调度器重新调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。

    • void join() :加入线程,当前线程中加入一个新线程,等待加入的线程终止后再继续执行当前线程。

      void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。如果millis时间到,将不再等待。

      void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。

    • public final void stop():强迫线程停止执行。 该方法具有不安全性,已被弃用,最好不要使用。

      • 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
      • 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
    • public void interrupt():中断线程,实际上是给线程打上一个中断的标记,并不会真正使线程停止执行。

    • public static boolean interrupted():检查线程的中断状态,调用此方法会清除中断状态(标记)。

    • public boolean isInterrupted():检查线程中断状态,不会清除中断状态(标记)

    • public void setDaemon(boolean on):将线程设置为守护线程。必须在线程启动之前设置,否则会报IllegalThreadStateException异常。

      • 守护线程,主要为其他线程服务,当程序中没有非守护线程执行时,守护线程也将终止执行。JVM垃圾回收器也是守护线程。
    • public boolean isDaemon():检查当前线程是否为守护线程。

    四、线程的生命周期状态

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ROugPaN2-1625147661047)(F:\JavaClass\JavaSE210323SZ\复习笔记\img\image-20210421092209975.png)]

    五、线程安全

    1. 线程安全问题的原因(条件)

      1. 多线程
      2. 共享资源
      3. 多条语句操作共享资源
    2. 线程安全问题的解决:

      使用关键字synchronized关键字,把操作共享资源的多条语句,捆绑成一句执行。

      1. 同步代码块

        synchronized(同步锁对象){
            //同步执行的代码块
        }
        
        
      2. 同步方法

        public synchronized void sale(){
            //同步执行的代码
        }
        
        
    3. 同步锁对象

      1. 锁对象可以是任意的对象
      2. 多个线程必须使用同一把锁
      3. 非静态台代码块,建议使用this
      4. 非静态方法中,默认使用this作为锁对象
      5. 静态方法中,默认使用的当前类的Class对象作为同步锁。
      6. 静态代码块中,建议使用当前类的Class对象作为同步锁。
    4. 单例模式懒汉式的线程安全问题解决

      public class Singleton{
          private static Singleton instance=null;
          private Singleton(){}
          
          public  static Singleton getInstance(){
              if(instance == null)
                  synchronized(Singleton.class){
                  	if(instance == null)
                          instance = new Singleton();
              	}
          }
         
      }
      
      

      六、线程间通信

      1. 多个线程中,一个线程执行完任务后需要通知到另一个线程来执行。这种情况就是线程间通信。

      2. 等待唤醒机制:可以实现线程间通信,使用Object类中的wait方法和notify方法。

      3. 经典生产者消费者问题:

        //共享资源:工作台
        public class WorkBanch {
            private int max = 10;//最多放10分餐
            private int num;//工作台当前的餐数
        
            //生成快餐放到工作台
            public synchronized void put() {
                if (num >= max) {
                    try {
                        this.wait();//工作台满后等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        
                System.out.println(Thread.currentThread().getName() + "生成了一份快餐放到工作台,现在有" + ++num + "份餐");
        
                this.notify();//随机唤醒在此监视器上等待的一个线程
            }
        
            //从工作台取餐
            public synchronized void take() {
                if (num <= 0) {
                    try {
                        this.wait();//没有餐,等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        
                System.out.println(Thread.currentThread().getName() + "取走了一份快餐,工作台现在有" + --num + "份餐");
        
                this.notify();//随机唤醒一个等待的线程
            }
        }
        
        

      八、释放锁的操作与死锁

      任何线程进入同步代码块、同步方法之前,必须先获得对同步监视器的锁定,那么何时会释放对同步监视器的锁定呢?

      1、释放锁的操作

      当前线程的同步方法、同步代码块执行结束。

      当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致当前线程异常结束。

      当前线程在同步代码块、同步方法中执行了锁对象的wait()方法,当前线程被挂起,并释放锁。

      2、不会释放锁的操作

      线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行。

      线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该该线程挂起,该线程不会释放锁(同步监视器)。应尽量避免使用suspend()和resume()这样的过时来控制线程。

      3、死锁

      不同的线程分别锁住对方需要的同步监视器对象不释放,都在等待对方先放弃时就形成了线程的死锁。一旦出现死锁,整个程序既不会发生异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。

    第十四章 网络编程

    一、相关概念

    1. 网络软件的架构

      1. B/S :Browser/Server

        只需要开发服务端,不需要开发客户端

        对网络带宽要求高

      2. C/S :Client/Server

        安全性相对高

        可以实现更好的客户端视觉效果渲染。

    2. 网络编程三要素

      1. 网络协议:计算机执行进行通信的一种规则
      2. IP地址:网络中计算机的唯一标识。
      3. 端口:计算机中每个程序的唯一标识。(0~65535)
    3. TCP协议和UDP协议

      1. TCP协议

        面向连接,安全性高,效率相对低

        理论上连接成功后传输的数据量无限

      2. UDP协议

        非面向连接,安全性低,效率相对高

        一次发生数据量有限(64k)

    二、TCP编程

    客户端与服务端都要使用Socket对象作为通信站点

    1. 客户端

      Socket s = new Socket("127.0.0.1",12345);
      //获取输出流
      OutputStream os = s.getOutputStream();
      //写数据
      os.write("hello".getBytes());
      //释放资源
      os.close();
      s.close();
      
      
    2. 服务端

      ServerSocket ss = new ServerSocket(12345);
      //接收Socket
      Socket s = ss.accept();
      //获取输入流
      InputStream is = s.getInputStream();
      //读取数据
      byte[] bys = new byte[1024];
      int len = is.read(bys);
      System.out.println(new String(bys,0,len));//控制台输出读取到的数据
      //释放资源
      is.close();
      s.close();
      
      

    三、UDP编程

    1. 发送端

      public class Send {
          public static void main(String[] args) throws IOException {
              //创建DatagramSocket
              DatagramSocket ds = new DatagramSocket();
              //创建数据包
              byte[] bytes = "hello UDP".getBytes();
              InetAddress ip = InetAddress.getByName("192.168.24.85");
              DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length, ip, 10086);
              //发送一个数据包裹
              ds.send(dp);
              //释放资源
              ds.close();
          }
      
      }
      
      
    2. 接收端

      public class Receive {
          public static void main(String[] args) throws IOException {
              //创建DatagramSocket对象
              DatagramSocket ds = new DatagramSocket(10086);
              //准备一个空包裹
              byte[] bytes = new byte[1024];
              DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
              while(true) {
      
                  //把数据接收到包裹中
                  ds.receive(dp);
                  //对方ip
                  InetAddress ip = dp.getAddress();
                  //从包裹中取数据
                  byte[] data = dp.getData();//数据
                  int length = dp.getLength();//数据长度
                  //控制台打印接收到的数据
                  System.out.println(ip.getHostAddress()+"="+new String(data, 0, length));
              }
              //释放资源
      //        ds.close();
          }
      }
      
      
      

    第十五章 反射

    一、类的加载

    1. 类的加载过程

      1. 加载:把.class字节码文件加载到内存中

      2. 链接

        1. 验证:语法分析、语义分析,保证jvm安全
        2. 准备:为静态变量赋默认初始值;为静态常量直接赋值
        3. 解析:把符号引用转为直接引用
      3. 初始化

        执行静态变量的直接赋值语句;执行静态代码块中的语句

    2. 导致类的初始化操作

      1. 哪些操作会导致类的初始化?

        (1)运行主方法所在的类,要先完成类初始化,再执行main方法

        (2)第一次使用某个类型就是在new它的对象,此时这个类没有初始化的话,先完成类初始化再做实例初始化

        (3)调用某个类的静态成员(类变量和类方法),此时这个类没有初始化的话,先完成类初始化

        (4)子类初始化时,发现它的父类还没有初始化的话,那么先初始化父类

        (5)通过反射操作某个类时,如果这个类没有初始化,也会导致该类先初始化

      2. 哪些使用类的操作,但是不会导致类的初始化?

        (1)使用某个类的静态的常量(static final)

        (2)通过子类调用父类的静态变量,静态方法,只会导致父类初始化,不会导致子类初始化,即只有声明静态成员的类才会初始化

        (3)用某个类型声明数组并创建数组对象时,不会导致这个类初始化

    3. 类加载器

      一个Java通过类加载器被加载到内存中,Java提供了不同的类加载器ClassLoader,对不同路径下的class文件进行加载

      1. 引导类加载器(Bootstrap ClassLoader)又称为根类加载器

        加载jre/lib目录下的jar,此类加载器是由c++编写的

      2. 扩展类加载器ExtClassLoader

        加载jre/lib/ext目录下的jar,此类是由Java编写,并继承自ClassLoader

      3. 应用类加载器AppClassLoader

        加载classpath目录下的class,此类是由Java编写,并继承自ClassLoader

      4. 自定义类加载器

        指定加载class的目录,需要继承ClassLoader

    4. 双亲委派模式

      类加载器接收到一个类的加载请求时,会委托父加载器进行加载,如果父类加载器中有加载过,则加载成功直接结束,否则自己加载此类,加载成功结束,如果都加载不成功,则ClassNotFoundException

      ​ 目的:防止类的重复加载;安全考虑

    二、Class类

    万物皆对象,每个类编译后生成的字节码文件,即class文件,在类加载后JVM会为每个class文件创建一个对象,也就是Class类的一个对象。这个Class对象封装了类在方法区内的数据信息,并且向Java程序员提供了访问方法区内的类数据信息的接口。

    一个类加载成功后的产物是一个Class类对象

    比如:Student类加载到内存中后,会得到一个Class c = Student.class

    获取Class对象的方式

    1. 直接获取,类型.class

      Class c = int.class

    2. Object类的getClass方法

      Class c = new Student().getClass();

    3. Class的静态方法forName

      Class.forName(“com.atguigu.test.Student”);

    4. 类加载器的loadClass方法

      类加载器.loadClass(“类的全路径名称”);

    三、反射

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

    Class对象是反射的根源。

    可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)

    你可能感兴趣的:(大数据学习专栏,java)