java基础(完整版)
阅读原文时间:2023年07月10日阅读:2

java

javaSE

block块级

line 行

组成部分、变量名、类名、方法名--------标识符

$\数字、_\字母

强类型语言---安全性高--速度会慢

  • 基础类型
  • 引用类型

int-----128·127

整数、浮点数、字符类型、Boolean类型

类、接口、数组

位、字节、1B=8bit位 字符:是指计算机中使用的字母、数字、字、符号

八进制:前缀 0

十六进制: 0x

float f = 0.1f //有限的、离散的、、舍入误差

double f = 0.1

BigDecimal大数据类型 数据工具类

Unicode 编码

Excel 最长是2的16次方 ---65536

\u0061

转义字符

\t制表符 \n换行

jadk7 新特性

数字之间 10_0000_0000

  • 强制转换 (类型)变量名 高---低
  • 自动转换 低---高

type varName [=value'][{,varNmae[=value]}]

作用域:

  • 类变量:static 关键字修饰的 static salary =
  • 实例变量:属于对象,如果不初始化,会输出默认值
  • 局部变量:方法内:局部变量必须声明和初始化

常量:

String X="3.14"

修饰符:修饰符不存在先后顺序

final

  • 算数运算符
  • 赋值运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 条件运算符:三目运算符?:
  • 扩展运算符

自增运算++

自减运算符--

package

阿里巴巴开发手册

javaDoc生成手册

Scanner对象 获取用户的输入

Scaner s = new Scanner (System.in);

next()和nextLine()方法获取输入的字符串

读取前用hasNext()和haseNextLine()是否有之前输入的数据

main(){
    Scaner s = new Scanner (System.in);
    if(s.hasNext()){
        String ss =s.next();
        syso("输出的内容是"+ss);
    }
    //关闭流
 s.close();
}

next()输入的是遇到的空白会去除,不能代有空白的字符

进阶:hasNextInt();

  • 单选泽

  • 双选择

  • if的多选择

  • if的嵌套选择

  • switch的多选择

    • case
    • break
    • default
  • while

  • do….while

  • for循环

jdk5 增强型的for循环

break、countinue

goto关键字

方法头----方法体

  • 修饰符

  • 返回值

  • 返回值类型

  • 参数类型

    • 形参
    • 实参
  • 方法体

  • 方法名相同

  • 参数不同

  • 返回值可以不同

  • 仅仅返回类型不同不能成为方法的重载

命令行执行的

javac编译

java运行要在src下面才能运行

jdk1.5之前

  • (double… i)这样就能输入多个 i
  • 每一个方法中只能指定一个可变参数,它必须是最后一个参数

A方法自己调用自己

  • 递归头

  • 递归体

    if(n==1){
    return 1;
    }else{
    return n*f(n-1);
    }

  • 相同的数据类型的数据集合

  • 按照一定的先后次序排列组合

  • 通过下标来访问他们

声明---创建

  • 建议 String[] a;

  • String a [];//c 和c++才有不专业

    String [] a =new int [10];
    a[i]--取值

数组的默认初始化

  • 数组是引用类型,他的元素相当于类的实例变量,因此数组一经过分配空间,其中的每个元素也按照实例变量同样的方式被隐藏初始化
  • 静态初始化::栈
  • 动态初始化::栈和堆

基本特点:

  • 数组的长度是确定的
  • 元素必须是相同的类型
  • 数组的元素可以是任何的数据类型
  • 数组变量属于引用类型
  • 数组本身是对象,java的对象是在堆中的,数组对象是在堆中的
  • 下标的合法区间[0,n-1]
  • 数组也是对象,数组的元素属于成员变量
  • 数组的长度是确定的,不可变,不能越界

数组的使用:

int[] a ={1,2,3,4,5};
//打印全部的数组元素
for(int i-0;i<a.length;i++){
    syso.(a[i]);
}
//计算所有元素的和
int sun=0;
for(int i-0;i<a.length;i++){
    //sum=sun+a[i]
    sun+=a[i];
}
//查找最大值
int max=arry[0];
for(int i-1;i<a.length;i++){
    if(array[i]>max){
        max=array[i];
    }
}
//增强的for循环  但是取不到下标
for(int array :a){
    syso(a);
}
//反转数组
int[] result new int[a.length];
for(int i-1;j<result.length;i<a.length;i++;j--){
     result[j]=a[i];
}

多维数组:

int[][] a={{1,2,3},{1,2,3},{1,2,3}};


遍历
for(int i=0;i<a.length;i++){
    for(int j=0;j<a[i].length;j++){
        syso.(a[i[j]]);
    }
}

对象Arrays

java.util.arrays

int[] a ={1,2,3,4,5};

static修饰可以直接用

  • 打印数组的元素

    Arrays.toString(a);

  • 排序

    Arrays.sort(a);//升序

  • 赋值

    fill方法
    Arrays.fill(a,0);

  • 比较

    比较equals方法 //比较数组的元素是否相等

  • 查找

    binarySearch能对排序好的查找进行二分查找

  • 记录数组一共有几行几列,有多少个不同值

  • 把具有不同值的元素和行列及值记录在一个小的规模的数组中,从而缩小小程序的规模

    int[][] array =new int[11][11];
    array[1][5]=10;
    array[5][5]=5;
    //获得有效值的个数
    int sum =0;
    for(int i=0;i<array.length;i++){
    for(int j=0;j<array[i].length;i++){
    if(array[i][j]!=0){
    sum++;
    }
    }
    }
    //创建稀疏数组
    int [][]array2 =new int[sum+1][3];
    array2[0][0]=11;
    array2[0][1]=11;
    array2[0][2]=sum;
    //遍历二位数组,将非零的值存放在数组中
    int count =0;
    for(int i=0;i<array.length;i++){
    fro(int j =0;j<array[i].length;j++){
    if(array[i][j]!=0){
    count++;
    array2[count][0]=i;
    array2[count][1]=j;
    array2[count][2]=array[i][j];
    }
    }
    }

  • 冒泡排序 O(n2)

    for(int i=0;iarray[j]){
    temp=array[j];
    array[j]=array[j+1];
    array[j+1]=temp;
    }
    }
    }

  • 选择排序

    for(int i =0;iarr[j]){
    int tem = arr[i];
    arr[i]=arr[j];
    arr[j]=tem;
    }
    }
    }

  • 二分查找(前提是拍好序列)

  • new的对象
  • 数组
  • 可以被所有的线程所共享的,不会存放别的对象的引用

  • 存放基本的变量类型
  • 引用的对象的变量

方法区

  • 可以被所有的线程共享
  • 包含了所有的clss和static变量

oop

对于描述复杂的事物,为了从宏观上把握,从整体上合理的分析,我们需要使用面向对象的思想来分析整个系统。但是在微观操作上,仍然需要面向过程的思想去处理

本质:已类的方式组织代码,已对象的组织(封装数据)

特征:

  • 封装
  • 继承
  • 多态

方法的调用、值传递、类和对象的关系

类是一种抽象的数据类型,但是不能表示一种具体的事物

对象是抽象的概念的具体实例

new 创建对象

类:

  • 属性
  • 方法

抽象的类要实例化

构造方法:

  • 必须和类的名字相同
  • 必须没有返回值

new的内存分析:

。。。。

封装:

  • 属性私有,get/set

高内聚,低耦合

继承

java类中只有单继承,没有多继承

extends

  • 继承是类和类之间的关系,类之间的关系好友依赖,组合,聚合
  • 继承是两个类的关系 源生类 派生类
  • 子类和父类之间有is a关系
  • Object
  • super
  • 方法的重写

Super方法

super.父类的方法直接写就行了

this当前类的

调用构造器只能在第一行

默认调用父类的构造器

如果父类没有无参的构造,子类也无法写无参的构造

子类的代码会隐藏父类的无参的构造

注意

  • super调用父类的构造方法,必须在构造方法的第一个
  • super必需只能出现在子类的方法或者构造方法中
  • super和this不能同时使用

前提:

  • this本身调用者这个对象
  • super:代表父类对象的应用

构造方法:

  • this()本身的构造
  • super父类的构造

重写@Override

  • 非静态的
  • 私有的不行
  • 方法名必须相同
  • 参数列表相同
  • 修饰符可以扩大
  • 重写可能会抛出异常,异常可以缩小不能扩大

public》protected》Default》private

多态

动态编译

interface implements

存在的条件:

  • 有继承关系
  • 子类重写父类的方法
  • 父类的引用指向子类对象

父类的应用指向子类

B b =new A();

class A extends B;

注意事项:

  • 多态是方法的多态,属性没有多态
  • 父类和子类,有联系 类型转换异常ClassCastException
  • 存在条件。。。。。前面有

方法要被重写--多态:

不能重写的

  • static属于类,不属于实例
  • final 修饰的无法 在常量池内
  • private修饰的

instanceof 判断一个数据的类型

x instanceof y;

x和y之间是否有父子关系

类型转换,子类的方法要类型转换。

子类----父类 ---向上转型

父类---子类------强制转换

private static int a;//多线程
private int b;

静态变量在一个特别的区里面;

public static run(){

}
public go(){

}
  • 静态方法只能静态方法
  • 静态方法随着类加载生成
  • 可以直接使用(静态代码块)

静态代码块static{}------匿名代码块{}-----构造方法

静态导入包

import static java.lang.PI;

被final定义的类不能被继承----断子绝孙

abstract:

抽象类的子类要实现抽象类的所有的方法;

extends

但是是单继承

  • 不能new抽象类,只能那子类去实现它:约束
  • 抽象类里面可以放普通方法
  • 抽象方法必须放在抽象类里面

interface implements

  • 只有规范,面向接口编程

接口的本质是契约

接口的方法都是public abstratact 的

  • 类实现接口必学实现接口中的方法
  • 接口里面的变量是常量public static final

接口不能实例化,没有构造方法

  • 成员内部类

  • 静态内部类

  • 局部变量

  • 匿名内部类

    public Class outer{
    private int id;
    public void out(){
    syso(“外部类”)
    }
    //内部类可以获得外部类的私有属性和方法
    public class Inner{
    public void in(){
    syso("内部类");
    }
    }
    }

    //内部类
    Outer out =new Outer();
    Outer.Innter inner= out.new Inner();

静态内部类:

public Class outer{
    private int id;
    public void out(){
        syso(“外部类”)
    }
    //内部类可以获得外部类的私有属性和方法
    public static class Inner{
        public void in(){
        syso("内部类");
            //这里就拿不到外部类的变量的值了,静态内部类无法访问静态方法
}
    }
}

局部内部类:

在方法里面写内部类:

public Class outer{
    private int id;
    public void out(){
        syso(“外部类”)
            public class Inner{
        public void in(){
        syso("内部类");
}
    }
    }
}

一个java里面可以写多个class类

class a{}
class b{}

匿名内部类:

接口 a = new 接口(){
    @Override
    方法
}
  • 异常是指运行中出现不预期的各种状况
  • 异常发生在程序运行期间,他影响了正常的执行流程

