java详细版

第一部分 java编程基础

第一章 java语言概述

1.jdk的安装配置

此电脑–>属性 -->高级系统设置 -->环境变量

  • JAVA_HOME:
        C:\Program Files\Java\jdk1.8.0_171
    path: 
    	%JAVA_HOME%\bin   %JAVA_HOME%\jre\bin  
    classpath:
    	.; %JAVA_HOME%\lib; %JAVA_HOME%\lib\tools.jar
    MAVEN_HOME:
       E:\devEn\apache-maven-3.6.1
    

类名首字母大写,包名项目名全小写

2.常见的dos命令

dir:列出当前目录下的文件以及文件夹

md:创建目录

rd:删除目录

cd:进入指定目录

cd…:回退到上一级

cd\:回退到根目录

del:删除文件

exit:退出dos命令行

第二章 基本语法

1.关键字和保留字

1.1关键字

定义:被java语言f赋予了特殊含义,用作专门用途的字符串

特点:关键字中所有的字母都是小写

用于定义数据类型的关键字
classinterfaceenumbyteshort
intlongfloatdoublechar
booleanvoid
用于定义流程控制的关键字
ifelseswitchcasedefault
whiledoforbreakcontinue
return
用于定义访问权限修饰符的关键字
privateprotectedpublic
用于定义类函数、变量的关键字
abstractfinalstaticsynchronized
用于定义简历实例引用实例的关键字
newthissuperinstanceof
用于处理异常的关键字
trycatchfinallythrowthrows
用于包的关键字
packageimport
其他修饰符的关键
nativestrictfptransientvolatileassert
用于定义数据类型值的字面值
truefalsenull
1.2保留字

定义:现有的java版本尚未使用,但是以后的版本可能会作为关键字使用,自己命名标识符的时候要避免使用关键字和保留字。
goto、const

2.标识符

标识符:凡是自己可以起名字的地方都可以叫标识符

比如:类名、变量名、方法名、接口名、包名…

2.1标识符的命名规则:
  1. 由英文字母大小写,数字0-9、_或$组成,其中数字不可以开头

    不可以使用关键字和保留字,但是可以包含

  2. java中严格区分大小写,长度无限制,不可包含空格

  3. java中的名称的命名规范

  • 包名:多单词组成是所有字母都要小写 xxyyyzzz

  • 类名、接口类、多单词组成 首字母要大写 XxxYyyZzz

  • 变量名、方法名:多单词使用组成,第一单词首字母小写,第二个单词开始每个首字母大写 xxYyyZzz

  • 常量名:所有字母都大写。多单词是每个单词用下划线连接XXX_YY_ZZ

3.变量

3.1变量的使用:
  1. java定义的变量格式 数据类型 变量名 = 变量值;

  2. 说明:

  • 变量法必须先声明后使用,
  • 变量都定义在其作用于内,在作用域内是有效的
  • 同一个作用域内不可以声明相同的两个变量
3.2变量的分类
  1. 按照数据类型分类
数据类型
基本数据类型
引用数据类型
数值型
字符型 char
布尔型 blooean
整数类型 byte,short,int,long
浮点型 float double
类 class
接口 interface
数组
字符串属于类
  1. 按照声明的位置分类

    成员变量 vs 局部变量

  2. long 类型不加L,会默认为int型
    float必须加f
    整形常量默认类型为int 浮点型默认为double

3.3 基本数据类型的运算

  1. 自动类型提升

​ 当容量小的数据类型的变量与容量大的数据类型做运算时,结果自动提升为容量大的 数据类型

byte、char、short -->int -->long -->float -->double

​ 特别的 :当byte、char、short三种类型的变量做运算时,结果为int型

  1. 强制类型转换
  • 自动类型提升运算的逆运算

  • 需要使用强转符 ()

  • 强制类型转换可能损失精度

  • byte、short和char的取值范围交叉,所以需要双向强制转换

    double num1 = 2.05;
    int num = (int) num1;
     //num = 2
    Math.random() * (n - m) + m;
    //生成[m,n)区间的随机数
    

    最高位为符号位,0为正数,1为负数,负数先除符号位按位取反得到反码,反码加一得到补码,计算机底层存储数据都是用补码

4.运算符

4.1算术运算符
运算符运算
+正号
-负号
+
-
*
/
%取余
++a先加后用
a++先用后加
–a先减后用
a–先用后减

提示:自加自减运算符谁在前边先用谁

4.2赋值运算符
  • 符号:=

    当“=”两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理,支持连续赋值

  • 扩展赋值运算符

    += -= /= *= %=

4.3比较运算符
比较运算符运算范例结果
==相等于4==3false
!=不等于4!=3true
<小于3<4true
>大于4>3ture
<=小于等于4<=3false
>=大于等于4>=3true
instanceof检查是否是类的对象“Hello” instanceof Stringtrue
4.4 逻辑运算符
逻辑运算符运算运算符运算运算符运算
&逻辑与|逻辑或逻辑非
&&短路与||短路或^逻辑异或
aba&ba&&ba|ba||b!aa^b
truetruetruetruetruetruefalsefalse
truefalsefalsefalsetruetruefalsetrue
falsetruefalsefalsetruetruetruetrue
falsefalsefalsefalsefalsefalsetruefalse

提示:

&和&&的区别

相同点1:&和&&的运算结果相同

相同点2:当符号左边是true时,二者都会执行符号右边的操作

不同点:当符号左边是false时,&继续执行右边的操作,&&不会执行右边的操作

|和||的区别

相同点1:|和||的运算结果相同

相同点2:当符号左边是false时,二者都会执行符号右边的操作

不同点:当符号左边是true时,|继续执行右边的操作,||不会执行右边的操作

4.5位运算符
运算符运算范例
<<左移3<<2=12
>>右移3>>1=1
>>>无符号右移3>>>1=1
&6&3=2
|6|3=7
^异或6^3=5
~取反~6=-7

位运算是对整数的二进制进行运算

4.5.1 拓展:权限模块

假设有两张表 用户表 以及 权限表

来源于 Unix 文件控制权限思想

userIDnamepasswordpromission
1张三111115
2李四222212
3王五3331
modIdinfourlvalue
1查看1
2添加2
3修改4
4删除8
//假如要判断李四是否有修改权限
if(lisi.promission & 4 != 0)
    假设李四的权限是:   XXXX XXXX
    与4进行与运算 &:   0000 0100   //如果李四有修改权限的 4的二进制位就会变成1, 
             结果 :   0000 0100   //4
//原理:与运算按二进制位运算  如果两个值都是1则为1
//要给王五添加修改权限
 if(wangwu.promission | 4 != 0)
     假设王五的权限是:  XXXX XXXX
     与4进行或运算 |:  0000 0100   //如果王五没有修改权限  4的二进制位就会变成1
     结果			:   XXXX X1XX
//原理:或运算安二进制位  有1则为1
//删除莫个人的修改权限
if(zhangsan.promission ^ -5 != 0)     
     假设王五的权限是: xxxx xxxx
     与4进行异或预算:  0000 0100  //如果张三有修改权限的话 4的二进制位就会变成0
     结果		     : XXXX X0XX
//原理:异或运算 两个都一样的情况下才会变成0      
      
        
    
    
//有一个int型的数字  XXXXXXXX  YYYYYYY  ZZZZZZZZ WWWWWWWW
//如果想要后八位    WWWWWWWW
                  需要将int& 1111 1111
               xxxx xxxx yyyy yyyy zzzz zzzz wwww wwww
          &    0000 0000 0000 0000 0000 0000 1111 1111
//进行与运算    0000 0000 0000 0000 0000 0000 wwww wwww
//想要得到zzzz zzzz的值  先将int型的数字右移八位在与 1111 1111进行与运算
           xxxx xxx yyyy yyyy zzzz zzzz wwww wwww >> 8
//溢出之后w位的就不要了  变成 xxxx xxxx yyyy yyyy zzzz zzzz
              xxxx xxxx yyyy yyyy zzzz zzzz
        &     0000 0000 0000 0000 1111 1111
//进行与运算    0000 0000 0000 0000 zzzz zzzz    

拓展:

50 << 1 = 50 * 2;

4.5.2 判断一个数是不是2的次幂
import java.util.Scanner;
public class Test1{
	public static void main(String[] args){
		System.out.println("input");
		Scanner sc = new Scanner(System.in);
		int n = Integer.parseInt(sc);

		check(n);
	}
 	public static void check(int num){
		if( (num & num -1) == 0 ){
            //因为num 和 num-1 的二进制数是完全相反的,所以进行与运算的时候,如果是0,则代表是二的次幂
			//如果不是0的话,代表这个数与减一的数有一样的,所以就不是而的次幂
			System.out.println("shi");
		}else{
			System.out.println("fou");
		}
		// 8  0000 1000
        // 7  0000 0111
        
        //4   0000 0100
        //3   0000 0011
        
        //16  0001 0000
        //15  0000 1111
	}
}
4.6三元运算符
  1. 结构: (条件表达式) ? 表达式1 : 表达式2
  2. 注意
  • 条件表达式的结果为boolean类型
  • 根据表达式真或假,决定执行表达式1还是表达式2,如果为真执行1,否则执行2
  • 三元运算符可以嵌套使用
int m = 10;
int n = 12;
String maxStr = (m > n) ? "m大" : "n 大";
//如果m = n
// String maxStr = (m > n) ? "m大" : ((m == n) ? "m = n" : "n大");

3. 凡是可以用三元运算符的低档都可以用 if -else,反之不行,如果两者都可以使用的话,优先使用 三元运算符,比较简洁高效

5. == 和 equals()的区别

5.1 ==的使用

==:运算符

  1. 可以使用在基本数据类型变量和引用数据类型变量中
  2. 如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等(不一定类型要相同);如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
5.2 equals()方法的使用
  1. equals()是一个方法,并非运算符
  2. 只能适用于引用数据类型
  3. Object类中equals()的定义
public boolean equals(Object obj){
    return (this == obj);
}

Object类中定义的equals()和== 的作用是相同的,比较两个对象的地址值是否相同,,即两个引用是否指向同一个对象实体 ;

  1. 像String、Date、File、包装类等都重写了Object类中的equals()方法,重写以后,比较的不是两个引用地址是否相等。而是比较两个引用的”实体内容“是否相同
  2. 我们自定义的类使用equals()方法的话,也是比较两个对象的实体内容,那么我们就需要对Object类中的equals()进行重写
public class EqualsTest{
    public static void main(String[] args){
        int i = 1;
        int j = 1;
        double d = 1.0;
        System.out.println(i == j);//true
         System.out.println(i == d);//true
        char c = 1;
        System.out.println(i == c); //true
        char c1 = 'A';
        char c2 = 65;
        System.out.println( c1 == c2);//true
        Customer user1 = new Customer("Tom",21); 
         Customer user2 = new Customer("Tom",21); 
        System.out.println( user1 == user2);//false
        
        String str1 = new String("Test");
         String str2 = new String("Test");
        System.out.println( str1 == str2);//false
        
        System.out.println( user1.equals(user2)); //false
         System.out.println( str1.equals(str2)); //true
    }
}

//自动创建一个Customer类
//自动生成get 和set方法
//生成一个空参和一个带参构造器

//*************************************
    @Override
    public boolean equals(Object obj){
        if( this == obj){
            return true;
        }
        if( obj instanceof Customer){
            Customer cust = (Customer)obj;
            return this.age == cust.age && this.name.equals(cust.name);
        }
        return false;
    }
5.3 自动生成重写equals方法

Source --> Generate hashCode() and equals()

6.程序流程控制

6.1 顺序结构

程序从上到下逐行的执行,中间没有任何的判断和跳转

6.2 分支结构
  1. if - else
 if(条件表达式){ 执行表达式 }
 
 if(条件表达式){ 执行表达式1 } else { 条件表达式2 }
 
 if(条件表达式1 ){ 
 	执行表达式 1
 } else if(条件表达式 2{ 
 	执行表达式 2
 } else{ 
 	执行表达式 3
 } 
  1. switch -case
// switch 支持的数据类型有 byte short char int string enum
 switch(表达式) {
	   case 条件1: 执行语句 1//break;
   	   case 条件2: 执行语句 2//break;
       default:执行最终条件;
       //break;

  }

示例:输入月份和日期,输出是2019年的第几天

import java.util.Scanner;
class SwitchCaseTest{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入2019年的月份");
        int month = scan.nextInt();
         System.out.println("请输入2019年的日期");
        int day = scan.nextInt();
        int sumDay = 0;
        switch(month){
            case 12:  sumDay += 30;
           //......
            case 4: sumDay += 31;
            case 3: sumDay += 28;
            case 2: sumDay += 31;
            case 1: sumDay += day;
        }
        System.out.println("2019年"+month+"月"+day+"日是当年的第"+sumDay+"天");
    }
}
6.3 循环结构
  • for循环

  • do{ … } while

  • while(){ … }

do -while 总是比while 多循环 一次

eg:输出100以内所有的质数

class PrimeNumber{
    public static void main(String[] args){
	        for(int i = 2; i < 100 ; i++){
	        	boolean isFlag = true;
	            for(int j = 2; j <= Math.sqrt(i);j++){
	                if(i % j ==0){
	                  isFlag = false;
	                  break; //如果被除尽,跳出
	                }
	            }
	            if( isFlag ){
	            	  System.out.print(i+"\t");
	            }
	        }
	    }
}

第三章 数组

3.1 数组的概述

  1. 数组的概念
  • 数组名
  • 下标或索引
  • 元素
  • 数组的长度
  1. 数组的定义:

    数组(Array) 是多个同类型的数据按照一定顺序排列的并使用 一个名字命名并通过编号的方式对这些数据进行统一的管理.

  2. 数组的特点

  • 数组是有序排列的
  • 数组属于引用数据类型的变量,数组的元素,既可以是基本数据类型,又可以是引用数据类型
  • 创建数组对象会在内存中开辟一整块连续的空间
  • 数组的长度一单确定,就不能更改
  1. 数组的分类
  • 按照维数,一维数组,二维数组…
  • 按照数组元素的类型,基本数据类型的数组、引用数据类型的数组

3.2 一维数组的使用

  1. 一维数组的声明和初始化
int[] ids;//声明
ids = new int[]{10001,1002,1003,1004};
//静态初始化
String[] names = new String[2];//动态初始化
//错误的写法
//int[] arr1 = new int[];
//int[5] arr2 = new int[5];
//int[] arr3 = new int[3]{1,2,3};
//总结:
  1. 遍历数组
int[] ids;//声明
ids = new int[]{10001,1002,1003,1004};
for(int i = 0; i < ids.length;i++){
  ....
}
//foreach用法
for(int arr: ids){
 System.out.println(arr);
}
  1. 二位数组输出杨辉三角
public class YangHuiTest{
    public static void main(String[] args){
        int yangHui[][] = new int[10][];
        for(int i = 0;i<yangHui.length;i++){
            yangHui[i] = new int[i + 1];
            yangHui[i][0] = yangHui[i][i] = 1;
            for(int j = 1; j <yangHui[i].length - 1 ;j++){
                yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j];
            }
        }
        //能不能用foreach遍历?
        for(int i = 0;i < yangHui.length; i++){
	        for(int j = 0;j < yangHui[i].length;j++){
	            System.out.print(yangHui[i][j] + "  ");
	        }
	        System.out.println();
        }
        //foreach用法
        for(int[] out :yangHui ){
			for(int inside:out){
				System.out.print(inside +" ");
			}
			System.out.println();
		}
        
    } 
}
  1. 数组中常见的算法
  • 数组元素的赋值

    杨辉三角、回形数等

  • 求数值型数组中的最大值,最小值,平均值,总和

    public class RandomTest {
       public static void main(String[] args){
    	   int[] arr = new int[10];
    	   for(int i = 0; i < arr.length;i++){
    		   arr[i] = (int)(Math.random() * 100 - 1 + 10);
    		   System.out.print(arr[i] +"\t");
    	   }
    	   System.out.println();
    	   //求数组的最大值
    	   int maxValue = arr[0];
    	   for(int x : arr){
    		   if(maxValue < x){
    			   maxValue =x;
    		   }
    	   }
    	   System.out.println("最大值为:" + maxValue);
    	   //求最小值
    	   int minValue = arr[0];
    	   for(int x : arr){
    		   if(minValue > x){
    			   minValue =x;
    		   }
    	   }
    	   System.out.println("最小值为:" + minValue);
    	   
    	   double sum = 0.0d;
    	   for(int x : arr){
    		 sum += x;
    		}
    	   double ave = sum / arr.length;
    	   System.out.println("总和为:" + sum);
    	   System.out.println("平均值:" + ave);
    	   
       }
    }
    
    
  • 数组的复制、反转(线性查找,二分查找)

