Java基础

JavaSE

1. Java 基础

1. JDK、JRE

JREJDK
含义java 运行环境(java)java 开发工具(javac)
内容java 核心类库 + JVMJRE + 开发工具
位置客户端装的开发者(程序员)装的

java -version:可以查看 JDK 的版本

配置环境变量

path:文件路径
classpath:类文件路径,规定 java JVM 在哪里去查找 class 文件,如果没有配置就在当前目录下查找,配置后就在配置后的目录下查找

配置临时环境变量

set path			   # 查看环境变量
set path=# 设置环境变量
set path=空格			 # 删除环境变量
set path=新值;%path%	 # 在已有的环境变量,再加新值
set classpath=路径	 # 在指定路径下查找
set classpath=路径;	 # 先在配置目录(指定路径)下查找,如果没有查找到,就在当前目录下查找
set classpath=.;路径	 # 在当前路径和指定路径下查找

2. 标识符

概念:java 所有的名字(变量名,数组名,方法名,类名,接口名…)

名字定义规则:

  1. 组成 = 字母 + 数字 + 下划线(_) + 美元符号($)
  2. 不能以数字开头
  3. 严重区分大小写
  4. 不能是关键字:java 中具有特殊含义的单词(48 个)
  5. 不能是保留字gotoconst

3. 数据类型

3.1 基本数据类型(八大基本数据类型)

  1. 整型:所有没有小数点的数

    数据类型关键字所占字节数取值范围
    字节型byte1-128(2 的 7 次方)到 127(减-1)
    短整型short2-2 的 15 次到 2 的 15 次方减 1
    整型int4-2 的 31 次到 2 的 31 次方减 1
    长整形long8-2 的 63 次到 2 的 63 次方减 1

    注意:long 值超过了 int 范围(2147483647)必须加 l 或者 L

  2. 浮点型:所有有小数点的数

    数据类型关键字所占字节数注意
    单精度float4值后面必须加 f 或者 F
    双精度double8值后面加 d 或者 D
  3. 字符型:所有的字符,只可以存储单个字符

    数据类型关键字所占字节数注意
    字符型char2值必须放在单引号(’’)里面
  4. 布尔型:所有产生两个相反的结果的数据

    数据类型关键字所占字节数注意
    布尔类型boolean1值只有两个 true 和 false

3.2 引用数据类型

  1. 数组
  2. 类(String 字符串类)
  3. 接口

3.3 数据类型的转换

精度排序(低到高):byte short char int long float double

自动转换(低转高):低精度类型 变量名 1=值; 高精度类型 变量 2=变量 1;

强制转换(高转低):高精度类型 变量名 1=值;低精度类型 变量 2=(低精度类型)变量名 1;

byte+byte=int
short+short=int

4. 运算符

运算符
算术运算符+ - * / %(求余) ++ –
赋值运算符+= -= *= /= %=
比较运算符> >= < <= == !=
逻辑运算符& (与) 、| (或)、 ! (非)、 ^ (异或)、 && (双与,效率更高) 、||(双或)
条件运算符(三目(三元)运算符)boolean 条件 条件为 true 时执行的语句 条件为 false 时执行的语句
位运算符<<(左移)、>>(右移)、>>>(无符号右移)、&(与) 、|(或) 、^(异或)、~(反码)

位运算符

<<:左移几位其实就是该数据乘以 2 的几次方。可以完成 2 的次幂运算
    如:3<<2=12 ==>3*2*2=12
>>:右移几位其实就是该数据除以 2 的几次方。对于高位出现的空位,原来高位是什么就用什么补这个空位
    如:3>>1=1 ==>3/2=1
>>>:无符号右移,数据进行右移时,高位出现的空位,无论原高位是什么,空位都用 0 补
    如:3>>>1=1 ==>3/2=1
^:一个数异或同一个数两次,结果还是这个数。如 6^3^3=6

5. java 语句

  1. 顺序结构:默认的执行流程

  2. 选择结构(分支结构)

    1. if

      1. 单分支

        if( boolean 条件 ){  } // boolean 条件为 true 是执行的语句  
        
      2. 双分支

        if( boolean 条件 ){    // boolean 条件为 true 是执行的语句
        }else{   }			  // boolean 条件为 false 是执行的语句 
        
      3. 多分支

        if( boolean 条件 1 ){  		// boolean 条件 1 为 true 是执行的语句
        }else if( boolean 条件 2 ){   // boolean 条件 2 为 true 是执行的语句
        }else if....{  				 // boolean 条件 n 为 true 是执行的语句
        }else{ }					 // 以上条件均不满足时执行的语句  
        
    2. switch

      // 注意:switch 表达式应为:byte、short、int、char、String
      switch(表达式){
          case 常量 1: //如果表达式==常量 1 就执行的语句
          	[break;]
          case 常量 2: //如果表达式==常量 2 就执行的语句
          	[break;]
          case 常量 n: //如果表达式==常量 n 就执行的语句
          	[break;]
          default: //如果表达式和所有 case 都不相等执行的语句
      }
      
  3. 循环结构

    1. while

      while(boolean 条件){ //循环执行的代码 }
      
    2. do while

      do{ //循环体 
      }while(boolean 条件);
      

      do-while 和 while 的区别?

    3. for

      for(初始化表达式;boolean 条件;迭代){ 
          //boolean 条件为 true 时循环执行的代码 
      }
      
  4. 局部代码块:可以定义局部变量的生命周期

    { // 局部代码块
        // 代码
    }
    

关键字 break 和 continue

break跳出 语句(循环、switch)执行,应用于选择和循环结构

continue结束本次循环,继续下一次循环,应用于循环结构

注意

  1. 这两个语句离开应用范围,存在是没有意义的

  2. 这两个语句单独存在,后面都不可以有语句,因为执行不到

6. 函数

  1. 函数结构

    // 修饰符 返回值类型 函数名(参数类型 参数名 1,参数类型 参数名 2,....)
    public static void main(String[] args) {
        // 执行语句(方法体)
        return 返回值;
    }
    
  2. 函数的重载(overload)

    重载:在同类中,函数名相同,参数列表不同(顺序、个数,类型不同)即可,与返回值类型无关

7. 数组

数组的特点

  1. 是一种数据类型,是一种引用数据类型
  2. 数据类型申明的变量存储的是一个数组对象
  3. 数组对象是一个可以存储多数据的容器
  4. 数组对象可以是任何类型,但每个数据类型必须保持一致
  5. 每个数据称为一个元素
  6. 数组一旦创建,其长度不可变

数组的声明

  1. 先定义,后赋值

    数据类型[] 数组名 = new 数据类型[长度];  // 定义数组
    数组名[下标] =; 					// 给对应下标元素赋值
    
  2. 定义并赋值

    数据类型 [] 数组名 = new 数据类型[长度];
    数据类型 [] 数组名 = new 数据类型[]{元素 1,元素 2...,元素 n};
    数据类型 [] 数组名 = {元素 1,元素 2...,元素 n}; //不规范,但常用
    
  3. 获得数组的长度 数组名.length

  4. 遍历(for/foreach)

  5. 元素有默认值

    整型:0   float0.0f   double0.0   char:空白字符 
    

内存剖析

栈内存:存储的是局部变量(既是方法中或局部代码块中的变量),而且变量所属的作用域一旦结束,该变量就自动释放
堆内存:存储的是数组和对象(其实数组就是对象),凡是 new 建立的储存在

image-20220112105106180

数组的最值、遍历、排序、查找

  1. 最值

    1. 方法1:定义变量记录较大的

      public static int getMax(int[] arr){
          int maxElement = arr[0]; // 初始化为数组中的任意一个元素。
          for(int x=1; x<arr.length; x++) {
              if(arr[x]>maxElement)
              maxElement = arr[x];
          }
          return maxElement;
      }
      
    2. 方法2:定义变量记录较大的下标

      public static int getMax(int[] arr){
          int maxIndex = 0; //初始化为数组中任意一个角标。
          for(int x=1; x<arr.length; x++){
              if(arr[x]>arr[maxIndex])
              maxIndex = x;
          }
          return arr[maxIndex];
      }
      
  2. 遍历

    public static void printArray(int[] arr){
        System.out.print("[");
        for(int x=0; x<arr.length; x++){
            if(x!=arr.length-1)
         		System.out.print(arr[x]+", ");
            else
            	System.out.println(arr[x]+"]");
        }
    }
    
  3. 排序:其实真正开发的时候,一般用 Aarrys.sort数组工具类的排序方法)

    1. 顺序排序

      1. 方法1

        int a[]={5,2,3,1,4};
        for(int i=0;i<a.length-1;i++){ 		// 控制比较的轮数
            for(int j=i+1;j<a.length;j++){	// 控制本轮的比较次数
                if(a[i]>a[j]){ 				// 如果前一个数大于后一个数
                    int temp=a[i]; 			// 将后一个数与前一个数交换位置
                    a[i]=a[j];
                    a[j]=temp;
                }
            }
        }
        
      2. 方法2:减少换位的操作,此方法效率更高

        public static void selectSort_2(int[] arr){
            for(int x=0; x<arr.length-1; x++){
                int num = arr[x];
                int index = x;
                for(int y=x+1; y<arr.length; y++){
                    if(num>arr[y]){
                        num = arr[y];
                        index = y;
                    }
                }
                if(index != x){ // 如果不等交换位置
                    int temp = arr[x];
                    arr[x] = arr[index];
                    arr[index] = temp;
                }
            }
        }
        
    2. 冒泡排序

      int a[]={5,2,3,1,4};
      for(int i=0;i<a.length-1;i++){ 			// 控制比较的轮数
          for(int j=0;j<a.length-i-1;j++){	// 控制本轮的比较次数
              if(a[j]>a[j+1]){ 				// 如果前一个数大于后一个数
                  int temp=a[j]; 				// 将后一个数与前一个数交换位置
                  a[j]=a[j+1];
                  a[j+1]=temp;
              }
          }
      }
      
  4. 查找

    1. 无序数组的查找

      public static int getIndex(int[] arr,int key){
          for(int x=0; x<arr.length; x++){
              if(arr[x]==key)  // 查到就返回 值
              return x;
          }
          return -1; // 没查到返回 -1
      }
      
    2. 有序数组的查找:折半/二分查找

      真实开发时,使用 Arrays.binarySearch 方法(数组工具类二分查找)

      public static void main(String[] args) {
          int[] arr = {13,15,19,28,33,45,78,106};  // 有序数组
          int index = halfSearch(arr,15);  		 // 折半查找
          int index1 = Arrays.binarySearch(arr,15);// 二分查找
          System.out.println("index="+index+"index1="+index1); 
          //存在返回的具体的角标位置,不存在返回-1
      }
      
      1. 折半查找

      2. 方法1

        public static int halfSearch(int[] arr,int key){
            int min = 0;
            int max = arr.length-1;
            int mid = (max+min)/2;
            while(arr[mid]!=key){
                if(key>arr[mid])
                	min = mid + 1;
                else if(key<arr[mid])
                	max = mid - 1;
                if(max<min)
                	return -1; 		// 不存在返回-1
                mid = (max+min)/2;	// 重新赋中间值
            }
            return mid; // 存在返回的具体的角标位置
        }
        
      3. 方法2

        public static int halfSearch_2(int[] arr,int key){
            int mid;
            int min = 0;
            int max = arr.length-1;
            while(min<=max){
                mid = (max+min)>>1; // 相当于 mid = (max+min)/2
                if(key>arr[mid])
                	min = mid + 1;
                else if(key<arr[mid])
                	max = mid - 1;
                else
                	return mid;
            }
            return -min-1;
        }
        
      4. 二分查找 :使用 Arrays.binarySearch 方法

多维数组

多维数组:如果一个数组的元素是数组,该数组是多维数组

二维数组:如果如果一个数组的元素是一维数组,该数组是二维数组

  1. 定义二维数组与赋值

    数据类型 [][] 数组名 = new 数据类型[长度][长度]; // 定义
    数组名[下标][下标]=;						  // 赋值
    数据类型 [][] 数组名 = {{数据 1,数据 2,数据 n},{数据 1,数据 2,数据 n}};  // 定义时就赋值
    
  2. 遍历(与一维数组遍历方法类似)

2. 面向对象(OOP)

1. 面向对象概述

:由一群相同共性的对象组成的群体

对象:一切客观存在,可以相互区别的个体