异常分为:

  • 检查性异常
  • 运行时异常
  • 错误Error

java.lang.Throwable 超类

  • ArrayLndexOutOfBoundsException 数组线标越界
  • NullPointerExceotion空指针异常
  • ArithmeticException算数异常
  • MissingResourceException 丢失资源
  • ClassNotFountException找不到类等异常

抛出异常:

捕获异常

关键字:

try catch finally throw throws

throw new ArithmeticException();//抛出一个异常
//一般在方法中使用,加入这个方法处理不了这个异常,就抛出异常
public void a throws ....

自定义异常

public ex extends Exception{
    //传递数字》10
    private int detail;
    public ex (int a){
        this.detail = a;
    }
    @Override
    public String toString(){
    return "myex{"+detail+"}";
}
}


throw new ex();

javaEE

常用API

  • public String toString() //打印地址 :类的全类名@内存地址

    • 存在的意义:为了被子类去重写,以便于返回对象的内容信息,而不是地址信息
  • public Boolean equals()//默认比较两个对象的地址是否相同

    public  Boolean equals(Object o){
       // 1.不是同一个对象比较
        if(this==0) return true;
        //o是不是null
        if(o==null||this.getClass()!=o.getClass()) return false;
        //o一定是Student类型不是null
        Student student =(Student) o;
        return sex==student.sex&&age==student.age&&Object.equals(name,student.name);
    }

可变的字符串类,看成一个对象容器

提高效率,如凭借、修改

1.构造器:

  • public StringBuilder()
  • public StringBuilder(String str)

2.常用方法

  • public StringBuilder append(任意类型) 添加数据并返回StringBuilder 对象本身

  • public StringBuilder reverse() 将对象的内容反转

  • public in length() 返回对象的长度

  • public String toString() 通过toString() 就可以实现StringBuilder 转换为String

    //例子
    public static String toString(int[] arr){
    if(arr!=null){
    StringBuilder sb =new StringBuilder ("[");
    for(int i =0;i<arr.length;i++){
    sb.append(arr[i]).append(i==arr.length-1?"":",");
    }
    //这里不能少;恒优雅
    sb.append("]");
    return sb.toString();
    }else{
    return null;
    }
    }

没有提供公开的构造器、工具类

全部是静态方法

  • public static int abs(int a) 获得绝对值
  • public static double ceil (double a) 向上取整
  • public static double floor(double a) 向下取整
  • public static int round(float a) 四舍五入
  • public static int max(int a,int b) 获得两个int 的较大值
  • public static double pow(double a,double b) 返回a 的幂
  • public static double random() 返回double的随机数【0.0,1.0)

System类的功能是相同的,都是直接用类名调用即可

System的方法:

  • public static void exit(int status) 终止当前的java虚拟机,非0表示异常的终止
  • public static long currentTimeMillis() 返回当前系统的事件毫秒值形式
  • public static void arraycopy (数据源数组,启始索引,目的地数组、起始索引、拷贝个数) 数组拷贝

解决浮点型的精度失真

public static BigDecima valueOf(double val); 包转成浮点对象为BigDecima对象

  • public BigDecima add(BigDecima b)加法
  • public BigDecima subtract(BigDecima b)减法
  • public BigDecima multiply (BigDecima b)乘法
  • public BigDecima divide (BigDecima b)除法
  • public BigDecima divide(舍入模式)除法

Date类在当前系统所在的此刻的日期时间

java.util.Date

Date time =new Date();
  • public long getTime() 获取对象的毫秒值1970.1.1.00.00

    long time =System.currentTimeMillis();

  • 毫秒值转变成日期对象

    public Date(long time);

    public void setTime(Long time)

设置日期对象的事件为当前的时间毫秒值的时间

SimpleDateFormat构造器

  • public SimpleDateFormat() 默认格式
  • public **SimpleDateFormat(String pattern)指定格式

SimpleDateFormat的格式化方法

  • public final String format(Date date) 将日期格式化成日期/时间字符串

  • public final String format (Object time)将时间毫秒值转化为日期/时间字符串

  • public Date parse(String source) 从给定字符串的开始解析文本以生成日期

    y 年
    M 月
    d 日
    H 时
    m 分
    s 秒

yyyy-MM-dd HH:mm:ss

Date d =new Date();
SimpleDateFormat sdf =new SimpleDateFormat(yyyy-MM-dd);
String s =sdf.format(d);



String s ="2022年05月06日 14:55:60"
SimpleDateFormat sdf =new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date d =  sdf.parse(s);
long time =d.getTime()+(2L*24*60*60+14*60*60+49*60+6)*1000;
sdf.format(time);
  • Calendar代表系统此刻日期对应的日期对象

  • Calendar是抽象类,不能直接创建对象

    Calendar cal =Calendar.getInstance();
    //先获取字段 syso (cal)
    int year =cal.get(Calendar.YEAR);
    int moth =cal.get(Calendar.MONTH);
    int days=cal.get(Calendar.DAY_OF_TEAR);
    cal.set(Calendar.HOUR,12);//一般不会修改日历
    //64天后的日期
    cal.add(Calendar.DAY_OF_TEAR,64);

  • LocalDate:不包含具体时间 2022-05-06getYear()\ getMonth()\getDayofMonth、getDayofYear、getDayofWeek、getMonth().getValue()、getMonthValue()

  • LocalTime:不包含日期时间

  • LocalDateTime:包含了日期时间

  • Instant代表的是时间戳得到的是标准时间英国

  • DateTimeFormatter用于做时间的格式化和解析

  • Duration用于计算时间的间隔

  • Period用于计算两个日期的间隔

和String类似

  • public static Xxxx now();静态方法,当前时间创建对象
  • public static Xxxx of(…..);静态方法,指定时间创建对象

8种数据类型的引用类型

byte-----Byte

short ------Short

int ------Integer

char----Character

float----------Float

double-------Double

boolean---Boolean

long------Long

  • 为了实现一切皆对象
  • 后面的集合和泛型只能支持包装类型,不支持基本数据类型

自动拆箱:包装类的变量可以直接赋值给基本数据类型

自动装箱:基本类型的数据和变量可以直接赋值给包装类的变量

特有功能:

  • 包装类的变量的默认值可以是null 容错率更高

  • 基本数据类型变成字符串

    • 调用toString()方法
    • Interger.toString(基本数据类型的数据)
  • 可以把字符串的数值变成真实的数据类型

    • Interger.parseInt("字符串类型的整数");

    public static boolean checkQQ(String s){
    if(s==null||s.length()<6||s.length()>20){
    return false;
    }
    //判断是否全为数字
    for(int i=0;i<s.length();i++){
    char ch = s.charAt(i);
    if(ch<'0'||ch<'9'){
    return false;
    }
    }
    return true;
    }

    //简化正则
    public static checkQQ(string s){
    return s!=null&&s.matches("\d{6,20}");
    }

  • 字符类

    • [abc]
    • [a-zA-z]
    • [a-z&&[^ m-p]]

默认匹配一个字符

预定义的字符集:

  • . 任何字符
  • \d 一个数字:[0-9]
  • \D 非数字
  • \s 一个空白的字符
  • \S 非空的字符
  • \w 英文数字下划线
  • \W 一个非单词字符

匹配多个字符

  • X? 一次或根本不
  • X* 零次或多次
  • X{n} 正好n次
  • X{n, }至少n次
  • X{n,m} 至少n次但不超过m次

public boolean matches (String regex);

//例子
String ss ="........"
//1.写正则:
String regex =""
//2.把爬取的规则编译成对象
    Pattern pa =Pattern.compile(regex);
//3.得到一个内存匹配的对象
Matcher ma = pa.matcher(ss);
//开始查找
whil(matcher.find()){
    String rs = matcher.group();
}

Arrays

数组的工具类:

  • public static String toString(类型[] a) 对数组进行排序

  • public static void sort (类型[] a) 对数组进行默认升序排序

  • public static void sort(类型[] a,Comparatorc) 使用比较器对象自定义排序

  • public static int binartSearch(int [] a,int key) 二分搜索数组中的数据,存在返回索引,不存在返回-1**-(插入的位置的索引+1)

    int[] a={1,2,3,5,6,10};
    Arrays.方法(a);

    //比较器
    Integer [] ages={1,2,3,4,5,6};
    Arrays.sort(ages,new Comparayor(){
    @Override
    public int compare(Integer o1,Integer o2){
    //指定比较规则
    return -(o1-o2);
    }
    })

  • 认为左边数据 大于 右边数据 返回正数

  • 认为左边数据 小于右边数据 返回负数

  • 认为左边数据 等于 右边数据 返回 0

Lambada表达式

只能简化函数接口的匿名内部类,一个抽象方法,

懒汉

  • 参数类型可以省略不写
  • 如果只有一个参数,参数类型可以省略,同时()也就可以省略
  • 如果lambda表达式的方法代码只有一行代码,可以省略大括号,同时省略分号
  • 如果lambda的方法体的代码只有一行代码,如果还是return语句,必须省略return,也不写;

作用简化匿名内部类的简化代码

(匿名内部类的重写的形参列表)->{

​ 被重写的方法

}

//简化匿名内部类的代码
@FunctionalInterface
public interface aaa{
    public void run();
}



main(String[] args){
aaa a =()->{
    syso("Lambada的方法");
}
}


go(()->{
       syso("Lambada的方法");
})

Collection集合体系

集合和数组都是容器。

  • 数组定义完后,类型确定,长度固定。
  • 数组增删都要放弃原有的数组或者移位

集合:

  • 大小不确定
  • 存储对象的一种容器
  • 非常适合做增删改查
  • 基本的数据类型用包装类

Collection单列:每个元素只包含一个值

Map双列:j键值对

Collection是一个接口:

  • List

    • ArrayList
    • LinkedList
  • Set

    • HashSet

      • LinkedHashSet
    • TreeSet

Collection集合特点:

  • List集合:添加的元素是有序、可重复、有索引

    • ArrayList、LinkedList:有序、可重复、有索引
  • Set集合特点:添加的元素是无序、不重复、无索引

    • HashSet:无序、不重复、无索引;LinkedHashSet:有序、不重复、无索引
    • TreeSet:按照大小默认升序,不重复,无索引

    Collection c =new ArratList();//约束数据类型
    Collection c =new ArratList<>();//JDK1.7后可以不写

add() 添加

  • 添加元素add()
  • 清空集合clear()
  • 判断集合是否为空isEmpty()
  • 获取集合的大小size()
  • 判断集合中的元素是否存在contains()
  • 删除集合中的元素remove() 默认只会删除前面的一个,要删除所有的要边遍历,边判断删除
  • 把集合变成数组Object[] a = array.toArray();

1.迭代器:

  • 遍历就是一个一个的把容器中的元素访问一遍
  • 迭代器在java中的代表是Iterator,迭代器是集合的专用的遍历方式

获取结合的迭代器:

Collection<String> sc =new ArrayList<>();
sc.add("我");
sc.add("是");
sc.add("大");
sc.add("佬");
sc.add("!");
//1.获得迭代器
Iterator<String> it =sc.iterator();
while(it.hasNext()){
    String a=it.next();
}

用一次,取一次越界会有越界异常

2.forEach遍历

  • 既可以遍历集合也可以遍历数组内部是迭代器,但是迭代器不能遍历数组
  • 实现了Iterator接口才能使用

格式:

for(元素数据类型 变量名:数组或者Collection集合){

​ 在此用变量即可,该变量就是元素

}

Collection<String> list =new ArrayList<>();
....
for(String it:list){
    syso(it);
}

3.lambda表达式

  • default void forEach(Consumer action) 结合lambda遍历集合

    list.forEach(new Cousumer(){
    @Overrride
    public void accept(String s){
    System.out.print(s);
    }
    })

栈:

后进先出、先进后出

  • 进入栈:压/进栈
  • 出栈:弹

队列

先进先出,后进后出

  • 入队列
  • 出队列

数组

  • 查询速度快,查询数据通过地址值和索引定位,查询任意诗句的耗时相同。(元素中在内存中是连续存储的)
  • 删除效率低:要将原始数据删除,同时后面的每个数据前移
  • 添加效率极低:添加位置后的每个数据后移,再添加元素

链表

链表中的元素是游离存储的,每个元素的节点包含数据值和下一个元素的地址

  • 链表的查询慢,无论查哪个数据都是从头开始
  • 链表的增删较快

单向链表

双向链表(java多用)

二叉树

父节点:左右节点、值

  • 只能有一个根节点
  • 节点的度
  • 高度
  • 兄弟节点

二叉查找树

目的:提高检索数据的性能

会变成瘸子

平衡二叉树

任意节点的左右两个自树的高度不超过1,任意节点的左右的两个自树都是一颗平衡二叉树

  • 进行左旋或者右旋

情况:左边高右边拉,右边高左边拉

红黑树

平衡二叉B树

  • 每个节点是红色或者是黑色,根节点是黑色
  • 如果一个节点没有子节点或者父节点,则该节点相应的指针值为Nil,这些Nil视为叶节点,叶节点是黑色的
  • 如果一个节点是红色的,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
  • 对于每个节点,从节点到所有的其所有的后代叶子节点的简单路径上,均包含相同的黑色节点

添加节点:

  • 添加节点可以黑色可以红色
  • 默认红色效率高

牛逼红黑树

  • ArrayList、LinedList:有序、可重复、有索引
  • 有序:存储和取出的元素顺序是一致的
  • 有索引:可以通过索引操作元素
  • 可重复:存储的元素可以重复操作

特有方法:

  • void add(int index,E element) 在集合中的指定位置插入指定的元素

  • E remove(int index) 删除指定索引出的元素,返回被删除的元素

  • E set (int index, E element)修改指定索引处的元素,返回被修改的元素

  • E get ( int index) 返回指定索引处的元素

    //多态
    List arr =new ArrayList<>();
    arr.add("Java");
    arr.add("Mybatis");
    arr.add("Mysql");
    //特有
    arr.add(2,"HTML");
    arr.remove(2);
    arr.get(2);
    arr.set(1,"springboot");

遍历方式:

通用的遍历方式都可以

ArrayList的底层原理:

基于数组实现

  • 在底层先创建一个10的默认数组
  • 有一个size指针指向下个位置--------现在的数组的长度
  • 扩容1.5倍,元素重新迁移

LinkedList的底层原理:

基于双链表,查询慢,首尾操作快,但是查询很慢

特有方法:

  • public void addFirst(E e) 在该列表的开头插入指定的元素push()

  • public void addLast(E e)将指定的元素追加到此列表的末尾pop()

  • public E getFirst()返回此列表中的第一个元素

  • public E getLast()返回此列表的最后一个元素

  • public E removeFirst()从此列表中删除并返回第一个元素

  • public E removeLast()从此列表中删除并返回最后一个元素

    //栈
    LinkedList stack =new LinkedList<>();
    stack.addFirst("java");
    stack.addFirst("HTML");
    stack.addFirst("CSS");
    stack.addFirst("Spring boot");
    //删除并取出
    stack.removeFirst()
    //队列
    LinkedList query =new LinkedList<>();
    query.addLast("java");
    query.addLast("HTML");
    query.addLast("CSS");
    query.addLast("Mybatis");
    //删除并取出
    query.removeFirst()

1.使用迭代器删除当前位置的元素不后移

Iterator<String> arr =list.iterator();
while(arr.hasNext()){
    String ss= is.next();
    //list.remove(); 这是不对的,要用迭代器来用remove
    it.remove();
}

2.foreach和lambda也是有bug的

3.for会漏删

结局方案:倒着删

  • 统一数据类型
  • 把运行时间出现的错误,编译时就能出现

自定义泛型类(架构师技术)

  • 定义了类的同时定义了泛型的类就是泛型
  • 泛型的格式

修饰符class类名<泛型变量>{}

public class MyArrayList<T>{

    public void add(T t){

    }
}


MyArrayList<String> a =new MyArrayList<>();
a.add("字符串");

自定义泛型方法

格式:

public<T> void show(T t){}

接受任意类型的参数

public<T> void show(T[] t){
    StringBuilder sb =new StringBuilder("[");
    if(t==null){
        return false;
    }
    for(int i =0;i<t.length;i++){
        sb.append(t[i]).append(i==t.length-1?"":",");
    }
    sb.append("]");
    System.out.print(sb);
}

泛型接口

public interface Data<E>{}


public interface Data<E>{
    public void add(E e);
}

泛型的通配符

  • ?可以在使用泛型时代表一切类型

  • E T K V是在定义泛型时使用

    go(ArrayList a){}

  • ?extends Car:必须是Car或者其子类 泛型上线

  • ?super Car:必须是Car或者是器父类 泛型下限

  • HashSet

    • LinkedHashSet
  • TreeSet

特点:

  • 无序行:存取的顺序不一致
  • 不重复:可以去重复
  • 无索引:没有带所有的方法

HashSet:无序、不重复、无索引

LinkedHashSet:有序、不重复、无索引

TreeSet:排序、不重复、无索引

//多态
Set<String> s =new HashSet<>();
//使用Collection的API
s.add("JAVA");
s.add("HTML");

HashSet:

采取的是哈希表组成

  • JDK8以前是数组和链表
  • JDK8以后数组+链表+红黑树

哈希值

  • JDK根据对象的地址,按照某种规则算出来的int类型的数值

    String name ="我";
    name.hashCode();--------得到哈希值

JDK1.7

  • 先创建一个16长度的数组 ---table
  • 根据元素的哈希值和数组的长度求余数,计算出应存入的位置(哈希算法)
  • 当前位置为null直接存入
  • 如果不为null用equals方法比较
  • 一样则不存,不一样则存入数组
    • JDK7中新元素占用老元素的位置,指向老元素
    • JD8中新元素挂在老元素下面,当长度超过8变为红黑树
  • 每次扩容为原来的2倍

先算hashCode哈希值然后在equals比较。

LinkedHashSet:

底层的机制依然是哈希表,但是每个元素又多了一个双链表的机制记录存储的顺序

  • 有序 不重复 无索引

TreeSet

  • 不重复 无索引 可排序

Tree集合基于红黑树的数据结构实现排序

按照大小排序,string 按照首字符的编号排序

方法一:

//实现Comparable接口
重写里面的compareTo方法实现排序

方法二:

Tree集合有参的构造器,实现对应的Comparable的对应的比较器,来制定比较规则

区分方法

希望元素可以重复,又有索引,索引查找快

  • ArrayList

希望元素可以重复,又有索引,增删首尾

  • LinkedList

如果希望增删改查都很快,但是元素没重复,无序、无索引

  • HashSet

可变参数

  • 可变参数的格式

    数据类型…参数名称

    main(String[] args){
    run();
    run(1,2,3,4);
    run(new int[]{10,20,30})
    }
    public static void run (int… nums){
    //外面看见的是一个参数,实际上是数组
    Arrays.toString(nums);
    }

  • 一个形参列表中只能有一个可变参数

  • 可变参数只能在最后

java.util.Collections:是集合的工具类

作用:Collections并不属于集合,是用来操作集合的工具类

常用的api

  • public static boolean addAll(Collection c,T… elements) 给集合对象添加元素
  • public static void shuffle(List list) 打乱集合元素的顺序

排序:

  • public static static void sort(List list) 将集合中元素按照默认规则排序

  • public static void sort (List list,Comparatorc) 将集合中的元素按照指定的规则排序

    List list =new ArrayList<>();
    Collection.addAll(list,23,5,6,4);
    Collection.sort(list);

  • 实现ComparaTo接口 实现compare方法

Map集合体系

双列集合体系

key=value(键值对集合)

  • Collection集合格式:[元素1,元素2,元素3]
  • Map集合格式:

Map

  • HashMap

    • LinkedHashMap
  • TreeMap

  • HashTable

    • Properties
  • Map集合的特点都是由键决定的

  • Map的集合的键是无序的,不重复的,无索引的,值可以重复

  • Map集合后面重复的键对应的值会覆盖前面重复的值

实现类的特点:

  • HashMap:元素按照键是无序的、不重复的、无索引的、值不做要求。(与Map体系一样)

  • LinkedHashMap:元素按照键是有序的,不重复的,无索引的,值不做要求

  • TreeMap 元素是按照键是排序的,不重复,无索引的,值不做要求

  • V put (key , V value) 添加元素

  • V remove (Object key) 根据键值对删除对应的元素

  • void clear() 移除所有的键值对

  • Boolean containsKey(Object key)判断集合是否包含指定的键

  • Boolean containsValue(Object value) 判断集合是否包含对应指定的值

  • Boolean isEmpty() 判断集合是否为空

  • int size() 集合的长度也就是集合中的键值对的个数

  • V get(Object key) 根据键得到对应的值

  • Set keySet() 获得全部的键的集合

  • Collection values(); 获得全部值的集合

  • putAll(Map a)合并其他的Map集合

1.键找值

...
Map<string,Integer> s = new HashMap<>();
....
Set<String> keys =s.keySet();
for(String key:keys){
    int value=s.get(key);
    syso(value);
}

2.键值对流程

先把Map集合转化成Set集合,Set集合中的每个元素都是键值对的实体类型了

遍历Set集合,然后提取键以及提取值

  • Set >entrySet() 获得所有的键值对

  • K getKey() 获得键

  • K getValue() 获得值


    Map s = new HashMap<>();
    ….
    //把Map集合变成Set集合
    Set> entries = s.entrySet();
    for(Map.Entry entry :entries){
    String key =entry.getKey();
    String value =entry.getValue;
    }

3.lambda

  • default void forEach(BiConsumer action) 结合lamdba 遍历

    maps.forEach( new BiConsumer(){
    @Overrride
    public void accept(String key,Integer value){
    syso(key------value)
    }
    })

  • 无序、不重复、无索引

  • 底层:哈希表 依赖hashCode和equals来判断键唯一