String[] arr = new String[]{"AA","BB","CC","DD","EE"};
//数组的复制
String[] arr1 = new String[arr.length];
for(int i = 0;i < arr1.length;i++){
    arr1[i] = arr[i];
    System.out.println(arr[i]);
}
//数组的反转

for(int i = 0;i < arr.length / 2;i++){
    String temp = arr[i];
    arr[i] = arr[arr.length - 1];
    arr[arr.length - 1] = temp;
}

//线性查找
String dest = "BB";
boolean isFlag = true;
for(int i = 0;i < arr.length;i++){
    if(dest.equals(arr[i])){
        System.out.println("指定元素的索引位置为" + i);
        isFlag = false;
        break;
    }
}
if(isFlag){
    System.out.println("没有找到");
}
  • 数组元素的排序算法
  1. 冒泡排序

升级版的双向冒泡(鸡尾酒排序法)点击查看

//冒泡排序
int[] arr = new int[]{43,56,45,78,-12,21,-98,0,12,19}; 
for(int i = 0;i < arr.length - 1;i++){
   for(int j = 0;j < arr.length - i - 1;j++){
       if(arr[j] > arr[j + 1]){
           int temp = arr[j];
           arr[j] = arr[j + 1];
           arr[j + 1] = temp;
       }
   }  
}
  1. 快速排序
public static int[] qsort(int arr[],int start,int end) {        
    int pivot = arr[start];        
    int i = start;        
    int j = end;        
    while (i<j) {            
        while ((i<j)&&(arr[j]>pivot)) {                
            j--;            
        }            
        while ((i<j)&&(arr[i]<pivot)) {                
            i++;            
        }            
        if ((arr[i]==arr[j])&&(i<j)) {                
            i++;            
        } else {                
            int temp = arr[i];                
            arr[i] = arr[j];                
            arr[j] = temp;            
        }        
    }        
    if (i-1>start) arr=qsort(arr,start,i-1);        
    if (j+1<end) arr=qsort(arr,j+1,end);        
    return (arr);    
}    
 
public static void main(String[] args) {        
    int arr[] = new int[]{3,3,3,7,9,122344,4656,34,34,4656,5,6,7,8,9,343,57765,23,12321};        
    int len = arr.length-1;        
    arr=qsort(arr,0,len);        
    for (int i:arr) {            
        System.out.print(i+"\t");        
    }    
}
 