对象和类之间的关联:对象是类的具体化,类是对象的抽象化(模板)

匿名对象:没有名字的对象 。其实就是对象的简写格式

  1. 当对象的方法仅调用一次的时候,就可以简化成匿名对象
  2. 匿名对象可以作为实际参数进行传递

1.1

类的格式:

修饰符 class 类名{
    // 1.属性(成员变量、全局变量):描述类的信息
    [修饰符] 数据类型 变量名[=初始值];
    
    // 2.构造器 构造函数 构造方法 constructor  作用是:创建对象
    [修饰符] 类名([参数列表]{//方法名必须和类名一致
    	//初始化代码
    }
    
    // 3.方法 行为 函数:让对象具有某种特定的功能
    [修饰符] 返回值(void)方法名([参数列表]{
         //行为代码
    }
}
  1. 全局(成员)变量局部变量的区别

    区别成员变量局部变量
    存在位置成员变量定义在局部变量定义在方法
    默认值成员变量有默认值局部变量若使用必须赋初始值
    修饰符成员变量可以用所有修饰符修饰局部只能用 final 修饰符修饰
    作用范围成员变量能作用于整个类局部变量只能作用于方法,语句,局部代码块中
    存储位置成员变量储存在堆内存的对象中局部变量储存于栈内存的方法中
    生命周期随着对象的创建而存在,消失而消失随着所属区域的执行而存在,结束而释放
  2. 成员变量静态变量(类变量)的区别

    区别成员变量静态变量
    生命周期随着对象的创建而存在,消失而消失随着类的加载而存在,随着类的消失而消失
    调用方式成员变量只能被对象调用静态变量可以被对象调用,还可被类名调用
    存储位置成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据静态变量数据存储在方法区(共享数据区)静态区,所以也叫对象的共享数据
    别名成员变量也称为实例变量静态变量称为类变量
  3. 普通方法构造器方法的区别

    区别构造方法普通方法
    格式构造方法没有返回值普通方法必须有返回值
    作用构造方法的作用是创建对象普通方法的作用是让对象具有某种特定的功能
    调用时机创建对象时调用构造方法普通方法必须在创建对象之后,用对象名来多次调用
    默认值一个类中没有构造器,系统会默认提供一个
    无参构造器,当类中有构造器时,系统将不再提供
  4. 参数

    1. 概念:参数本质就是一个特殊的局部变量
    2. 作用:调用方法时动态的传入数据
    3. 传参:调用方法时,实参传递给形参
  5. 值传递和引用传递

    1. 值传递:对象被值传递了,意味着传递了对象的一个副本,该副本被改变不会影响源对象的值
    2. 引用传递:对象被引用传递了,意味着传递的引用(堆的地址),外部对象被改变,会影响源对象的值
  6. 返回值

    1. 无返回值:void

    2. 有返回值

      [修饰符] 返回数据类型 方法名([参数列表]){
          // 行为代码
          return; // 结束方法并返回一条数据
      }
      

1.2 几个关键字和修饰符

  1. overload(重载):在同类中,方法名相同,参数列表不同(顺序、个数,类型不同)即可

  2. override(重写 ):在子类中,方法名相同,返回值相同,参数列表相同(个数、类型、顺序)

    当父类的方法不能满足子类的需求,子类对该方法重新定义,称为重写
    注意:

    1. 子类的访问修饰符必须 >= 父类
    2. 静态只能覆盖静态,或被静态覆盖(此处有错误:静态方法不能被重写,可以被继承)
    3. overloadoverride 的区别
  3. this(当前对象)

    1. 调用成员变量:当成员变量名和局部变量名相同时,局部变量把成员变量隐藏起来,如果想调用成员变量,必须加 this. 成员变量名
    2. 调用构造器:如果当前的构造器无法完成初始化,需借助其他构造器帮助完成初始化,使用 this(参数),该句必须放在第一行,该调用不会创建对象,只是借助方法来完成初始化
  4. super:就是 this 的父类对象

    1. 属性:子类属性和父类属性相同时,想使用父类属性,使用 super.属性名

    2. 方法:子类重写父类的方法,当子类中想调用该父类的方法,使用 super.方法()

    3. 构造器super([参数]),如果子类构造器没有调用父类构造器,默认调用父类无参构造器,调用构造器必须放在方法的第一行this([参数])和 super([参数])不能共存

      注意:

      1. 每一个子类的构造方法在没有显示调用 super()系统都会提供一个默认的 super(),super() 书写在第一行
      2. 可以在子类构造方法中显示调用 super([参数列表]),完成对特定父类构造方法的调用
      3. 成员变量局部变量重名的时候用 this 区分。
        父类子类的成员变量重名时用 super 区分。
      4. this 指代一个本类对象的引用。
        super 代表一个父类空间。super 指向父类。

    优先级:static > 父类 > 属性 > 构造器

  5. static 修饰符:优先被加载,且执行一次

    1. 修饰变量:称为类变量,因为该变量是所有对象共享的变量

      调用:可以用对象名来调用,也可以用类名调用

      注意:静态变量实例变量(对象变量)的区别?

    2. 修饰方法:称为类方法,静态方法只能调用静态变量和静态方法

      调用:可以用对象名来调用,也可以用类名调用

      注意:

      1. .static 优先于对象存在,因为 static 的成员随着类的加载就已经存在了
      2. 静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
      3. 类方法不能使用 this 或 super,因为没有 this 实例可供使用
      4. static 修饰的方法不能被重写可以被继承,static 和 abstract 不能共存
      5. 静态方法实例方法(对象方法)的区别及静态变量实例变量(成员变量)的区别
    3. 静态代码块

      static{
      	//代码语句:此代码仅执行一次
      }
      
  6. final 修饰符

    1. final 修饰变量:变量就变成常量,只能赋值一次,一旦被赋值不能再次赋值

      final 修饰的变量是一个常量,对所有的对象都一样,一般在 final 之前加上 static

      常量所有字母都大写,多个单词中间用_连接

    2. 修饰成员变量:成员属性定义成常量必须赋初始值,或在构造器中赋值

    3. 修饰局部变量:可以不赋初始值,但在方法结束之前赋值(冗余代码)

    4. final 修饰方法能继承但不能被重写

    5. final 修饰不能有子类,即不可以被继承

1.3 代码块

  1. 静态代码块

    1. 随着类的加载而执行,而且只执行一次

    2. 作用:用于给类进行初始化(构造方法是对象进行初始化

    3. 格式

      static{
      	//代码语句: 给类进行初始化,此代码仅执行一次
      }
      
  2. 构造代码块

    1. 类中的独立代码块

    2. 特点:随着对象的创建而创建,只要 new 一个对象,就执行一次

      静态代码块,随着类的加载而加载,只执行一次

    3. 注意:

      1. 构造代码块:可以给所有对象进行初始化
      2. 构造函数:是给对应的对象进行初始化
    4. 格式:

      class Person{
          private String name;
          public Person(){  // 构造函数
              System.out.println("给对应对象进行初始化")
          }	
          {				  // 构造代码块
              System.out.println("给所有对象进行初始化")
          }
      }
      
  3. 局部代码块

    1. 可以定义局部变量的生命周期

    2. 格式:

      public void jubuFunction(){  
          { // 局部代码块
              // 代码
          }
      }
      

1.4 访问修饰符

作用域publicprotecteddefaultprivate
同一类中okokokok
同一包中okokok
子类中okok
不同包中ok

2. 面向对象的三大特征

2.1 封装

  1. 概念:将类中的成员隐藏起来,只让可靠的对象访问
  2. 分类:属性封装、方法封装
  3. 规范:一般在编程时只封装属性
  4. 具体步骤:把属性设为 private,提供 public 的 getter 和 setter 方法来间接访问属性
  5. 封装的好处:将变化隔离,便于使用,提高了重用性和安全性

注意:

  1. 子类可以直接访问父类中的私有成员吗???

    不能,可以通过创建公共的访问方法来访问
    
  2. 私有化仅是封装的一种体现而已

2.2 继承

  1. 概念:现有的类派生出新的类,现有的类被称为父类,派生出来的类称为子类(派生类),子类能吸收父类的数据属性和行为,并有拓展自己新的能力

  2. 优缺点:

    1. 好处:提高了代码的复用性,让类与类之间产生了关系,给第三个特征多态提供了前提
    2. 缺点:打破了封装性
  3. 语法

    [访问修饰符] class 子类类名 extends 父类类名{
    	//类的实体
    }
    
  4. 继承范围

    1. 同包下,子类可以继承父类除私有的属性和方法
    2. 不同包下,子类可以继承父类 public 和 protected 的属性和方法
    3. 子类无法继承父类的构造器
    4. 子类最多只能有一个父类(单继承,多实现)
  5. 子类的创建过程(new 子类())

    具体执行步骤

    1. 系统会获取相应的父类构造器,创建一个父类对象
    2. 再使用子类构造器创建子类对象
    3. 最后将两个对象关联起来

    提问:为什么子类实例化的时候要访问父类中的构造函数呢?

    那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,要先看父类是如何对自己的内容进行初始化的。所以子类在构造对象时,必须访问父类中的构造函数,就在子类的构造函数中加入了 **super()**语句。

    1. 如果父类中没有定义空参数构造函数,那么子类的构造函数必须用 super 明确要调用父类中哪个构造函数
    2. 如果子类构造函数中如果使用 this 调用了本类构造函数时,那么 super 就没有了,因为 super 和 this 都只能定义第一行且只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。

2.3 多态

  1. 概念:一个事物多种形态,简单说,就是一个对象对应着不同类型

    多态在代码中的体现:父类或者接口的引用指向其子类的对象

  2. 优缺点:

    1. 优点:提高了代码的扩展性和重用性,前期定义的代码可以使用后期的内容
    2. 缺点:前期定义的内容不能使用(调用)后期子类的特有内容
  3. 分类

    1. 方法的多态:overloadoverride
    2. 变量的多态:使用父类声明的对象变量,即可以存储父类类型对象,也可以存储子类类型对象
  4. 变量多态的前提

    1. 继承 或 实现

    2. 方法重写

    3. 转换类型

      1. 向上转型:把一个子类类型的对象转化为父类类型,此操作会使变量拥有只有父类没有被重写的方法及自己重写的方法,会失去自己独有的属性和方法
      2. 向下转型:子类类型的对象由原来父类类型强制转化为原来的子类类型

      多态的转型:类型判断-instance of(只能用于引用数据类型判断)

  5. 多态时,类中成员的变化特点

    1. 成员变量

      1. 编译时:参考引用型变量所属的类中的是否有调用的成员变量:有,编译通过;没有,编译失败
      2. 运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成员变量

      简单说:编译和运行都看等号的左边

    2. 成员函数(非静态)

      1. 编译时:参考引用型变量所属的类中的是否有调用的函数。有,编译通过,没有,编译失败
      2. 运行时:参考的是对象所属的类中是否有调用的函数

      简单说:编译看左边,运行看右边。因为成员函数存在覆盖特性

    3. 静态函数

      1. 编译时:参考引用型变量所属的类中的是否有调用的静态方法
      2. 运行时:参考引用型变量所属的类中的是否有调用的静态方法

      简单说,编译和运行都看等号的左边。其实对于静态方法,是不需要对象的。直接用类名调用即可

  6. 多态的理解
    多态允许将子类的对象当做父类对象使用,某父类类型的引用指向其子类类型的对象,调用的方法是该子类的方法(前提是重写),这里的引用和调用方法的代码编译前就已经决定了,而引用指向的对象可以在运行期间进行多态

3. 抽象类

当一个类在描述事物的时候,如果没有足够的信息来描述这个事物,这个类就声明为抽象类

  1. 抽象类:使用 abstract 修饰的类,就称为抽象类
  2. 抽象方法:使用 abstract 修饰的方法称为抽象方法,该方法没有方法体
  3. 抽象类的作用:约定和模板
  4. 什么时候定义抽象类?当无法确定该行为时,把该方法定义为抽象方法

注意:

  1. 一个类中如果有抽象方法,那么这个类一定为抽象类

  2. 有抽象方法的类一定是抽象类,抽象类不一定有抽象方法

  3. 普通的子类必须重写父类及父类继承的抽象方法,否则,这个子类还是抽象类

  4. 抽象类不能实例化因为调用抽象方法没意义

  5. 抽象类中有构造函数用于给子类对象进行初始化

  6. 抽象类一定是个父类,因为需要子类覆盖其方法后才可以对子类实例化

  7. 抽象类可以不定义抽象方法,但是很少见,目的就是不让该类创建对象

    通常这个类中的方法有方法体,但是却没有内容。AWT 的适配器对象就是这种类

    abstract class Demo{
        void show1(){}
        void show2(){}
    }
    
  8. 抽象关键字 abstract 不能和那些关键字共存

    1. private:抽象方法是要被子类重写,private 是私有化,不让重写
    2. static:抽象方法是要被子类重写,没有方法体,而 static 方法不让重写
    3. final:因为 final 的作用是不让子类重写

抽象类和一般类的异同点

相同点:抽象类和一般类都是用来描述事物的,都可在内部定了成员。
不同:

区别一般类抽象类
信息是否充足有足够的信息描述事物描述事物的信息有可能不足
能否有抽象不能定义抽象方法,只能定非抽象方法可定义抽象方法,也可以定义非抽象方法
能否被实例可以被实例化不可以被实例化

4. 接口

  1. 本质:比抽象类更抽象

  2. 定义语法

    接口中成员的修饰符是固定的

    [访问修饰符] interface 接口名{
        //静态常量属性  public static final
        //抽象方法     public abstract
        //没有构造器
    }
    
  3. 实现接口(单继承多实现

    [访问修饰符] class 类名 implements 接口 1,接口 2......{
    	//类的主体(必须实现接口的抽象方法)
    }
    
  4. 接口之间可以多继承

    [访问修饰符] interface 接口名 extends 接口 1,接口 2......{}
    
  5. .注意

    1. 一个普通的类实现一个接口,必须实现接口及其父类的所有抽象方法

    2. 一个抽象类实现一个接口,可以不用重写接口的方法(抽象方法可以有抽象方法)

    3. 接口中的成员都是公共的权限 public

    4. 接口成员修饰符是固定的,通常不写,系统会默认给加上,但是不能写成其它的修饰符

    5. 接口只能定义静态常量

    6. 类与类之间是继承关系类与接口直接是实现关系

      接口与接口之间是继承关系,而且接口可以多继承

  6. 接口作用:和抽象类一样,起到约定和模板的作用,达到了对类的扩展,实现多继承的特点

接口与抽象类的区别?

区别接口抽象类
结构接口需要被实现,而且可以多实现抽象类需要被继承,而且只能单继承
方法类型接口中只能定义抽象方法,必须由子类去实现,接口中的成员必须由固定的修饰符抽象类中可以定义抽象方法非抽象方法子类继承后,可以直接使用非抽象方法
关系接口的实现like a 关系,在定义体系额外功能抽象类的继承is a 关系,在定义体系基本共性内容

5. 内部类

5.1 内部类

内部类:先实例化外部类,再用外部类实例化内部类

  1. 分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容,这时就把还有的事物定义成内部类。一般用于类的设计

  2. 内部类编译的结果有两个字节码文件Outer.classOuter$Inner.class

    class Outer{ 	  // 外部类
        class Inner{  // 内部类
            
        }
    }
    
  3. 内部类访问特点

    1. 内部类可以直接访问外部类中的成员,包括私有成员

    2. 外部类要访问内部类,必须先建立内部类的对象

      为什么内部类能直接访问外部类中成员呢? 那是因为内部类持有了外部类的引用外部类名.this

      class Outer{ 	  // 外部类
          private int num =31;
          class Inner{  // 内部类
              void show(){
                  System.out.println("外部类的变量 num ="+ num); //可以访问外部类的成员
              }
          }
          public void method(){
              Inner in = new Inner(); // 外部类要访问内部类,必须先创建内部类的对象
              in.show();
          }
      }
      
  4. 注意

    1. 如果内部类是静态的,相当于一个外部类
    2. 如果内部类中定义了静态成员该内部类也必须是静态的
  5. 内部类的声明(实例)

    1. 直接访问外部类中的内部类中的成员(这种格式不多见,因为一般内部类定义为私有的

      public static void main(){
          //先 new 外部类,再用外部类 new 内部类,相当于是对象.属性
          Outer.Inner in = new Outer().new Inner();
          in.show();
      }
      
    2. 如果内部类是静态的,相当于一个外部类

      //相当于类名.属性,因为是静态的,对象一加载就存在,可正常 new
      Outer.Inner in = new Outer.Inner();
      in.show();
      
    3. 如果内部类是静态的成员是静态的

      Outer.Inner.function();
      

5.2 局部内部类

局部内部类:内部类可以存放在局部位置

内部类在局部位置上只能访问局部中被 final 修饰的局部变量,因为 final 定义的局部变量相当于一个常量,延长了其生命周期,使得方法在消亡时,其内部类仍然可以访问该变量

注意方法中局部内部类不允许有访问修饰符,和局部变量相同

5.3 匿名内部类

匿名内部类:内部类的简写格式,其实就是一个匿名子类对象

必须有前提:内部类必须继承外部类或者实现一个外部接口(在 new 的时候去重写或者实现类的方法)

格式new 父类 or 接口(){子类内容}

父类 变量名 = new 父类(){子类内容};
接口 变量名 = new 接口(){子类内容};
abstract class Demo{
    abstract void show();
}
class Outer{
    int num = ;
    class Inner extends Demo{
        void show(){
            System.out.println("外部类的变量 num ="+ num);
        }
    }
    public void method(){
        // new Inner().show();
        new Demo(){  //匿名内部类
            void show(){
                System.out.println("外部类的变量 num ="+ num);
            }
        }.show();
    }
}
public class InnerClassDemo{
    public static void method(String[] args){
        new Outer().method);
    }
}

通常的使用场景

  1. 当函数参数是接口类型时,而且接口中的方法不超过三个
  2. 可以用匿名内部类作为实际参数进行传递

5.4 静态内部类

使用方法,跟外部类一样

6. 单例设计模式

解决的问题:保证一个类在内存中的对象唯一性

对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性

注意:在单线程下,单例设计模式是安全的,而在多线程下,单例设计模式是不安全的

如何保证对象唯一性?

  1. 不允许其他程序用 new 创建该类对象(私有化该类构造函数
  2. 在该类创建一个本类实例(在本类中 new 一个本类对象)
  3. 对外提供一个方法让其他程序可以获取该对象(定义一个公有的方法,返回创建的对象)

6.1 饿汉式

开发时常用

特点:类一加载,对象就已经存在了

class Single{							
    private static Single s = new Single(); // 通过 new 在本类中创建一个本类对象
    private Single(){}    				    // 私有化该类构造函数
    public static Single getInstance(){		// 定义一个公有的方法,将创建的对象返回
    	return s;
    }
}

6.2 懒汉式

面试时常用

特点:类加载时,没有对象,只有调用了 getInstance 方法时,才会创建对象,是延迟加载形式。

class Single{
    private static Single s = null;
    private Single(){}
    public static Single getInstance(){
        if(s==null)
        	s = new Single();
        return s;
    }
}

3. 异常

异常:程序在编译或者运行时发生的意外

1. 异常的体系

Throwable:无论是错误(Error),还是异常(Exception),问题发生就应该可以抛出,让调用者知道并处理。

该体系的特点:就在于 Throwable 及其所有的子类都具有可抛性

throws、throw:凡是可以被这两个关键字所操作的类和对象都具备可抛性

区别throwsthrow
位置使用在函数上使用在函数内
抛出内容抛出的是异常类,可以抛出多个,用逗号隔开抛出的是异常对象

(Throwable)不正常情况分成了两大类

  1. 一般不可处理的:Error

    特点:是由 JVM 抛出的严重性的问题,这种问题发生一般不针对性处理,直接修改程序,如:内存溢出

  2. 可以处理的:Exception

    1. 编译期异常(非运行时异常/检查异常)-----Exception 以及其子类(除 RuntimeException

      编译时就进行检测,让这种问题有对应的处理方式,这样的问题都可以针对性的处理

      常见:

      1. ParseException 解析异常
      2. ClassNotFoundException 找不到类
    2. 运行时异常(未检查异常)-----RuntimeException

      异常发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的而或者引发了内部状态的改变导致的。这种异常一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。

      常见:

      1. NullPointerException 空指针
      2. ArrayIndexOutOfBoundsException 数组下标越界
      3. StringIndexOutOfBoundsException 字符串下标越界
      4. ClassCastException 类型转换异常
      5. ArithmeticException 算术异常

    注意

    1. 编译期异常:不能避免,必须处理,否则编译不通过
    2. 运行时异常:可以不用处理
    3. 如果程序产生异常没有得到处理,那么程序将会不能通过编译或者终止运行

2. 异常处理方式

  1. 抛:throws

    [修饰符] 返回值 方法名(参数列表) throws 异常类
    
  2. 捕捉:try_catch

    try{
    	//可能出现异常的语句
    }catch(异常对象 1 对象名 1){
    	//处理方式
    }catch(异常对象 2 对象名 2){
    	//处理方式
    }finally{
    	//始终会执行
    }
    
  3. 声明:throw

    throw new 异常类型();
    

异常处理的原则

  1. 如果抛出需要编译时异常,那么函数上 必须要声明,否则必须在函数内try_catch 捕捉,否则编译失败
  2. 如果调用到了声明异常的函数,要么 try_catch 要么 throws,否则编译失败
  3. 功能内容可以解决,用 catch解决不了,就 throws 告诉调用者,由调用者解决
  4. 一个功能如果抛出了多个异常,那么调用时,必须有对应多个 catch 进行针对性的处理
  5. 内部有几个需要检测的异常,就抛几个异常抛出几个,就 catch 几个

3. 自定义异常

  1. 继承于 Exception
  2. 继承于 RuntimeException

注意

  1. 子类重写父类异常方法,则子类抛出的异常 <= 父类异常,即是子类不能抛出比父类大的异常
  2. 父类抛出多个异常,子类只能抛出父类异常的子集
  3. 如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛,就只能 try

4. 线程

**java.lang.Thread **

1. 基本概念

进程:正在进行中的程序,是操作系统的调度单位,是一种系统资源,有独立的地址空间

线程:线程是进程中的一个独立调度执行的任务单元

多线程:一个进程中多条执行路径

多线程的优缺点

  1. 优点:解决了多个线程同时运行问题,充分利用 CPU 的资源
  2. 缺点:线程太多会导致效率降低

注意:

  1. 一个程序运行至少有一个进程,一个进程至少有一个线程
  2. 线程比进程更容易调度
  3. 线程的创建比进程的开销小
  4. 线程之间的切换也比进程开销小
  5. 每个线程都有自己的堆栈,程序计数器和自己局部变量,多线程间能共享数据
  6. 多线程提高了并发性,有效的利用闲置的 cpu 的资源
  7. JVM 启动时就启动至少有两个线程:主线程 main,垃圾回收线程 GC

2. Thread 类

  1. 属性

    MAX_PRIORITY   // 最高优先级 10
    MIN_PRIORITY   // 最低优先级 1
    NORM_PRIORITY  // 默认优先级 5
    
  2. 构造器

    Thread();
    Thread(String name);
    Thread(Runnable runab);
    Thread(Runnable runab,String name);
    
  3. 方法

    Thread currentThread(); 	// 返回当前运行的线程
    String getName(); 			// 获得线程的名字
    void run(); 				// 存放具体操作的代码
    void start(); 				// 使线程开始启动,Java 虚拟机去调用 run 方法
    void sleep(long miliss);	// 休眠
    void setDaemon();			// 设置为守护线程(即是后台线程)
    void setPriority();			// 设置线程优先等级
    void join();				// 让某线程先执行
    void yield();				// 暂停线程
    void interrupt();			// 让某线程中断执行,若是冻结状态的,可使冻结转换为运行
    

3. 实现线程的方式

  1. 继承 Thread(不常用)

    1. 定义一个类继承 Thread
    2. 覆盖 Thread 类中的 run 方法
    3. 直接创建 Thread 的子类对象创建线程
    4. 调用 start 方法开启线程并调用线程的任务 run 方法执行
  2. 实现 Runnable (常用)

    1. 定义一个类实现 Runnable 接口
    2. 覆盖接口中的 run 方法,将线程的任务代码封装到 run 方法中
    3. 通过 Thread 类创建线程对象,并将 Runnable 接口的子类对象作为 Thread 类的构造函数的参数进行传递
    4. 调用线程对象的 start 方法开启线程

    实现 Runnable 接口的好处

    1. 线程任务从线程的子类分离出来,进行了单独的封装,按照面向对象的思想将任务的封装成对象
    2. 避免了 java 单继承局限性。所以较为常用

4. 线程状态

  1. 初始化状态:创建线程对象的时候
  2. 可运行状态:对象调用 start()方法时,进入 cpu 队列中进行排队
  3. 运行状态:cpu 运行线程时
  4. 阻塞状态:线程放弃运行,不在队列中
    1. sleep 方法:当前线程阻塞,休眠,这时候该线程不在队列中,并且释放 cpu 的资源给其他线程,时间结束之后重新开始排队
    2. join 方法:当前线程调用其他线程,当前被阻塞,直到另一个线程运行完毕当前线程才开始重新排队
    3. wait 方法:当前线程阻塞,并放弃该对象的锁,直到被唤醒才重新排队
  5. 终止状态:线程运行完毕

wait 和 sleep 的区别

不同点waitsleep
所属类java.lang.Objectjava.lang.Thread
是否释放锁释放不释放
是否执行权释放执行权释放执行权
唤醒时机等待被 notify 唤醒到一定的时间自动唤醒
使用范围同步方法 或者 同步块所有地方

5. 线程并发

当运行一个程序,启动了多个线程,这些线程就进入 CPU 队列中进行排队,争夺 cpu 的执行权,但 cpu 不会一直执行某个线程,只是在某个时间点上运行一个线程,cup 会计算队列里面的线程的优先级,选取线程优先级最高的线程运行,cpu 在运行时某个线程会分配时间片,时间片到期就结束,该线程就暂停运行,该线程又进行重新排队,在某个时间,多个线程在 cpu 上交替运行,这就叫线程并发

并发:当前多个线程并发执行,可能会出现争夺同一个资源,导致数据不一致。

  1. 解决思路:就是将多条操作共享数据线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算

  2. 解决办法

    1. 同步 synchronized

      同步的前提:同步中必须有多个线程并使用同一个锁

      1. 同步方法(锁:是固定的 this

        public synchronized void method(){    
            //要同步的代码
        }
        
      2. 静态同步函数(锁:是该函数所属字节码文件对象,可用 getClass 获取,也可用当前类名.class 表示)

        public static synchronized void method(){    
            //要同步的代码
        }
        
      3. 同步代码块(锁:是任意的对象

        public void method(){    
            synchronized(锁对象[只能是引用数据类型]){ //代码块    	
                //要同步的代码    
            }
        }
        

      同步的优缺点

      1. 优点:解决了线程的并发安全问题
      2. 缺点:相对降低了效率,因为同步的线程的都会判断同步锁
    2. Lock 锁

      所在包:java.util.concurrent.locks

      jdk1.5 以后将同步 封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显式动作

      两个重要的接口

      1. Lock 接口:出现替代了同步代码块或者同步函数,将同步的隐式锁操作变成显式锁操作,更为灵活,可以在锁上加上多组监视器

      2. Condition 接口:出现替代了 Object 中的 waitnotifynotifyAll方法,将这些方法进行了封装,变成 Condition 监视器对象,锁可以进行任意组合,一个锁可以挂多个监视器

        await()		<==>  wait()
        signal()	<==>  notify()
        signalAll() <==>  notifyAll()
        

      Lock 简单应用

      // 只是一个简单格式,代码不完整
      public class Resource{    
          Lock lock = new ReentrantLock();	// 创建一个锁对象    
          Condition Condition = lock.newCondition();// 通过锁对象获取该锁上的监视器对象 
          public void set(String name){        
              lock.lock();// 加锁        
              try{            
                  while(true){                
                      Condition.await();//等待                
                      //中间执行代码                
                      Condition.signalAll();// 唤醒所有            
                  }        
              }finally{            
                  lock.unlock();//解锁        
              }    
          }
      }
      

死锁:自己掌握对方等待的资源,而对方有掌握了自己等待的资源

6. 线程间通信

线程间通讯:多个线程在处理同一资源,但是任务却不同

通信机制等待/唤醒机制

  1. 使用方法有

    wait() 		 // 让线程处于冻结状态,被 wait 的线程会被存储到线程池中。
    notify()	 // 唤醒线程池中任意一个线程。
    notifyAll()	 // 唤醒线程池中的所有线程
    

    这些方法都必须定义在同步中,因为是用于操作线程状态的方法,必须要明确操作的是哪个锁上的线程

    为什么操作线程的方法 waitnotifynotifyAll 定义在了 Object 类中

    因为这些方法是监视器的方法。监视器其实就是锁。锁可以是任意的对象,任意的对象调用的方式一定定义在 Object 类中

  2. 生产者/消费者问题

    1. 要使用 while 来判断标记
    2. 使用 notifyAll 来会唤醒对方线程
  3. 停止线程的方法

    1. 定义停止标签(常用)

      任务中都会有循环结构,只要控制住循环就可以结束任务,控制循环通常就用定义标记来完成

    2. Interrupt(不建议使用)

      如果线程处于了冻结状态无法读取标记。可以使用 interrupt() 方法让 wait() 的线程冻结状态强制恢复到运行状态中来,让线程具备 cpu 的执行资格。但是强制动作会发生了 InterruptedException,记得要处理

5. Java 常用类库

类库:是 java 语言提供的,编写好的一些类,每个都具有一定特殊的功能性的类

java.lang 下类都不需要导包

类库学什么?

  1. 有哪些类
  2. 这个类有什么属性 ,什么构造器 ,什么方法
  3. 这些属性有什么作用,表示什么意思
  4. 这些方法的参数是什么意思,返回值又什么意思,有什么作用

1. Object 类

java.lang.Object

  1. 构造器:Object();

  2. 方法

    equals(Object o); 	// 比较两个对象是否相等,比较的是对象的地址
    getClass(); 		// 返回当前运行的类,能够在运行时知道当前对象所在的类
    hashCode(); 		// 返回对象的哈希码值
    toString();		// 把一个对象作为一个字符串返回 ,
    				// 该字符串=getClass().getName()+@+十六进制的 hashCode()
    
    1. equals:比较的是对象的地址。在实际应用中,可能不需要比较地址,可能需要比较两个对象的某些属性是否相等,所以说在自定义的类中通常覆盖 equals 方法
    2. toString:将当前对象的信息用字符串描述,但默认返回的是对象名加十六进制的哈希地址,没有实际意义,因此大多数情况下,在子类中,要覆盖 toString 方法

2. String 类

java.lang.String

String 类的特点:字符串对象一旦被初始化不会被改变

  1. 构造器

    String();
    String(String str); // 把一个字符串常量转化为一个字符串对象
    String(char[] c);   // 把一个字符数组转化为字符串对象
    String(byte[] b);   // 把一个字节数组转化为字符串对象
    
  2. 方法

    1. 获取

      int length();						// 获取字符串中字符的个数(长度)
      char charAt(int index) 				// 给一个下标,返回该下标出的字符
      int indexOf(int ch)
      int indexOf(int ch,int fromIndex)
      int indexOf(String str); 			// 查找 str 首次出现的下标,没有返回-1
      int indexOf(String str,int fromIndex)
      int lastIndexOf(int ch)
      int lastIndexOf(int ch,int fromIndex)
      int lastIndexOf(String str); 		// 查找 str 最后一次出现的下标,没有返回-1
      int lastIndexOf(String str,int fromIndex);    
      int codePointAt(int index) 			// 返回指定下标处的字符 UNicode 编码值
      int codePointBefore(int index) 		// 返回指定索引之前的字符(Unicode 代码值)
      String substring(int index); 		 // 字符串从 index 开始截取到最后
      String substring(int start,int end); // 字符串从 index 开始截取到 end
      
    2. 转换

      String[] split(String regex); // 用str拆分字符串,涉及到正则表达式
                                    // 如果str作为开始,则str之前的空白也作为一个元素
                                    // 如果str作为结尾,则str之后的空白不作为一个元素
      String replace(String oldstr,String newstr); 	  // 替换
      String replaceFirst(String oldstr,String newstr); // 替换第一个
      String toLowerCase(); 				 // 大转小
      String toUpperCase(); 				 // 小转大
      String concat(String str) 			 // 将指定字符串连接到此字符串的结尾。
      String trim(); 						 // 去掉首尾空白
      byte[] getBytes(); 					// 把一个都字符串对象转化为字节数组
      char[] toCharArray(); 				// 把字符以字符数组返回
      String valueOf(任何类型); 		      // 把任何类型的数据转化为一个字符串对象
      
    3. 判断

      boolean equals(Object obj);			// 两个字符串内容是否相同
      boolean equalsIgnoreCase(string str);// 忽略大写比较字符串内容
      boolean contains(String str); 		// 是否包含 str 指定的字符串
      boolean endsWith(String str); 		// 是否以什么结束
      boolean startsWith(String str); 	// 是否以什么开始
      boolean isEmpty(); 					// 字符串对象的 length 是否为 0
      
    4. 比较

      int compareTo(String anotherString) // 按字典顺比较字符串的大小
      int compareToIgnoreCase(String str) // 按字典顺序比较两个字符串,不考虑大小写
      string intern()						// 对字符串池进行操作的
      

3. StringBuffer/StringBuilder

java.lang.StringBuffer/StringBuilder

StringBufferStringBuilder:前者比后者多一个 synchronized 线程同步,故线程安全,后者不安全

注意:StringStringBufferStringBuilder 的区别?

StringBuffer(线程安全)

StringBuffer:字符串缓冲区,用于储存数据的容器

特点

  1. 长度的可变
  2. 可以存储不同类型数据
  3. 最终要转成字符串进行使用
  4. 可以对字符串进行修改

jdk1.5 以后出现了功能和 StringBuffer 一模一样的对象,就是 StringBuilder

不同的是:

  1. StringBuffer 是线程同步的,通常用于多线程
  2. StringBuilder 是线程不同步的,通常用于单线程,它的出现提高效率

StringBuffer 的使用

  1. 构造器

    StringBuffer(); 			// 构造一个不带字符的缓冲区,默认初始容量为 16 个字符
    StringBuffer(int i); 		// 构造一个不带字符,但具有指定初始容量的字符串缓冲区。
    StringBuffer(String str); 	// 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容
    
  2. 方法:大多数与 String 类一致,不一致的有

    // 增:
    StringBuffer append(boolean | char | int ....);     // 拼接在末尾
    StringBuffer insert(int index,boolean|char|int....) // 在指定的下标处插入字符
    
    // 删:
    StringBuffer delete(int start,int end); // 删除[start,end)区间的字符
    StringBuffer deleteCharAt(int index);   // 删除指定下标处的字符
    
    // 改:
    StringBuffer replace(int start,int end,String srt); // 替换
    StringBuffer reverse(); 						    // 反转
    void setCharAt(int index,char ch); 					// 修改指定下标除的字符
    // 查:
    char charAt(index);       // 查找下标为 index 的字符
    int indexOf(string);	  // 查找 string 的第一次出现的下标
    int lastIndexOf(string);  // 查找 string 的最后一次出现的下标
    

4. 包装类

java.lang.Number

4.1 Number 类

  1. 构造器

    Number();
    
  2. 方法

    byte byteValue();   // 将 Number 类型转化为 byte 类型
    short shortValue(); // 将 Number 类型转化为 short 类型
    //其他的数字类型的Value()方法为抽象方法,在其子类中实现的
    

4.2 包装类

包装类:是 Number 类的子类

为了方便操作基本数据类型值,将其封装成了对象,在对象中定义了属性和行为丰富了该数据的操作

基本类型包装类
byteByte
shortShort
intInteger
charCharacter

拆箱:将包装类型转化成基本类型 装箱:将基本类型转换成包装类型

Integer

  1. 属性

    static MAX_VALUE int // 类型的最大值
    static MIN_VALUE int // 类型的最小值
    
  2. 构造器

    Integer(int value); 	// 把一个 int 的基本数据类型转化为 Integer 对象
    Integer(String number); // 把一个 String 字符串类型转化为 Integer 对象
    
  3. 基本类型—>字符串

    1. 基本类型数值+""

    2. String 类中的静态方法 valueOf

      static String valueOf(基本类型数值); // 将基本类型数值转为 String
      
  4. 方法(延伸至所有包装类)

    1. 字符串类型或基本类型===>包装类型

      static Integer valueOf(int i); 		// 把一个 int 的基本数据类型转化为 Integer对象
      static Integer valueOf(String i);   // 把一个 String 字符串类型转化为 Integer对象
      
    2. 包装类型或字符串类型===>基本类型

      只有 Character 没有 parse 方法

      int intValue();   // 将包装类型 Integer 转换为基本类型 int
      byte byteValue(); // 将包装类型 Byte 转换为基本类型 byte
      static int parseInt("intstring");        	  // 使用 Integer 类的 parseInt
      static long parseLong("longstring");	 	  // 使用 Long 类的 parseLong
      static boolean parseBoolean("booleanstring"); // 使用 Boolean 类的 parseBoolean
      
    3. 基本类型===>字符串类型

      1. 基本类型数值+""

      2. String 类中的静态方法 valueOf

        static String valueOf(基本类型数值); // 将基本类型数值转为 String
        
    4. 整数具备不同的进制体现

      1. 十进制–>其他进制

        static String toBinaryString(int i); // 转换为二进制
        static String toOctalString(int i);  // 转换为八进制
        static String toHexString(int i); 	 // 转换为十六进制
        
      2. 其他进制–>十进制

        static int parseInt("string",radix);   // 将字符串转化为radix的进制的类型
        static long parseLong("string",radix); // 将字符串转化为radix的进制的类型
        

Character 常用方法

static boolean isDigit(char ch);     // ch 是否为数字
static boolean isLetter(char ch);    // ch 是否为字母
static boolean isUpperCase(char ch); // ch 是否为大写字母
static boolean isLowerCase(char ch); // ch 是否为小写字母

5. Math 类

java.lang.Math Math 类中的方法是静态的

  1. 属性

    E  // 自然底数
    PI // 圆周率
    
  2. 方法 static

    double abs(double a); 	// 绝对值
    double ceil(double a); 	// 向上取整
    double floor(double a);	// 向下取整
    double rint(double a);  // 四舍五入,点五取整
    double round(double a); // 四舍五入
    long round(double a); 	// 返回最接近参数的 long 值
    int round(float a); 	// 返回最接近参数的 int 值
    double random(); 		// [0,1)
    double pow(double a, double b);//返回第一个参数的第二个参数次幂的值
    

6. System 类

java.lang.System System 类中的方法和属性都是静态的

  1. 属性

    err  // 错误打印输出流
    out  // 输出流 java.io.PrintStream
    in   // 输入流 java.io.InputStream
    
  2. 方法

    void exit(int status);    // 终止 Java 虚拟机 ,停止运行,参数非零非正常终止
    long currentTimeMillis(); // 获取基准时间到现在的毫秒值
    void setProperty(String key, String value); // 设置系统属性信息,信息是全局,其他程序都可用
    String getProperty(“属性”);  // 获取系统属性信息
    Properties getProperties(); // 获取系统的属性信息,并存储到了 Properties 集合
    

    Properties 集合的使用方法

    Properties prop = System.getProperties();        // 获取系统的属性信息,并存到 Properties
    Set<String> nameSet = prop.stringPropertyNames();// 得到所有键名
    for(String name : nameSet){
        String value = prop.getProperty(name);       // 根据键得到值
        System.out.println(name+"::"+value);
    }
    

7. Date 类

java.util.Date

  1. 构造器

    Date();       // 返回本机的时间
    Date(long L); // 把毫秒数 L 转化为 date 对象 (基准时间+毫秒值)
    
  2. 方法

    boolean after(Date d);  // 是否比指定时间晚
    boolean before(Date d); // 是否比指定时间早
    int compareTo(Date d);  // 比较两个时间顺序 (值为 1 0 -1)
    long getTime();         // 时间毫秒值
    void setTime(long L);   // 设置毫秒值
    
    1. 日期对象毫秒值之间的转换

      1. 毫秒值===>日期对象

        1. 通过 Date 对象的构造方法new Date(timeMillis);
        2. 通过 Date 对象的 setTime 方法来设置:void setTime(long L);
      2. 日期对象===>毫秒值

        通过 Date 对象的 getTime 方法来获得

    2. 日期对象字符串之间的转换

      1. 日期对象===>日期格式的字符串,对日期对象进行 format 编码

        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG);
        dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
        dateFormat = new SimpleDateFormat("yyyy--MM--dd");
        String str_date = dateFormat.format(date);
        
      2. 将日期格式的字符串===>日期对象,对日期对象进行 parse 解码

        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG);
        dateFormat = new SimpleDateFormat("yyyy---MM---dd");
        Date date = dateFormat.parse(str_date);
        

8. Calender 类

java.util.Calendar

  1. 属性

    YEAR     	// 年
    MONTH    	// 月
    DATE    	// 日
    HOUR 12 	// 小时制
    HOUR_OF_DAY // 24 小时制
    MINUTE 		// 分
    SECOND 		// 秒
    DAY_OF_MONTH
    DAY_OF_WEEK
    DAY_OF_YEAR
    WEEK_OF_MONTH
    WEEK_OF_YEAR
    
  2. 方法

    Calendar getInstance();   		// 获得一个日历对象
    int get(属性) 				   // 获得属性的值
    void set(属性,int value) 		   // 设置属性的值
    Date getTime(); 		 		// 把一个日历对象转化为日期对象
    void setTime(Date date);  		// 把一个日期转化为一个日历对象
    long getTimeInMillis();         // 获得毫秒值
    void setTimeInMillis(long L);   // 设置毫秒值
    void set(int year,int month,int date)
    void set(int year,int month,int date,int hour,int minute,int second);
    void add(属性,int value);        // 给指定的字段添加值,value 可以为负
    

9. 格式化转换器

java.text.DateFormat/NumberFormat

  1. DateFormat:日期格式器

    SimpleDateFormat:把一个日期格式化

    1. 构造器

      SimpleDateFormat() ;
      SimpleDateFormat(String datestr);// 指定格式
      
    2. 特殊字符(格式)

      y // 年
      M // 月
      d // 日
      H // 0-23
      h // 1-12
      m // 分
      s // 秒
      E // 周
      
    3. 方法

      String format(Date date); // 把日期按指定格式化解析成一个字符串
      Date parse(String str);   // 把一个字符串按指定格式解析成一个日期对象
      
  2. NumberFormat:数字格式器

    DecimalFormat

    1. 构造器

      DecimalFormat();
      DecimalFormat(String str);
      
    2. 特殊字符

      0 // 数字 是 阿拉伯数字
      # // 数字 是 阿拉伯数字,如果不存在则显示为 0
      . // 数字 是 小数分隔符或货币小数分隔符
      - // 数字 是 减号
      % // 前缀或后缀 是 乘以 100 并显示为百分数
      
    3. 方法

      String format(Number number); // 把数字按指定格式化解析成一个字符串
      Number parse(String str)      // 把一个字符串按指定格式解析成一个数字
      

6. 集合

  1. 为什么会出现集合?

    对象是为了封装特有的数据,对象多了需要存储,如果对象的个数不确定,就用集合来存

  2. 数组和集合同是容器,他们有什么区别?

    容器最基本的功能:添加,删除

    1. 数组可以存储对象和基本数据类型,而集合只能存储对象
    2. 数组的长度是固定的,集合的长度是可变的

集合的特点:

  1. 用于存储对象的容器
  2. 集合的长度是可变
  3. 集合中不可以存储基本数据类型

1. Collection(接口)

java.util .Collection

常用方法:

  1. 添加

    boolean add(Object obj) 		// 添加一个对象
    boolean addAll(Collection coll) // 添加一堆对象
    
  2. 删除

    boolean remove(Object obj) 			// 移除一个对象
    boolean removeAll(Collection coll) 	// 移除一堆对象
    void clear() 						// 清空集合
    
  3. 判断

    boolean contains(Object obj) 		 // 是否包含这个对象
    boolean containsAll(Collection coll) // 是否包含一堆对象
    boolean isEmpty() 					 // 判断集合是否为空
    
  4. 获取

    int size() 			// 获取集合的长度
    Iterator iterator() // 返回在此 collection 的元素上进行迭代的迭代器
    
  5. 其他方法

    boolean retainAll(Collection coll)  // 取两个集合的交集
    Object[] toArray(); 				// 将集合转成数组
    

Iterator 接口:是对所有的 Collection 集合进行元素取出公共接口,只要是 Collection 容器,就可以用 Iterator 接口去取

  • 该对象必须依赖于具体容器,因为每一个容器的数据结构都不同,所以该迭代器对象是在容器中进行内部实现的。对于使用容器而言,具体的实现不重要,只要通过容器获取该实现的迭代器的对象即可。

2. List(接口)

java.util .List

特点List 有序,可重复(取出和存入的顺序一致,元素都有索引(角标),元素可以重复)

常用方法:

  1. 添加

    boolean add(Object obj);
    void add(int index, Object obj) // 在列表的指定位置插入指定元素(可选操作)
    
  2. 删除

    Object remove(int index) // 移除列表中指定位置的元素。
    boolean remove(Object o) // 从此列表中移除第一次出现的指定元素(如果存在)
    
  3. 修改

    Object set(int index, Object obj) // 用指定元素替换列表中指定位置的元素(可选操作)
    
  4. 获取

    Object get(int index) 	// 返回列表中指定位置的元素。
    int indexOf(Object obj) // 返回此列表中第一次出现的指定元素的索引;如果不存在,则返回 -1
    int lastIndexOf(Object obj) // 返回此列表中最后出现的指定元素的索引;如不存在,则返回 -1
    List subList(from,to);
    ListIterator listIterator();//获取列表迭代器对象,它可以实现在迭代过程中完成对元素的增删改查
    

    注意:只有 list 集合具备 ListIterator 迭代功能

List 接口的实现类

  1. Vector数组实现,是同步的,线程安全的,查询很慢

  2. ArrayList数组实现,是不同步的,线程不安全的,查询的速度快,替代了 Vector

  3. LinkedList链表实现,是不同步的,线程不安全的,增删元素的速度很快

ArrayListLinkedList 比较:

不同点ArrayListLinkedList
内部结构数组链表
是否可存null可以存 null可以存 null
是否同步不同步不同步
特点适合遍历和查找,不适合添加和删除不适合遍历和查找,适合添加和删除
适合场景查询速度较快,增删速度比较慢查询速度比较慢,增删速度较快

LinkedList 特有的常用方法(jdk 1.6 之前):

  1. addFirst(); addLast();
  2. getFirst(); getLast(); // 获取但不移除,如果链表为空,抛出 NoSuchElementException
  3. removeFirst(); removeLast(); // 获取并移除,如果链表为空,抛出 NoSuchElementException

LinkedList 特有的常用方法(jdk 1.6 之后):

  1. offerFirst(); offetLast();
  2. peekFirst(); peekLast(); // 获取但不移除,如果链表为空,返回 null
  3. pollFirst(); pollLast(); // 获取并移除,如果链表为空,返回 null

3. Set(接口)

java.util .Set

特点Set 无序,不可重复

**常用方法:**和 collection 接口的方法一样

boolean add(E e); 							// 添加元素
boolean addAll(Collection<? extends E> c);	// 添加多个元素
boolean remove(Object o) 	// 移除某个元素
void clear(); 				// 移除所有元素
int size(); 				// 集合长度
boolean equals(Object o) 	// 比较指定的对象与列表是否相等。
boolean isEmpty(); 			// size==0
boolean contains(Object o); // 是否包含
boolean containsAll(Collection<?> c); // 是否包含所有元素,则返回 true。
Iterator<E> iterator()      // 返回在此 collection 的元素上进行迭代的迭代器。
Object[] toArray()          // 将 set 集合转换成 Object 数组

子类 HashSet、TreeSet、LinkedHashSet 三者的比较:

不同点HashSetTreeSetLinkedHashSet
内部结构哈希表二叉树链表
是否有序输入输出的顺序可能不同输出顺序为输入排序后结果输入输出顺序相同
是否同步不同步不同步不同步

3.1 HashSet

HashSet:内部数据结构是哈希表,是不同步的

如何保证该集合的元素唯一性呢?

是通过对象的 hashCodeequals 方法来完成对象唯一性的

  1. 如果对象的 hashCode 值不同,那么不用判断 equals 方法,就直接存储到哈希表
  2. 如果对象的 hashCode 值相同,那么要再次判断对象的 equals 方法是否为 true
    1. 如果为 true,视为相同元素,不存
    2. 如果为 false,那么视为不同元素,就进行存储

记住:如果元素要存储到 HashSet 集合中,必须覆盖 hashCode 方法和 equals 方法

哈希表确定元素是否相同

  1. 判断的是两个元素的哈希值是否相同。如果相同,再判断两个对象的内容是否相同。
  2. 判断哈希值相同,其实判断的是对象的 hashCode 的方法。判断内容相同,用的是 equals 方法
  3. 如果哈希值不同,是不需要判断 equals

3.2 TreeSet

TreeSet:可以对 Set 集合中的元素进行排序,是不同步的

判断元素唯一性的方式:就是根据比较方法的返回结果是否是 0,是 0,就是相同元素,不存

TreeSet 对元素进行排序的方式

  1. 元素自身具备比较功能,就需要实现 Comparable 接口,覆盖 compareTo 方法

  2. 集合自身具备比较功能,定义一个类实现 Comparator 接口,覆盖 compare 方法

    该对象作为参数传递给 TreeSet 集合的构造函数

4. Map(接口)

java.util .Map

Map:一次添加一对元素(键和值)。Map 集合称为双列集合
Collection:一次添加一个元素。Collection 集合称为单列集合

Map 集合存储的是键值对,必须保证键的唯一性

Map 常用的实现类

  1. Hashtable :内部结构是哈希表同步的,不允许 null 作为键和值

    Properties:用于操作以键值对形式存在的配置文件,可以和 IO 技术相结合

    1. Properties 集合特点

      1. 该集合中的键和值都是字符串类型
      2. 集合中的数据可以保存到流中,或者从流获取
    2. 常用方法

      void setProperty(String k, String v); 	// 储存
      String getProperty(String k);  			// 取出
      Set<String> stringPropertyNames();      // 取出所有键
      Enumeration<?> propertyNames() 			// 取出所有键的枚举
      void list(PrintStream out); 			// 取出 properties 集合中的元素通过字节流输出
      void list(PrintWriter out);
      void store(OutputStream out, String comments); // 将集合中的数据存入到文件中
      void store(Writer writer, String comments);
      void load(InputStream inStream);               // 读取一个文件中的配置信息
      void load(Reader reader);
      

      读取

      Properties prop = System.getProperties();   	  // 获取系统的属性信息
      Set<String> nameSet = prop.stringPropertyNames(); // 得到所有键名
      for(String name : nameSet){
          String value = prop.getProperty(name);        // 根据键得到值
          System.out.println(name+"::"+value);
      }
      
  2. HashMap : 内部结构是哈希表不同步的,允许 null 作为键和值

  3. TreeMap : 内部结构是二叉树不同步的,可以对 Map 集合中的键进行排序

HashMapHashTable 的比较:

不同点HashMapHashTable
内部结构哈希表哈希表
是否可存null允许 null 作为键和值不允许 null 作为键和值
是否同步不同步同步
取出元素迭代方式IteratorEnumeration
哈希值的使用不同会重新计算 hash 值直接使用对象的 hashCode

HashTable 有一个 contains()方法,功能和 containsValue()功能一样

HashMap

  1. 构造器

    HashMap();
    
  2. 方法(一一对应 映射)

             V put(K key,V value); 			// 添加键值对。如果没有返回 null,存相同键,值会被覆盖
             V get(Object key); 			// 给键获得值
             V remove(Object key); 			// 给键删除指定的键值对
          void clear(); 					// 清空 map 集合
       boolean containsKey(Object key); 	// 判断集合是否包含该键
       boolean containsValue(Object value); // 判断集合是否包含该值
       boolean isEmpty(); 		// 如果次映射中未包含键值映射关系,则返回 true
           int size(); 			// 集合长度
           Set entrySet(); 		// 返回键值对视图关系
           Set keySet(); 		// 获得所有的键
    Collection values(); 		// 获得所有的值
    

    Set entrySet():将键和值的映射关系作为对象存储到了 Set 集合中,而这映射关系类型就是 Map.Entry 类型,成功解决了 map 集合没有迭代器的问题

    //Map.Entry<Integer, String>内部类的用法
    Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
    Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
    while(it.hasNext()){
        Map.Entry<Integer, String> me = it.next();
        Integer key = me.getKey();
        String value = me.getValue();
        System.out.println(key+"::::"+value);
    }
    

MapCollection 的区别?

CollectionCollections 的区别?

5. Collections 集合工具类

java.util.Collections

**常用方法:**方法都是静态的

void sort(List list); 	 	 // 对 list 集合进行指定顺序的排序,升序
void shuffle(List list); 	 // 随机
void reverse(List list); 	 // 颠倒,逆序
T max(List list);		     // 最值
int binarySearch(List list); // 二分查找
boolean replaceAll();        // 替换所有

6. Arrays 数组工具类

java.util.Arrays

**常用方法:**方法都是静态的

List asList(元素 1,元素 2,元素 n,....);  // 将任意个元素转为集合
void sort(任何类型数组); 				   // 对数组进行指定顺序的排序,升序
源数组类型 copyOf(源数组,新数组的长度); 	  // 复制指定长度的数组,得到新数组

7. 泛型

泛型:广泛的引用数据类型。出现于 JDK1.5 开始出现的安全机制,泛型解决了对象的向上转型和向下转型

好处:将运行时期的问题 ClassCastException 转到了编译时期,避免了强制转换的麻烦

说明:它代表不确定的类型,当在访问时,如果没有特殊指定类型,它默认 Object

泛型的特点类型参数化,更灵活,类型更安全

什么时候用?

当操作的引用数据类型不确定的时候,就使用**<>,将要操作的引用数据类型传入**即可。

其实<>:就是一个用于接收具体引用数据类型的参数范围

在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型

泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全。

运行时,会将泛型去掉,生成的 class 文件中是不带泛型的,这个称为泛型的擦除

为什么擦除呢?因为为了兼容运行的类加载

泛型

泛型类 泛型方法 泛型接口

泛型通配符:? (表示未知类型)

泛型的限定

  1. 泛型上限:? Extends E (是 E 类型或者 E 的子类,都可以)

    一般存储对象的时候用。这样取出都是按照上限类型来运算的,不会出现类型安全隐患

    比如添加元素:addAll

  2. 泛型下限:? super E (是 E 类型或者 E 的父类,都可以)

    一般取出对象的时候用。比如:比较器

7. 文件以及 IO 流

1. File 文件类

java.io.File

File:硬盘上的一个文件或者一个目录的抽象表现形式

  1. 构造器

    File(String pathName);
    
  2. 方法:如果文件存在,就不创建,不存在就创建

    // 获取
    getName(); 			// 获得文件名称
    getPath()// 获得文件相对路径
    getAbsolutePath();	// 获得文件绝对路径
    length(); 			// 文件大小
    lastModified();		// 获得最后一次修改的时间
    getFreeSpace();     // 剩余空间
    getTotalSpace();    // 总空间
    getUsableSpace();   // 可用空间
    getParent(); 		// 获得父级目录
    getParentFile()// 获得父级文件
    list()// 获得当前目录下所有目录及文件 string[]
    listFiles()// 获得当前目录下所有目录及文件 file[]
    listRoots();        // 获取目录文件
    // 判断
    canExecute(); 		// 是否可执行
    canRead(); 			// 是否可读
    canWrite(); 		// 是否可写
    isHidden(); 		// 是否是隐藏文件
    isFile(); 			// 是否是文件
    isDirectory();		// 是否是目录
    exists(); 			// 是否存在
    // 创建
    delete(); 			// 删除文件或文件夹(空文件夹)
    createNewFile();	// 创建新文件
    mkdir(); 			// 创建单个目录
    mkdirs(); 			// 创建多个目录
    renameTo(File file);// 重命名
    

1.1 过滤器 filter 应用

  1. FileNameFilter 接口:过滤文件名

    public class FileNameFilterDemo{
        public static void main(String[] args){
            File dir = new File("c:\\");
            String[] names = dir.list(new FilterByJava()); // 查找指定文件的文件名
        }
    }
    class FilterByJava implements FileNameFilter{
        @Override
        public boolean accept(File dir,String name){
            return name.endsWith(".java");  // 返回所有以.java结尾的文件名
        }
    }
    
  2. FileFilter 接口:过滤文件

    public class FileFilterDemo{
        public static void main(String[] args){
            File dir = new File("c:\\");
            File[] files = dir.listFile(new FilterByHidden()); // 查找指定的文件
        }
    }
    class FilterByHidden implements FileFilter{
        @Override
        public boolean accept(File pathname){
            return pathname.isHidden();  // 返回所有隐藏的文件
        }
    }
    
    

分隔符:

  1. Windows://
  2. Uniux:\

2. IO 流

:是一组有序有起点有终点字节集合,是计算机的数据传输的一种抽象表现形式

IO 流:用来处理设备之间的数据传输,java 对数据的操作是通过的方式,用于操作流的对象都在 io 包

输入流和输出流都是相对于内存而言。

  1. 输入流:将外部设备中的数据读取到内存中
  2. 输出流:将内存中的数据写入到外部设备中

编码:把看得懂的东西变成看不懂的东西

解码:把看不懂的东西变成看的懂得东西

OutputStreamWriter字符流通向字节流的桥梁,可使用指定的 charset 将要写入流中的字符编码成字节

简单说: 字符流=字节流+编码表

字节流:基本操作与字符流相同,但是它不仅可以操作字符,还可以操作其他媒体文件

如果要操作文字数据,建议优先考虑字符流
如果要操作流数据,建议优先考虑字节流

流分类:

字节流的两个顶层父类:1.InputStream 2.OutputStream

字符流的两个顶层父类:1.Reader 2.Writer

类型12
方向输出流 OutputStream输入流 InputStream
处理数据类型字节流 Stream字符流 Reader/Writer
功能节点流缓冲流(过滤流)

2.1 文件流

  1. 文件字节流

    1. 文件字节输入流:FileInputStream

      创建读取流对象时,必须要明确被读取的文件,一定要确定该文件是存在的

      1. 构造器

        FileInputStream(String path);
        FileInputStream(File file);
        
      2. 方法:如果文件存在,就覆盖,不存在就自动创建

        读取方式:单字符读取、多字符读取(自定义缓冲区)

        int read(); 		 // 读取一个字节
        int read(byte [] b); // 读取缓冲的字符数组,把数据保留在数组中,返回读取的长度,没有返回-1
        close(); 			 // 关闭,应该放在 finally 中且被判断流是否为 null
        
    2. 文件字节输出流:FileOutputStream

      1. 构造器

        FileOutputStream(String path);
        FileOutputStream(File file);
        FileOutputStream(String path,boolean b); // 是否续写
        FileOutputStream(File file,boolean b);
        
      2. 续写、换行(系统换行符:LINE_SEPARATOR 由 System.getProperty("line.separator")得到)

  2. 文件字符流

    FileReader 字符输入流
    FileWriter 字符输出流

2.2 转换流

转换流 = 字节流 + 编码集

  1. 字符流转换为字节流OutputStreamWriter

    1. 构造器

      OutputStreamWriter(OutputStream);
      
    2. 方法

      writer(int c); 		// 写入单个字符
      writer(String str); // 写入一个字符串
      flush() 			// 刷新该流的缓冲。
      close()
      
  2. 字节流转换为字符流InputStreamReader

    1. 构造器

      InputStreamReader(InputStream);
      

什么时候使用转换流呢?

  1. 源或目的对应的设备是字节流,但操作的却是文本数据,可以使用转换作为桥梁,便捷对文本操作
  2. 一旦操作文本且涉及到具体的指定编码表时,必须使用转换流

2.3 缓冲流

  1. 输入缓冲流:BufferedReader,BufferedInputStream

    1. 方法

      String readLine(); //读取整行
      
  2. 输出缓冲流:BufferedWriter、BufferedOutputStream

    1. 构造器

      BufferedInputStream(InputStream);
      
    2. 方法

      newLine(); //换行
      
1. 装饰设计模式

装饰设计模式:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决

特点:装饰类和被装饰类都必须所属同一个接口或者父类

  • 装饰和继承都能实现一样的特点:进行功能的扩展增强。 有什么区别呢?装饰比继承灵活

    public class PersonDemo{
        public static void main(String[] args){
            Person p = new Person();
            NewPerson p1 = new Newperson(p);  // 装饰方式
            p1.chifan();
            NewPerson2 p2 = new Newperson2(); // 继承方式
            p2.chifan();
        }
    }
    class Person{
        void chifan(){
            System.out.println("吃饭");
        }
    }
    // 此类就是为了增强Person而出现的
    class NewPerson{
        private Person p;
        public NewPerson(Person p){
            this.p = p;
        }
        public void chifan(){
            System.out.println("开胃酒");
            p.chifan();
            System.out.println("甜点");
        }
    }
    class NewPerson2 extends Person{
        public void chifan(){
            System.out.println("开胃酒");
            p.chifan();
            System.out.println("甜点");
        }
    }
    
  • LineNumberReader:可以查询出行号。装饰类 BufferedReader 的子类

    public class LineNumberReaderDemo{
        public static void main(String[] args) throws IOException{
            FileReader fr = new FileReader("文件.txt");
            LineNumberReader lnr = new LineNumberReader(fr);
            String line = null;
            while((line =lnr.readLine()) != null){
                System.out.println(lnr.getLineNumber()+":"+line);
            }
            lnr.close();
        }
    }
    

2.4 对象流

序列化:把对象转换成字节码,对象流中的对象必须实现 Serializable 接口

注意

  1. transient(非静态数据不想被序列化可以使用这个关键字修饰)
  2. static(静态数据不会被序列化)

对象流:把对象存入文件中,或者将文件中的对象数据读出存入对象

  1. 对象输入流:ObjectInputStream EOFException

    1. 构造器

      ObjectInputStream(InputStream);
      
    2. 方法

      Object readObject();
      
  2. 对象输出流:ObjectOutputStream NotSerializableException 未实现序列化

    1. 构造器

      ObjectOutputStream (OutputStream);
      
    2. 方 法

      writeObject(Object o);
      

2.5 IO 包中常见流

1. 打印流

打印流PrintWriterprintStream,可以直接操作输入流文件

  1. PrintWriter:字符打印流, 在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类
    1. 构造函数参数:字符串路径、File 对象、字节输出流、字符输出流
    2. 重要方法:append、flush、format、print、println、write
  2. PrintStream:字节打印流,提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式、不抛 IOException,打印的所有字符都使用平台的默认字符编码转换为字节
    1. 构造函数参数:字符串路径、File 对象、字节输出流
    2. 重要方法:append、flush、format、print、println、write
2. 序列流

序列流SequenceInputStream 对多个流进行合并,文件分割和合并

3. 管道流

管道流PipeInputStreamPipeOutputStream:输入输出可以直接进行连接,通过结合线程使用

4. 随机访问文件

RandomAccessFile:自身具备读写的方法。通过 skipBytes(int x)seek(int x)来达到随机访问

特点:

  1. 该对象即能读,又能写

    该对象内部维护了一个 byte 数组,并通过指针可以操作数组中的元素,可以通过 getFilePointer 方法获取指针的位置和通过 seek 方法设置指针的位置

  2. 其实该对象就是将字节输入流字节输出流进行了封装

  3. 该对象的源或者目的只能是文件,通过构造函数就可以看出

5. 其他流
  1. 操作基本数据类型:DateInputStream、DateOutputStream
  2. 操作字节数组:ByteArrayInputStream、ByteArrayOutputStream
  3. 操作字符数组:CharArrayReader、CharArrayWriter
  4. 操作字符串:StringReader、StringWriter

2.6 编码表

常见码表

  1. ASCII:美国标准信息交换码
  2. ISO8859-1:拉丁码表、欧洲码表
  3. GB2312:中国的中文编码表
  4. GBK:中国的中文编码表的升级
  5. Unicode:国际标准码
  6. UTF-8:最多用三个字节来表示一个字符

8. 网络编程

1. 网络模型

位置作用
应用层应用程序间的交换和数据交换
主要是一些终端的应用,比加说 FTP(各种文件下载),WEB(IE 浏览),QQ 之类的
(可以把它理解成我们在电脑屏幕上可以看到的东西,就是终端应用)
表示层进行对接收的数据 进行解释加密与解密压缩与解压缩等,
也就是把计算机能够识别的东西转换成人能够能识别的东西
会话层通过传输层(端口号:传输端口与换收端口)建立数据传输通路
传输层定义了一些传输数据的协议(如:TCP/UDP)和端口号(如:WWW 80),
将从下层接收的数据进行分段和传输,到达目的地址后再进行重组,常把这一层数据叫做
网络层从下层接收到的数据进行 IP 地址的封装与解封装,
这一层工作的设备是路由器,常把这一层的数据叫做数据包
数据连接层将从物理层接收的数据进行 MAC (网卡)地址,
在这一层工作的设备是交换机,数据通过交换机来传输,常把这一层的数据叫做
物理层主要定义物理设备(网线/光纤)标准,用于传输比特流,这一层的数据叫做比特

2. 网络通讯要素

网络通讯要素:IP 地址、端口号、传输协议(TCP/UDP)

2.1 IP 地址

InetAddress 类:表示互联网协议(IP)地址,对应于网络层

本地环回地址:127.0.0.1
对应主机名:localhost

2.2 端口号

端口:是用来标示应用程序

有效端口0 - 65535,其中 0 - 1024 系统使用或者是保留端口,尽量不要用,因为系统要使用

2.3 传输协议

传输协议:其实就是通讯规则,对应于传输层

Socket(套接字):就是为网络服务提供的一种机制,网络通信其实就是 Socket 间的通信

  1. Socket 可以理解为通信的两端,数据就是在 Socket 之间进行传输。
  2. 通信的两端都有 Socket,数据在两个 Socket 间通过 IO 传输

常见协议:TCP,UDP(都是传输层的协议)

  1. TCP:面向连接,可靠传输协议
  2. UDP:不面向连接,不可靠

TCP/UDP 协议比较

区别UDPTCP
是否连接将数据及源和目的封装成数据包,不需要建立连接建立连接,形成传输数据的通道
传输数据量每个数据报的大小限制在64k内在连接中进行大数据量传输
是否可靠因无连接,是不可靠协议通过三次握手完成连接,是可靠协议
传输速度不需要建立连接,速度快必须建立连接,效率会稍低点

3. 网络通信应用

我们编写网络通信程序,其实是在应用层

3.1 UDP 通信

  1. 发送端

    创建 UDP 发送端思路

    1. 建立 udp 的 socket 服务
    2. 将要发送的数据封装到数据包中
    3. 通过 udp 的 socket 服务将数据包发送出去
    4. 关闭 socket 服务
    public class UDPSendDemo {
        public static void main(String[] args) throws IOException {
            DatagramSocket ds = new DatagramSocket(8888); // 1.udpsocket 服务
            String str = "udp 传输演示:哥们来了!";
            byte[] buf = str.getBytes();
            // 2.使用 DatagramPacket 将数据封装到的该对象包中。
            DatagramPacket dp = new DatagramPacket(buf,		// 数据
                                             buf.length,	// 长度
                  					    InetAddress.getByName("127.0.0.1"),//地址
                                             10000);		// 端口号
            ds.send(dp); // 3.通过 udp 的 socket 服务将数据包发送出去。使用 send 方法。
            ds.close();  // 4.关闭资源。
        }
    }
    
  2. 接收端

    建立 UDP 接收端思路

    1. 建立 udp socket 服务,因为是要接收数据,必须要明确一个端口号
    2. 创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析这些数据
    3. 使用 socket 服务的 receive 方法将接收的数据存储到数据包中
    4. 通过数据包的方法解析数据包中的数据
    5. 关闭资源
    public class UDPReceDemo {
        public static void main(String[] args) throws IOException {
            DatagramSocket ds = new DatagramSocket(10000); // 1.建立 udp socket 服务
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf,buf.length); // 2.创建数据包
            ds.receive(dp);		// 3.使用接收方法将数据存储到数据包中,阻塞式的。
            // 4.通过数据包对象的方法,解析其中的数据,比如:地址,端口,数据内容。
            String ip = dp.getAddress().getHostAddress();
            int port = dp.getPort();
            String text = new String(dp.getData(),0,dp.getLength());
            System.out.println(ip+":"+port+":"+text);
            ds.close(); // 5.关闭资源。
        }
    }
    

3.2 TCP 通信

  1. 客户端

    TCP 客户端建立思路

    1. 创建 tcp 客户端 socket 服务。建议该对象一创建就明确目的地,要连接的主机

    2. 如果连接建立成功,说明数据传输通道已建立

      该通道就是 socket 流 ,是底层建立好的。 既然是流,说明这里既有输入,又有输出。

      想要输入或者输出流对象,可以找 Socket 来获取,可以通过 getOutputStream()getInputStream()来获取两个字节流。

    3. 使用输出流,将数据写出

    4. 关闭资源

    public class ClientDemo {
        public static void main(String[] args) throws Exception {
            Socket socket = new Socket("127.0.0.1",10002);// 1.创建客户端 socket 服务
            OutputStream out = socket.getOutputStream();	 // 2.获取 socket 流中的输出流
            out.write("tcp 演示:哥们又来了!".getBytes());	    // 3.使用输出流将指定的数据写出
            socket.close();//关闭资源。
        }
    }
    
  2. 服务端

    TCP 服务端建立思路

    1. 创建服务端 socket 服务,通过 ServerSocket 对象
    2. 服务端必须对外提供一个端口,否则客户端无法连接
    3. 获取连接过来的客户端对象
    4. 通过客户端对象获取 socket 流读取客户端发来的数据,并打印在控制台上
    5. 关闭资源:关客户端,关服务端
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            ServerSocket ss = new ServerSocket(10002); // 1.创建服务端对象
            Socket s = ss.accept();					  // 2.获取连接过来的客户端对象。阻塞式
            InputStream in = s.getInputStream(); 	  // 3.获取输入流,要读取客户端发来的数据
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            String text = new String(buf,0,len);
            String ip = s.getInetAddress().getHostAddress();
            System.out.println(ip+":"+text);
            s.close();
            ss.close();
        }
    }
    

3.3 网络架构

网络架构

  1. C/S(client/server)

    特点:该结构的软件,客户端和服务端都需要编写,开发成本较高,维护较为麻烦

    好处:客户端在本地可以分担一部分运算

  2. B/S(browser/server)

    特点:该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代,开发成本相对低,维护更为简单
    缺点:所有运算都要在服务端完成

客户端、服务端

最常见的客户端:浏览器:IE

最常见的服务端:服务器:Tomcat

客户端 IE 如何给服务端 Tomcat发请求?

  1. 客户端 IE 发送的请求:请求行+消息头+请求体

    // 请求行: 请求方式(GET) 请求的资源路径(/myweb/1.html) http协议版本(HTTP/1.1)
    GET / HTTP/1.1 
    // 请求消息头: 属性名:属性值
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash,application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
    Accept: */*
    Accept-Language: zh-cn,zu;q=0.5
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
    Host: 192.168.1.100:9090
    Connection: Keep-Alive
    // 空行
    // 请求体
    
  2. 服务端 Tomcat 返回应答消息:应答行+消息属性信息+应答体

    // 应答行:http协议版本(HTTP/1.1) 应答状态码(200) 应答状态描述信息(OK)
    HTTP/1.1 200 OK
    // 应答消息属性信息:属性名:属性值
    Server: Apache-Coyote/1.1
    ETag: W/"199-1323480176984"
    Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
    Content-Type: text/html
    Content-Length: 199
    Date: Fri, 11 May 2012 07:51:39 GMT
    Connection: close
    // 空行
    // 应答体
    <html>
        <head>
        <title>这是我的网页</title>
        </head>
        <body>
            <h1>欢迎光临</h1>
            <font size='5' color="red">这是一个 tomcat 服务器中的资源,是一个 html 网页</font>
        </body>
    </html>
    

GET 提交和 POST 提交的区别

  1. 在客服端的区别

    区别GETPOST
    是否显示提交的信息都显示在地址栏中提交的信息不显示地址栏中
    封装位置将信息封装到了请求消息的请求行将信息封装到了请求体
    安全性对于敏感的数据信息不安全对于敏感信息安全
    数据体积对于大数据不行,因为地址栏存储体积有限可以提交大体积数据
  2. 在服务端的区别

    如果提交中文到 tomcat 服务器会出现乱码,服务器默认会用 iso8859-1 进行解码,解决方法:

    1. get 提交和 post 提交都有效

      1. 通过 iso8859-1 进行编码,再用指定的中文码表解码即可
      2. URLDecoder.decode(user,“utf-8”)
    2. 对于 post 提交,还有另一种解决办法,就是直接使用服务端一个 request 对象

      request 对象的 setCharacterEncoding 方法直接设置指定的中文码表就可以将中文数据解析出来。这个方法只对请求体中的数据进行解码

9. XML

1. 概述

XML:可扩展的标记语言,由 W3C 发布,版本 1.0

XML作用

  1. 用于软件配置
  2. 描述数据之间的关系
  3. 数据传输

2. XML 使用

  1. 定义方法

    <?xml version="1.0"?>
    <?xml version="1.0" encoding="GBK"?> 
    
  2. 元素标记命名规则

    1. 区分大小写
    2. 不以数字开头,不能有空格和冒号(😃
    3. 一个良好的 xml 有且只有一个根目录
    4. 不能以 XML(xml 或者 Xml 等)开头
  3. 属性:一个标记可以有多个属性,每个属性都有自己名称值

  4. CDATA 区:xml 解析程序不会处理 CDATA 区中的内容,而是直接输出

  5. 注释:

    <!-- 注释 -->
    
  6. 特殊字符:

    &  &amp;
    

3. XML 解析

  1. dom W3C 官方推荐

    特点:解析器读入整个文档,然后构建一个内存树形结构,然后就可以使用 Document 接口来操作这树形结构,消耗计算内存

  2. SAX 不是官方标准 ,是 xml 社区上标准

    特点:不必加载所有文档,就可以操作文档对象

4. DOM4J 编程

  1. 体系结构

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kX928ZNU-1648561039749)(link-picture\image-20220111233522129.png)]

  2. dom 解析方式

    加 dom4j 的 jar:dom4j-1.6.1.jar

    拷贝 jar 包,然后新建文件夹,把 jar 放入,点击右键 build path,然后 add build path

  3. dom 解析常用方法

    SAXReader read = new SAXReader(); 				 // 创建一个 XML 解析流
    Document doc = read.read(new File("xml 的路径")); // 获得 Document
    Element root = doc.getRootElement(); 			 // 获得根元素
    
    // 操作 Element 的方法
    String getName(); 					// 获得标记名
    String getText(); 					// 获得文本值
    String attitudteValue(String name);	// 用属性名获得属性值
    List elements(); 					// 获得所有的子元素
    Element getParent(); 				// 获得该元素的父级元素
    Iterator elementIterator();			// 获得所有的子元素的迭代器
    

5. XPath

Xpath:是在 XML 文档中查找信息的语言,它简化了 DOM4j 查找节点(Node)的过程,通过元素和属性进行查找

需要导入 jar 包:jaxen-1.1-beta-6.jar

  1. 语法

    /Students/Student 		// 绝对路径下获得根目录下所有直接 Student 子元素
    /Students//Student 		// 相对路径下获得根目录下所有的 Student 子元素
    Student//name 			// 获得所有属于 Student 的子元素的 name 元素
    //@id 					// 获得所有带 id 属性的元素
    //Student[@id] 			// 获得所有带 id 属性的 Student 元素
    //Student[@id='110'] 	// 获得所有带 id 属性值为 110 的 Student 元素
    //Student[@age>=18] 	// 获得所有带 age 属性值大于等于 18 的 Student 元素
    //Student[@sex='女' and @age>20]
    //Student[@sex='女' or @age>20]
    
  2. 方法

    Node selectSingleNode(String xpath); // 返回是第一个满足 xpath 条件的 Node 对象
    List<Node> selectNodes(String xpath);// 返回所有满足 xpath 条件的 Node 对象的 List 集合
    

6. DOM 操作(增、删、改、查)

DOM 操作方法:

DocumentHelper.createDocument(); 					// 创建一个 Document
DocumentHelper.createElement("name"); 				// 创建一个根目录
DocumentHelper.createAttribute(元素, "属性", "属性值");// 创建属性
add(属性/元素); 				// 添加到 Document
addAttribute("属性", "属性值"); // 添加属性
属性.setValue("属性值"); 	   // 修改属性
remove(子元素); 				// 删除子元素

10. 反射机制

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

  1. 获取 Class 对象字节码文件对象

    获取 Class 对象后,再用 newInStance() 创建对象

    getClass();					// 方式1
    静态的属性.class/对象.class	// 方式2
    Class.forName(“带包名的类名”)	// 方式3
    
  2. 获取 Class 对象构造方法

    getConstructor();
    
  3. 获取 Class 对象字段

    getField(“字段名称”);			// 只能获得公共的属性
    getDeclareField(“字段名称”);	// 既获得公共的属性,也可获得私有的属性
    field.setAccessiable(ture);	  // 对私有字段的访问取消权限检查(即是暴力访问):
    
  4. 获取 Class 对象方法

    getMethods();		// 获取的都是公共的方法
    getDeclareMethod();	// 可以获得本类中的私有方法
    

11. 正则表达式

正则表达式:用于操作字符串数据,通过一些特定的符号来体现的。虽然简化了,但是阅读性差

1. 常见的符号

  1. 字符

    [abc] 			# 包含 a、b 或 c
    [^abc] 			# 包含任何字符,除了 a、b 或 c
    [a-zA-Z] 		# 包含 a 到 z 或 A 到 Z
    [a-d[m-p]] 		# 包含 a 到 d 或 m 到 p
    [a-z&&[def]] 	# 包含 d、e 或 f
    [a-z&&[^bc]] 	# 包含 a 到 z,除了 b 和 c
    [a-z&&[^m-p]] 	# 包含 a 到 z,除了 m 到 p
    
  2. 预定义字符

    . 	# 任何字符
    \d 	# 数字:[0-9]
    \D 	# 非数字: [^0-9]
    \s 	# 空白字符:[ \t\n\x0B\f\r]
    \S 	# 非空白字符:[^\s]
    \w 	# 单词字符:[a-zA-Z_0-9]
    \W 	# 非单词字符:[^\w
    
  3. 边界

    ^ 	# 行的开头
    $ 	# 行的结尾
    
  4. 量词

    X? 		# X 最多一次
    X* 		# X 任意次
    X+ 		# X 至少一次
    X{n} 	# X,恰好 n 次
    X{n,} 	# X,至少 n 次
    X{n,m} 	# X,至少 n 次,但是不超过 m 次
    
  5. 运算符

    (X) 	# X,作为捕获组
    

2. 常见操作

正则类正则规则进行对象的封装

  1. 常用两个类

    1. Pattern 类:java.util.regex.Pattern
    2. Matcher 类:java.util.regex.Matcher
  2. 正则表达式对字符串操作原理

    1. 匹配:其实使用的就是 String 类中的 matches 方法
    2. 切割:其实使用的就是 String 类中的 split 方法
    3. 替换:其实使用的就是 String 类中的 replaceAll()方法
  3. 正则表达式对字符串操作

    Pattern p = Pattern.compile("regex");	// 将正则表达式封装成对象
    Matcher m = p.matcher("str"); 			// 获取要对字符串操作的匹配器对象 Matcher
    boolean b = m.matches();				// 通过 Matcher 匹配器对象的方法对字符串进行操作
    

    例如:

    String str = "da jia hao,ming tian bu fang jia!";
    String regex = "\\b[a-z]{3}\\b";				// 正则表达式
    Pattern p = Pattern.compile(regex);				// 1.将正则封装成对象
    Matcher m = p.matcher(str);						// 2.通过正则对象获取匹配器对象
    //使用 Matcher 对象的方法对字符串进行操作。
    //既然要获取三个字母组成的单词,使用 Matcher 对象的查找方法:find();
    System.out.println(str);
    while(m.find()){
        System.out.println(m.group());				//获取匹配的子序列
        System.out.println(m.start()+":"+m.end());
    }
    


//Student[@id] // 获得所有带 id 属性的 Student 元素
//Student[@id=‘110’] // 获得所有带 id 属性值为 110 的 Student 元素
//Student[@age>=18] // 获得所有带 age 属性值大于等于 18 的 Student 元素
//Student[@sex=‘女’ and @age>20]
//Student[@sex=‘女’ or @age>20]


2. 方法

~~~java
Node selectSingleNode(String xpath); // 返回是第一个满足 xpath 条件的 Node 对象
List<Node> selectNodes(String xpath);// 返回所有满足 xpath 条件的 Node 对象的 List 集合

6. DOM 操作(增、删、改、查)

DOM 操作方法:

DocumentHelper.createDocument(); 					// 创建一个 Document
DocumentHelper.createElement("name"); 				// 创建一个根目录
DocumentHelper.createAttribute(元素, "属性", "属性值");// 创建属性
add(属性/元素); 				// 添加到 Document
addAttribute("属性", "属性值"); // 添加属性
属性.setValue("属性值"); 	   // 修改属性
remove(子元素); 				// 删除子元素

10. 反射机制

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

  1. 获取 Class 对象字节码文件对象

    获取 Class 对象后,再用 newInStance() 创建对象

    getClass();					// 方式1
    静态的属性.class/对象.class	// 方式2
    Class.forName(“带包名的类名”)	// 方式3
    
  2. 获取 Class 对象构造方法

    getConstructor();
    
  3. 获取 Class 对象字段

    getField(“字段名称”);			// 只能获得公共的属性
    getDeclareField(“字段名称”);	// 既获得公共的属性,也可获得私有的属性
    field.setAccessiable(ture);	  // 对私有字段的访问取消权限检查(即是暴力访问):
    
  4. 获取 Class 对象方法

    getMethods();		// 获取的都是公共的方法
    getDeclareMethod();	// 可以获得本类中的私有方法
    

11. 正则表达式

正则表达式:用于操作字符串数据,通过一些特定的符号来体现的。虽然简化了,但是阅读性差

1. 常见的符号

  1. 字符

    [abc] 			# 包含 a、b 或 c
    [^abc] 			# 包含任何字符,除了 a、b 或 c
    [a-zA-Z] 		# 包含 a 到 z 或 A 到 Z
    [a-d[m-p]] 		# 包含 a 到 d 或 m 到 p
    [a-z&&[def]] 	# 包含 d、e 或 f
    [a-z&&[^bc]] 	# 包含 a 到 z,除了 b 和 c
    [a-z&&[^m-p]] 	# 包含 a 到 z,除了 m 到 p
    
  2. 预定义字符

    . 	# 任何字符
    \d 	# 数字:[0-9]
    \D 	# 非数字: [^0-9]
    \s 	# 空白字符:[ \t\n\x0B\f\r]
    \S 	# 非空白字符:[^\s]
    \w 	# 单词字符:[a-zA-Z_0-9]
    \W 	# 非单词字符:[^\w
    
  3. 边界

    ^ 	# 行的开头
    $ 	# 行的结尾
    
  4. 量词

    X? 		# X 最多一次
    X* 		# X 任意次
    X+ 		# X 至少一次
    X{n} 	# X,恰好 n 次
    X{n,} 	# X,至少 n 次
    X{n,m} 	# X,至少 n 次,但是不超过 m 次
    
  5. 运算符

    (X) 	# X,作为捕获组
    

2. 常见操作

正则类正则规则进行对象的封装

  1. 常用两个类

    1. Pattern 类:java.util.regex.Pattern
    2. Matcher 类:java.util.regex.Matcher
  2. 正则表达式对字符串操作原理

    1. 匹配:其实使用的就是 String 类中的 matches 方法
    2. 切割:其实使用的就是 String 类中的 split 方法
    3. 替换:其实使用的就是 String 类中的 replaceAll()方法
  3. 正则表达式对字符串操作

    Pattern p = Pattern.compile("regex");	// 将正则表达式封装成对象
    Matcher m = p.matcher("str"); 			// 获取要对字符串操作的匹配器对象 Matcher
    boolean b = m.matches();				// 通过 Matcher 匹配器对象的方法对字符串进行操作
    

    例如:

    String str = "da jia hao,ming tian bu fang jia!";
    String regex = "\\b[a-z]{3}\\b";				// 正则表达式
    Pattern p = Pattern.compile(regex);				// 1.将正则封装成对象
    Matcher m = p.matcher(str);						// 2.通过正则对象获取匹配器对象
    //使用 Matcher 对象的方法对字符串进行操作。
    //既然要获取三个字母组成的单词,使用 Matcher 对象的查找方法:find();
    System.out.println(str);
    while(m.find()){
        System.out.println(m.group());				//获取匹配的子序列
        System.out.println(m.start()+":"+m.end());
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值