Set系列集合的底层就是Map实现的,只是Set集合中的元素只要数据,不要键而已

  • 有序、不重复、无索引

  • 底层是:哈希表和双链表

  • 不重复、无索引、可排序

  • TreeMap的底层和TreeSet的底层原理是一样的

自定义排序:

  • 类实现Comparable接口
  • 自定义Comparator比较器对象,重写比较规则

统计投票人数:

Stream流

简化集合和数组操作的API

List<String> list =new ArrayList<>();
Collection.addAll(list,"张1","张2","王");
 List<String> list2 -new ArrayList<>();
 for(String name:list){
    if(name.startsWith("张“)){
        list.add(name);
    }
}



list.Stream().filter(s->s.startsWith("张").filter(s->slength()==2)).forEach(s->System.out.print(s));

技术思想:

  • 先得到一个集合或者数组的Stream流

  • 把元素放到传送带上

  • 然后就使用Stream流简化API来操作元素

  • 集合获得Stream流的方式

    • 可以用Collection接口中的默认方法Stream()

default Stream stream() 获得当前集合对象的Stream

  • 数组获得Stream流的方式
  • public static Stream stream (T[] array) 获取当前数组的Stream流
  • public static Stream of(T…values) 获得当前的数组/可变数据的Stream流

日志技术

  • 将系统执行的信息选择性的输出到指定的位置

  • 多线程

  • 日志规范

  • 日志框架(JCL slf4j

    • log4j 性能不好
    • JUI
    • Logback加强
  • logback-core:为其他的模块提供了基础,必须有

  • logback-classic 他是log4j的一个改良版本,同时它实现了slf4j的api

  • logback-access模块和tomcat和jetty等servlet容器集成,已提供http访问日志功能


    <contextName>logback</contextName>
    
    <property name="log.path" value="F:\\logback.log" />
    
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- <filter class="com.example.logback.filter.MyFilter" /> -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
              <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n
            </pattern>
        </encoder>
    </appender>
    
    <appender name="file"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
        </rollingPolicy>
    &lt;encoder&gt;
        &lt;pattern&gt;%date %level [%thread] %logger{36} [%file : %line] %msg%n
        &lt;/pattern&gt;
    &lt;/encoder&gt;
    </appender> <root level="debug"> <appender-ref ref="console" /> <appender-ref ref="file" /> </root> <logger name="com.example.logback" level="warn" />

创建logback的日志对象

public static Looger LOGGER=LoggerFactory.getLogger("Test.class");


LOGGER.debug("main方法开始");
LOGGER.info("我记录的日志第二行");
LOGGER.trace("a="+a);
LOGGER.error("有错误");

输出到控制台:

..

日志级别

trace<debug<info<warn<error

File、方法递归、IO流

  • File类可以定位文件:进行删除、获取文件本身的信息

    • 但是不能读写文件内容
  • IO流可以对硬件中的文件读写

    字节流--音乐视频文件

    字符流---文本文件

java.io.File 代表操作系统的文件对象(文件、文件夹)

  • 定位文件
  • 获取文件本身的信息
  • 删除文件
  • 创建文件

常用方法:

  • public File(String pathname) 根据路径创建文件对象

  • public File (String parent, String Child) 从父路径名字字符和子路径名字字符创建文件对象

  • public File (File parent , String Child) 根据父路径对应文件对象和子路径名字字符串创建文件对象

    main(){
    //创建File对象
    //路径写法:D:\hjz\a.jpg
    // D:/hjz/a.jpg
    //File.separator 分隔符
    //相对路径 相对到工程下 "sprngboot/src/data.txt"
    File f = new File("D:\hjz\a.jpg");
    Long a =f.length();//文件的字节大小
    f.exists()//判断文件夹是否存在
    }

方法:

  • public boolean isDirectory () 测试 抽象路径名表示的File是否为文件夹

  • public boolean isFile()测试 抽象路径名表示的File是否为文件

  • public boolean exists()测试 抽象路径名表示的File是否存在

  • public String getAbsolutePath()返回的抽象路径名的绝对路径名字符串绝对路径

  • public String getPath()将此抽象路径名转化为路径名字符串自己定义的路径

  • public String getName()返回由此抽象名表的文件或文件夹的名称

  • public Long lastModified()返回文件最后修改的时间的毫秒

    File f = new File("D:\hjz\a.jpg");

方法:

  • 创建:

    • public boolean createNameFile() 创建一个新的空白文件夹
    • public boolean mkdir()创建一个一级文件夹
    • public boolean mkdirs()创建一个多级文件夹
  • 删除:

    • public boolean delete() 删除由此路径表示的文件、空文件夹

删除非空文件夹要写算法

遍历:

  • public String[] list() 获取当前目录下所有的一级文件夹名称“到一个字符串数组中去返回

  • public File[] listFiles()常用 获取当前目录下所有的“一级文件对象”到一个文件对象数组中去返回重点

    • 不存在返回null
    • 调用者是文件返回null
    • 调用者是一个空文件夹返回一个长度为0的数组
    • 调用者是一个有内容的文件夹时,将里面的所有文件和文件夹的路径放在File数组中返回
    • 包含隐藏内容

    File f =new File("D://")
    File[] names=f.listFiles();
    for(File url:names){
    syso(url.getAbsolutePath);
    }

1.递归公式

2.递归的终结点

3.递归的方向

1-n的阶乘

public static int f(int n){
    if(n==1){
        return 1;
    }else{
        return f(n-1)*n;
    }
}

1-n的和

public static int f(int n){
    if(n==1){
        return 1;
    }else{
        return f(n-1)+n;
    }
}

猴子吃桃子

/**
        f(x)-f(x)/2-1=f(x+1)
    等价变化:
        f(x)=2f(x+1)+2
    终点
    f(10)=1
*/
public static int f(int n){
    if(n==10){
        return 1;
    }else{
        return 2*f(n+1)+2;
    }

}

文件搜索

1.先定位一级文件对象

2.遍历一遍一级文件对象,判断是否文件

3.如果是文件,判断是否是自己想要的

4.如果是文件夹,需要继续递归进去重复上面的过程

public static void searchFile(File dir,String name){
    if(dir!=null&&dir.isDirectory){
        //可以找了
        //获得一级文件对象
        File[] files=dir.ListFiles();
        //判断一级文件夹的对象
        if(files!=null&&files.length>0){
            for(File f:files){
                //判断当前遍历的一级文件对象是文件还是目录
                if(file.isFile()){
                    //是不是要找的文件
                    if(file.getName().contains(name)){
                        System.out.print("找到了文件是"+file.getAbsolutePath());
                            //启动它
                            Runtime r =Runtime.getRuntime();
                        r.exe(file.getAbsolutePath());
                    }else{
                        //是文件夹继续递归调用
                        searchFile(file,fileName);
                    }
                }
            }
        }
    }else{
        System.out.print("当前搜索的不是文件夹");
    }
}

啤酒问题

盖子换酒,瓶子换酒(套娃)

//买的一共酒
public static int totalNumber;
//记录瓶子的数量
public static int lastBottleNumber;
//记录剩余的盖子数目
public static int lastCoverNumber;
public static void buy(int money){
    int buyNumber = money/2;
    totalNumber+=buyNumber;
    //换成钱
    int coverNumber = lastCoverNumber+ buyNumber;
    int bottleNumber=lastBottleNumber+buyNumber;
    //统计一共多少钱
    int allNumber=0;
    if(coverNumber>=4){
        allNumber+=coverNumber/4*2;
    }
    lastCoverNumber=coverNumber%4;
    if(lastBottleNumber>=2){
        allNumber+=(bottleNumber/2)*2
    }
    lastBottleNumber = bottleNumber%2;
    if(allNumber>=2){
        buy(allNumber);
    }
}

IO流

  • 计算机底层不能存储字符,只能存储0 1
  • 二进制转化成十进制

ASCII字符集

  • 美国信息交换标准代码:128个字符信息一个字节存储1个字符、一个字节是8位256

GBK字符集

  • 包含了几万个汉字繁体字和日韩文字、兼容ASCII字符编码表一个中文用两个字节

Unicode码表

  • 统一码是计算机科学领域栗的一项业界字符编码UTF-8(中文是以3个字节)\UTF-16

编码前的字符集和编码好的字符集要相同,不然会应为不同的字符位数错误

  • byte[] getBytes()使用平台的默认字符集将String编码为一系列字节,将结果存储到新的字节数组中

  • byte[] getBytes(String charsetName)使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

  • String(byte[] bytes)通过平台的默认字符集解码在指定的字节数组构造新的String

  • String(byte[] bytes,String charsetName)通过指定的字符集解码指定的字节数组来构造新的String

    String s ="abc我爱你中国";
    byte[] bytes = s.getBytes();//默认编码
    byte[] bytes = s.getBytes("GBK");
    String ss=new String(bytes);//默认编码
    String ss=new String(bytes,"GBK");

IO流:输入输出流读写数据

  • 字节流音乐,视频
  • 字符流文本内容

读入到内存输入流

写入到磁盘输出流

字节流:

  • InputStream

    • FileInputStream

      • public int read() 每次读一个,没有返回-1
      • public int read(byte[] buffer)每次读一个字节数组,没有返回-1
  • OutputStream

    • FileOutPutStream

      • public int write()
      • public int write(byte[] buffers)
      • public int write(byte[] buffers,int pos,int len) 写一部分

字符流:

  • Reader

    • FileReader
  • Writer

    • FileWriter

FileInputStream

  • 上面的都是抽象类

    • 实现类*水流模型

    //1.创建一个输入流管道
    //InputStream is =new FileInputStream(new File("D://…"));
    //简化
    InputStream is =new FileInputStream("D://…");
    int b =is.read();//读取一个字节,读完返回-1

    Byte[] buffer = new byte[1024];//1kb
    InputStream is =new FileInputStream("D://…");
    int len =is.read(buffer);
    String rs= new String(butter);

常用方法:

Byte[] buffer = new byte[1024];//1kb
InputStream is =new FileInputStream("D://...");
int len=0;
while((len=is.read(butter)!=-1)){
    System.out.print(new String(butter,0,len));
}

中文乱码无法解决

//自己暴力实现
Byte[] buffer = new byte[(int)file.length()];//1kb
File file =new File("D://...");
InputStream is =new FileInputStream(file);
int len=0;
while((len=is.read(butter)!=-1)){
    System.out.print(new String(butter,0,len));
}


Byte[] buffer = is.readAllBytes();//JDK9出现
File file =new File("D://...");
InputStream is =new FileInputStream(file);
int len=0;
while((len=is.read(butter)!=-1)){
    System.out.print(new String(butter,0,len));
}

FileOutPutStream

//写会自动生成
OutputStream os =new FileOutPutStream("D://a.txt");
//OutputStream os =new FileOutPutStream("D://a.txt",true);  追加数据
os.write('a');
os.writ(98);
//写数据必须刷新数据
os.flush();
os.close();//关闭资源
byte[] buffer ={'a',97,98,90};
os.write(buffer);
byte[] buffer ="我是中国人".getBytes("GBK");
os.writer(buffer);
//注意是没有换行的
os.write("\r\n".getBytes());//换行

学会字节流完成文件的复制--支持一切

try{
   //创建一个字节输入流
   InputStream is =new FileInputStream("D://img.jpg");
    //创建一个字节输出流和目标文件接通
    OutputStream os =new FileOutPutStream("D://a.txt");
   //定义一个字节数组
    byte[] buffer = new byte[1024];
    int len ;记录读取数据的字节数
        while(len=is.read(buffer)!=-1){
            os.write(buffer,0,len);
        }
    //关闭流
    os.close();
    is.close();
}catch (Exception ex){
    e.printStackTrace();
}

资源释放的方式

   InputStream is=null;
   OutputStream os=null;

try{
   //创建一个字节输入流
 is =new FileInputStream("D://img.jpg");
    //创建一个字节输出流和目标文件接通
  os =new FileOutPutStream("D://a.txt");
   //定义一个字节数组
    byte[] buffer = new byte[1024];
    int len ;记录读取数据的字节数
        while(len=is.read(buffer)!=-1){
            os.write(buffer,0,len);
        }

}catch (Exception ex){
    e.printStackTrace();
}finally{
        //关闭流
    //下面都要try ---catch---try{..}catch{...}
    //非空校验 if(os!=null){os.close()}
    os.close();
    is.close();
}

JDK7:

try(
       //创建一个字节输入流
   InputStream is =new FileInputStream("D://img.jpg");
    //创建一个字节输出流和目标文件接通
    OutputStream os =new FileOutPutStream("D://a.txt");
){
   //定义一个字节数组
    byte[] buffer = new byte[1024];
    int len ;记录读取数据的字节数
        while(len=is.read(buffer)!=-1){
            os.write(buffer,0,len);
        }
    //关闭流
    os.close();
    is.close();
}catch (Exception ex){
    e.printStackTrace();
}

JDK9:

不好
  • Reader

    • FileReader
  • Writer

    • FileWriter

    Reader fr=new FileReader("D://img.txt");
    Writer fw=new FileWriter("D://a.txt");
    int code = fr.read();//每次读取一个字符 没有返回-1

FileReader

  • public FileReader(File file)
  • public FileReader(String pathname)

常用方法:

  • public int read()每次读取一个字符 没有返回-1
  • public int read(char[] buffer)每次读取一个字符数组 没有返回-1

问题:

  • 中文不会乱码
  • 性能较慢

Filewrite

  • public FileWriter(File file)
  • public FileWriter(File file,boolean append)
  • public FileWriter(String pathname)
  • public FileWriter(String pathname,boolean append)

常用方法:

  • public void write(int c)

  • public void write(char[] cbuf)

  • public void write(char[] cbuf,int off,int len)写一部分

  • public void write(String str)

  • public void write((String str,int off,int len)

  • flush()

  • close()

    Write fw =new FileWrite("D://img.jpg");
    fw.write('s');

自带缓冲区,提高原始流的性能

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter

自带了8kb的缓冲池

字节缓冲流

构造器:

  • public BufferedInputStream (InputStream is)

  • public BufferedOutputStream(OutputStream os)

    try(
    //创建一个字节输入流
    InputStream is =new FileInputStream("D://img.jpg");
    BufferedInputStream bis =new BufferedInputStream(is);
    //创建一个字节输出流和目标文件接通
    OutputStream os =new FileOutPutStream("D://a.txt");
    BufferedOutputStream ois=new BufferedOutputStream(os);
    ){
    //定义一个字节数组
    byte[] buffer = new byte[1024];
    int len ;记录读取数据的字节数
    while(len=bis.read(buffer)!=-1){
    bos.write(buffer,0,len);
    }
    }catch (Exception ex){
    e.printStackTrace();
    }

字符缓冲流:

  • public BufferedReader (Read is)
  • public BufferedWriter(Writer os)

新增输入流方法:

  • public String readLine() 读取一行数据,如果没有完毕,无行课读取返回null

输出流:

  • public void newLine() 换行操作

不同编码读取会乱码

  • 使用字符输入转换流
  • 先提取原始的字节流
  • 然后在将字节流转换成对应的编码格式

转换流:

  • InputStreamReader
  • OutputStreamWriter

构造器:

  • public InputStreamReader (InputStream is)
  • public InputStreamReader(InputStream is,String charset)

字符输出转换流:

  • public OutputStreamWriter (OutputStream os)
  • public OutputStreamWriter(OutputStream os,String charset)

对象字节输出流

ObjectOutputStream

对象字节输入流

ObjectInputStream

构造器:

  • public ObjectOutputStream (OutputStream os)

  • public ObjectInputStream (InputStream is)

    //对象系列化
    //实体类要实现接口
    Serialiazble

    Student st =new Student (…);
    ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream("D://a.txt"));
    //调用序列化方法
    oos.writeObject(st);
    oos.close();

    //对象反序列化
    ObjectInputStream ois = new ObjectInputStream(new FileOutputStream("D://a.txt"));
    //调用序列化方法
    Student st=( Student)ois.readObject(st);
    ois.close();

不想序列化

//实体类属性字段加
private transient String password;

字节输出流;

PrintStream

字符输出流

PrintWriter

PrintStream

构造器:

  • public PrintStream(OutputStream os)
  • public PrintStream(File file)
  • public PrintStream(String filePath)

方法:

  • public void print(XXX xxx)

PrintWriter

构造器:

  • public PrintWriter(OutputStream os)
  • public PrintWriter(File file)
  • public PrintWriter(String filePath)

方法:

  • public void print(XXX xxx)

    PrintStream ps =new PrintStream("D://s。text");

  • 是一个Map集合,但是HashMap更好用

存放键值对的信息

Propreties ps =new Propreties();
ps.setPropreties("admin","123456");
ps.put("password","123456");
ps.store(new FileWriter("D://a.txt","give me 100"));
//路径,心得
//加载属性到Propreties对象中
ps.load(new FileReader("D://a.txt"));
ps.get("admin");
ps.getPropreties("admin");

我醉了经典白学

commonis-io

FileUtils

  • String readFileToString(File file,String encoding) 读取文件中的数据,返回字符串
  • void copyFile(File srcfile,File destFile) 复制文件
  • void copyDirectoryToDirectory(File srcDir,File destDir) 复制文件夹

NIO

Files.copy(Path.of(""),Path.of(""));
Files.deleteIfExists(Path.of(""))

多线程

  • 多线程的创建
  • Thread类的方法
  • 线程安全、线程同步
  • 线程通信、线程池
  • 定时器、线程状态..

Thread类

  • java是通过java.lang.Thread类来代表线程的
  • 按照面向对象的思想,Thread类应该提供了实现多线程的方式

方式一

1.定义一个线程类:extends Thread

public class MyThread extends Thread{
//2.重写run方法
@Override
public void run(){
    for(int i=0;i<5;i++){
        System.out.print(i);
    }
}
}


public clss ThreadDemo1{
    main(){
        //3.new 一个新线程
        Tread t =new MyThread();
        //4.调用start方法
        t.start();
            for(int i=0;i<5;i++){
        System.out.print(i);
    }
    }
}

优缺点:

1.编码简单

2.线程类继承了Thread类不利于扩展

为什么用start()不用run()?

直接run()是普通方法执行,依然是一个主线程

不要把主线程的任务放到执行之前,还是单线程

方式二

  • 创建一个线程任务实现接口Runnable接口,重写run()方法

  • 创建线程类对象

  • 把对象任务交给Tread处理

    public MyThread implements Runnable{
    @Override
    public void run(){
    for(int i=0;i<5;i++){
    System.out.print(i);
    }
    }
    }

    public class a{
    main(){
    //创建一个任务对象
    Runnable a = new MyThread();
    //任务对象交给Thread处理
    Thread t = new Thread(a);
    t.start();
    for(int i=0;i<5;i++){
    System.out.print(i);
    }
    }
    }

Thread的构造器:

  • public Thread(String name) 可以为当线程指定名称
  • public Thread(Runnable target)分装Runnable对象为线程对象
  • public Thread(Runnable target,String name)

优缺点:

  • 实现接口,扩展性强
  • 多一层封装,如果线程有执行结果是不可以直接返回的 run()没有返回值

匿名内部类:

public class a{
    main(){
        //创建一个任务对象
        Runnable a = new Runable(){
            @Override
    public void run(){
            for(int i=0;i<5;i++){
        System.out.print(i);
    }
        };
        //任务对象交给Thread处理
        Thread t = new Thread(a);
        t.start();
                    for(int i=0;i<5;i++){
        System.out.print(i);
    }
    }
}

方式三:JDK5.0 实现Callable接口和FutureTask

  • 得到任务对象

    • 实现Callable重写call(),
    • 用FutureTask把Callable对象分装成线程的任务对象
  • 把线程对象交给Thread

  • 调用Thread的strat()启动线程

  • 线程执行完毕后,通过FutureTask的get方法区获取任务执行的结果

    pubilc class A implements Callable{
    private int n;
    public A(n){
    this.n=n;
    }
    @Override
    public String Call() throw Exception{
    String sum=0;
    for(int i=0;i<n;i++){
    sum+=i;
    System.out.print(i);
    }
    return "结果是"+sum;
    }
    }

    public class B {
    main(){
    Callable c = new A(10);
    FutureTask f = new FutureTask<>(c);
    //FutureTask实现了Runable接口
    Thread t =new Thread(f);
    t.start();
    //没有结果会等待
    try{
    String s =f.get();
    }catch(Excetion e){
    e.printStackTrace();
    }
    }
    }

优缺点:

  • 实现接口扩展性强

  • 可以得到结果

  • 较为复杂

  • getName()获取线程名字

  • setName()修改线程名字

  • currentThread()获取线程的对象

    定义一个线程类:extends Thread

    public class MyThread extends Thread{
    //2.重写run方法
    @Override
    public void run(){
    for(int i=0;i<5;i++){
    System.out.print(i);
    }
    }
    }

    public clss ThreadDemo1{
    main(){
    //3.new 一个新线程
    Tread t =new MyThread();
    //4.调用start方法
    t.setName("1号线程")
    t.start();
    Thread m =Thread,currentThread();
    for(int i=0;i<5;i++){
    System.out.print(i);
    }

    }

    }

主线程的名称就是main

  • public static void sleep(long time) 让当前的线程休眠,单位毫秒

    main(){
    for(int i =0;i<5;i++){
    if(i==3){
    //技术优化点
    Thread.sleep(3000);
    }
    }
    }

  • 存在多线程共享

  • 同时访问共享资源

  • 存在修改共享资源

    public class ThreadDemo{
    main(){
    Account a =new Account ("郝泾钊",10000);
    //小明小红
    new DrawThread(acc,"小明").start();
    new DrawThread(acc,"小红").start();
    }
    }

    @Date
    @All..
    @Null..
    public class Account{
    private String card;
    private double money;
    public void drawMoney (double money){
    //判断是谁来取钱
    String name= Thread.currentThread().getName();
    //判断是否够钱
    if(this.money>=money){
    //这样更容易不安全
    System.out.print(name+"来取钱成功,出"+money);
    this.money-=moey;
    }else{
    //余额不足
    System.out.print(name+"来取钱,余额不足");
    }
    }
    }

    public class DrawThread extends Thread{
    private Account acc;
    public DrawThread(Account acc,String name){
    super(name);
    this.acc=acc;
    }
    @Override
    public void run(){
    acc.drawMoney(1000);
    }
    }

线程同步

  • 加锁

    @Date
    @All..
    @Null..
    public class Account{
    private String card;
    private double money;
    public void drawMoney (double money){
    //判断是谁来取钱
    String name= Thread.currentThread().getName();
    synchronized("heima"){
    //判断是否够钱
    if(this.money>=money){
    //这样更容易不安全
    System.out.print(name+"来取钱成功,出"+money);
    this.money-=moey;
    }else{
    //余额不足
    System.out.print(name+"来取钱,余额不足");
    }
    }
    }
    }

synchronized(){}:

  • 锁用随机对象好不好? 不好 同步代码块

建议使用共享资源作为锁对象

@Date
@All..
@Null..
public class Account{
    private String card;
    private double money;
    public void drawMoney (double money){
           //判断是谁来取钱
       String name= Thread.currentThread().getName();
        synchronized(this){
                 //判断是否够钱
        if(this.money>=money){
            //这样更容易不安全
            System.out.print(name+"来取钱成功,出"+money);
            this.money-=moey;
        }else{
            //余额不足
            System.out.print(name+"来取钱,余额不足");
        }
        }
    }
}
  • 实例方法用this
  • 静态方法用类名.class

方法上修饰synchronized

默认用this,但是代码要高度面向对象

@Date
@All..
@Null..
public class Account{
    private String card;
    private double money;
    public synchronized void drawMoney (double money){
           //判断是谁来取钱
       String name= Thread.currentThread().getName();
                 //判断是否够钱
        if(this.money>=money){
            //这样更容易不安全
            System.out.print(name+"来取钱成功,出"+money);
            this.money-=moey;
        }else{
            //余额不足
            System.out.print(name+"来取钱,余额不足");
        }
    }
}
  • 同步代码块好还是同步方法好?

    • 同步代码块好,性能好
  • 同步方法原理了?

    • 也是用synchronized修饰默认是this
  • public ReentrantLock() 获得Lock的对象

方法:

  • void lock() 获得锁

  • void unlock() 释放锁

    @Date
    @All..
    @Null..
    public class Account{
    private String card;
    private double money;
    private final Lock lock =new ReentrantLock();
    public void drawMoney (double money){
    //判断是谁来取钱
    String name= Thread.currentThread().getName();
    //判断是否够钱
    lock.lock();
    if(this.money>=money){
    //这样更容易不安全
    System.out.print(name+"来取钱成功,出"+money);
    this.money-=moey;
    }else{
    //余额不足
    System.out.print(name+"来取钱,余额不足");
    }
    lock.unlock();
    }
    }

  • 线程之间相互发送数据

  • 共享的数据的情况决定自己做什么

常见模型:

  • 生产者与消费者模型:
  • 生产者线程产生数据,唤醒消费者;然后等待自己;消费者消费完数据之后唤醒生产者,然后等待自己。

方法:

Object类中:

  • void wait() 让当前线程等待并释放占用锁,直到另一个线程调用notify或notifyAll方法
  • void notify() 唤醒末个等待的线程
  • void notifyAll()唤醒正在等待的所有线程

上述方法要用同步锁对象来调用

例子:

@Date
@All..
@Null..
public class Account{
    private String card;
    private double money;
    public synchronized void drawMoney (double money){
           //判断是谁来取钱
       String name= Thread.currentThread().getName();
                 //判断是否够钱
        if(this.money>=money){
            //这样更容易不安全
            System.out.print(name+"来取钱成功,出"+money);
            this.money-=moey;
            //没钱了,唤醒别的线程
            this.notifyAll();
            this.wait();
        }else{
           //当前等待,唤醒别的线程  先叫醒别人在打晕自己
            this.notifyAll();
            this.wait();
        }
    }
    public synchronized void deposit(double money){
           //判断是谁来存钱
       String name= Thread.currentThread().getName();
                 //判断是否够钱
        if(this.money==0){
            //这样更容易不安全
            System.out.print(name+"来存钱成功,存钱"+money);
            this.money+=moey;
            //有钱了,唤醒别的线程
            this.notifyAll();
            this.wait();
        }else{
           //有钱不存钱
            this.notifyAll();
            this.wait();
        }
    }
}


main(){
    Account acc =new Account("132",0);
    //创建两个取钱线程
    new DrawThread(acc,"小明");
    new DrawThread(acc,"小红");
       //创建两个存钱线程
     new SaveThread(acc,"亲爹");
     new SaveThread(acc,"亲爹");
    new SaveThread(acc,"亲爹");

}

取钱:

public class DrawThread extends Thread{
private Account acc;
public DrawThread(Account acc,String name){
    super(name);
    this.acc=acc;
}
    @Override
    public void run(){
        while(true){
                 acc.drawMoney(1000);
            try{
                      Thread.sleep(3000);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

存钱:

public class SaveThread extends Thread{
private Account acc;
public DrawThread(Account acc,String name){
    super(name);
    this.acc=acc;
}
    @Override
    public void run(){
        acc.deposit(1000);
         try{
                      Thread.sleep(3000);
            }catch(Exception e){
                e.printStackTrace();
            }
    }
}
  • 创建线程的开销很大,----线程池解决

线程池的接口:ExecutorService

1.使用ExecutorService的实现类ThreadPoolExecytor自创建一个线程

ExecutorService------->ThreadPoolExecytor

2.使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象

public ThreadPoolExecutor(int corePoolSize,//核心线程数
                          int maximumPoolSize,//最大线程数
                          long keepAliveTime,//线程空闲时间
                          TimeUnit unit,//时间单位
                          BlockingQueue<Runnable> workQueue,//任务队列
                          ThreadFactory threadFactory,//线程工厂
                          RejectedExecutionHandler handler//拒绝策略)
{
    ...
}
  • corePoolSize 核心线程数,默认为1。

    • 设置规则:

      CPU密集型(CPU密集型也叫计算密集型,指的是运算较多,cpu占用高,读/写I/O(硬盘/内存)较少):corePoolSize = CPU核数 + 1

      IO密集型(与cpu密集型相反,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。):corePoolSize = CPU核数 * 2

  • maximumPoolSize

    • 最大线程数,默认为Integer.MAX_VALUE 一般设置为和核心线程数一样
  • keepAliveTime

    • 线程空闲时间,默认为60s,一般设置为默认60s
  • unit

    • 时间单位,默认为秒
  • workQueue

    • 队列,当线程数目超过核心线程数时用于保存任务的队列。(BlockingQueue workQueue)此队列仅保存实现Runnable接口的任务。(因为线程池的底层BlockingQueue的泛型为Runnable)

      无界队列

      队列大小无限制,常用的为无界的LinkedBlockingQueue,使用该队列作为阻塞队列时要尤其当心,当任务耗时较长时可能会导致大量新任务在队列中堆积最终导致OOM。阅读代码发现,Executors.newFixedThreadPool 采用就是 LinkedBlockingQueue,而博主踩到的就是这个坑,当QPS很高,发送数据很大,大量的任务被添加到这个无界LinkedBlockingQueue 中,导致cpu和内存飙升服务器挂掉。

      当然这种队列,maximumPoolSize 的值也就无效了。当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

      有界队列

      当使用有限的 maximumPoolSizes 时,有界队列有助于防止资源耗尽,但是可能较难调整和控制。常用的有两类,一类是遵循FIFO原则的队列如ArrayBlockingQueue,另一类是优先级队列如PriorityBlockingQueue。PriorityBlockingQueue中的优先级由任务的Comparator决定。

      使用有界队列时队列大小需和线程池大小互相配合,线程池较小有界队列较大时可减少内存消耗,降低cpu使用率和上下文切换,但是可能会限制系统吞吐量。

      同步移交队列

      如果不希望任务在队列中等待而是希望将任务直接移交给工作线程,可使用SynchronousQueue作为等待队列。SynchronousQueue不是一个真正的队列,而是一种线程之间移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接收这个元素。只有在使用无界线程池或者有饱和策略时才建议使用该队列

  • threadFactory

    • 线程工厂,用来创建线程。

      为了统一在创建线程时设置一些参数,如是否守护线程,线程一些特性等,如优先级。通过这个TreadFactory创建出来的线程能保证有相同的特性。

      它是一个接口类,而且方法只有一个,就是创建一个线程。

      如果没有另外说明,则在同一个ThreadGroup 中一律使用Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的NORM_PRIORITY 优先级和非守护进程状态。

      通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。

      如果从newThread 返回 null 时ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务

  • handler

    • 拒绝策略,默认是AbortPolicy,会抛出异常。

      当线程数已经达到maxPoolSize,且队列已满,会拒绝新任务。

      当线程池被调用shutdown()后,会等待线程池里的任务执行完毕再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务。

      AbortPolicy 丢弃任务,抛运行时异常。

      CallerRunsPolicy 由当前调用的任务线程执行任务。

      DiscardPolicy 忽视,什么都不会发生。

      DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务。

核心线程--临时线程

临时线程什么时候创建?

新任务提交任务是发现核心任务都在忙时,任务队列也满了,并且可以创建临时线程,此时会创建临时线程

什么时候会开始拒绝任务?

核心线程和临时线程都在忙,任务队列也满了,新的任务会被拒绝。

方法:

  • void execute(Runnable command) 执行任务、命令,没返回值--一般Runable任务
  • Future submit(Callable task)执行任务、命令,又返回值,--一般Callable任务
  • void shutdown()等任务执行完毕后关闭线程
  • List shutdownNow()立即关闭线程,停止执行的任务,并返回队列中未执行的任务

新任务的拒绝策略:

  • ThreadPoolExecutor.AborPolicy 丢弃任务并抛出RejectedExccutionException默认

  • ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常不推荐

  • ThreadPoolExecutor.DiscardOldestPolicy抛弃队列中等待最久的任务,然后把当前任务加入到队列中

  • ThreadPoolExecutor.CallerRunsPolicy由主线程负责调用任务的run()方法从绕过线程池执行

    public class TreadPoll{
    main(){
    //创建线程池对象
    ExcutorService pool =new ThreadPoolExcutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AborPolicy() )
    }
    //模拟线程处理
    Runnable target =new MyRunnable();
    pool.execute(target);
    pool.execute(target);
    pool.execute(target);
    //任务队列
    pool.execute(target);
    pool.execute(target);
    pool.execute(target);
    pool.execute(target);
    pool.execute(target);
    //创建临时线程
    pool.execute(target);
    pool.execute(target);
    //拒绝策略触发
    pool.execute(target);
    //关闭线程池(开发中一般不会使用)
    pool.shutdownNow();
    pool.shutdown();
    }

    public class MyRunnable implement Runnable{
    @Override
    public void run(){
    for(int i =0 ;i<5;i++){
    System.out.print(Thread.cuurentThread().getNmae()+"编写了hello world");
    }
    try{
    Thread.sleep(3000);
    }catch(Exception e){
    e.printStackTrace();
    }
    }
    }

处理Callable任务

public class TreadPoll{
    main(){
       //创建线程池对象
       ExcutorService pool =new ThreadPoolExcutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AborPolicy() )
    }
    Future<String> f1=pool.submit(new MyCallable(100));
    Future<String> f2=pool.submit(new MyCallable(100));
    Future<String> f3=pool.submit(new MyCallable(100));

    String rs = f1.get();
    String rs2 =f2.get();
    String rs3 = f3.get();

}
  • public static ExecutorsService newCachedThreadPool() 线程池的数量随着任务的增加而增加,如果执行完毕空闲一段时间会被回收
  • public static ExecutorsService newFixedThreadPool(int nThreads)创建固定的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新的线程替代它
  • public static ExecutorsService newSingleThreadExecutor()创建一个线程池对象,如果线程出现异常而结束,那么线程池会补充一个新的线程
  • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务

Executors底层也是实现 ThreadPoolExecutor实现的

main(){
    ExecutorService pool=Executors.ExecutorsService newFixedThreadPool(3);
}

但是大型的并发项目会出现系统分险

  • 内存溢出,线程的内存溢出
  • 任务没有限制

方式一:Timer

方法二:newScheduledThreadPool

Timer

构造器:

  • public Timer() 创建定时器对象

方法:

  • public void schedule(TimerTask task,long delay, long period) 开启一个定时器执行task任务

问题:

  • Timer是单线程,存在延时与定时器的时间有出入的情况

  • 可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续的任务执行

    main(){
    Timer timer =new Timer();
    timer.scedule(new TimerTask(){
    @Oberride
    public void run(){
    //业务
    System.out.print("定时器");
    }
    },3000,2000)
    }//3秒延时调用2秒周期调用

newScheduledThreadPool;

Executors

  • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务

方法:

  • public ScheduledFuture scheduleAtFixedRate(Runnable command,long initalDelay ,long period,TimeUnit unit) 周期调度方法

优点:

  • 基于线程池执行,某个任务情况不会影响其他的定时任务的执行

    main(){
    ScheduledExecutorService pool =Executor.newScheduledThreadPool(3);
    pool.scheduleAtFixedRate(new TimeTrask(){
    @Override
    public void run (){
    //业务
    }
    },0,2,TimeUnit.SECONDS);
    }//初始化延迟事件0秒 周期延迟2秒单位秒

多线程:并发和并行同时进行

生命周期

  • new 新建状态
  • Runnable 可运行状态start()
    • Blocked锁阻塞状态
    • waiting无限等待状态wait()
    • Timed Waiting (计时等待)
      • sleep状态的线程好了不用强锁、、、我不要脸
      • wait状态的线程的时间到了,并得到锁,可以跑
      • wait状态时间没到,被唤醒,并得到锁可以跑
      • wait没有得到锁会进入锁阻塞
  • Teminated被终止状态

网络编程

  • Client-Server(CS)
  • Browser/Server(BS)

1.客户端--服务端

安装客户端

  • 更新。
  • 依赖PC

2.浏览器和服务端

  • 分布式
  • 兼容性
  • 一站开发

网络通信:

  • UDP 不确定在线 不做消息确认

  • TCP可靠的通信

  • 及时通信

  • 模拟BS通信

  • IP地址:设备在网络中的地址,唯一标识

  • 端口:应用程序在设备中的唯一标识

  • 协议:数据在网络中的传输规则,常见的有UDP协议和TCP协议

IPv4:

  • 32位(4字节)
  • 点分十进制

IPv6:

  • 128位(16个字节),号称可以为地球上的每一粒沙子编号
  • 冒分十六进制

域名

  • 公网地址、私网地址(局域网使用)
  • 192.168..开头就是局域网 192.168.0.0--192.168.255.255,专门内部使用

Ip命令:

  • ipcofig:查看本机ip
  • ping IP的地址:检查网络是否连通

特殊id:

  • 127.0.0.1或者localhost:只会找本机

InetAddress

  • public static InetAddress getLocalHost() 返回主机的ip

  • public static InetAddress getByName()得到指定的主机ip地址对象,参数是域名或者ip地址

  • public String getHostName()获取此ip地址的主机名

  • public String getHostAddress()返回ip地址的主机名

  • public boolean isReachable(int timeout)在毫秒内连通该ip地址对应的主机,连通返回true

    main(){
    //1.获得本机ip对象
    InetAddress ip = InetAddress .getLocalHost();
    //得到域名
    InetAddress ip = InetAddress .getByName("www.baidu.com");
    //公网的ip
    InetAddress ip = InetAddress .getByName("112.82.248.76");

标识在计算机上运行的程序,规定的是一个16的二进制,0-65535.

端口类型:

  • 周至端口:0-1023(HTTP:80,FTP:21)
  • 注册端口:1024-49151(Tomcat:8080,MySQL:3306)
  • 动态端口:49152-65535

连接和通讯数据的规则--------网络通讯协议

  • OSI参考模型:世界互联网协议规范
  • TCP/IP参考模型:事实的国际标准

TCP:

  • 应用层

    • HTTP\FTP\DNS\SMTP
  • 传输层

    • TCP\UDP
  • 网路层

    • IP\ICMP
  • 数据链路层+物理

    • 物理寻址、比较流

传输层的协议:

  • TCP:传输控制协议
  • UCP:用户数据报协议

TCP:

  • 采用TCP协议,必须双方先建立连接,它使面向连接的可靠通信协议
  • 传输前,采用三次握手方式建立连接,所以是可靠的
  • 在连接中可以进行大数据量的传输
  • 连接、发送数据都需要确认、且传输完毕后、还要释放已建立的连接。通信效率较低

TCP协议的场景:

  • 对信息安全要求较高的场景,文件下载,金融数据通信

TCP的三次握手

  • 客户端向服务器发送请求--等待服务器确认
  • 服务器向客户端返回了一个相应--告诉客户端接受到了请求
  • 客户端向服务器再次发出确认信息---连接建立

TCP的四次挥手

  • 客户端向服务器发出取消请求
  • 服务器向客户端返回一个相应---表示收到客户端取消请求
  • 服务器向客户端发出确认消息
  • 客户端再次发出消息--连接取消

UDP:

  • 一中无连接、不可靠的传输协议
  • 将数据源ip、目的地ip、和端口封装成数据包、不需要建立连接
  • 每个数据包的大小限制在64kb内
  • 发送不管对方是否准备好,接收方也不确认,所以是不可靠的
  • 可以发送广播、发送数据结束时无需释放资源、开销小、速度快

适合语音通话、视频会话

数据包:

构造器:

  • public DatagramPacket(byte[] buf,int length, InetAddress,int port)port接受的端口
  • public DatagramPacket(byte[] buf,int length) 创建接受端的数据包 buf储存的内容 length 能接受的长度

DatagramSocket发送端和接收端对象

构造器:

  • public DatagramSocket()
  • public DatagramSocket(int port)

方法:

  • public void send( DatagramPacket dp) 发送数据包

  • public void receive( DatagramPacket p)接收数据包

    main(){
    DatagramSocket sock =new DatagramSocket();
    //数据包
    byte[] buffer ="我是韭菜".getBytes();
    DatagramPacket packet =new DatagramPacket(buffer,buffer.length,InetAddress.getLocalHost(),8888);
    sock.send(packet);
    sock.close();
    }

    main(){
    DatagramSocket sock =new DatagramSocket(8888);
    //数据包
    byte[] buffer =new byte[1024*64];
    DatagramPacket packet =new DatagramPacket(buffer,buffer.length);
    sock.receive(packet);
    String s =new String(buffer);
    socket.close();
    }

多发多收

以后吧累了

面向连接,安全,可靠

java.net.Socket

Socket:

  • public Socket(String host,int port) 创建Socket对象与服务器连接,参数为服务器的ip和端口

方法:

  • OutputStream getOutputStream()获得字节输出流

  • InputStream getInputStream() 获得字节输入流

    main(){
    try{
    //创建Socket管道建立连接
    Socket socket =new Socket("127.0..0..1",7777);
    //得到字节输出流
    getOutputStream is =socket.getOutputStream();
    //变成高级流
    PrintStream ps =new PrintStream(is);
    //发送消息
    ps.print("约么");
    ps.flush();
    //socket.close();不建议关闭流
    }catch(Exception e){
    e.printStackTrace();
    }
    }

ServerSocket(服务端)

  • public ServerSocket(int port) 注册服务端

    main(){
    try{
    //创建ServerSocket管道建立连接
    ServerSocket ss =new ServerSocket(7777);
    Socket socket =ss.accept();
    //得到字节输出流
    getInputStream is =socket.getInputStream();
    //变成高级流
    BufferedReader br =new BufferedReader(new InputStreamReader(is));
    //收消息
    while(ms=br.readLine()!=null){
    System.out.print(socket.RemoteSocketAddress()+"说了"+ms)
    }
    //socket.close();不建议关闭流
    }catch(Exception e){
    e.printStackTrace();
    }
    }

多发多收

  • 客户端

    main(){
    try{
    //创建Socket管道建立连接
    Socket socket =new Socket("127.0..0..1",7777);
    //得到字节输出流
    getOutputStream is =socket.getOutputStream();
    //变成高级流
    PrintStream ps =new PrintStream(is);
    Scanner sc =new Scanner(System.in);

    //发送消息
        while(true){
            System.out.print("请说");
                String ms = sc.nextLine();
            ps.println(ms);
            ps.flush();
        }
        //socket.close();不建议关闭流
    }catch(Exception e){
        e.printStackTrace();
    }

    }

ServerSocket(服务端)

  • public ServerSocket(int port) 注册服务端

    main(){
    try{
    //创建ServerSocket管道建立连接
    ServerSocket ss =new ServerSocket(7777);
    Socket socket =ss.accept();
    //得到字节输出流
    getInputStream is =socket.getInputStream();
    //变成高级流
    BufferedReader br =new BufferedReader(new InputStreamReader(is));
    //收消息
    while(ms=br.readLine()!=null){
    System.out.print(socket.RemoteSocketAddress()+"说了"+ms);
    }
    //socket.close();不建议关闭流
    }catch(Exception e){
    e.printStackTrace();
    }
    }

但是服务daunt不可以接受多个客户端信息。

多客户端

  • 客户端

    main(){
    try{
    //创建Socket管道建立连接
    Socket socket =new Socket("127.0..0..1",7777);
    //得到字节输出流
    getOutputStream is =socket.getOutputStream();
    //变成高级流
    PrintStream ps =new PrintStream(is);
    Scanner sc =new Scanner(System.in);

    //发送消息
        while(true){
            System.out.print("请说");
                String ms = sc.nextLine();
            ps.println(ms);
            ps.flush();
        }
        //socket.close();不建议关闭流
    }catch(Exception e){
        e.printStackTrace();
    }

    }

ServerSocket(服务端)

  • public ServerSocket(int port) 注册服务端

    main(){
    try{
    //创建ServerSocket管道建立连接
    ServerSocket ss =new ServerSocket(7777);
    //收消息
    while(ms=br.readLine()!=null){
    Socket socket =ss.accept();
    new SerberThread(socket).start();
    }
    //socket.close();不建议关闭流
    }catch(Exception e){
    e.printStackTrace();
    }
    }

线程:

public class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
    this.socket-socket;
}
    @Override
    public void run(){
        try{
             //得到字节输出流
    getInputStream is =socket.getInputStream();
    //变成高级流
    BufferedReader br =new  BufferedReader(new InputStreamReader(is));
    //收消息
            while(ms=br.readLine()!=null){
                System.out.print(socket.RemoteSocketAddress()+"说了"+ms);
            }
        //socket.close();不建议关闭流
        }catch{
            e.printStrackTrace();
        }
    }
}

线程池优化

  • 客户端

    main(){
    try{
    //创建Socket管道建立连接
    Socket socket =new Socket("127.0..0..1",7777);
    //得到字节输出流
    getOutputStream is =socket.getOutputStream();
    //变成高级流
    PrintStream ps =new PrintStream(is);
    Scanner sc =new Scanner(System.in);

    //发送消息
        while(true){
            System.out.print("请说");
                String ms = sc.nextLine();
            ps.println(ms);
            ps.flush();
        }
        //socket.close();不建议关闭流
    }catch(Exception e){
        e.printStackTrace();
    }

    }

ServerSocket(服务端)

  • public ServerSocket(int port) 注册服务端

    //定义线程池
    private Static ExecutorService pool =new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue(2,Executor.defaultThreadFactorty(),new ThreadPoolExcutor.AbortPolicy()));
    main(){
    try{
    //创建ServerSocket管道建立连接
    ServerSocket ss =new ServerSocket(7777);
    //收消息
    while(ms=br.readLine()!=null){
    Socket socket =ss.accept();
    Runner a =new SerberThread(socket);
    pool.excute(a);
    }
    //socket.close();不建议关闭流
    }catch(Exception e){
    e.printStackTrace();
    }
    }

线程:

public class ServerThread implement Runnable{
private Socket socket;
public ServerThread(Socket socket){
    this.socket-socket;
}
    @Override
    public void run(){
        try{
             //得到字节输出流
    getInputStream is =socket.getInputStream();
    //变成高级流
    BufferedReader br =new  BufferedReader(new InputStreamReader(is));
    //收消息
            while(ms=br.readLine()!=null){
                System.out.print(socket.RemoteSocketAddress()+"说了"+ms);
            }
        //socket.close();不建议关闭流
        }catch{
            e.printStrackTrace();
        }
    }
}

优点:

  • 适合通信时长较短的案例

  • 客户端

    main(){
    try{
    //创建Socket管道建立连接
    Socket socket =new Socket("127.0..0..1",7777);
    //创建一个读线程
    new ClienThread(socket).start();
    //得到字节输出流
    getOutputStream is =socket.getOutputStream();
    //变成高级流
    PrintStream ps =new PrintStream(is);
    Scanner sc =new Scanner(System.in);

    //发送消息
        while(true){
            System.out.print("请说");
                String ms = sc.nextLine();
            ps.println(ms);
            ps.flush();
        }
        //socket.close();不建议关闭流
    }catch(Exception e){
        e.printStackTrace();
    }

    }

  • 客户端的线程

    public class ClienrThread implement Runnable{
    private Socket socket;
    public ClienThread(Socket socket){
        this.socket-socket;
    }
        @Override
        public void run(){
            try{
                 //得到字节输出流
        getInputStream is =socket.getInputStream();
        //变成高级流
        BufferedReader br =new  BufferedReader(new InputStreamReader(is));
        //收消息
                String line;
                while(line=br.readLine()!=null){
                    System.out.print(socket.RemoteSocketAddress()+"说了"+line);
                }
            //socket.close();不建议关闭流
            }catch{
                e.printStrackTrace();
            }
        }
    }

ServerSocket(服务端)

  • public ServerSocket(int port) 注册服务端

    //定义线程池
    private Static ExecutorService pool =new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue(2,Executor.defaultThreadFactorty(),new ThreadPoolExcutor.AbortPolicy()));
    //客户端的留言
    public static List allSocket = new ArrayList<>();
    main(){
    try{
    //创建ServerSocket管道建立连接
    ServerSocket ss =new ServerSocket(7777);
    //收消息
    while(ms=br.readLine()!=null){
    Socket socket =ss.accept();
    allStock.add(socket);
    Runner a =new SerberThread(socket);
    pool.excute(a);
    }
    //socket.close();不建议关闭流
    }catch(Exception e){
    e.printStackTrace();
    }
    }

线程:

public class ServerThread implement Runnable{
private Socket socket;
public ServerThread(Socket socket){
    this.socket-socket;
}
    @Override
    public void run(){
        try{
             //得到字节输出流
    getInputStream is =socket.getInputStream();
    //变成高级流
    BufferedReader br =new  BufferedReader(new InputStreamReader(is));
    //收消息
            while(ms=br.readLine()!=null){
                System.out.print(socket.RemoteSocketAddress()+"说了"+ms);
                sendMssageToAll(line);
            }
        //socket.close();不建议关闭流
        }catch{
            e.printStrackTrace();
        }
    }
    private void sendMssageToAll(String msg){
        for(Socket socket:ServlerThread.allSocket){
            PrintStream ps =new  PrintStream(socket.getOutputStream());
            ps.println(msg);
            ps.flush();
        }
    }
}

单元测试

  • 最小的功能单元编写测试代码,java针对方法,检查方法的正确性

JUnit单元测试框架

@Test注解

public class A {
    @Test
    public void a(){
        .....
    }
}
  • 必须导入jar包
  • 定义的测试方法必须是无参数无返回值的,且公开的方法
  • 测试的方法要用@Test注解

注解

  • @Test
  • @Before 实例方法,每个测试方法之前执行
  • @After 实例方法,每个测试方法之前执行
  • @BeforeClass 静态方法,所有测试方法之前执行一次
  • @AfterClass静态方法,在所有测试方法之后执行一次

初始化资源

释放资源

反射

是指对于任何一个Clss类,在运行是都可以直接得到这个类的全部成分

  • 类构造对象:Constructor

  • 类的成员变量对象:Filed

  • 类的成员方法对象:Method

  • 动态获取类的信息以及动态的调取类中的成分的能力称为java语言的反射机制

    Class c = A.class;

获得类对象

Class类中的静态方法:

  • forName(String className)

  • 类名.class

  • 对象.getClass()

    main(){
    Class c =Class.forName("com.hjz.entity.Student");
    Class c =Student.class;
    Student s =new Student();
    Class c = s.getClass();
    }

获得构造器对象:

1.获得Class类对象

2.获得构造器对象

  • Constructor getConstructors()返回所有的构造器数组(只拿public)

  • Constructor getDeclredConstructors()返回所有的构造器数组,有就能拿到

  • Constructor getConstructors( Class… paramerTypes)返回单个构造器

  • Constructor getDeclredConstructors( Class… paramerTypes)

    main(){
    Class c =Student.class;
    Constructor[] cs = c.getConstructors();
    Constructor[] cs = c.getDeclredConstructors(String.class,int.class);//有一个构造方法是啥用啥
    }

创建对象:

  • T newInstance(Object…initargs) 指定的构造器创建对象

  • public void setAccesible(boolean flag) 设置为true 表示取消访问检查,进行暴力反射

    main(){
    Class c =Student.class;
    Constructor cs = c.getDeclredConstructors();//有一个构造方法是啥用啥
    //反射会破坏封装性
    cs.setAccesible(true);//是私有的
    Student s = (Student)cs.new newInstance();
    }

获得成员变量对象:

1.获得Class类对象

2.获得成员变量对象

  • Filed[] getDeclredFileds()
  • Filed getDeclredFiled(String name)

方法:

  • getType()

    main(){
    Field agef =c.getDeclredFiled("age");
    agef.setAccessible(true);
    Student s =new Student();
    agef.set(s.18);
    int age = (int) agef.get(s);
    }

获得方法对象

  • Method[] getMothod()
  • Method getDeclredConstructor( ,String name,Class… paramerTypes)

….和之前的一样

反射的作用

  • 反射是在运行时使用的技术,此时集合泛型就不能产生约束了,此时是可以为集合存入其他任何类型的元素的

    ArrayList list =new ArrayList<>();

实际跑起来都是Arraylist的类型了,不用管Integer了

  • 反射的通用框架

1.定义一个方法可以接受任意的对象

2.每次收到一个对象后,解析这个对象的全部成员变量

3.这个对象是任意的

4.遍历这个成员变量,提取成员变量的具体的值

5.把名称和值放到成员变量对应的文件里面

注解

JDK5 引入的标注

  • 对java的类、方法、对象有特殊处理

自定义注解

public @interface 注解名称{
    public属性名称 属性名()default 默认值;
}

例子:

public @interface MyBook{
    String name();
    String[] authors();
    double price();
}


public class a{
    @MyBook(name="java",autors={"黑马","我的"},price=200)
    public void ss(){

    }
}

只有一个value属性可以写可以不写

元注解

注解上的注解

  • @Target:约束自定义注解只能在哪使用

    发现ElementType是个枚举。属性作用如下:

    TYPE:接口、类、枚举

    FIELD:字段、枚举的常量

    METHOD:方法

    PARAMETER:方法参数

    CONSTRUCTOR:构造函数

    LOCAL_VARIABLE:局部变量

    ANNOTATION_TYPE:注解

    PACKAGE:包

  • @Retention:申明注解的生命周期

    按生命周期来划分可分为3类:

    1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;

    2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;

    3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyBook{
    String name();
    String[] authors();
    double price();
    }

注解解析

  • Annotation:注解的顶级接口,注解都是Annotation的类型对象
  • AnnotatedElement:给接口定义了注解解析相关的解析方法

动态代理(重点)

代理为对象的行为实现一些辅助操作:

有时间看吧

xml

xml解析---xpath解析技术

可扩展标记语言

数据表示格式

<?xml version="1.0" encoding="utf-8">
<--注释有且仅有一个-->
  • &lt小于
  • &gt大于
  • &amp 和
  • &apos 单引号
  • &quot 引号

文档约束

  • DTD
  • schema

解析数据技术:Dom4J框架底层技术

  • SAX解析
  • DOM解析

数据检索技术XPath

  • Dom4J需要进行全文检索,然后寻找资源
  • Xpath技术适合数据检索

完结了我草终于2022.05.07