/*//方式二*/
更高效点的代码:(TextendsComparable和SortUtil都是自己封装的类,里面重写和实现了compareTo和swap方法)
public <TextendsComparable<?superT>>
T[] quickSort(T[] targetArr,int start,int end){
	inti=start+1,j=end;
	T key=targetArr[start];
	SortUtil<T> sUtil=new SortUtil<T>();
 
	if(start==end)return(targetArr);

    /*从i++和j--两个方向搜索不满足条件的值并交换
    *
    *条件为:i++方向小于key,j--方向大于key
    */
    while(true){
        while(targetArr[j].compareTo(key)>0)j--;
        while(targetArr[i].compareTo(key)<0&&i<j)i++;
        if(i>=j)break;
        sUtil.swap(targetArr,i,j);
        if(targetArr[i]==key){
            j--;
        }else{
            i++;
        }
    }
 
    /*关键数据放到‘中间’*/
    sUtil.swap(targetArr,start,j);

    if(start<i-1){
        this.quickSort(targetArr,start,i-1);
    }
    if(j+1<end){
        this.quickSort(targetArr,j+1,end);
    }
    returntargetArr;
}
 
 
/*//方式三:减少交换次数,提高效率/*/
private<TextendsComparable<?superT>>
voidquickSort(T[]targetArr,intstart,intend){
	inti=start,j=end;
    Tkey=targetArr[start];
 
while(i<j){
	/*按j--方向遍历目标数组,直到比key小的值为止*/
	while(j>i&&targetArr[j].compareTo(key)>=0){
		j--;
	}
	if(i<j){
		/*targetArr[i]已经保存在key中,可将后面的数填入*/
		targetArr[i]=targetArr[j];
		i++;
	}
	/*按i++方向遍历目标数组,直到比key大的值为止*/
	while(i<j&&targetArr[i].compareTo(key)<=0){
        /*此处一定要小于等于零,假设数组之内有一亿个1,0交替出现的话,而key的值又恰巧是1的话,那么这个小		于等于的作用就会使下面的if语句少执行一亿次。*/
        i++;
	}
	if(i<j){
        /*targetArr[j]已保存在targetArr[i]中,可将前面的值填入*/
        targetArr[j]=targetArr[i];
        j--;
    }
}
/*此时i==j*/
targetArr[i]=key;//应加判断
 
/*递归调用,把key前面的完成排序*/
this.quickSort(targetArr,start,i-1);
 
 
/*递归调用,把key后面的完成排序*/
this.quickSort(targetArr,j+1,end);
//两个递归应加判

3.3 Arrays 工具类的使用

方法作用
boolean equals(int[] a,int[] b)判断两个数组是否相等
String toString(int[] a)输出数组信息
void fill(int[] a,int val)用指定值填充数组
void sort(int[] a)对数组排序
int binarySearch(int[] a,int key)堆排序后的数组进行二分法检索指定的值

数组常见异常

1.数组角标越界:ArrayIndexOutOfBoundsException

2.空指针异常:NullPointerException

第四章 面向对象编程 上

1面向对象与面向过程

  • 二者都是一种思想,面向对象是相对于面向过程而言的。面向过程强调的是功能行为,以函数为最小对象,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象。以类/对象为最小单位,考虑谁来做。

  • 面向对象三大特征

    封装(encapsulation)

    继承(inheritance)

    多态(polymorphism)

2 java基本元素:类和对象

类:属性 方法

3 对象的创建与使用

class Person{
    String name;
    int age;
    boolean isMale;
    public void eat(){
        System.out.println("人可以吃饭");
    }
    public void sleep(){
        System.out.println("人能睡觉");
    }
}
Person p = new Person();
p.name = "Tom";
p.isMale = true;
p.age = 18;
p.eat();p.sleep();

4类的成员之一:属性

属性 vs 局部变量

  1. 相同点
  • 定义变量的格式一样, 数据类型 变量名 = 变量值
  • 先声明,后使用
  • 变量都有相对应的作用域
  1. 不同点
  • 在类中声明的位置不同

    属性:直接定义在类的{}内

    局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量

  • 关于权限修饰符的不同

    属性:可以再声明属性是,指明权限,使用权限修饰符。

    局部变量:不可以使用权限修饰符。

    常见的权限修饰符:private、public、缺省、protected、final

  • 默认初始化值

    属性:类的属性,根据其类型,都有默认的初始化值。

    类型默认值
    整型byte、short、int、long0
    浮点型double、float0.0
    字符型char0
    Booleanfalse
    引用数据类型类、数组、接口null

    局部变量:无默认值。

    特别的:形参在调用的时候,赋值即可

  • 在内存中加载的位置不一样

    属性:加载到堆空间

    局部变量:加载到栈空间

5类的成员之二:方法

  1. 举例
  • 按照是否有形参分类

    无返回值有返回值
    无形参void method(){}返回值类型 method(){}
    有形参void method(形参列表){}返回值类型 method(形参列表){}
  1. 方法的声明:

    权限修饰符 返回值类型 方法名(形参列表){

    ​ 方法体

    }

  2. 方法名:属于标识符,要见名知意

  3. return关键字的使用

  • 使用在方法中

  • 作用:

    结束方法

    针对于有返回值的方法,使用return返回想要的数据。

    例子1:

public class CircleTest{
    public static void main(String[] args){
        Circle c1 = new Circle();
        c1.radius = 2;
        System.out.println("圆的面积为:" + c1.findArea());
        System.out.println("矩形的面积为:" + method(12,8));
        }
    public static void method(int m,int n){
        return m * n;
    }
}
class Circle{
    double radius;
    public double findArea(){
        return Math.PI * radius * radius;
    }
}

例子2:

public class StudentTest{
   public static void main(String[] args){
       Student[] students = new Student[20];
       for(int i = 0;i < students.length;i++){
           students[i] = new Student();
            students[i].number = (i + 1);
            students[i].state = (int)(Math.random() * 6 + 1);
           students[i].score = (int)(Math.random() * (100 - 0 + 1) + 1);
       }
   } 
}
class Student{
    int number; //学号
    int state;	//年级
    int score;  //得分
}

6 扩展一

6.1 匿名对象的使用
public class InstanceTest{
    public static void main(String[] args){
        Phone p = new Phone();
        p.sendEmail();
        p.playGame();
        
        //匿名
        new Phone().sendEmail();
         new Phone().playGame();
        
    }
}
class Phone{
    double price;
    public void playGame(){
        System.out.println("玩游戏");
    }
    public void sendEmail(){
        System.out.println("发邮件");
    }
}
6.2 方法的重载
  1. 定义

    在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可

public class OverLoadTest{
    public static void main(String[] args){
   	        
       OverLoadTest olt = new OverLoadTest();
       System.out.println(olt.getSum(1.2,2.0));
        //如不想声明对象,直接输出getSum();需将方法声明为静态(static)方法
        //静态方法可以再没有对象实例的情况下直接调用
    }
    //如下的方法构成了重构
    public int getSum(int i,int j){
        return i + j;
    }
    public double getSum(double i,double j){
        return i + j;
    }
}
6.3 可变个数形参的方法
  1. 可变个数形参的格式 数组类型 … 变量名
public void show(String ... strs){
    //TODO
}
//调用可变个数形参时,传入参数随意个
  1. 可变个数形参与数组类型不能同时存在
public void show(String ... strs){}
public void show(String[] strs){}
//JDk5.0以前用数组,所以不能同时存在
  1. 可变个数形参在方法的形参中,必须声明在最后,且只能声明一个可变形参
public void show(int i,String ... strs){}
  1. 引用类型的值转换 用类
class Data{
	int m;
	int n;
}
main(){
	Data data = new Data();
	data.m = 10;
	data.n = 20;
	swap(data.m,data.n);
}
swap(){
	int temp = data.m;
	data.m = data.n;
	data.n = temp;
}

7 扩展二

7.1 OOP特征一:封装性
  • 属性私有化,方法公有化
class Animal{
    //私有化属性,公有化方法
    private String name;
    private int age;
    private int legs;
    
    //自动化生成Getter和Setter方法
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
    //当一个属性没有配套的getter、setter方法时直接用属性名当做方法名
    public int legs(){//实际上的方法全名是getLegs()
        return legs;
    }
    //JavaBean
}
  • 权限修饰符
修饰符类内部同一个包不同包的子类同一个工程
private
缺省
protected
public
7.2 类的成员之三:构造器
  1. 作用

​ 创建对象

  1. 说明
  • 如果没有显式的定义类的构造器的话,则默认提供一个空参构造器 (权限跟随类的权限)
  • 定义构造器的格式: 权限修饰符 类名(形参列表){}
  1. JavaBean
  • 类是公共的
  • 有一个公共的无参构造器
  • 有属性和对应的get、set方法

8 关键字的使用

8.1 this关键字的使用
  1. this可以用来修饰:属性,方法,构造器
  2. this修饰属性和方法:
  • this理解为:当前对象
  1. this调用构造器
  • 可以在构造器内用this()调用其他构造器,具体调用哪个看形参
  • 构造器中不能通过this(形参列表)调用自己本身
  • 规定:this(形参列表)必须放在本构造器的首行,且只能调用一个
8.2 package关键字的使用
  1. 为了更好的实现项目中类的管理
  2. 使用package声明类或接口所属的包,声明在首行
  3. 需要见名知意,一般为域名的反写
  4. 每个 “ . ” 代表一层文件目录

第五章 面向对象编程 中

1.重写Override/Overwrite

1.1 方法的重写
  1. 发生在两个有继承关系的类中,且发生在子类里边(子类认为父类的方法不适用在子类里边,对父类的方法进行重写)

  2. 子类重写的方法的权限修饰符要大于等于父类中方法的权限修饰符

  3. 重写方法的返回类型在JDk5.0以前需要一模一样在JDK5.0以后支持斜变类型

    即支持返回其父类的子类类型

  4. 子类的异常处理部分要小于等于父类的异常类型

  5. @Override注解,表示下边被注解的方法必须要重写父类的某个方法

1.2 方法的重载

方法重载的条件

  1. 必须发生在同一个类体

  2. 方法名需要完全相同

  3. 方法的参数需要不同

    • 参数类型不同

    • 参数个数不同

    • 参数顺序不同

方法重载对返回值类型修饰符没有要求

方法重载的作用是为了满足用户的不同需求

区分方法的重写和重载
  • 二者的概念:

  • 重写和重载的具体规则

  • 重载:不表现为多态性

    重写表现为多态性

2. super的使用

  • super理解为父类的,可用来调用属性,方法,构造器

  • super的使用

    1. 在子类的方法或构造器中,通过使用super.属性/super.方法的方式,显式的调用父类中声明的属性或方法,通常情况下省略super.
    2. 特殊的:当子类的父类定义同名的属性时,要想在子类中调用父类的属性,必须显式的使用super调用
  • super调用构造器

    1. 在子类的构造器中显示的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
      1. super(形参列表)的使用,必须声明在子类构造器的首行
      2. 在类的构造器中,针对于this(形参列表)或super(形参列表)只能二选一,不能同时出现
    2. 在构造器的首行,没有限时的声明this(形参列表)或super(形参列表),则默认的是父类中空参的构造器
    3. 在类的多个构造器中,至少有一个类的构造器中会用了super(形参列表),调用父类的构造器

3.子类对象实例化过程

  1. 从结果来看

    子类继承父类以后,就获取了父类中声明的属性或方法

    创建子类的对象,在堆空间,就会加载所有父类中声明的属性

  2. 从过程来看

    通过子类的构造器创建子类对象时,一定会间接或直接的调用其父类的构造器,进而调用父类的父类的构造器,,直接调用了java.lang.Object类的空参构造器为止,因为家在所有父类的结构,所以才可以看到内存中有父类的结构,子类对象才可以考虑进行调用

4. OOP特征三:多态性

  1. 多态性可以理解为一个事物的多种形态
  2. 对象的多态性,父类的引用指向子类的的对象
Person p1 = new Women();
Person p2 = new Men();
  1. 多态的使用:虚拟方法调用

    有了对象的多态性以后,在编译时,只能调用父类中声明的方法,但是在运行期间,实际执行的是子类重写父类的方法,

    编译看左边,执行看右边

  2. 多态是运行时行为

5. Object类的使用

  • .Object是所有类的父类
5.1 clone()的使用
  1. 将Object类的克隆方法权限改大变成public的,然后用super.clone()调用父类的克隆方法,强转成要返回的类型

  2. 将要实现克隆方法的类实现允许克隆的接口**(implements Cloneable)**

  3. 在main()方法中调用,并抛出异常

    public class Exec1 {
        public static void main(String[] args)throws Exception{
    		OS android = new OS("安卓");
    		OS flyme = android.clone();
    		flyme.name = "魅族";
    		System.out.println(android == flyme);
        }
    }
    class OS implements Cloneable{
    	String name;
    	public OS(String name){
    		this.name = name;
    	}
    
    	@Override
    	public OS clone() throws CloneNotSupportedException{
    		return (OS)(super.clone());
    	}
    }
    
5.2 finalize()

对象的遗言方法,当一个对象要被gc()回收掉的时候回主动执行的一个方法

面试题

final 和 **finalize()**的区别

雷锋和雷锋塔的区别,final是一个修饰符,表示最终的可以用来修饰类,方法,变量

finali是Object类型里边的一个方法,当对象要被回收的时候会主动执行的一个方法

5.3 toString()
  • 重写toString()方法。打印自己想要的信息
public class TestToString2{
    public static void main(String[] args){
		Person p1 = new Person("黄晓明",35,'男');
		Person p2 = new Person("baby",28,'女');
		System.out.println(p1);
		System.out.println(p2);
    }
}
class Person{
	String name;
	int age;
	char sex;

	public Person(String name,int age,char sex){
		this.name = name;
		this.age = age;
		this.sex = sex;
	}

	@Override
	public String toString(){
		return name + (sex == '男' ? "\t先生" : "\t女士") + age + "岁";
	}
}
5.4 equals()

重写equals()方法

public class ExecEquals1{
    public static void main(String[] args){
		Food f1 = new Food("猪耳朵拌黄瓜",23,"凉菜");
		Food f2 = new Food("猪耳朵拌黄瓜",25,"凉菜");

		System.out.println(f1.equals(f2));
    }
}
class Food{
	String name;
	double price;
	String type;

	public Food(String name,double price,String type){
		this.name = name;
		this.price = price;
		this.type = type;
	}
	@Override
	public boolean equals(Object obj){
		if(this == obj) return true;
        if(obj == null) return false;
		if(obj instanceof Food){
			Food food = (Food) obj;
			return this.name.equals(food.name) && this.type.equals(food.type);
		}
		return false;
	}

}
5.5.hashCode()
  • 得到一个对象的散列将一大组数据分散成不同的小组特征码
  • 当equals()方法被重写以后,通常也需要重写hashCode()方法,以便维护hashCode()方法的通用规范,该方法规定相等的对象应该有相等的哈希值

6.包装类的使用

服务于集合

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter(不存在parse方法)
  1. java提供了八种基本数据类型对应的包装类,使得基本数据类型的变量具有了类的特征。
6.1 基本数据类型,包装类,String的相互转换
public class WrapperTest{
    public static void main(String[] args){
        
    }
    @Test
    public void test1(){
        
    }
    //自动装箱   基本数据类型 --> 包装类
    int num1 = 10 ;
    Integer in1 = num1;
    
    //自动拆箱    包装类 --> 基本数据类型
    int num2 = in1; 
    //基本数据类型,包装类   --->String类型
    int  num = 10;
     //方式一 连接运算
    String str1 = num + "";
    //方式二 :调用String的valueOf(Xxx xxx)
    float f1 = 1.3;
   String str2 = String.valueOf(f1);
    
    //String  --> 基本数据类型,包装类
    String str3 = "123";
    int num4 = Integer.paserInt(str3);
} 

例题

Object obj1 = true ? new Integer(1) : new Double(2.0);
System.out.println(ojb1);
//结果为1.0
//三元运算符运算式要保证两个结果类型一致。所以会对Integer类型的进行自动类型提升  变为Double型


//***************************
Object obj2;
if(true)
    obj2 = new Inetger(1);
else
    obj2 = new Double(2.0);
System.out.println(ojb2);

Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println( i == j);//false
//Integer内部定义了IntegerCache的结构,在其中定义了Integer[]
//保存了-128~127范围的整数,如果用自动装箱的方式,给Integer固执的范围在这个范围内,可以直接使用数组的元素,不用new了,提高了效率
Integer m = 1;
Integer n = 1;
System.out.println( m == n);//false

Integer i = 128;
Integer j = 128;
System.out.println( x == y);//false

第六 面向对象编程 下

1.关键字 static

  • static 可以用来修饰属性,方法,代码块,内部类
1.1 static 修饰属性
  • static 修饰的变量也称为静态变量
  1. 按照是否使用static修饰可以分为

    静态变量(类变量) vs 非静态变量(实例变量)

    非静态变量:创建了类的多个对象,每个对象都独立的拥有一套类的非静态属性,改变其中一个对象的非静态属性时,不会导致其他对象同样的属性修改。

    静态变量:创建了类的多个对象,多个对象共享一个静态变量,当通过一个对象修改静态变量的值的时候,其他对象调用此变量是,是修改过的。

  2. static修饰的属性

  • 静态变量随着类的加载而加载,可以直接通过类.静态变量的方法调用
  • 静态变量的加载早于对象的加载
  • 由于类只会加载一次,所以静态变量在内存中也只会有一份,存在于方法区的静态域中
  1. 举例

    System.out
    Math.PI;  
    
类变量实例变量
可以调用不可以调用
对象可以调用可以调用
public class StaticTest1{
    public static void main(String[] args){
		Chinese c1 = new Chinese();
        c1.name = "张三";
        c1.age = 20;
        
        Chinese c2 = new Chinese();
        c2.name = "李四";
        c2.age = 45;
        c2.nation = "CHN";
        System.out.println(c1.nation);
    }
}
class Chinese{
    String name;
    int age;
    static String nation ;
}
1.2 static修饰方法-
  • static修饰的方法叫静态方法
  1. 随着类的加载而加载,可以通过类.静态方法的方式进行调用
静态方法非静态方法
yesno
对象yesyes
  1. 静态方法中只能调用静态的方法或属性

    非静态方法中,既可以调用非静态的方法。也可以调用静态的方法。

public class StaticTest2{
    publiv static void main(String[] args){

    }
}

**static注意点 **

  1. 在静态方法内,不能使用this关键字和super关键字
1.3 如何确定属性或方法要不要声明成静态的
  1. 属性

    属性可以被多个对象所共享的,不会随着对象的变化而变化的

    类中的常量通常定义为static的

  2. 方法

    操作静态属性的方法,通常设置为静态的

    工具类中的方法,通常定义为static的,如Math,Arrarys。

2.main方法的语法

  1. main()方法是程序的入口
  2. main()方法也是一个普通的静态方法
  3. main()方法可以作为跟控制台交互的方式

3.类的成员之四:代码块

用来初始化类,对象

如果要用修饰符修饰的话只能用static

4.关键字 final

final修饰的类不可以有子类,但是可以有父类,final修饰的方法不可以被覆盖,但是可以被继承,当final修饰变量的时候,一旦赋值之后就不可以更改

final修饰属性时,保护的是属性的值不受改变,当final修饰的是引用数据类型时,保护的是引用的地址不发生改变

5. 抽象类与抽象方法

  1. 抽象类

    抽象类表示这个类不形象不具体,特点是不允许创建对象

    抽象类也是类,也有构造方法,但是不可以用来创建对象,是给子类构造器首行的super()调用的

  2. 抽象方法表示这个类型一定会这个方法,但是现在给不出来具体的实现,待留给子类去实现当一个类中出现了抽象方法以后,这个类一定变成抽象方法,

    public abstract Animal{
        //抽象方法的特点是不能有方法体,直接()结束
        public abstract void eat();
    }
    

    抽象方法里边既可以出现抽象方法又可以出现普通方法

6. 接口(interface)

  • 接口相当于工业生产中的规范

  • 接口不允许创建对象但是可以用匿名实现类

    class、interface、enum、@interface在编译之后都

    可以生成class文件

    //如何定义一个接口
    interface XXX{
        //属性
        //接口默认加上三个修饰符
        //public static final
        int x = 34;
        
        //方法:返回类型 +方法签名
        //接口默认加上两个修饰符
        //public abstract
        void show();
    }
    

    两两之间的关系

    类和类之间:extends

    类和接口之间:implements

    接口和就扣之间:extends

    java中的类只允许单根继承,但是接口允许多重继承,一个类在继承另外一个类的同时还可以实现多个接口

6.1接口和抽象类之间的区别
  1. 是java中的两个类型,抽象类属于类是class,接口是interface

  2. 里边边定义的属性不一样

    抽象类里边定义的属性就是普通属性,最多加上一个default,

    接口里边定义的属性都是静态的**[public static final]**

  3. 里边定义的方法不一样

    抽象类里边既可以定义抽象方法,又可以定义普通方法

    接口里边只能定义抽象方法从jdk8.0开始可以出现普通方法了

6.2 接口的应用
  1. 代理模式

  1. 工厂模式

    • 简单工厂模式
    
    

7.类的成员之五:内部类

  • java中允许把一个类声明在另外一个类中

    class Person{
        static class Phone{
            
        }
        
        class PC{}
    }
    // Person.Phnone p = new Person.Phone();
    //Person p = new Person();
    //Person.PC p1 = p.new PC();
    

    在局部内部类的方法中(show),如果调用局部内部类所声明的方法(method)的局部变量(num),要求变量必须声明成final的

    public class Test{
        pubilc void method(){
            //JDK 7及以前需要显示的声明为final的 8及以后则不需要
            final int num = 1;
            class AA{
                public void show(){
                    System.out.println(num);
                }
            }
        }
    }
    
    7.1 成员内部类

    如果成员内部类不是静态的,那么内部类中也不能出现静态的属性或方法

    7.4 匿名内部类

    匿名内部类创建对象:

    new 父类/接口(参数){

    ​ 抽象方法的具体实现

    }

8. 单例模式

  • 在某一个类中只能存在一个对象实例

实现单例模式

  1. 私有化构造器避免在其他类调用构造器

  2. 内部创建静态的类的对象

  3. 提供静态的公共的方法,返回类的对象

8.1 懒汉模式
//懒汉式
public class Singleton1{
    public static void main(String[] args){
       Order order1 = Order.getInstance();
       Order order2 = Order.getInstance();
       Order1 == Order2;//true
    }
}
class Order{
    //1.私有化构造器
    private Order();
    //2.声明当前类的对象,没有初始化
    //4.此对象也必须声明为静态的(static)
    private static Order instance = null;
    //3.声明公共的静态的返回当前对象的方法
    publicstatic synchronized Order getInstance(){
       if(instance == null){
           instance = new Order();
       } 
        return instance;
    }
}
8.2 饿汉模式
//饿汉式
public class Singleton{
    public static void main(String[] args){
        Bank bank1 = Bank.getInstance();
        Bank bank2 = Bank.getInstance();
        bank1 == bank2;//true
    }
}
class Bank{
    //私有化构造器
    private Bank();
    //内部创建类的将静态对象
	private static Bank instance = new Bank();
    //提供公共的静态方法,返回类的对象
    public static Bank getInstance(){
        return instance;
    }
}
好处坏处
懒汉式延迟对象创建目前的写法是线程不安全的,用synchronized修饰即可
饿汉式饿汉式是线程安全的对象加载时间过长

第七章 异常处理

java中的异常分为两部分

  • **Error:**JVM都无法解决的问题,比如jvm内部错误,资源耗尽等,例如Stack OverflowError
  • Exception:其他变成错误或者偶然的外部因素导致的可以使用专门的代码处理。例如:空指针等

1.常见的异常类型

java.lang.Throwable
java.lang.Error
java.lang.Exception
非运行时异常
IOException
FileNotFoundException
ClassNotFoundException
运行时异常RuntimeException
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
NumberFormatException
InputMismatchException
ArithmeticException
1.1 常见运行时异常解决方案
常见运行时异常大概原因关注点
ArithmeticExecption(算术异常)一个整数除以0/ x
NegativeArraySizeExecption

2.异常处理机制

异常的处理:抓抛模型

过程一:“抛”,程序在执行的过程中,一旦出现异常,就会在异常代码出生成一个对应的异常类对象,并将此对象抛出,一单抛出一场对象以后,后边的代码就不再执行

过程二:“抓”,可以理解为异常的处理方式。①try - catch - finally ② throws + 异常类型

catch一般会有getMessage()he printStackTrace()一般用这个

2.1try - catch - finally
try{
    //可能出现异常的代码
}catch(异常类型1 变量名){
    //处理异常的方式1
}catch(异常类型2 变量名){
    //处理异常的方式3
}finally{
    //可选的,写不写都可以,写了的话就是一定会执行的代码
}
//JDK 7之后可以用 | 连接
try{
    //可能出现的代码
}catch(异常类型1 | 异常类型2 e){
    
}
  • try保卫可能会出现异常的代码

  • catch捕获异常

  • finally一定会被执行的代码

    范围小的异常要放在上边,

①使用try-catch-finally处理编译时异常,使得程序在编译时不在报异常,但是运行是可能报错,相当于讲一个编译时异常延迟到运行时出现了

②由于运行时异常比较常见,所以通常不针对运行时异常编写try- catch - finally,但是针对编译时异常一定要处理

③**finally里永远不要出现return语句,否则try-catch中间的return就不会执行**

2.2throws + 异常处理
  • 一般写在方法声明处,说明可能会抛出的异常类型,当抛出异常的时候,后边的代码就不会执行了

如何选择使用哪一种异常处理机制

​ ①如果父类中被重写的方法没有throws方式处理异常,那么子类重写的方法也不能使用throws,所以子类重写的方法只能用try - catch

​ ②执行的方法a中,先后有调用另外的方法,而且是递进关机,建议使用throws方法处理,执行的方法a建议使用try-catch

2.3 throw new Exception
2.4异常对象的产生

​ ①系统自动生成的异常对象

​ ②手动生成一个异常对象并抛出**(throw)**

3.如何自定义异常

public class MyException extends RuntimeException{
    static final long serialVersionUID = -12178941256195L;
    public MyException(){
        
    }
    public MyException(String msg){
        super(msg);
    }
}

4. 关闭资源

try{
    n.close();
}catch(Exception e){
    e.printStackTrace();
}finally{
    try{
        m.close();
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        try{
            o.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

第二部分 java高级编程

第八章 枚举类&注解

1. 枚举类的使用

  • 当一个类的对象只有有限个,是确定的,我们称此类为枚举类

  • 当需要定义一组常量时,建议使用枚举类

  • 如果枚举类只有一个对象,则可以作为单例模式的实现方式

1.1 如何定义枚举类
  1. JDK5.0以前,自定义枚举类

    class Season{
        //声明Season对象的属性:private final修饰
        private final String name;
        private final String desc;
        //2.私有化构造方法,并给对象赋值
        private Season(String name,String desc){
            this.name = name;
            this.desc = desc;
        }
        //3.提供当前枚举类的多个对象,声明为public static final
        public static final Season SPRING = new Season("春天","春暖花开");
        public static final Season SUMMER = new Season("夏天","夏日炎炎");
        public static final Season AUTUMN = new Season("秋天","秋高气爽");
        public static final Season WINTER = new Season("冬天","冰天雪地");
        
        public String getName(){
            return name;
        }
        public String getDesc(){
            return desc;
        }
    }
    class Test{
        @Test
        public void test(){
            Season spring = Season.SPRING;
            System.out.println(spring);
        }
    }
    
  2. JDK5.0.可以使用enum关键字定义枚举类

    • 默认父类是 java.lang.Enum ,不用重写toString() 方法
    public class Test{
        @Test
        public void test(){
            System.out.println(Season1.SUMMER);
        }
    }
    enum Season1{
        //1.提供枚举类的多个对象,对象之间用 , 隔开 最后一个用 ;
        SPRING("春天","春暖花开"),
        SUMMER("夏天","夏日炎炎"),
        AUTUMN("秋天","秋高气爽"),
        WINTER("冬天","冰天雪地");
        
        private final String name;
        private final String desc;
       
        public String getName(){
            return name;
        }
        public String getDesc(){
            return desc;
        }
    }
    
1.2 Enum的常用方法
  1. values()
Season1[] v = Season1.values();
for(Season1 s: v){
    System.out.println(s);
}
  1. valueOf()

    //valueOf(String objName) 返回美剧类中对象名是objName的对象
    //如果没有对应的objName的枚举类对象,则抛出异常
    System.out.println(Season1.valueOf("WINTER"));
    
1.3 使用 enum 关键字的枚举类实现接口
  1. 跟普通类一样的实现方法

    interface info{
        void show();
    }
    enum t implements info{
        w,A;
        @Override
        public void show(){}
    }
    
  2. 每个对象都重写方法

    interface info{
        void show();
    }
    enum t implements info{
        W{
            @Override
             public void show(){}
        },
        A{
             @Override
             public void show(){}
        };
    }
    
    

2. 注解的使用

  • 从JDK5.0开始,java增加了队元数据的支持,也就是注解(Annotation)
  • 注解就是代码中的**特殊标记**,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理,通过使用注解,可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。
  • 注解可以像修饰符一样被使用,可以用来**修饰包,类,构造方法,方法,成员变量,参数,局部参数的声明**,这些信息被保存在注解的“name = value” 对中。
  • 可以说 框架 = 注解 + 反射 + 设计模式。
  1. 生成文档相关的注解

    注解作用
    @author标明开发该类的作者,多个作者用,分开
    @version标明该类模块的版本
    @see参考
    @since从哪个版本开始
    @param对方法中某个参数的说明,没有参数不能写
    @return对返回值的说明,void 不能写
    @exception对可能抛出的异常说明,没有显式的用throws抛出异常的不能写

    其中@return @param @exception 只能用于方法

    @param 格式要求 @param 形参名 形参类型 形参说明

    @return 格式要求 @return 返回值类型 返回值说明

    @execption 格式要求 @execption 异常类型 异常说明

    @param @execption 可以并列多个

  2. 在编译时进行格式检查(JDK内置的三个基本注解)

    注解含义
    @Override限定重写父类方法,只能用于方法
    @Deprecated表示修饰的元素已经过时了
    @SuppressWarnings抑制编译器警告
  3. 如何自定义注解

    //声明为@interface
    public @interface AnnotationTest{
        String[] value();
    }
    //自定义注解通常会指明两个元注解,一折Retention指明生命周期,一个Target指明能够声明哪些结构
    
  4. JDK中的四种元注解

    Retention、Target、Documentd、Inherited

    是对现有注解进行解释说明的注解

    1. @Retention:指明注解的生命周期,SOURCE \ CLASS (默认行为) \ RUNTIME ,只有声明为RUNTIME生命周期的注解,才能通过反射获取
    2. @Target: 指明注解可以声明可以哪些结构
    3. @Documented:表示所修饰的注解在javadoc解析时保留下来
    4. @Inherited 被修饰的注解有继承性

第九章 java集合

JCF集合框架
Collection单值类型集合:接口
Map键值对类型集合:接口
List有序不唯一
ArrayList
Vector
Stack
LinkedList
Set无序唯一
SortedSet有序唯一
HashSet
LinkedHashSet
HashMap
LinkedHashMap
TreeMap
Hashtable
Properties

1. Iterator迭代器

  • 如何创建迭代器

    Iterator<类型> i = list.iterator();
    
  • ​ 使用迭代器遍历集合

    for(Iterator<类型> i = list.iterator();i.hasNext();){
        
    }
    //for循环不通用
    //foreach遍历集合的同时删除集合里边的元素,会报错CME 并发修改异常
    //所以需要用迭代器自己的remove()方法
    
1.1迭代器方法
  1. 如何创建一个迭代器

    Iterator<泛型> car = list.iterator();
     //<>里边的泛型一定要和集合的泛型保持一致
    
  2. hasNext()

    判断集合是不是还有下一个元素、

  3. next()

    取出下一个元素

  4. remove()

    删除集合里边的元素

2. List

2.1 ArrayList
  1. 如何创建集合对象

    //jdk5.0以前 默认装Object[]
    ArrayList list = new Array();
    //jdk5.0之后 可以加泛型
    ArrayList<String> list = new ArrayList<String>();
    //7.0 后边的泛型可以省略
    Array<Integer> list = new ArrayList<>();
    
  2. 如何往集合添加元素

    //一次添加一个元素
    list.add(44);
    list.add(45);
    //一次添加多个元素    集合名字  元素
    Collections.addAll(list,22,22,33,4,5,5);
    
  3. 如何得到集合的大小

    list.size();
    
  4. 如何得到某一个元素

    list.get(下标);
    
  5. 判断集合是否包含一个元素

    list.contains(元素);
    
  6. 如何遍历集合

    for(int i = 0;i < list.size();i++){
        System.out.println(list.get(i));
    }
    for(Integer x: list){
        System.out.println(x);
    }
    
  7. 使用迭代器遍历集合

    //hadNext()判断迭代器后边是否还有元素
    for(Iterator<泛型> iter = list.iterator;car.hasNext();){
        //next()去除先一个元素
        car.next();
    }
    
2.1.1 ArrayList常用方法
  • remove()

    remove方法有两个,一个传下标,另外一个传元素,判断两个元素是不是一样的看元素底层的equals()方法。==具体看传入的参数的equals();==传入的参数会主动调用自己的equals()方法和集合里的每一个对象作比较

    //一次只可以删除一个对象
    
  • contains()

    比较集合是否包含指定元素也是用的equals

  • clear()

    清空集合用clear();

面试题

CollectionCollections 的区别

Collection 是所有单值类型集合的父接口 :interface

Collections 是集合的工具类 :class

2.1.2 ArrayList拓展🐴
  1. 集合扩容

    当创建一个数组对象的时候需要确定数组的大小

    ArrayList底层是基于Object[]数组实现的,集合里边存几个元素时根据ArrayList的构造方法决定的

    ①ArrayList list = new ArrayList(100);传入多少就开辟多少

    ②ArrayList list = new ArrayList();不传参数,底层默认开辟10块空间

    集合会自己扩容,所以不用担心不够用

    JDK6.0及以前 x * 3 / 2 + 1

    JDK7.0及以后 x + (x >> 1 )

    //把集合扩容到指定的空间
    list.ensureCapacity(300);
    //减少集合空间
    list.trimToSize();
    
  2. 手写集合

    public class Exec1{
        public static void main(String[] args){
    
    		AList list = new AList();
    		list.add("123");
    		list.add("456");
    		list.add(666);
    		System.out.println(list.size());
    		System.out.println(list.contains(new Integer(666)));
    		list.remove(0);
    		list.add("999");
    		System.out.println(list);
    		list.remove("999");
    		System.out.println(list);
    
    		//前后都要加泛型
    		AList<Integer> list1= new AList<>();
    		CollectionsTest.addAll(list1,123,123,234,543,7657);
    		System.out.println(list);
    
    		AList<Teacher> t = new AList<>();
    		t.add("赵信");
    		System.out.println(t);
    		t.remove("赵信");
    		System.out.println(t.size());
    
        }
    }
    class CollectionsTest{
    	public static void addAll(AList<Integer> list,Integer ... obj){
    		for(Integer data: obj){
    			list.add(data);
    		}
    	}
    }
    class AList<E>{
    	//数组用来存放元素
    	private Object[] data;
    	//元素个数
    	private int size;
    	//有参构造方法,用户传进来集合大小
    	public AList(int x){
    		if(x < 0){
    			System.out.println("ArrayIndexOutOfBoundsException:" + x);
    		}
    		data = new Object[x];
    	}
    	//无参构造方法,默认为10
    	public AList(){
    		this(10);
    	}
    	//得到集合大小
    	public int size(){
    		return size;
    	}
    	//得到元素
    	public Object get(int x){
    		return data[x];
    	}
    	//添加元素
    	public void add(Object obj){
    		//判断如果集合满了,就进行扩容
    		if(data.length == size){
    			Object[] temp = new Object[size + (size >> 1)];
    			System.arraycopy(data,0,temp,0,size);
    			data = temp;
    		}
    		data[size] = obj;
    		size++;
    	}
    	//删除元素,按照下标进行删除
    	public void remove(int x){
    		/*
    		  删除指定下标的元素,相当于把指定下标以后的元素复制到指定下标处,
    		  复制完成之后元素个数减一
    		*/
    		System.arraycopy(data,x + 1,data,x,size - x - 1);
    		size--;
    	}
    	//删除元素,按照指定元素删除
    	public void remove(Object obj){
    		for(int i = 0; i < size;i++){
    			//挨个遍历数组,找到一样的就删除吊
    			if(obj.equals(data[i])){
    				remove(i);
    			}
    		}
    	}
    	//判断集合里边是否包含指定元素
    	public boolean contains(Object obj){
    		if(obj == null) return false;
    		for(int i = 0;i < size;i++){
    			if(obj.equals(data[i])){
    				return true;
    			}
    		}
    		return false;
    	}
    	@Override
    	public String toString(){
    		String str = "[";
    		for(int i = 0; i < size -1;i++){
    			str = str + data[i] + ",";
    		}
    		return str + data[size - 1] + "]";
    	}
    }
    class Teacher{
    	String name
    	public Teacher(String name){
    		this.name = name;
    	}
    	@Override
    	public String toString(){
    		return name;
    	}
    }
    
  3. addAll()

    ArrayList<Integer> list = new ArrayList<>();
    ArrayList<Integer> test = new ArrayList<>();
    Collectoins.addAll(list,1,2,3,4,5,6);
    //直接把集合塞到另外一个集合里边
    test.addAll(list);
    
2.2 Vector
  • 语法和ArrayList一模一样

面试题

VectorArrayList的区别

  1. 同步线程不同

    Vector同一时间允许一个线程进行访问,效率较低但是不会出现并发错误

    ArrayList同一时间允许多个线程进行访问,效率较高,但是可能会出现并发错误

    从JDk5.0之后

  2. 扩容机制不同

    ArrayList:分版本

    ​ JDK6.0及以前 x * 3 / 2 + 1

    ​ JDK7.0及以后 x + (x >> 1)

    Vetor:分构造方法

    ​ Vetor(10) -> 2倍扩容 10 - 20 -30

    ​ Vetor(10,3) -> 定长扩容 10 -13 -16

  3. 出现版本不同可答可不答

    Vetor : 1.0

    ArrayList: 1.2

2.3 LinkedList

面试题

LinkedListArrayList之间的区别

  1. LinkedList和ArrayList的底层数据结构不同,导致优劣不同

    ArrayListLinkedList
    底层数据结构数组链表
    优点随机查找、遍历较快添加删除元素效率较高
    缺点添加删除元素效率低随机查找、遍历效率慢
2.4 Stack
  • 采用栈结构,先进后出
  1. 添加元素

    Stack<Integer> list = new Stack<>();
    list.push(666);
    
  2. 拉出元素

    System.out.println(list.pop());
    

3. Set

Set集合修改元素的步骤

public class RemoveTest{
    public static void main(String[] args){
    	Set<Integer> set = new HashSet<>();
        Collections.addAll(set,11,22,33,44,55);
        
        //1.创意一个临时的 同类型集合
        Set<Integer> temp = new HashSet<>();
        for(Iterator<Integer> car = set.iterator();car.hasNext();){
            if(car.next() == 55){
                //2.删除原有的元素
                car.remove();
                //3。吧修改后的元素放到临时集合中
                temp.add(45);
            }
        }
        //4.把修改之后的元素放回老集合中
        set.addAll(temp);
    }
}
3.1 HashSet
  • 没有顺序
  • 相同的元素只能添加一次
  • 所有涉及到下标的方法都没有了
  • 基于哈希表实现

HashSet的用法与ArrayList的用法基本一样但是所有跟下标有关的方法都不可以使用了

包含get()、remove()、for()遍历集合

  1. 如何创建对象

    HashSet<Integer> set = HashSet<>();
    
  2. 遍历集合

    for(Integer x : set){
        System.out.println(x);
    }
    for(Iterator<Iterger> car = set.iterator();car.hasNext();){
        System.out.println(set.next());
    }
    

HashSet的唯一性

唯一:内存里的同一个对象,不会添加多次

“唯一”:将两个不同的对象视为相等的对象取决于***hashCode()*** 和***equals()***

HashSet会根据传入对象的hashCode()得到的哈希码来决定具体分到哪一个组,如果两个对量的哈希码值是一样的话,才会调用equals来判断两个对象是不是一个对象,如果equals返回两个对象是一个对象的话,就不可以重复添加

当两个对象的哈希码值一样的时候,有3 种情况

①内存里的同一个对象、不可以重复添加

②视为相等对象、会调用equals()方法来是不是同一个对象

③重码

适用的方法有 add()、remove()、contains();

拓展

  1. 当有重复元素的时候,会抛弃新元素。老元素留着
  2. 当一个元素已经添加进HashSet集合的时候,不要随意修改参与生成hashCode()值的属性,如果一定要修改,要先删除后修改再添加
3.1.1 HashSet常用方法
  1. addAll

    import java.util.*;
    public class Exec1{
        public static void main(String[] args){
    		ArrayList<String> list = new ArrayList<>();
    		Collections.addAll(list,"张三","李四","李四","张三","王五");
    		HashSet<String> e = new HashSet<>();
            //将另外一个集合里边所有的东西撞到HashSet里边
    		e.addAll(list);
    		System.out.println(e);
    		System.out.println(e.size());
        }
    }
    
3.2 LinkedHashSet
  • 用法和HashSet一样
  • 作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据
  • 优点:对于频繁的便利操作,优先考虑LinkedHashSet

3.3 TreeSet

  • 可以按照添加对象的指定属性进行排序

  • 向 TreeSet 中添加数据,要求是**相同类的对象**

  • 与 TreeMap 一样采用红黑树的存储结构

  • 有序,查询速度比List块

  • compareTo方法一样的返回0

    在使用TreeSet的时候应该尽量保证compareTo方法有可能返回0

    否则Tree Set集合的 add 方法用于不会认定有重复元素,无法保证唯一
    同时TreeSet的 remove 方法也不乏删除元素 ,
    add()、remove()、contains()、都是以来与compareTo()返回值是0的
    如果需求就是compareTo方法就是无法返回0的,必须借助迭代器的删除方法

    class User implements Comparable{
        private String name;
        private int age;
        //get  set 方法
        public User(String name,int age){
            this.name = name;
            this.age = age;
        }
        //重写hashCode 和 equals 方法
        @Override
        public int compareTo(Object o){
            if(o instanceof User){
                User u = (User)o;
                return this.getName().compareTo(u.getName());
            }else{
                throw new RuntimeException("输入的类型有误");
            }
        }
    }
    class TreeSetTest{
        @Test
        public void test(){
            TreeSet<User> t = new TreeSet<>();
            t.add("Tom",22);
            t.add("Lee",20);
            t.add("Wangwu",18);
        }
    }
    
3.3.1 TreeSet的遍历方式
//for Iterator
//lambda表达式
set.forEach(System.out::println);
set.forEach((x) -> System.out.println(x);)

3.3.2得到TreeSet的第一个和最后一个元素
//得到第一个元素
set.first();
//做后一个元素
set.last();
//pollFirst()选出并移除第一个元素

4. Map

Map
HashMap
LinkedHashMap
TreeMap
Hashtable
Properties
  • key 是不可以重复的,相当于用 Set 存储的,唯一无序
  • value 是可以重复的,无序
4.1 HashMap
  • HashMap 作为 Map 的 主要实现类,线程不安全,效率较高,可以存储 null 的 key 和 value
  • Hashtable 作为原始的实现类,线程安全,效率低,不能存储 null 的 key 和 value
public class MapTest{
    public static void main(String[] args){
    	Map map = new HashMap();
    }
}

默认容量是 16
默认加载因子是 0.75 也就是扩容的临界值是12

4.1.1常用方法
  1. put() 添加

    //添加元素
    map.put("AA",123);
    
  2. put() 修改

    //修改元素
    map.put("AA",1234);
    
  3. putAll()

    //将一个map添加到另外一个map中
    Map m = new HashMap();
    m.putAll(map);
    
  4. remove() 移除

    //remove(Object key)移除参数放key
    System.out.println(map.remove("CC"));
    
  5. clear() 清空数据

    map.clear();
    
  6. get() 获取指定 key 的value

    System.out.println(map.get("AA"));
    //当没有填入的参数的时候返回null
    
  7. containsKey / containsValue

    //判断当前map是否包含指定的key
    System.out.println(map.containsKey("AA"));//true
    //判断当前map是否包含指定的key
    System.out.println(map.containsValue(123));//true
    
  8. isEmpty() 判断当前map是否为空

    System.out.println(map.isEmpty());
    

    对元数据的操作

  9. keySet() 遍历map里所有的key

    Set set = map.keySet();
    for(Iterator i = set.iterator();i.hasNext()){
        System.out.println(i.next());
    }
    
  10. values() 遍历map里所有的value

    Collection c = map.values();
    for(Object o : c){
        System.out.println(c);
    }
    
  11. entrySet() 遍历所有的 key - value

    Set e = map.entrySet();
    for(Iterator i = e.iterator();i.hasNext();){
        //entrySet 集合中的元素都是 entry
        Map.Entry e = (Map.Entry)(i.next()); 
        System.out.println(e.getKey() + "--" + e.getValue());
    }
    
    1. getKey()

      //获取记录的键
      System.out.println(e.getKey());
      
    2. getValue()

      //获取对应的值
      System.out.println(e.getValue());
      
    3. setValue()

      //修改值
      e.setValue();
      

      无论我们使用keySet()、values()、entrySet()所得到的的都不是一个新的集合

    12.lambda表达式遍历Map集合

    map.forEach((k,v) -> System.out.println(k));
    map.forEach((k,v) -> System.out.println(v));
    map.forEach((k,v) -> System.out.println(k + ":" + v));
    

面试题:HashMap的底层实现原理

JDK 7以前

HashMap map = new HashMap();
  1. 在实例化以后,底层创建了一个长度为16的一维数组 Entry[] table
map.put(key1,value1);
  1. 调用 key1 所在类的 hashCode() 计算哈希值,在一定处理后(& 15),用来确定在Entry 数组中的存放位置。
  2. 如果此位置上没有数据,此时 key1 - value1 添加成功(添加的是value),
  3. 如果该位置有位置,意味着此位置有一个或多个数据,比较 key1 和已经存在的 key 的哈希值
    如果 key1 的哈希值与已经存在的数据的哈希值都不相同,就添加成功
    如果和以及存在的某一个相同,就判断equals,返回 false 就添加成功 返回 true 使用value 1 替换相同 key 的value值

JDK8底层实现有所不同

  1. new HashMap() : 底层没有创建一个长度为16的数组
  2. JDK 8 底层的数组是 Node[] 而非 Entry[]
  3. 首次调用 put() 方法,底层创建长度为 16 的数组
  4. JDK 7 底层结构只有数组 + 链表 JDK 8底层数据结构:数组 + 链表 + 红黑树
    当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前的数组长度 > 64 时,此时此索引位置上的所有数据改为使用红黑树存储
4.2 LinkedHashMap
  • 保证在遍历map元素时,可以按照添加的顺序实现遍历。
  • 在原有的 HashMap 的底层结构基础上,添加了一对指针,指向前一个和后一个元素。
  • 对于频繁的遍历操作,执行效率高于 HashMap
@Test
public void test(){
	Map map = new LinkedHashMap();
    map.put(1,"AA");
    map.put(1,"BB");
    map.put(1,"CC");
    System.out.println(map);
    
    Map map1 = new HashMap();
    map1.putAll(map);
    System.out.println(map1);
}
4.3 TreeMap
  • 保证按照添加的 key - value 对进行排序,实现排序遍历
  • 按照 key 进行排序,要求key必须是同一个类创建的对象
class Test{
    @Test
    public void test(){
        TreeMap map = new TreeMap();

        map.put(new User("Tom",23),98);
        map.put(new User("Jerry",21),91);
        map.put(new User("Jack",20),78);
        map.put(new User("Rose",22),58);
        //compareTo自然排序
        Set e = map.entrySet();
        for(Iterator car = e.iterator();car.hasNext();){
            Map.Entry et = (Map.Entry)(car.next());
            System.out.println(et.getKey() + "--" + et.getValue());
        }

    }
    @Test
    public void t2(){
        TreeMap map = new TreeMap(new Comparator(){
            @Override
            public int compare(Object o1,Object o2){
                if(o1 instanceof User && o2 instanceof User){
                 	User u1 = (User)o1;
                    User u2 = (User)o2;
                    return Integer.compareTo(u1.getAge(),u2.getAge());
                }
            }
        });
    }
}
class User implements Comparable{
    private String name;
    private int age;
    
    public User(String name,int age){
        this.name = new name;
        this.age = new age;
    }
    //重写 toString(),equals(),compareTo()方法
}
4.4 Hashtable
4.4.1 Properties
  • 常用来处理配置文件, key 和 value 都是 String 类型
public class PropretiesTest{
    Propreties pros = new Propreties();
    FileInputStream fis = new FileInputStream("jdbc.properties");
    pros.load(fis);
    String name = pros.getProperty("name");
    String pwd = pros.getProperty("password");
}
//配置文件
/*
name=zhaojinhui
password=123456
*/

配置文件出现中文乱码解决方法

Setting – > File Encodings --> √ Transparent native-to-ascii conversion

5. Collections 工具类

  • 是一个操作**Collection 和 Map **的工具类
5.1 常用方法
方法作用
reverse(List)反转List中元素的顺序
shuffle(List)对List进行随机排序
sort(List)根据元素自然顺序队List里元素升序排列
sort(List,Comparator)根据指定的比较规则排序
swap(List,int i,int j)将List集合 i 处和 j 处元素交换
方法作用
max(Collection)根据自然顺序,返回最大值
max(Collection,Comparator)根据定制顺序返回最大值
min(Collection)根据自然顺序返回最小值
min(Collection,Comparator)根据定制顺序返回最小值
frequency(Collection,Object)返回指定元素出现的次数
copy(List i,List j)将 j 中的内容复制到 i 中
replaceAll(List i,Object o,Object n)用 n 替换 i 集合里边的 o
public class Test{
    public static void main(String[] args){
    	ArrayList<Integer> arr = new ArrayList<>();
        Collections.addAll(arr,1,2,3,4,5);
        List dest = Arrays.asList(new Object[arr.size()]);
        System.out.println(dest.size());
    }
}
  • Collections 类提供了多个synchronizedXxx() 方法,该方法可以将制定集合包装成线程同步的集合,从而解决多线程并发访问时产生的线程安全问题除了Vector (Stack) Hashtable,其他的集合都是线程不安全的
  • 在多线性高并发的情况下应该是用ConcurrentHashMap
List oldList = new ArrayList();
List newList = Collections.synchronizedList(oldLiset);

6. Java比较器

6.1 Comparable接口

自然排序 Comparable接口的使用

  • 像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个队想的方法

  • 重写compareTo(obj) 的规则:
    如果当前对象 this 大于形参对象 obj ,则返回正整数
    小于,返回负整数
    等于,返回0

  • 对于自定义类,如果需要排序,可以让自定义类实现Comparable接口,重写compareTo(obj)在方法中指明如何排序

    public class CompareTest{
        @Test
        public void test(){
            Goods[] arr = new Goods[5];
            arr[0] = new Goods("lenovo",34);
            arr[1] = new Goods("huawei",65);
            arr[2] = new Goods("dell",14);
            arr[3] = new Goods("xiaomi",43);
            arr[4] = new Goods("ausu",43);
            Arrays.sort(arr);
        }
        
    }
    class Goods implements Comparable{
        String name;
        double price;
        public Goods(String name,double price){
            this.name = name;
            this.price = price;
        }
        //指明按照什么方式排序
        @Override
        public int compareTo(Object o){
            if(o instanceof Goods){
                Goods g = (Goods)o;
                if(this.price > g.price){
                    return 1;
                }else if(this.price < g.price){
                    return -1;
                }else{
                    return this.name.copareTo(g.name);
                }
            }
            throw new RunTimeException("传入的数据类型不一致!");
        }
    }
    
6.2 Comparator接口

定制排序

  1. **当元素的类型没有实现Comparable接口而有不方便修改代码,或者实现了Comparable接口排序规则不适合当前的操作,name可以考虑使用Camparator排序,**强行队多个对象进行整体排序的比较
  2. 可以将Comparator传递到 sort 方法,从而允许在排序上实现精确控制(如Collections.sort 或Arrays.sort)
@Test
public void test(){
    Arrays.sort(arr,new Comparator<Goods>(){
       //按照产品名称从低到高
        @Override
        public int compare(Goods i,Goods j){
         if(i instanceof Goods && j instanceof Goods){
         	Goods g1 = (Goods)i;
            Goods g2 = (Goods)j;
             
            if(g1.getName().equals(g2.getName())){
            	return Double.compare(g1.getPrice(),g2.getPrice());    
            }else{
                return g1.getName().compareTo(g2.getName());
            }
         }   
        }
    });
}

测试类

@Data
public class Test implements Comparator<Test>{
    private Integer orders;
}

Lambda式简化版1

import iava.util.*;
public class TestComparator{
    public static void main(String[] args){
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list,22,33,77,14,44,55,66);
        Collections.sort(list,(x,y) -> x - y);
    }
}

Lambda简化版2

import iava.util.*;
public class TestComparator{
    public static void main(String[] args){
        List<Test> list = new ArrayList<>();
        COllections.addAll(list, ...);
        Comparator<Test> comp = Comparator.comparing(Test::getOrders);
        Collections.sort(list,comp);
}

Lambda不当人简化版简化版3

list.sort(Comparator.comparing(Test::getOrders));
6.3 两种接口的对比
  • Comparable 接口的方式一旦确定,保证Comparable接口实现类的对象在任何位置都可以比较大小
  • Comparator 属于临时性的比较

第十章 泛型

1. 为什么要有泛型

  • 指定集合里边只能装某种数据类型
  • 编译时就会进行检查,防止类型错误
  • 异常类不能是泛型

2.泛型使用范例

public class DAO<T>{
    //表的共用操作
    //增删改查
}

public class StudentDAO extends DAO<Student>{
    //只能操作某一个表的DAO
}
  1. 泛型方法的使用
//当返回值类型不确定的时候可以使用泛型方法
public <E> e test(){}

3.泛型在继承方面的体现

3.1 泛型在继承方面的体现
  • 类 A 是类 B 的父类,E 和 E 二者不具备子父类关系,是两个并列的结构
  • 但是 A 是 B 的父类
List<Object> list = null;
List<String> li = null;
//不可以这么使用,此时的list和li不具有子父类关系
//list = li;
3.2 通配符的使用
  • 通配符 ?
@Test
public void test(){
    List<Object> list1 = null;
    List<String> list2 = null;
    List<?> list = null;
    
    list = list1;
    list = list2;
}
//List<?> 只可以添加null 其他都不可以添加
  • 有限制条件的通配符

? extends A:

​ G<? extends A> 可以作为 G 和 G 谷类的,其中B 是 A 的子类

? super A:

G<? extends A> 可以作为 G 和 G 谷类的,其中B 是 A 的父类

public class Person{}
class Student extends Person{}
class Test{
    @Test
    public void test(){
        List<? extends Person> list = null;
        List<? super Person> list2 = null;
        
        List<Student> s = null;
        List<Person> p = null;
        List<Object> o = null;
        
        list = s;
        list = p;
        //不可以
        //list = o;
        //不可以
        //list2 = s;
        list2 = p;
        list2 = o; 
    }
}

第十一章 IO流

1.File类的使用

  • java.io.File 类:**文件和文件目录路径**的抽象表示形式,和平台无关,声明在java.io下
  • File 能新建、删除、重命名文件和目录,但是 File 不能访问文件内容本身,如需要访问文件内容,需要借助输入/输出流
  • 想要在Java程序中表示一个真实存在的文件或目录,name必须有一个File对象,但是在Java程序中的一个File对象,可能没有一个真实存在的文件或目录
  • File 对象可以作为参数传递给li流的构造器
1.1 File 类的常用方法
  1. 创建 File 类的对象

    • 相对路径 :相较于某个路径下,指明的路径
    • 绝对路径:包含盘符在内的文件或文件目录的路径
    • 在Windows下路径分隔符用 / 在UNIX下用 \
    • 为了避免在不同操作系统出现混淆,java 提供了一个常量,根据操作系统,动态提供分隔符 public static final String separator
    //构造器一 File(String filePath)
    //相对路径
    File file1 = new File("Hello.txt");
    //绝对路径
    File file2 = new File("D:\\Study\\java\\java培训详细版.md");
    //使用常量的方式
    //"D:" + File.separator + "Study" +File.separator + "java" File.separator + "java培训详细版.md"
    
    //构造器二 File(String parentPath,String childPath)
    File file3 = new File("D:\\Study\\java","Test");
    //构造器三 File(File parentFile,String childPath)
    File file4 = new File(file3,"tset.txt");
    
  2. 获取绝对路径 getAbsolutePath()[一等优先级]

    //public String getAbsolutePath()
    System.out.println(file1.getAbsolutePath());
    
  3. 获取相对路径 getPath()[一等优先级]

    //public String getPath()
    System.out.println(file1.getPath());
    
  4. 获取名称 getName()[一等优先级]

    //public String getName()
    System.out.println(file1.getName());
    
  5. 获取上层文件目录路径,没有返回null getParent()[一等优先级]

    //public String getParent()
    System.out.println(file1.getParent());
    
  6. 获取文件字节总数 length()[一等优先级]

    //public long length()
    System.out.println(file1.length());
    
  7. 获取最后一次修改时间 毫秒值 lastModified()[一等优先级]

    //public long lastModified()
    System.out.println(new Date(file1.lastModified());
    

    以下两个方法适用于文件目录

  8. 获取指定目录下所有文件或文件目录的名称数组 list()[特等优先级]

    //public String[] list()
    File file4 = new File("D:\\study");
    String[] list = file.list();
    for(String s : list){
        System.out.println(s);
    }
    
  9. 获取指定目录下的所有文件或目录的File数组listFiles()[特等优先级]

    //public File[] listFiles()
    File[] fs = file4.listFiles();
    for(File f : fs){
        System.out.println(f);
    }
    
  10. 得到当前系统的所有根目录listRoots()[特等优先级]

    //public static listRoots
    File[] fs = File.listRoots();
    
  11. 把文件重命名为指定的文件路径 renameTo()[高危]

    //public boolean renameTo(File dest)
    File f1 = new File("hello.txt");
    File f2 = new File("D:\\Study\\hello.txt");
    boolean re = f1.renameTo(f2);
    System.out.println(re);
    /*
    	要想保证是true,需要 f1 在硬盘中存在的,且 f2 不能再硬盘中存在
    */
    

    2. File类的判断功能

  12. 是否是文件目录 isDirectory()[一等优先级]

    //public boolean isDirectory()
    File f1 = new File("hello.txt");
    System.out.println(f1.isDirectory());//false
    
  13. 是否是文件 isFile()[一等优先级]

    System.out.println(f1.isFile());
    
  14. 是否存在 exists()[一等优先级]

    System.out.println(f1.exists());
    
  15. 是否可读 canRead()

    System.out.println(f1.canRead());
    
  16. 是否可写 canWrite()

    System.out.println(f1.canWrite());
    
  17. 是否隐藏 isHidden()

    System.out.println(f1.isHidden);
    

    3. File类的创建删除功能

    方法作用
    createNewFile()创建文件,如果存在返回false不进行创建
    mkdir()创建文件目录,存在则不创建
    mkdirs()[高危]创建文件目录,如果上一级目录不存在,一并创建
    delete()[高危]删除文件或文件夹,不经过回收站
    File file = new File("hi.txt");
    if(!file.exists()){
        file.createNewFile();
    }else{
        file.delete();
    }
    
    File file1 = new File("D:\\io\\io1 ");
    file1.mkdir();
    file1.mkdirs();
    

    例题

    判断指定目录下是否有.jpg文件,如果有输出文件名

    import java.io.*;
    public class JpgTest{
        public static void main(String[] args){
        	File srcFile = new File("D:\\Study");
            String[] fileNames = srcFile.list();
            for(String name : fileNames){
                if(name.endsWith(".jpg")){
                    System.out.println(name);
                }
            }
        }
    }
    

    遍历指定目录下所有文件名称,包括文件目录中的文件

    import java.io.*;
    public class FileTest{
        public static void main(String[] args){
            File dir = new File("D:\\Study\\Yitu");
            printSubFile(dir);
        }
       	private static void printSubFile(File dir){
            File[] subFiles = dir.listFiles();
            for(File f : subFiles){
                if(f.isDirectory()){
                    printSubFile(f);
                }else{
                    System.out.println(f.getAbsolutePath());
                }
            }
        }
    }
    

2. IO流原理及流的分类

  • 用于**处理设备之间的数据传输**,如读/写文件、网络通讯等
  • java程序中,对于数据的输入/输出操作以**流(Stream)**的方式进行
  • java.io 包下提供了各种 “ 流” 类的接口,用一获取不同种类的数据,并通过**标准的方法**输入或输出数据
  1. 流的分类

    • 按操作数据单位不同:字节流(8 bit)、字符流(16 bit)
    • 按数据流的流向不同:输入流、输出流
    • 按流的角色不同分为:节点流、处理流
    • 字节流读取中文会乱码,因为一个中文占用两个字节,所以需要用字符流读取
    抽象基类字节流字符流
    输入流InputStreamReader
    输出流OutputStreamWriter
    分类字节输入流字节输出流字符输入流字符输出流
    抽象基类InputStreamOutputStreamReaderWriter
    访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
    访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
    访问管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
    访问字符串StringReaderStringWriter
    缓冲流BufferedInputStreamBufferedOutputStreamBufferrdReaderBufferedWriter
    转换流InputStreamReaderOutputStreamWriter
    对象流ObjectInputStreamObjectOutputStream
    ****FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
    打印流PrintStremPrintWriter
    推回输入流PushbackInputStreamPushbackReader
    特殊流DataInputStreamDataOutputStream
2.1FileInputStream/FileOutputStream
  1. try-catch-finally

    import java.io.*;
    public class TestFileCopy{
        public static void main(String[] args) throws IOException{
    		FileInputStream fis = null;
    		FileOutputStream fos = null;
    		try{
    			fis = new FileInputStream("DNF - 痛苦之村列瑟芬.mp3");
    			fos = new FileOutputStream("DNF - 痛苦之村列瑟芬1.mp3");
    			byte[] data = new byte[3 << 20];
    			int len;
    			while((len = fis.read(data)) != -1){
    				fos.write(data,0,len);
    			}
    			//太慢了
    			/*
    			while((data = fis.read()) != -1){
    				fos.write(data);
    			}
    			*/
    		}catch(IOException e){
    			e.printStackTrace();
    		}finally{
    			try{
    				fis.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}finally{
    				try{
    					fos.close();
    				}catch(IOException e){
    					e.printStackTrace();
    				}
    			}
        	}
    	}
    }
    
  2. TWR 7.0新特性[超级重要🐴]

    import java.io.*;
    public class TestFileCopyWithTWR{
        public static void main(String[] args){
    		try(FileInputStream fis = new FileInputStream("1.jpg");FileOutputStream fos = new FileOutputStream("2.png")){
    			byte[] data = new byte[1024];
    			int len;
    			while((len = fis.read(data)) != -1){
    				fos.write(data,0,len);
    			}
    		}catch(IOException e){
    			e.printStackTrace();
    		}
        }
    }
    
  3. FileOutputStream的构造方法

    FileOutputStream( File f / String name) 这种模式如果有文件则会把源文件删除,在创建新的文件。想要在源文件的基础上追加文件则需要用 FileOutputStream(File f,true)

3 节点流

3.1 FileReader / FileWriter
  1. FileReader
  1. read() 返回读入的一个字符,如果达到文件末尾,则返回 -1
  2. 为了保证流资源一定会执行关闭操作,并需用try-catch-finally捕获异常
import java.io.*;
public class FileReaderTest{
    @Test
    public void test(){
        File file = null;
        FileReader fr = null;
        try{
            //1.实例化 File 类的对象,指明要操作的文件
            file = new File("hi.txt");
            //2.提供具体的流
            fr = new FileReader(file);
            //3.数据的读入
           int data = fr.read();
           while(data != -1){
               System.out.print((char)data);
               data = fr.read();
           }
            /*
            int data;
            while((data = fr.read()) != -1){
                System.out.println((char)data);
            }
            */
        }catch(IOExecption){
            e.printStackTrace(); 
        }finally{
            try{
                 //4.流的关闭
                 if(fr != null)
           		 	fr.close();
            }catch(IOExecption){
            	e.printStackTrace(); 
       		}
        }
    }
    
    //对 read() 操作升级,使用 read 的重载方法
    @Test
    public void testFileReader1{
        File file = null;
        FileReader fr = null;
        try{
            //1.File 类的实例化
        	file = new File("Hi.txt");
            //2.FileReader流的实例化
            fr = new FileReader(file);
            //3.读入操作
            //read(char[cbuf]):返回每次读入 cbuf数组中的字符串个数,如果达到文件末尾返回-1
            char[] cbuf = new char[5];
            int len;
            while((len = file.read(cbuf)) != -1){
    			//方式一
                for(int i = 0;i < len;i++){
                    System.out.print(cbuf[i]);
                }  
                //方式二
                String str = new String(cbuf,0,len);
                System.out.print(str);
            }
        }catch(IOExecption e){
            e.printStackTrace();
    	}finally{
            //4.资源的关闭
        }
    }
}
  1. FileWriter

说明

  1. 输出操作,对应的 File 可以不存在,并不会报异常

  2. File 对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建这个对象
    如果存在:①如果流使用的构造器是 FileWriter(file ,false) / FileWriter(file) ,对原有文件覆盖②如果使用的是 FileWriter(file,true) 不会对原有文件覆盖,而是在原有文件基础上追加内容
@Test
public void testFileWriter(){
     File file = null;
     FileWriter fw = null;
    try{
        //1. 提供 File 类对象,指明写出到的文件
        file = new File("Hi1.txt");
        //2.提供 FileWriter 的对象,用于数据写出
        fw = new FileWriter(file,false);
        //3.写出的操作
        fw.write("Hello World!");
    }catch(IOExecption e){
        e.printStackTrace();
    }fianlly{
        fw.close();
    }
}

使用 FileWriter 和 FileReader 实现文本文件的复制

import java.io.*;
//不能用字符流处理图片文件
public class TestFileCopy{
    @Test
    public void test(){
        FileReader fr = null;
         FileWriter fw = null;
       try{
            //1.创建 File 类的对象,指明读入和写出的文件
            File srcFile = new File("Hei.txt");
            File destFile = new File("Hi.txt");
            //2.创建输入流和输出流的对象
           	fr = new FileReader(srcFile);
            fw = new FileWriter(destFile);
            //3.数据输入输出操作
            char[] c = new char[5];
            int len;//记录每次读出来的字符个数
            while((len = fr.read(c)) != -1){
                //每次写出 len 个字符
                fw.write(c,0,len);
            }
       }catch(IOExecption e){
           e.printStackTrace();
       }finally{
            //4.资源的关闭
            try{
                if(fw != null)
                    fw.close();
            }catch(IOExecption){
                 e.printStackTrace();
            }finally{
            	try{
                    if(fr != null)
                        fr.close();
                }catch(IOExecption){
                     e.printStackTrace();
                } 
            }
       }
    }
}

对于文本文件**(.txt .java .c .cpp)**使用字符流处理,对于非文本文件使用字节流处理

3.2BufferedInputStream/BufferedOutputStream
  • 提高流的读取,写入速度
  1. 实现非文本文件的复制

    import java.io.*;
    public class BufferedTest{
        @Test
        public void BUfferedTest(){
             FileInuputStream fis = null;
             FileInuputStream fis = null;
             BufferedInputStream bis = null;
             BufferedOutputStream bos = null;
            
            try{
                //1.造 File 对象
                File file1 = new File("hi.jpg");
                File file2 = new File("hei.jpg");
                //2.造流
                //2.1 造节点流
                fis = new FileInputStream(file1);
                fis = new FileOutputStream(file2);
                //2.2造缓冲流
                bis = new BufferedInputStream(fis);
                bos = new BufferedOutputStream(fos);
                //3.读取写入
                byte[] b = new byte[10];
                int len;
                while((len = bis.read(b)) != -1){
                    bos.writer(b,o,len);
                }
            }finally{
                //4.资源关闭
                //先关闭外层,再关内层
                bos.close();
                bis.close();
                //关闭外层流的同时,内层流会自动关闭
             fw.close();
                fr.close();
            }
        }
    }
    
3.3 DataInputStream/DataOutputStream
  • 都属于**字节流、过滤流**
  • 作为过滤流,是为了给原本的节点流添加读写基本数据类型的功能的
  • 过滤流不能直接连接文件,只能连接其他的流
  • **DataInputStream **不再以-1作为读取结束的标志。如果到了文件结果还尝试进行读取会导致EOFException -> EndOfFileException
import java.io.*;
public class TestDataStream{
	public static void main(String[] args)throws Exception{

		//我们想要把人物等级保存下来~等到明年春暖花开日 再继续游戏~
		/*
		int level = 7365;
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.data"));
		dos.writeInt(level);
		dos.close();
		*/

		DataInputStream dis = new DataInputStream(new FileInputStream("data.data"));
		int x = dis.readInt();
		dis.close();
		System.out.println(x);
	}
}
3.4 ObjectInputStream/ObjectOutputStream
  • 同样是**字节流、过滤流**
  • 为了给原本的节点流添加读取对象的功能的
  • 如果到达文件结尾会触发EOFException

注意点

想要持久化一个对象 必须先要序列化这个类型
如果想要将A类的对象写出到磁盘当中 则A类必须实现序列化接口
implements Serializable
而如果A类当中还有其它引用类型的属性 则这些属性的类型
也要实现序列化接口 否则A对象持久化会出现异常
如果某些属性 无关紧要 不需要保存到文件当中
可以使用transient修饰
transient = 短暂的 转瞬即逝的 = 不参与持久化的
在写出一个对象的时候 transient的属性 将直接写出null
所以这个属性的类型 也就不需要序列化了~

import java.io.*;
import java.text.*;
public class TestObjectStream2{
	public static void main(String[] args){
		Wish myWish = new Wish("能早点在一起上课~网络教学就是坑!有个屁用!","5v");
		System.out.println(myWish);

		//请许下自己的愿望 并且将愿望保存在磁盘文件当中
		try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("月光宝盒.data"))){
			oos.writeObject(myWish);
		}catch(Exception e){
			e.printStackTrace();
		}

	}
}
class Wish implements Serializable{//愿望
	String content;//愿望的内容
	String name;//许愿人姓名
	long time;//许下愿望的时间
	public Wish(String content,String name){
		this.content = content;
		this.name = name;
		time = System.currentTimeMillis();
	}
	@Override
	public String toString(){
		SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
		return content + "\n\t\t\t" + name +"\n\t\t\t" + f.format(time);
	}

}

4 字符流

Reader / Writer 是字符流的抽象基类

4.1FileReader/FileWriter

这两个类只能用来读取文本文件,但是字节流通用语所有文件

.txt .java .html .js .css .jsp .asp .php等

用法用FileInputStream / FileOutputStream类似

4.2 BufferedReader/BufferedWriter
  1. BufferedReader / BufferedWriter

    • 给原本的流添加一个变长的缓冲空间,从而实现以行为单位的读取
    • 文件结束返回null
    import java.io.*;
    public class TestBufferedWriter{
    	public static void main(String[] args)throws Exception{
    		//春眠不觉晓 处处闻啼鸟 夜来风雨声 花落知多少
    		BufferedWriter bw = new BufferedWriter(new FileWriter("鹅鹅鹅.txt"));
    		bw.write("鹅鹅鹅");
    		bw.newLine();//能够写出当前操作系统所匹配的换行标识
    		bw.write("鹅项向天歌");
    		bw.newLine();
    		bw.write("鹅毛浮绿水");
    		bw.newLine();
    		bw.write("鹅可能死了");
    		bw.close();
    	}
    }
    
  2. PrintWiter

    PrintWriter 和BufferedWriter 相比的优势

    1. PrintWriter既可以当做节点流 也可以当做过滤流,构造方法允许传入 File对象 / String路径 / 流!
    2. PrintWriter既可以连接字节流 又可以连接字符流,构造方法既可以传入 FileWriter 也可以传入 FileOutputStream
    3. 当做节点流使用的时候 构造方法第二个参数可以指定字符编码
      new PrintWriter(“鹅鹅鹅.txt”,“utf-8”);
    4. 当做过滤流使用的时候 构造方法第二个参数可以指定自动清空缓冲
      new PrintWriter(new FileWriter(“abc.txt”),true);//autoFlush
    5. 它的println() = write() + newLine()
    import java.io.*;
    public class TestPrintWriter{
    	public static void main(String[] args)throws Exception{
    		PrintWriter pw = new PrintWriter("春晓.txt");
    		pw.println("春眠不觉晓");//write()+newLine();
    		pw.println("处处闻啼鸟");
    		pw.println("夜来风雨声");
    		pw.print("花落知多少");
    		pw.close();
    
    	}
    }
    

5. 转换流

  • 转换流提供了在字节流和字符流之间的转换
  • 通常使用转换流来处理文件乱码问题,
  • 字节大输入流转换成字符输入流**InputStreamReader、字符输出流转换成字节输出流OutputStreamWriter**
public class InputStreamReaderTest{
    public static void main(String[] args) throws IOExecption{
    	FileInputStream fis = new FileInputStream("Test.txt");
        InputStreamReader isr = new InputStreamReader(fis);
        char[] c = new char[10];
        int len;
        while((len = isr.read(c)) != -1){
            String str = new String(c,0,len);
            System.out.println(str);
        }
        isr.close()
    }
}

6. NIO2

第十二章 多线程

1.基本概念:程序、进程、线程

程序(Program)

为了完成特定的任务、用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象

进程(process)

是程序的一次执行过程,或是正在运行的程序,是一个动态的过程,有自身的生命周期

线程(thread)

进程可以进一步细分为线程,是一个程序内部的一条执行路径

  • 若一个进程同一时间并行执行多个线程,就是支持多线程的
  • 线程最为调度和执行的单位,每个线程都拥有独立的运行栈和程序计数器(pc),线程切换的开销小
  • 一个进程的多个线程共享相同的内存单元/内存地址空间,他们从同一个堆空间中分配对象,可以访问相同的变量和对象,使得线程间的通信更简洁、高效,但是多个线程操作共享的系统资源时可能会带来安全隐患

2.线程的创建和使用

2.1 多线程的创建
  1. 方式一:继承Thread类

    ①创建一个类继承于Thread类

    ②重写***Thread***的***run()***方法 -->将此线程要执行的操作声明在***run()***中

    ③创建一个***Thread***类的子类对象

    ④通过此对象调用***start()***,第一步启动当前线程,第二部调用当前线程的 run()

    public class MyThread extends Thread{
    	@Override
      	public void run(){
     		for(int i = 0; i < 100;i++){
                if(i % 2 == 0){
                   System.out.println(i);
                }
            }		     
      	}
    }
    public class ThreadTest{
        public static void main(String[] args){
            //创建Thread类的子类对象
        	MyThread t1 = new MyThread();
            //通过此线程调用start()方法
            t1.start();
        }
    }
    
  2. 方式二:实现Runnable接口

    ①创建一个实现了 Runnable接口的类

    ②实现 Runnable 中的抽象方法:run()

    ③创建实现类的对象,将此对象作为参数传递到 Thread 类的构造器中,创建 Thread 类的对象

    ④通过 Thread 类的对象调用 start()

    /**
    创建三个窗口同时卖100张票
    */
    class MThread implements Runnable{
       private int ticket = 100;
    	@Override
       public void run(){
           //TODO
           while(true){
               synchronized(this){
                   if(ticket > 0){
                     System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
                       ticket--;
                   }else{
                       break;
                   }
               }
           }
       }
    }
    public class Test{
       public static void main(String[] args){
       	MThread m = new MThread();
           Thread t1 = new Thread(m);
           Thread t2 = new Thread(m);
           Thread t3 = new Thread(m);
           
           t1.setName("窗口1");
    	t2.setName("窗口2");
           t3.setName("窗口3");
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    
  3. 比较两种创建多线程的方式

    开发中: 优先选择 实现 Runnable 接口的方式。原因:① 实现的方式没有类的单继承性的局限性 ② 实现的方式更适合来处理多线程有共享数据的情况

    联系 : public class Thread implements Runnable

    相同点: 两种方法都需要重写 run() 将线程要执行的操作声明在 run() 中。

    例题:创建两个线程一个打印100以内奇数,一个打印偶数

    public class ThreadTest {
        public static void main(String[] args){
     		new Thread(){
    			@Override
    			public void run(){
    				for(int i = 0; i < 100;i++){
    					if(i % 2 == 1){
    					   System.out.println(Thread.currentThread().getName() + ":" + i);
    					}
    				}
    			}
            }.start();
    
      		new Thread(){
    			@Override
    			public void run(){
                	for(int i = 0; i < 100;i++){
    					if(i % 2 == 0){
    					   System.out.println(Thread.currentThread().getName() + ":" + i);
    					}
           			}
    			}
            }.start();
    
        }
    }
    
    
2.2 Thread中的常用方法
  1. start()

    启动当前线程,调用当前线程的 run()

  2. run()

    通常需要重写Thread类中的方法,将创建的线程要执行的操作声明在此方法中

  3. currentThread()

    静态方法,返回执行当前代码的线程

  4. getName()

    获取当前线程的名字

    同样的也有setName()方法

  5. yield()

    释放当前CPU的执行权

  6. join()

    在主线程a中调用线程b的 join()。此时线程a进入阻塞状态,直到线程b完全执行完,a才会结束状态

  7. sleep()

    让当前线程休眠多少毫秒

2.3 线程的调度
  1. 线程的优先级

线程的最大优先级是10,最小为1,默认为5

  1. 获取和设置当前线程的优先级

    getPriority()h获取当前的优先级

    setPriority()设置当前线程的优先级

3.线程的生命周期

线程.png

4.多线程常用方法

控制线程相关方法

  1. setPriorty(inyt)[不建议使用的]

    setPriority(int) 可以设置现成的优先级别,可选范围是 1 - 10 ,默认级别为5,线程的优先级别越高,抢到时间片的**概率越高,并不代表一定抢到时间片**

  2. static sleep(long)

    使当前线程休眠多少毫秒,会从运行态变成阻塞态

  3. static yield()

    当前线程放弃已经持有的时间片,允许其他线程执行

  4. join()

    当前线程邀请其他线程先执行,谁在运行中,join就在谁的体内

    注意:
    1. 线程章节所有的静态方法,不要关注是谁调用的方法,而要关注谁的线程体内;
    2. 这个章节所有主动进入阻塞状态的方法,都出要进行异常处理。因为他们都有throws InterruputedException的声明,这是一个非运行时异常,必须出来

    线程的其他方法

  5. setName() / getName()

    设置和得到线程的名字

  6. static activeCount()

    得到程序中所有活跃线程的总数[就绪 + 运行 + 阻塞]

  7. setDaemon()

    设置线程成为守护线程;守护线程是为了给其他线程提供服务的,当程序中只有守护进程的时候,守护进程会自动结束
    守护线程要设置成while(true);必须按在调用 start() 方法之前就设置成守护线程

  8. interrupt()

    中断线程的阻塞状态

  9. static currentThread()

    • 在主方法中使用相当于得到了主线程的线程对象
    • 在 run() 调用的其他方法中,用来获取当前的线程是谁
    • 不应该直接出现在 run() 方法中,因为返回的线程相当与this

5. 线程的同步

  • 在java中通过同步机制,来解决线程安全问题
  • 操作同步代码时,只能有一个线程参与,其他线程等待,相当于是一个单线程的过程,效率较低
  • 当锁标记没被释放的时候,其他线程会进入锁池进行等待
  1. 方式一:同步代码块

    synchronized(同步监视器){
        //需要被同步的代码
    }
    

    说明
    ①操作共享数据的代码,即为需要被同步的代码
    ②🐴共享数据: 多个线程共同操作的变量,如ticket
    ③同步监视器,俗称锁。任何一个类的对象都可以充当锁, 要求:多个线程必须共用一把锁

    ④在实现 Runnable 接口的创建多线程的方式中,可以考虑使用 this 充当同步监视器,在继承Thread的方式中,慎用

  2. 方式二:同步方法

    如果操作共享数据的代码完整的声明在一个方法中,可以将此方法声明成同步的

修改懒汉式

class Bank{
    private static Bank instance = null;
    public static Bank getInstance(){
        if(instance == null){
            synchronized(Bank.class){
                if(instance == null){
                    instance = new Bank();
                }
            }
        }
        return instance;
    }
}
  1. 方式三:Lock(锁) ---- JDK5.0新增

    Lock构造方法是可以传参指定是否创建公平锁

    new ReentrantLock( true ) 按照先来后到 默认false

     class Window implements Runnable{
         private int ticket = 100;
         //1.实例化ReentrantLock对象
         private ReentrantLock lock= new ReentrantLock();
             
         @Override
         public void run(){
             while(true){
                 try{
                     //2.调用锁定方法lock()
                     lock.lock();
                     if(ticket > 0){
                         try{
                             Thread.sleep(100);
                         }catch(InterruptedException e){
                             e.printStackTrace();
                         }
                         System.out.println("卖票" + ticket);
                         ticket--;
                     }
                 }finally{
                     //3.调用解锁方法unlock()
                     lock.unlock();
                 }
          }
         }
    

}


**<font color=blue>synchronized和Lock区别</font>**

> ==相同点:==
> 两者都可以解决线程安全问题
>
> ==不同点:==synchronized机制在执行完相应的同步带吗后,自动的释放同步监视器,Lock需要手动的启动同步用完释放
>
> 建议顺序  Lock--同步代码块--同步方法
> 

6. 线程的通信

涉及到的三个方法
wait() : 使当前线程进入阻塞状态,并释放同步锁
notify() : 唤醒被 wait() 的线程,如果有多个线程同时阻塞,就优先唤醒优先级高的,一样时随机唤醒。
notifyAll() : 唤醒所有阻塞的线程

①这三个方法只能出现在同步代码块或者同步方法中;
②且调用者必须是同步代码块或同步方法中的同步监视器
③这三个方法是定义在Object类中的

例子:使用两个线程交替打印1-100

class Number implements Runnable{
    private int num = 1;
    @Override
    public void run(){
        while(true){
            synchronized(this){
                notify();
                if(num <= 100){
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    try{
                        wait();
                    }catch(InterruptedException){
                        e.printStackTrace();
                    }
                }else{
                    break;
                }
            }
        }
    }
}
public class Test{
    public static void main(String[] args){
    	Number num = new Number();       
        Thread t1 = new Thread(num);
        Thread t2 = new Thread(num);
        
        t1.setName("线程1");
        t2.setName("线程2");
        
        t1.start();
        t2.start();        
    }
}

面试题:sleep() 和wait() 的异同

①相同点: 一旦执行方法,都可以使当前的线程进入阻塞状态

②不同点:

  1. 两个方法的声明位置不同:Thread类中声明sleep(),Object类中声明wait()
  2. 调用要求不同:sleep()可以在任何需要的场景下调用,wait()必须使用在同步代码块或者同步方法中
  3. 是否释放同步监视器:如果两个方法都是用在同步代码块或者同步方法中,sleep()不会释放同步监视器,wait()则会。

生产者和消费者问题

生产者(Productor) 将产品交给店员(Clerk)。而消费者从店员处取走产品,店员一次只能持有固定数量的产品(20),如果生产者使徒生产更多的产品,店员会让生产者停一下,如果店里有空位置放了,店员会通知生产者继续生产,如果没有产品了。会告诉消费者等一下,有了会通知缴费者取走商品

public class ProductTest{
   public static void main(String[] args){
       Clerk clerk = new Clerk();
       Producer p1 = new Producer(clerk);
       Customer c1 = new Customer(clerk);
       
       p1.setName("生产者");
       c1.setName("消费者");
       
       p1.start();
       c1.start();
   }  
}
class Clerk{
    //产品数量
    private int num = 0;
    //生产产品
    public synchronized void produceProduct(){
    	if(num < 20){
          num++;  System.out.println(Thread.currentThread().getName() + "开始生产第" + num + "个产品");
          notify();
        }else{
          	try{
                wait();
            }catch(InterriptedExceptione){
                e.printStackTrace();
            }  
        } 
    }
    //消费产品
    public synchronized void sonsumeProduct(){
        if(num > 0){
    		 System.out.println(Thread.currentThread().getName() + "开始消费第" + num + "个产品");
            num--;
            notify();
        }else{
            try{
                wait();
            }catch(InterriptedExceptione){
                e.printStackTrace();
            }
        }
    }
}
class Producer implements Runnable{
   //生产者
    private Clerk clerk;
    
    public Producer(Clerk clerk){
        this.clerk = clerk;
    }
    
    @Override
    public void run(){
       System.out.println("生产者开始生产产品...");
        while(true){
            clerk.produceProduct();
        }
    }
}
class Customer implements Runnable{
    //消费者
    private Clerk clerk;
    
    public Customer(Clerk clerk){
        this.clerk = clerk;
    }
    
    @Override
    public void run(){
      	System.out.println("消费者开始消费产品...");
      while(true){
            clerk.consumeProduct();
        }  
    }
}

7.JDK5.0新增的线程创建方式

1. 实现Callable接口

与使用 Runnable相比,使用 Callable功能更强大

  • 相比 run() 方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回类型
  • 需要借助 FutureTask 类,比如获取返回结果
class NumThread implements Callable{
    @Override
    public Object call() throws Exception{
        int sum = 0;
        for(int i = 1;i <= 100;i++){
            if(i % 2 == 0){
            	sum += i; 
            }
        }
        return sum;
    }
}
public class Test {
    public static void main(String[] args){
    	NumThread num = new NumThread();
        FutureTask ft = new FutureTesk(num);
        new Thread(ft).start();
        System.out.println(ft.get());
    }
}
  1. 创建一个实现Callable的实现类

  2. 实现 call() 方法,将次线程要执行的操作声明在call() 方法中

  3. 创建Callable实现类的对象

  4. 将此对象传递到FutureTask构造器中,创建FutureTask对象

  5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象并调用start()

2.使用线程池

提前创造号多个线程,放入线程池中,使用时直接获取,使用完放回池中,可以避免频繁的创建销毁、实现重复利用。

好处

  1. 提高了响应速度(减少了创建新线程的时间)
  2. 降低资源消耗(重复利用线程池中的线程,不需要每次创建)
  3. 便于线程管理
public class ThreadPool{
    public static void main(String[] args){
    	//提供指定数量的线程
        ExecutorService es = Executors.newFixedThreadPool(10);
        //适合适用于Runnable
        es.execute(new NumThread);
        //适合使用于Callable
        //es.submit();
        //关闭线程池
        es.shutdown();
    }
}

第十三章 java常用类

1. 字符串相关类

1.1 String类
1.1.1 new和不new的区别
public class TestString{
    public statuc void main(String[] args){
		String s1 = new String("a");
   		String s2 = new String("a");
        //false
       	System.out.println(s1 == s2);
        
        String s3 = "a";
        String s4 = "a";
        //true
        System.out.println(s3 == s4);
 }  
}

不new的话,如果是第一次遇见这个字符串,就会在常量池创建一个引用,从始至终就创建了一次,如果再有新的字符串创建,优先在常量池查找

1.1.2 String常用的20个方法
  1. 和长度有关的方法

    序号返回类型方法签名作用
    1intlength()得到一个字符串里边的字符个数
  2. 和数组有关的方法

    序号返回类型方法签名作用
    2byte[]getBytes()将一个字符串转换成字节数组
    3char[]toCharArray()将一个字符串转换成字符数组
    4String[]split(String)将一个字符串按照指定的内容劈开
  3. 和判断内容有关的方法

    序号返回类型方法签名作用
    5booleanequals(String)区分大小写的判断两个字符串的内容是否一模一样
    6booleanequalsIgnoreCase(String)忽略大小写的比较两个字符串的内容是否一模一样
    7booleancontains(String)判断一个字符串里面是否出现了某个指定内容
    8booleanstartsWith(String)判断一个字符串是否以指定的内容开头
    9booleanendsWith(String)判断一个字符串是否以指定的内容结尾
  4. 和改变内容有关的

    序号返回类型方法签名作用
    10StringtoUpperCase()将一个字符串全部转换成大写
    11StringtoLowerCase()将一个字符串全部转换成小写
    12Stringreplace(String,String)将一个字符串里面出现的某个内容全部替换成指定的内容
    13StringreplaceAll(String,String)将一个字符串里面出现的某个内容全部替换成指定的内容 【支持正则表达式】
    14StringreplaceFirst(String s1,String s2)将字符串中第一次出现的s1换第二个s2
    15Stringtrim()去除字符串前后的空格
    16Stringsubstring(int x,int y)截取x到y - 1的字符串
    17Stringsubstring(int x)截取 x 到最后的字符串
  5. 和位置有关的方法

    序号返回类型方法签名作用
    18charcharAt()找到指定下标处对应的一个元素
    19intindexOf(String)找到某个内容第一次出现的下标
    20intlastIndexOf(String)找到某个内容最后一次出现的下标
1.1.3 String StringBuffer StringBuilder 之间的区别
  1. ***String***和***StringBuffer、StringBuilder***之间的区别

    String类创建对象的时候正好够用,但是StringBuffer以及StringBuilder在创建对象的时候会预留16块缓冲区,为了防止追加连接的时候效率过低

    public class TestString{
        public static void main(String[] args){
            String s = new String("");
            long t1 = System.currentTimeMillis();
            for(int i = 0;i <= 100000;i++){
            	s += i;
            }
            long t2 = System.currentTimeMillis();
        	System.out.println(t2 - t1);
            
            StringBuffer bf = new StringBuffer("");
            long t3 = System.currentTimeMillis();
            for(int i = 0;i <= 100000;i++){
            	bf.append(i);
            }
            long t4 = System.currentTimeMillis();
        	System.out.println(t4 -t3);
        }
    }
    
  2. ***StringBuffer***和***StringBuilder***之间的区别

    • StringBuffer同一时间允许一个线程进行访问,效率较低,但是不会出现并发错误
    • StringBuilder同一时间允许多个线程进行访问,效率较高,但是可能会出现并发错误
1.2 StringBuffer 和 StringBuilder

当 StringBuffer 空间被占满了,还要新增数据的话,会进行扩容,公式(原有长度 + 新增字符串长度) * 2

StringBUffer的常用方法

  1. 增加:append

    append(xxx); 用于字符串拼接

  2. 删除:delete

    delete(int start, int end); 用于删除指定位置的内容

  3. 修改 setCharAt / replace

    setCharAt(int n,char c);把指定下标的内容替换成指定字符

    replace(int start, int end ,String str);把[start,end)位置的内容替换成str

  4. 查询:charAt

    与String用法一样

  5. 插入:insert

    insert(int offset, xxx);在指定位置插入xxx

  6. 反转:reverse

    把当前字符序列逆转

2. JDK8.0之前的日期API

2.1 System的静态方法currentTimeMillis()

返回当前时间到1970年1月1日0:0:0之间的毫秒数,通常称之为时间戳

2.2 Date类

java.util.Date
|----- java.sql.Date 对应的是数据库中的日期类型的变量

  1. 构造方法:Date()

    Date date1 = new Date();
    //显示当前的年月日时分秒
    System.out.println(date1.toString());
    //获取当前Date对象对应的时间戳
    System.out.println(date1.getTime());
    
  2. java.sql.Date如何实例化对象

    //import java.sql.Date;
    java.sql.Date d = new java.sql.Date(12312421414L);
    
  3. 如何把 util.Date 对象转换成 sql.Date 对象

    //强转
    Date d2 = new java.sql.Date(12312412L);
    java.sql.Date d3 = (java.sql.Date)d2;
    //使用getTime()
    Date d4 = new Date();
    java.sql.Date d5 = new java.sql.Date(d4.getTime());
    
    
2.3 Calendar类

2.4 SimpleDateFormat类
public class Test{
    public static void main(String[] args){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //格式化 日期到字符串
        String format1 = sdf.format(date);
        System.out.println(format1);
        //解析  字符串到日期
        //要求字符串必须是符合SimpleDateFormat格式的
        Date date2= sdf.parse("2020-02-06 17:48:13");
        System.out.println(date2);
        
    }
}

3. JDK8.0之后的日期API

3.1 LocalDate,LocalTime,LocalDateTime
public class Test{
    public static void main(String[] args){
        //now():获取当前的日期
    	LocalDate lc = LocalDate.now();	
        /*
        	时间用LocalTime
        	日期加时间 LocalDateTime
        */
        //of()
        LocalDateTme ldt = LocalDateTime.of(2020,2,6,17,56,48);
        /*
        	其他方法
        	getXXX()
        */
        LocalDateTme ldt2 = LocalDateTime.withDayOfMonth(2);
    }
}
3.2 Instant
public class {
    public static void main(String[] args){
 		Instant in = Instant.now();   
    }
}
3.3 DateTimeFormatter
  1. 预定义的标准格式
   DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
   LocalDateTime lc = LOcalDateTime.now();
   System.out.println(dtf.format(lc));   

第十四章 网络编程

1. 网络通信协议

TCP

  • 使用TCP协议之前,需建立TCP链接,形成传输数据通道
  • 传输前采用**三次握手方式,点对点通信是安全可靠的**
  • TCP进行通信的两个应用进行分别是 客户端 、 服务器
  • 在连接过程中**可以进行大数据量的传输**
  • 传输完毕之后**需要释放已经建立的连接,效率低**

UDP

  • 将数据、源、目的封装成数据包,不需要建立连接

  • 每个数据包的大小限制在64K以内

  • 发送时不管对方是否准备好,接收方收到也不确认,因此不安全的

  • 可以进行广播发送,发送数据结束时,无需释放资源,开销小,速度快

public class TCPTest{
    public static void main(String[] args) throws IOException{
    	InetAddress inet = InetAddress.getByName("127.0.0.1");
        Socket socket = new Socket(inet,9999);
        
        OutputStream os = socket.getOutputStream();
        os.write("这是客户端".getBytes());
        os.close();
        socket.close();
    }
    @Test
    public void server(){
        ServerSocket ss = new ServerSocket(9999); 
        Socket socket = ss.accept();
        InputStream is = socket.getInputStream();
        byte[] data = new byte[1024]; 
        int len;
        while((len = is.read(data) != -1){
            String str = new String(data,0,len);
            System.out.println(str);
        }
        System.out.println(socket.getInetAddress().getHostAddress());
    }
}

第十五章 java反射机制

1.Java反射机制概述

  • 反射被视为**动态语言**的的关键,反射机制允许程序在执行期间借助于 Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法
  • 加载完类之后,在堆内存的方法去产生了一个Class 类型的对象,这个对象包含了完整的类的结构信息。可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,称之为反射
正常方式
引入需要的包类名称
通过new实例化
取得实例化对象
反射方式
实例化对象
getClass方法
阁道完整的包类名称

问题

反射是不是跟封装性有矛盾?

第十六章 jdk8中Lambda表达式与Stream API的使用

1. Lambda表达式

Lambda是一个**匿名函数,可以理解为一段可以传递的代码**。使用它可以写出更简洁灵活的代码。

示例一:

@Test
public void test(){
    Comparator<Integer> com1 = new Comparator<Integer>(){
        @Overrdie
        public int compare(Integre i1.Integer i2){
            return Integer.compare(i1,i2);
        }
    }
}
//使用Lambda表达式
Comparator<Integer> com2 = (i1.i2) -> Integer.compare(i1,i2);
//使用
Compare<Integer> com3 = Integer::compare;

  1. 举例:(i1,i2) -> Integer.compare(i1,i2);

    -> lambda操作符

    左边lambda形参列表

    右边lambda体,抽象方法的实体

第十七章 jdk 9 / 10 /11的新特性

第三章 IDE的使用

1. Eclipse的使用

1.快捷键的使用

懒得写,用的多了就会了

  1. ctrl alt down 复制多行
  2. 上下移动 alt ↑
  3. 进去父类 alt←
  4. 集成树 ctrl T
  5. 批量修改 alt shift R
  6. 选中结构变成大小写 Ctrl Shift X/y
  7. 注释 CTRL SHIFT C

2.DeBug调试

2.IDEA的使用

网址:http://www.jetbrains.com/idea/download/#section=windows

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-quMFafoG-1593855136188)(D:\Study\java\QQ截图20200202001250.png)]

1.快捷键的使用

  1. 代码注释 Ctrl + / 取消注释Ctrl + Shift +/
  2. 两次shift 随时搜索
  3. **创建目录 ctrl shift alt s --> moudles -->resources **
  4. 提示 ctrl alt 空格

https://blog.csdn.net/qq_38963960/article/details/89552704

1. Ctrl 快捷键

Ctrl + F 在当前文件进行文本查找 (必备)
Ctrl + R 在当前文件进行文本替换 (必备)
Ctrl + Y 删除光标所在行 或 删除选中的行 (必备)
Ctrl + D 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 (必备)
Ctrl + W 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围 (必备)
Ctrl + E 显示最近打开的文件记录列表
Ctrl + N 根据输入的 类名 查找类文件
Ctrl + G 在当前文件跳转到指定行处
Ctrl + J 插入自定义动态代码模板
Ctrl + P 方法参数提示显示
Ctrl + Q 光标所在的变量 / 类名 / 方法名等上面(也可以在提示补充的时候按),显示文档内容
Ctrl + U 前往当前光标所在的方法的父类的方法 / 接口定义
Ctrl + B 进入光标所在的方法/变量的接口或是定义出,等效于 Ctrl + 左键单击
Ctrl + K 版本控制提交项目,需要此项目有加入到版本控制才可用
Ctrl + T 版本控制更新项目,需要此项目有加入到版本控制才可用
Ctrl + H 显示当前类的层次结构
Ctrl + O 选择可重写的方法
Ctrl + I 选择可继承的方法
Ctrl + + 展开代码
Ctrl + - 折叠代码
Ctrl + / 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 (必备)
Ctrl + [ 移动光标到当前所在代码的花括号开始位置
Ctrl + ] 移动光标到当前所在代码的花括号结束位置
Ctrl + F1 在光标所在的错误代码出显示错误信息
Ctrl + F3 调转到所选中的词的下一个引用位置
Ctrl + F4 关闭当前编辑文件
Ctrl + F8 在 Debug 模式下,设置光标当前行为断点,如果当前已经是断点则去掉断点
Ctrl + F9 执行 Make Project 操作
Ctrl + F11 选中文件 / 文件夹,使用助记符设定 / 取消书签
Ctrl + F12 弹出当前文件结构层,可以在弹出的层上直接输入,进行筛选
Ctrl + Tab 编辑窗口切换,如果在切换的过程又加按上delete,则是关闭对应选中的窗口
Ctrl + Enter 智能分隔行
Ctrl + End 跳到文件尾
Ctrl + Home 跳到文件头
Ctrl + Space 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 Ctrl + 逗 号 (必备)
Ctrl + Delete 删除光标后面的单词或是中文句
Ctrl + BackSpace 删除光标前面的单词或是中文句
Ctrl + 1,2,3…9 定位到对应数值的书签位置
Ctrl + 左键单击 在打开的文件标题上,弹出该文件路径
Ctrl + 光标定位 按 Ctrl 不要松开,会显示光标所在的类信息摘要
Ctrl + 左方向键 光标跳转到当前单词 / 中文句的左侧开头位置
Ctrl + 右方向键 光标跳转到当前单词 / 中文句的右侧开头位置

2. Alt快捷键

Alt + enter 例如 new Person(),按了之后前边会自动加Person person;

Alt + Shift + z 包含代码块

2.常用设置

1.自动导包设置

Setting --> Editor --> Auto Import

Insert Import on paste 改成All

并把下边Add 和Optimize勾选上

  1. 方法体分隔符

Setting --> Editor --> Appearance

show Line number
show method separators 这个是每个方法体结束之后会有一个灰色的虚线,方便看方法体结束的

  1. 忽略大小写的提示(较为实用)

Setting --> Editor --> Code completion Case sensitive 改成None

  1. 添加头部注解

Setting --> Editor --> File and Code Templates Includes --> File Header

/**
@author zhaojinhui
@create ${YEAR}-${MONTH}-${DAY} ${TIMe}
*/
  1. 编码集

Setting --> Editor --> File Encoding UTF-8

  1. 自动编译

Setting --> Build --> Compiler

***Build project***和***Compiler independent***需要勾选

3.模板的使用

Setting --> edtior --> General -->Postfix Compiler

edtior ->Live Templates 这个里边可以自定义模板比如自定义数据库连接啊,多线程创建啊

3. IDEA常用插件

Key promoter 提示快捷键

JRebel 更改不需要重新部署

Lombok 不需要写get、set方法

AiXCode 智能提示

FindBugs-IDEA FindBugs[^FindBugs]: https://blog.csdn.net/zhaohonghan/article/details/88996697

String Manipulation字符串转换插件

3. 单元测试的使用

1.JUnit的使用

  1. 选中当前工程 --> Build path --> Add libraries -->JUint --> 下一步

  2. 创建Java类,进行单元测试

    此时的java类要求: ①此类是public的 ② 此类提供公共的无参构造器

  3. 声明的单元测试要求.

    ①方法的权限是public ②没有返回这没有形参

  4. 在测试上需要声明注解@Test,并导入org.junit.Test包

  5. 声明玩测试方法以后,可以在方法体内测试相关的代码,写完之后,双击单元测试方法名,run as -->JUnit Test

    1. 如果执行结果没有异常是绿条,否则红条

[^FindBugs] : [^FindBugs]: https://blog.csdn.net/zhaohonghan/article/details/88996697

4.一个IDEA配置的网页

https://jadyer.cn/2016/04/20/idea-config

1.IDEA的快捷键

  • 自动补全:Alt + 回车
  • 快速输入main函数:键入 main 再按 Ctrl+J 键(或者键入 psvm 再按 Tab 键)
  • 快速输入System.out.println:键入 sout 再按 Tab 键(对应Eclipse中的syso)
  • 快速生成普通for循环: 键入 fori 再按 Tab 键或 Ctrl+J 键
  • 快速生成foreach循环:键入 iter 再按 Tab 键或 Ctrl+J 键
  • 查询某方法被其它地方调用:Ctrl+Alt+H(其实:Alt + F7 更好用)
  • 定位文件或直接定位某一行:Ctrl+N 或者 Ctrl+Shift+N 时输入文件名后,再跟上冒号和行号,如 LoanHelper:22
  • 返回上一个方法: Ctrl + Alt + 方向键左
  • 合并develop分支到master:master分支上工程上右键—Git—Repository—Merge Changes—Branches to merge选择develop分支
  • 常用快捷键:http://wiki.jikexueyuan.com/project/intellij-idea-tutorial/keymap-introduce.html
  • 缩进用Tab还是空格:https://bigc.at/tabs-vs-spaces.orz
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: Java详细接口文档模板主要包括接口概述、接口定义、接口参数、接口返回值、接口示例、错误码说明等内容。 接口概述部分应该包括接口的名称、URL、请求方式(GET/POST/PUT/DELETE等)、功能描述、接口本等信息,为其他开发人员提供基本信息。 接口定义部分应该包括接口的详细定义,包括各个参数的名称、类型、是否必填、默认值等信息,以及接口的请求示例和返回示例。 接口参数部分应该列出接口的请求参数,包括参数的名称、类型、是否必填、默认值等信息。如果有复杂的参数结构,可以使用表格或者树型结构来说明。 接口返回值部分应该列出接口的返回值,包括返回值的类型、说明等信息。如果有复杂的返回值结构,可以使用表格或者树型结构来说明。 接口示例部分应该提供一些常用的接口使用示例,包括请求参数和返回值。可以根据实际需求提供多个示例,覆盖不同的使用场景。 错误码说明部分应该列出接口可能返回的错误码及其说明。对于常见的错误码,可以提供示例和解决方法,方便其他开发人员快速定位错误。 以上是Java详细接口文档模板的基本内容,可以根据具体项目需求进行适当的调整和扩展。编写完整和清晰的接口文档对于项目开发和维护非常重要,可以提高团队协作效率和代码质量。 ### 回答2: Java详细接口文档模板是用来记录Java程序接口的规范和使用说明的文档模板。它通常包括以下几个方面的内容。 1. 接口名称和描述:明确接口的名称以及其功能和用途的简要描述。 2. 接口方法和参数:列出接口中定义的方法及其参数的详细说明。包括方法的名称、输入参数、返回值类型以及异常处理等。 3. 接口的使用示例:提供一个或多个使用该接口的示例。示例可以帮助开发人员更好地理解接口的使用方法和调用规则。 4. 接口的实现注意事项:对于实现该接口的类,列出一些需要注意的事项,例如接口方法的实现细节、特殊的参数要求等。 5. 接口的扩展和本变更:如果接口有扩展或本变更的计划,可以在文档中进行说明,包括新增的方法或已废弃的方法等。 6. 接口的错误处理和异常情况:对于可能出现的错误或异常情况,进行详细的说明和处理建议,帮助开发人员解决问题和进行错误调试。 7. 接口的依赖和使用要求:列出使用该接口的条件和依赖,例如所需的Java本、必要的第三方库等。 8. 接口的返回值和数据结构:对于接口返回的数据结构,进行详细的说明,包括数据类型、字段含义和可能的取值范围等。 通过使用Java详细接口文档模板,可以提供给使用者一个清晰的接口使用指南,并且帮助开发人员更高效地使用和实现接口,减少沟通成本和错误发生的可能性。 ### 回答3: Java详细接口文档模板一般包含以下几个方面的内容: 1. 接口概述: 在这一部分,需要对接口进行简要的概括和介绍。包括接口的功能、作用以及设计的初衷等。 2. 接口定义: 在这一部分,需要对接口的定义进行详细说明。包括接口的名称、参数、返回值、异常等。可以使用表格的形式列出接口的各个属性及其说明。 3. 接口方法: 在这一部分,需要详细描述接口的方法及其功能。包括每个方法的输入参数、输出参数、返回值等。可以使用类似于Java代码的形式来展示接口方法的签名和说明。 4. 接口示例: 在这一部分,可以给出一些具体的接口方法示例,用于说明接口的使用方法和效果。可以提供一些典型的输入和输出示例,并对其进行详细的解释。 5. 接口实现: 如果接口已经有具体的实现,那么在这一部分可以对接口的实现进行说明。包括实现的类名、方法的具体实现逻辑等。 6. 接口注意事项: 在这一部分,可以给出一些接口使用的注意事项和限制。比如对输入参数的合法性进行要求,对返回值的约定等。 7. 接口变更历史: 如果接口在不同的本中有过修改,那么在这一部分可以列出接口的变更历史。包括每个本对接口进行了哪些修改,修改的原因以及影响等。 以上是一个基本的Java详细接口文档模板的内容,具体可根据项目需求进行适当的调整和补充。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值