java基础

Table of Contents

一、排序

二、重写与重载

1 重写:

2 重载:

三、java内存模型        ​

四、可变参数

可变参数跟数组是一样的,以下就是方法重写

五、常见面试错误

 六、值传递机制

七、UML类图

八、封装、继承、多态

九、== 和equals比较

十、自动装箱,自动拆箱

十一、8种基本数据类型

十二、二进制: 

 十三、多线程,jvm分配内存解读多线程

同步代码块

同步方法:    

 同步锁

           Lock 与synchronizede区别

 Thread类中常用的方法

线程通信

示例 线程通信交替打印abc

         使用信号量Semaphore:方法是acquire () 获取和release() 释放

         生产者消费者模型

十四、File

1 文件流  

1.1 code

2 缓冲流

2.1 code

3 转换流

3.1 code

4 标准输入输出流

5 数据流

7 打印流

8 随机存取文件流 RandomAccessFile

9 对象流

9.1 code

10 访问数组流

十五、网络通信

1、网络编程中两个主要问题

2、网络编程中两个要素

3、网络通信协议

4、 IP地址:inetAddress

5、端口号

6、网络协议

TCP示例:客户端发送消息,服务端接收消息

TCP示例: 客户端发送图片给服务端,服务端将文件保存到本地

TCP示例:从客户端发送的文件给服务端,服务端保存到本地,并返回“发送成功”给客户端

UDP示例: UDP 的网络编程

URL编程:通过地址可以获取网上上面的协议,地址,端口,参数等以及下载网络资源

十六、常用类

1 String 

1.1 内存结构划分jvm

1.2 String 常用方法

1.3 String的几个基本算法问题:

2 StringBuilder,StringBuffer

2.1 面试题:StringBuilder,StringBuffer,String异同的

2.2 StringBuffer StringBuilder常用方法

2.3 总结

十七、日期和时间

1 jkd1.8以前的日期和时间

2 jkd1.8以后的日期和时间

十八、java比较器 自然排序Comparable 或者 定制Comparator

1 comparable自然排序

2 comparator

十九、常用类 System,Math,BigInteger,BigDecimal

1 System

2 Math

3  BigInteger,BigDecimal

二十、集合

1 Collection 和Collections

2 List

3 Set

4 Map

21 java8 9 10 11 新特性 

java8 看专递

java9 

 java10 新特性:局部变量类型推断var

java11 新特性


一、排序

1 冒泡排序


    /**
     * 冒泡排序:升序
     */
    @Test
    public void test06() {

        int[] arr = new int[]{-93,2,-87,23,11,107,-23};

        for (int i = 0; i <arr.length-1 ; i++) {

            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j]>arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }

       Arrays.stream(arr)
                .forEach(System.out::print);
    }

2 快速排序

/**
     * 快速排序
     * 从小到大排序:在数组中随机选一个数(默认数组首个元素),数组中小于等于此数的放在左边,大于此数的放在右边,再对数组两边递归调用快速排序,重复这个过程。
     */
    @Test
    public void test07() {

        int[] data = {9,-17,22,78,-11,2,83,189,76};
        System.out.println("排序之前"+Arrays.toString(data));

        quickSort(data);
        System.out.println("排序之后"+Arrays.toString(data));
    }

    private static void swap (int[] data,int i,int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }

    private static void subSort(int[] data,int start,int end) {
        if(start < end) {
                // base 随机获取的比较数据,默认获取第一个值
                int base = data[start];
                int low = start;
                int high = end +1;
                while(true) {
                    while(low < end && data[++low]-base<=0)
                        ;
                    while (high>start && data[--high]-base>=0)
                        ;

                    //当左侧有值,有比base更大,右侧比bae的值更小时候,并且low比high指针小时候,需要交换位子
                    // 使 左侧的数都小于base,右侧的都大于base值分成两份。递归下去
                    if(low < high) {
                        swap(data,low,high);
                    }else {
                        break;
                    }
                }

                //将base得知 放在中间,将左右两边隔开,一边比base小,一边比base大
                swap(data,start,high);
                subSort(data,start,high-1);
                subSort(data,high+1,end);
        }
    }

    public  static void quickSort(int[] data) {
        subSort(data,0,data.length-1);
    }

二、重写与重载


1 重写:


    1 方法名和参数列表相同,方法体不同
    2 访问修饰符可以不能小于父类
    3 异常不能抛出父类更大的
    4 返回的值类型可以相同或者是父类返回值的子类
    
    


2 重载:


    1 方法名相同,参数列表不同
    2 访问修饰符没有固定
    3 返回值类型没有规定
    4 抛出异常没有固定,可以相同也可以不同或者没有
    
    子类和父类中同名和同参数的方法要么都声明为static(非重写),要不都声明为非static(考虑重写)
面试时,问:重载(Overload)和重写(Override)的区别?

答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。

三、java内存模型
    
    

元数据区域
元数据区域取代了1.7版本及以前的永久代。元数据和永久代本质上都时方法区的实现。方法区皴法虚拟机加载的类型西,静态变量,常量数据。
参数设置:-XX:MetaspaceSize=18m
-XX:MaxMetaspaceSize=60m
直接内存
java.nio 中使用DirectBuffer相关使用(此处未完待续。。。。。。。。。) 

四、可变参数

可变参数的写法:调用可变参数:就当做是数组

可变参数必须声明在方法末尾,并且一个方法只能有一个可变参数

public static void paly(int age ,String ... args) {
    System.out.println(args.length);
    for (int i = 0; i < args.length ; i++) {
        System.out.print(args[i]+"\t");
    }
}

 //调用可变参数:就当做是数组

@Test public void test08() { System.out.println(Math.sqrt(9)); ArrayDemoTest.paly(1,"aa","dd","fe","fewf","eee","aaafewfwf"); ArrayDemoTest.paly(2,new String[]{"aa","dd","fe","fewf","eee","aaafewfwf"}); }

可变参数跟数组是一样的,以下就是方法重写

五、常见面试错误

@Test
public void test10() {

    int[] arr = new int[]{1,2,3};
    //println(Object x)
    System.out.println(arr);//[I@69d0a921

    char[] arr1 = new char[]{'a','b'};
    //println(char x[])
    System.out.println(arr1);// ab
}

 六、值传递机制

如果参数是基本数据类型,此时实参赋值给形参是实参真实存储的数据值

如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值。

String常量值也需要注意一下。

七、UML类图

如果一个类中n个构造器,那么最多哟n-1个调用“this(形参列表)” 的,并且必须将this构造器放在首行。,一个构造器只能有一个this的构造器。

import static :导入指定类或接口中的静态结构

Ssytem.out.println("hello"): 可以写成 out.println("hello");

构造方法可以处于public、protected、private和默认四种访问级别之一。
public
public这里就不多说了
private
当构造方法为private级别时,意味着只能在当前类访问它,不能被继承,不能被其他程序用new创建实例对象。可以对比其他几种修饰符的作用:abstract修饰的类,不允许被实例化,这点和private修饰构造方法相同,但abstract修饰的类可以被继承,拥有子类,可以创建子类的实例;final类禁止被继承,这点和private修饰构造方法相同,但是final类可以用new创建实例对象。
protected
如果构造函数是protected,那么该类可以继承,可以在被包内其他类中产生实例,但是无法在包外或者子类以外的地方产生实例.

类的权限修饰符

外部类:public或者缺省

成员内部类:public  protected  缺省 private

局部内部类:什么都不能写

八、封装、继承、多态

继承性:

   体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有属性和方法,特别似乎父类中声明为private的属性和方法,子类继承父类后仍然认为获取了父类中私有的结构,只是因为封账性的影响,使得子类不能直接调用父类的结构而已。

   子类继承父类后,还可以声明自己特有的属性和方法,实现功能的扩展。

多态性:对象动态性和行为多态性

Person  p1 = new Man();对象多态性

p1.eat()//  行为的多态性

1 何为多态:对象的多态性,父类的引用指向子类的对象

2 多态的使用,虚拟方法 调用

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

   总结:编译看左边,运行看右边

3 对象的多态性只适用于方法,不适用于属性。

4 多态是运行时行为。

5 instanceof 向下转型前需要判断一下是否是这个类型的实例

九、== 和equals比较

==  如果是基础类型就比较值,如果是引用类型比较的就是地址值

equals:需要重写equals和hashcode,重写以后比较的两个实体内容是否相同,而不再是两个引用的地址是否相同。

十、自动装箱,自动拆箱

@Test
public void test15() {

    //三母运算符要求前后数据类型统一,所以编译时候会自动类型提升
    Object o1 = true?new Integer(1):new Double(2.0);
    System.out.println(o1);//1.0

    Object o2;
    if(true) {
        o2 = new Integer(1);

    }else {
        o2 = new Double(2.0);
    }
    System.out.println(o2);
}

@Test
public void test16() {
    Integer i = new Integer(1);
    Integer j = new Integer(2);
    System.out.println(i==j);//false

Integer内部定义了IntegerCache结构,定义了一个数组,保存了-128-127范围
的整数,如果我们使用自动装箱方式,给Integer赋值就会从这里使用,超过就会new。
    Integer m = 1;
    Integer n = 1;
    System.out.println(m==n);//true

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

十一、8种基本数据类型

这里强调下,正常对于环境变量,系统会检查用户环境变量,之后再检查系统环境变量,如果有相同的变量名,并不会将两者的内容合并在一起。 

 

java语言特点:

面向对象(封装,继承,多态),健壮性,跨平台型 

**** byte short char 三个相互运算需要用int数据类型接收


整型常量:默认类型是int   byte b = 12;  int a = b+1;
浮点型常量:默认类型是double  byte b = 12; double a  = b+12.1;

十二、二进制: 

二进制转十进制:二进制转化为十进制:2的n次幂方乘以值,从2的0次幂开始

 

计算机底层都是以补码的方式存储数据 

 十进制转二进制:除2取余数,然候取逆

二进制转化为八进制和十六进制 

 % 取余结果正负是跟被取余的符号一致。

异或:就是当a和b不同时候为true,否则就是false

左移运算:相当于 往左边移动多少位,比如2位就相当于每个数都扩大了2的2次幂。

System.out.println(2<<3);//16

右移就是看最高位是0就用0补,如果是1就用1补,

无符号右移就是都是用0补。

0表示false,1表示true

 @Test
    public void test0006() {

        //交换
        int a = 10;
        int b = 20;
        System.out.println("a:"+a+",b:"+b);
        //方式一:定义临时变量

        int temp = a;
         a = b;
         b = temp;

//        方式二:相加再减
        a=a+b;
        a = a-b;
        b = a-b;

//        方式三:使用位运算符 m = (m^n)^n
        a =a^b;
        b = a^b;
        a = a^b;
        System.out.println("a:"+a+",b:"+b);
    }

数组:

//数组复制的四种方式
//分别为使用
// Arrays 类的 copyOf() 方法和 copyOfRange() 方法
// 、System 类的 arraycopy() 方法和
// Object 类的 clone() 方法。下面来详细介绍这 4 种方法的使用。

 十三、多线程,jvm分配内存解读多线程

在JVM内部,Java内存模型把内存分成了两部分:线程栈区和堆区,下图展示了Java内存模型在JVM中的逻辑视图: 

JVM中运行的每个线程都拥有自己的线程栈,线程栈包含了当前线程执行的方法调用相关信息,我们也把它称作调用栈。随着代码的不断执行,调用栈会不断变化。

线程栈还包含了当前方法的所有本地变量信息。一个线程只能读取自己的线程栈,也就是说,线程中的本地变量对其它线程是不可见的。即使两个线程执行的是同一段代码,它们也会各自在自己的线程栈中创建本地变量,因此,每个线程中的本地变量都会有自己的版本。

所有原始类型(boolean,byte,short,char,int,long,float,double)的本地变量都直接保存在线程栈当中,对于它们的值各个线程之间都是独立的。对于原始类型的本地变量,一个线程可以传递一个副本给另一个线程,当它们之间是无法共享的。

堆区包含了Java应用创建的所有对象信息,不管对象是哪个线程创建的,其中的对象包括原始类型的封装类(如Byte、Integer、Long等等)。不管对象是属于一个成员变量还是方法中的本地变量,它都会被存储在堆区。

下图展示了调用栈和本地变量都存储在栈区,对象都存储在堆区:

一个本地变量如果是原始类型,那么它会被完全存储到栈区。 
一个本地变量也有可能是一个对象的引用,这种情况下,这个本地引用会被存储到栈中,但是对象本身仍然存储在堆区。

对于一个对象的成员方法,这些方法中包含本地变量,仍需要存储在栈区,即使它们所属的对象在堆区。 
对于一个对象的成员变量,不管它是原始类型还是包装类型,都会被存储到堆区。

jdk1.8后  Static类型的变量以及类本身相关信息都会随着类本身存储在堆区。

static 成员变量在 Class 对象里,也就是在 堆上

推荐看下这篇文章: JDK 1.8 下的 java.lang.Class 对象和 static 成员变量在堆还是方法区?_Jalen Xu的博客-CSDN博客

堆中的对象可以被多线程共享。如果一个线程获得一个对象的应用,它便可访问这个对象的成员变量。如果两个线程同时调用了同一个对象的同一个方法,那么这两个线程便可同时访问这个对象的成员变量,但是对于本地变量,每个线程都会拷贝一份到自己的线程栈中。

备注:方法区是虚拟机规范中对运行时数据区划分的一个内存区域,不同的虚拟机厂商可以有不同的实现,而HotSpot虚拟机以永久代来实现方法区,所以方法区是一个规范,而永久代则是其中的一种实现方式。 


1.8同1.7比,最大的差别就是:元数据区取代了永久代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存。 

public static void main(String[] args) {
        TicketTest1 demo1 = new TicketTest1();

        Thread t1 = new Thread(demo1);
        Thread t2 = new Thread(demo1);
        Thread t3 = new Thread(demo1);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }

}

class TicketTest1 implements Runnable {
    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {

        // 不加锁就会产生重票
        while(true) {
            synchronized(obj) {
                if (ticket>0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {

                    }
                    System.out.println(Thread.currentThread().getName()+":"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }

        }



    }


同步代码块
同步方法
同步锁 Lock

同步代码块


synchronized() {}
1 操作共享数据的代码,即为需要被同步的代码
2 共享数据:多个线程共同操作变量,比如ticket就是共享数据
3 同步监视器:俗称锁,任何一个类的对象都可以充当锁
                    要求:多个线程必须操作同一个锁
                    补充:在实现Runnable接口创建多线程的方式中。我么可以考虑使用this或类当做同步监视器
                    
                    在继承Thread类创建多线程方式中,慎用this作为同步监视器,考虑使用当前类充当同步监视器如:TicketTest.class

                    因为这个类也是一个对象  Class clazz = TicketTest.class   并且类只加载一次,只有一个,类信息在方法区(jdk8方法区没有了,是在元数据区)
    


同步方法:    


1 同步方法仍然涉及到同步监视器,只是不需要我们显示的声明
2 非静态方法,同步监视器是this,静态方法是当前类本身class                 

 同步锁

如果是用同步锁lock,那么 await  signal signalAll也需要用在同步锁中

           
Lock 与synchronizede区别


相同点:两者都解决线程安全问题
不同点:synchronized机制在执行完相应的同步代码后,自动释放同步监视器
         lock需要手动启动同步(lock),同时结束的时候需要手动实现(unlock)

 Thread类中常用的方法


    start 启动当前线程,调用当前线程run方法
    run 通常需要重写Thread类中此方法,将创建的线程要执行的操作声明在此方法中
    currentThread 静态方法,返回当前代码线程的线程
    getName 获取当前线程名称
    setName 设置当前线程名称
    yield 释放cpu执行权
    join 在线a中调用线程b的join方法,此时线程a就进入阻塞状态,
            知道线程b执行完以后线程a才结束阻塞。不会释放锁
    stop 已过时
    sleep(long time) 让当前线程睡吧指定时长 ,并且阻塞状态,不释放锁对象
    isAlive  判断当前线程释放存活


线程通信


wait  一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器
notify  一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就会唤醒优先级高的那个,如果优先级一样就随机

wait 对于中断和虚假唤醒解决就是放在循环中(官网推荐)
notifyAll  一旦执行此方法,就会唤醒所有被wait的线程

说明:
wait notify  notifyAll必须使用在同步代码块或者同步代码块中
这三个方法的调用者必须是同步代码块或者同步方法的同步监视器。

notify()  / notifyAll  唤醒在此对象监视器上等待的单个线程。 会继续执行wait方法之后的代码,并不是重新重头开始执行,而是接着等待的地方继续执行。

示例 线程通信交替打印abc


public class ABCConditionDemo {


    public static void main(String[] args) {

        //方式一
        /*ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 3 ; i++) {
            executorService.submit(() -> { System.out.println("AAA"); });
            executorService.submit(() -> { System.out.println("BBB"); });
            executorService.submit(() -> { System.out.println("CCC"); });
        }

        executorService.shutdown();*/

//        方式二

        Param param = new Param();

        Letter lA = new Letter(param, 0, "A");
        Letter lB = new Letter(param, 1, "B");
        Letter lC = new Letter(param, 2, "C");

        new Thread(lA).start();
        new Thread(lB).start();
        new Thread(lC).start();

    }

}



class Letter implements Runnable {
    private Param param;

    private int process;

    private String name;

    public Letter(Param param, int process, String name) {
        this.param = param;
        this.process = process;
        this.name = name;
    }

    @Override
    public void run() {
        //此处不能用this,因为调用的时候不是唯一,而param是唯一的
        synchronized (param) {

            for (int i = 0; i < 10; i++) {

                int state = param.getState();
                System.out.println("i:"+i+",state:"+state+"process:"+process+",线程名:"+Thread.currentThread().getName());
                while (state != process) {
                    try {
                        param.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
//                    //再一次获取最新的状态
                    state = param.getState();
//                    System.out.println(state);
                }
                System.out.println(Thread.currentThread().getName()+"----"+name+"----");

                param.setState(++state % 3);//设置状态

                param.notifyAll();//在同步代码块中使用,并且调用者是锁对象,唤醒其他两个等待的线程
            }

        }

    }
}

class Param {
    int state =0;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }
}

         使用信号量Semaphore:方法是acquire () 获取和release() 释放


class ConcurrentPrint {
    // 共享资源个数都初始为1
    private static Semaphore s1 = new Semaphore(1);
    private static Semaphore s2 = new Semaphore(1);
    private static Semaphore s3 = new Semaphore(1);
    Thread t1 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                try {
                    s1.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("A");
                s2.release();
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                try {
                    s2.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("B");
                s3.release();
            }
        }
    });
    Thread t3 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                try {
                    s3.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("C");
                s1.release();
            }
        }
    });

    public void fun() throws InterruptedException {
        // 先占有输出BC的线程的信号量计数
        // 则只能从输出A的线程开始。获取信号量A,然后释放B-获取B-释放C-获取C-释放A,由此形成循环
        s2.acquire();
        s3.acquire();
        t2.start();
        t3.start();
        t1.start();
    }

    public static void main(String[] args) throws InterruptedException {
        ConcurrentPrint cp = new ConcurrentPrint();
        long t1 = System.currentTimeMillis();
        cp.fun();
        while (true) {
            if (System.currentTimeMillis() - t1 >= 10)
                System.exit(0);
        }
    }

}


         生产者消费者模型


public class ProducerAndConsumerDemo {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer producer = new Producer(clerk);
        Producer producer2 = new Producer(clerk);
        producer.setName("生产者1");
        producer2.setName("生产者2");
        producer.start();
        producer2.start();


        Consumer consumer = new Consumer(clerk);
        consumer.setName("消费者1");
        consumer.start();
        Consumer consumer2 = new Consumer(clerk);
        consumer2.setName("消费者2");
        consumer2.start();

    }
}

/**
 * 店员
 */
class Clerk {
    private int  num;

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    /**
     * 生产商品
     */
    public synchronized void pro() {
        //当小于20的时候生产 否则等待

        while(num >=1) { //避免虚假唤醒
            try {
                wait();
            } catch (InterruptedException e) {

            }
        }
        num++;
        System.out.println(Thread.currentThread().getName()+":正在生产第"+num+"个产品");
        notify();

    }


    /**
     * 消费产品
     */
    public synchronized void cus() {
        //当大于0时候开始消费,如果没有了就需要等待
        while(num<=0) {
            try {
                wait();
            } catch (InterruptedException e) {

            }
        }
        System.out.println(Thread.currentThread().getName()+":正在消费第"+num+"个产品");
        num--;
        notify();
    }
}

class Producer extends Thread {

    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    public Clerk getClerk() {
        return clerk;
    }



    public void setClerk(Clerk clerk) {
        this.clerk = clerk;
    }



    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":开始生产产品");
        while(true) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
            }
            clerk.pro();
        }
    }
}

class Consumer extends Thread {

    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    public Clerk getClerk() {
        return clerk;
    }

    public void setClerk(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":开始消费产品");
        while(true) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
            }
            clerk.cus();
        }
    }
}


 

十四、File

1文件和文件目录的抽象表现形式,与平台无关
2File能新建,删除,重命名文件和目录,但是File不能访问内容本身,如果需要访问内容,需要输入输出流。
3想要在java程序中表示一个真实存在的文件或者目录,那么必须有一个File对象,但是java程序中的一个File对象可能没有一个真实存在的文件或者目录。
4File对象可以作为参数传递给流的构造器。

/将文件file3移动到file4的地方并且重命名为file4的文件名,
//需要保证file3 存在并且file4不存在。
    boolean rename = file3.renameTo(file4);
    System.out.println(rename);
    
boolean directory = file.isDirectory();//是否是一个目录
boolean file1 = file.isFile();//是否是一个文件
boolean exists = file.exists();//是否存在
boolean b = file.canRead();//是否可读
boolean b1 = file.canWrite();//是否可写
boolean hidden = file.isHidden();//是否隐藏


boolean newFile = file.createNewFile();//创建文件,若文件存在则不创建,返回false
boolean mkdir = file.mkdir();//创建文件目录,如果此文件目录存在,就不创建,如果此文件目录的上层不存在,也不创建
//创建如果没有写盘符,那么默认是在项目路径下
boolean mkdirs = file.mkdirs();//创建文件目录,如果文件上级不存在也一并创建。
boolean delete = file.delete();//删除文件或者文件夹,注意:java删除不走回收站,要删除一个文件目录,则该目录中不能包含文件或者文件夹
 

@Test
    public void test1() {

        File file = new File("hello.txt");
        System.out.println(file);//仅仅是内存中的一个对象

        File file2 = new File("abc", "hi.txt");
        System.out.println(file2);

        File file3 = new File(file2, "nih.txt");
        System.out.println(file3);


        String absolutePath = file.getAbsolutePath();
        String path = file.getPath();
        String name = file.getName();
        String parent = file.getParent();
        long length = file.length();//字节数(不能获取目录长度)
        long l = file.lastModified();

        //获取目标下面的文件或者目录名称数组
        String[] list = file.list();
        //获取目录文件下面的file数组

        File[] files = file.listFiles();
    }

    @Test
    public void rename() {

        //前提:file存在,并且hi.txt不存在,则会返回true,文件会移动过去并且重命名
        File file = new File("hello.txt");
        boolean rename = file.renameTo(new File("hi.txt"));
        System.out.println(rename);
    }

    @Test
    public void test3() {

        File file = new File("hello.txt");
        boolean directory = file.isDirectory();
        boolean file1 = file.isFile();
        boolean exists = file.exists();

        boolean b = file.canRead();
        boolean b1 = file.canWrite();
        boolean hidden = file.isHidden();
        if(file.exists()) {
// 要删除一个目录的话这个目录下面不能有文件
            boolean delete = file.delete();
        }else {
            try {
                //如果文件存在就不创建
                boolean newFile = file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //创举文件目录,如果上层目录不存在就不创建
        boolean mkdir = file.mkdir();
//        举文件目录,如果上层目录不存在就一并创建
        boolean mkdirs = file.mkdirs();


    }

看后面比如转换流:InputStreamRead

  文件流
* 数组流
  字符串流
* 缓冲流
* 转换流
* 
* 打印流:标准输入输出流
* 对象流
* 数据流

* RandomAccessFile 随机存取文件流
  
NIO2 中新增了  Path  Paths  FIles

1 文件流  

 对于文本文件使用字符流  .txt .java  ...
 对于非文本文件使用字节流  .doc 图片,音频,.ppt ....

 文本文件复制也可以使用字节流
 非文件文件复制不能用字符流
使用字节流处理文本文件可能出现乱码问题,后面可以用转换流转换就不会出现乱码

1.1 code

public void copy(String inName,String outName) {
        File f1 = new File(inName);
        File f2 = new File(outName);


        try ( FileInputStream fileInputStream = new FileInputStream(f1);
              FileOutputStream fileOutputStream = new FileOutputStream(f2)) {

            byte[] bytes = new byte[1024];
            int len;
            while ((len = fileInputStream.read(bytes)) != -1) {
                fileOutputStream.write(bytes, 0, len);
            }
            System.out.println("复制成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     *
     */
    @Test
    public void test03() {
        File f1 = new File("寒烟柔.jpg");
        File f2 = new File("寒烟柔tst.jpg");


        try ( FileInputStream fileInputStream = new FileInputStream(f1);
              FileOutputStream fileOutputStream = new FileOutputStream(f2)) {

            byte[] bytes = new byte[1024];
            int len;
            while ((len = fileInputStream.read(bytes)) != -1) {
                fileOutputStream.write(bytes, 0, len);
            }
            System.out.println("复制成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    @Test
    public void test02(){
        FileInputStream fileInputStream = null;
        try {
            File file = new File("hi.txt");
            fileInputStream = new FileInputStream(file);
            int read = fileInputStream.read();// 返回的是读取的字节数据
            while (read != -1) {
                System.out.println((char)read);
                read = fileInputStream.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fileInputStream != null){
                    fileInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 使用字节流处理文本文件可能出现乱码问题
     */
    @Test
    public void test01() {
        File file = new File("hello.txt");
        try (FileInputStream fileInputStream = new FileInputStream(file)) {

            byte[] bytes = new byte[5];
            int len;
            while ((len = fileInputStream.read(bytes)) != -1) {
                // 中文乱码乱码
                System.out.println(new String(bytes, 0, len));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
 /**
     * 字符流不能处理图片文件
     */
    @Test
    public void test06() {
        File f1 = new File("寒烟柔.jpg");
        File f2 = new File("寒烟柔2.jpg");

        try (FileReader fileReader = new FileReader(f1);
             FileWriter fileWriter = new FileWriter(f2);) {
            char[] chars = new char[5];
            int len;
            while ((len = fileReader.read(chars)) != -1) {
                fileWriter.write(chars, 0, len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }




    /**
     * 文件复制
     */
    @Test
    public void test05() {

        File f1 = new File("hi.txt");
        File f2 = new File("f2.txt");

        try (FileReader fileReader = new FileReader(f1);
             FileWriter fileWriter = new FileWriter(f2);) {
            char[] chars = new char[5];
            int len;
            while ((len = fileReader.read(chars)) != -1) {
                fileWriter.write(chars, 0, len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Test
    public void test04() {
        // 1指明写出文件的位置  如果文件不存在会创建文件,如果存在就会覆盖或者追加内容
        File file = new File("hi.txt");
        // 2 提供一个write写出  第二个参数true就是在原有文件追加 ,false就是覆盖
        try (FileWriter fileWriter = new FileWriter(file,false)) {
            // 3 写出操作 //没有换行  \n可以换行
            fileWriter.write("hi i have a deram! \n");
            fileWriter.write("you need a dream too !");
            // 4 流的关闭
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Test
    public void test03() {
        FileReader fileReader = null;
        try {
            File file = new File("hello.txt");
            fileReader = new FileReader(file);
            char[] chars = new char[5];
            int len ; //返回的事char数组字符的个数

            while((len = fileReader.read(chars)) != -1) {
                System.out.print(new String(chars,0,len));
            }

        } catch (IOException e) {

        } finally {
            if(fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void test02() {
        FileReader fileReader = null;
        try {
            File file = new File("hello.txt");
            fileReader = new FileReader(file);
            int  read = 0; //返回读取的字符

            while ((read = fileReader.read()) != -1) {
                System.out.println((char)read);

            }
        } catch (IOException e) {

        } finally {
            if(fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * FileReader 读取hello.txt 中内容
     *
     */
    @Test
    public void test01() {

        FileReader reader = null;
        try {
//            File file = new File("hello.txt");
//            new FileReader(file);

            reader = new FileReader("hello.txt");

            int len ;
            while(( len = reader.read()) != -1) {
                System.out.print((char)len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(reader != null) {
                    reader .close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }

2 缓冲流

缓冲流的处理

BufferedInputStream
BUfferedOutputStream

BufferedWriter
BufferedReader

作用:提高流额读取和写出速度,因为内部提供了一个缓冲区



流关闭:先关外层,在关内层
说明:关闭外层流的同时,内层流也会自动关闭,关于内层流的关闭可以省略

 处理流就是套接在已有的流基础上

2.1 code

 @Test
    public void test03() {
        int a = 12;
        int b = 5;
        int c = a^b;

        int d = c^a;
        int e = c^b;

        System.out.println("d="+d);
        System.out.println("e="+e);
    }





    /**
     * BufferedReader
     * BUfferedWriter  bufferedWriter.newLine()   可以换行
     */
    @Test
    public void test02() {


        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("hello.txt")));
             BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("hello2.txt")))) {

            char[] chars = new char[1024];
            int len;
            //方式一
            while ((len = bufferedReader.read(chars)) != -1) {
                bufferedWriter.write(chars, 0, len);
            }
//            方式二
            String data; //data不包含换行符
            while((data = bufferedReader.readLine())!= null ) {
                //换行符自己添加
                bufferedWriter.write(data+"\n");
//                bufferedWriter.newLine();//重新换行
            }

//            bufferedReader.close();
//            bufferedWriter.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /*
     流关闭:先关外层,在关内层
     说明:关闭外层流的同时,内层流也会自动关闭,关于内层流的关闭可以省略
     */
    @Test
    public void test01() throws FileNotFoundException {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;

        try {
            fileInputStream = new FileInputStream("hello.txt");
            fileOutputStream = new FileOutputStream("helloout.txt");
            bufferedInputStream = new BufferedInputStream(fileInputStream);
            bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            byte[] bytes = new byte[1024];
            int len ;
            while((len = bufferedInputStream.read(bytes)) !=-1){
                bufferedOutputStream.write(bytes,0,len);
//                bufferedOutputStream.flush();//清空缓冲区
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(bufferedOutputStream!=null) {
                    bufferedOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bufferedInputStream != null) {
                    bufferedInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

3 转换流

*转换流属于字符流
* InputStreamReader: 将一个字节输入流转换为字符的输入流
* OutputStreamWriter: 将字符的输入流转化为字节的输出流
*
* 作用:提供字符流和字节流的转换
*
* 解码:字节,字节数组----》字符数组,字符串
* 编码:字符数组,字符串---》 字节数组,字节

3.1 code

/**
     * 综合使用 转换流
     *
     * 读取hhello.txt中的文件编码集市utf-8
     * 然后写出到新的文件中hellonew.txt,编码集是gbk
        
        这样在hellonew.txt文件中需要用gbk编码才能正常看到文件。否则乱码
     *
     *
     * */
    @Test
    public void test02() {
        try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("hello.txt"),"utf-8");
                OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("hellonew.txt"), "gbk")) {

            char[] chars = new char[5];
            int len;

            while ((len = inputStreamReader.read(chars)) != -1) {
                outputStreamWriter.write(chars, 0, len);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    /*
    InputStreamReader 实现字节到字符的输入流转换,解码操作
     */
    @Test
    public void test01() {

        //  把字节转换为字符流
        InputStreamReader inputStreamReader = null;
        try (FileInputStream fis = new FileInputStream("hellonew.txt")) {
            // 第二个参数 字符集,取决于当初这个文件保存的字符集
            inputStreamReader = new InputStreamReader(fis, "gbk");

            char[] chars  = new char[5];
            int len ;

            while((len = inputStreamReader.read(chars)) != -1) {
                String s = new String(chars, 0, len);
                System.out.println(s);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

hellonew.txt是用gbk编码的文件,读取的时候用gbk读取 

 @Test
    public void test07() {
        try (
          InputStreamReader isr = new InputStreamReader(new BufferedInputStream(new FileInputStream(new File("hellonew.txt"))),"gbk");
        ){

            char[] buf = new char[10];
            int len ;

            CharArrayWriter caw = new CharArrayWriter();

            while((len=isr.read(buf)) !=-1) {
                caw.write(buf,0,len);
            }

            System.out.println(caw.toString());
            /**
             * 安保费IE无附件为i
             * f就同步锁如果是用同步锁lock,
             * 那么 await ?signal signalAll也需要用在同步锁中Lock 与synchronizede区别相同点:两者都解决线程安全问题
             * 不同点:synchronized机制在执行完相应的同步代码后,
             * 自动释放同步监视器lock需要手动启动同步(lock),同时结束的时候需要手动实现(unlock)Thread类中常用的方法start 启动当前线程,调用当前线程run方法run 通常需要重写Thread类中此方法,将创建的线程要执行的操作声明在此方法中currentThread 静态方法,返回当前代码线程的线程
             * ield 释放cpu执行权join 在线a中调用线程b的join方法,
             * 此时线程a就进入阻塞状态,知道线程b执行完以后线程a才结束阻塞。不会释放锁top 已过时isAlive ?判断当前线程释放存活
             */
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

4 标准输入输出流

 /**
     * 1 标准输入, 输出流
     *  System.in 标准输入流,默认是从键盘输入
     *  System.out 标准输出流,默认输出到控制台
     *
     *  1.2
     *  System类的setIn(InputStream is) /setOut(PrintStream) 重新制定输入输出流
     *
     *  1。3 练习
     *    从键盘输入字符串,要求将读取到的郑航字符串转化成大写输出
     *    然后继续进行输入操作,知道输入e或者exit时候,退出程序
     *
     *
     */
    @Test
    public void test01() {
        BufferedReader reader = null;
        try {
            InputStream in = System.in;
            InputStreamReader inputStreamReader = new InputStreamReader(in);
            reader = new BufferedReader(inputStreamReader);

            while(true) {
                System.out.println("请输入字符串:");
                String line = reader.readLine();
                if("e".equalsIgnoreCase(line) || "exit".equalsIgnoreCase(line)){
                    System.out.println("程序结束");
                    break;
                }
                System.out.println(line.toUpperCase());
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

5 数据流

/**
     * 数据流
     *为了方便java操作基本手机类型和String的数据,可以使用数据流
     * 数据流有两个类:用于读取和写出基本数据类型,String类型的数据
     *
     * DataInputStream DataOutputStream
     *
     * 分别套接在InputStream 和 OutputStream子类上面
     *
     * DataInputStream中方法
     *  boolean readBoolean()
     *  char readChar()
     *  double readDouble()
     *  long readLong()
     *  String readUTF()
     *  byte readByte()
     *  float readFloat()
     *  short readShort()
     *  int readInt()
     *  void readFully(byte[] bs);
     *
     *  DataOutputStream 中方法
     *  将上述方法read改为write就可以
     *
     *注意点:读取不同类型的数据顺序要与当初写入的顺序一致,否则报错
     *
     */
    @Test
    public void test03() {
        DataOutputStream dos = null;
        try {
            dos = new DataOutputStream(new FileOutputStream("data.txt"));
            dos.writeUTF("张三");
            dos.writeInt(22);
            dos.writeBoolean(true);


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (dos != null) {
                    dos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 数据流
     */
    @Test
    public void test04() {

        DataInputStream dis = null;
        try {
            dis = new DataInputStream(new FileInputStream("data.txt"));
            String name = dis.readUTF();
            int age = dis.readInt();
            boolean isMail = dis.readBoolean();

            System.out.println("name:"+name);
            System.out.println("age:"+age);
            System.out.println("isMail:"+isMail);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (dis != null) {
                    dis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

6 对象流

7 打印流

/**
     * 打印流
     * 用指定的打印流替换System的默认输出流,
     * 将默认的输出到控制台到文件中
     */

    @Test
    public void test02() {
        PrintStream ps = null;
        try {

            FileOutputStream fos  = new FileOutputStream(new File("receive.txt"));
            ps = new PrintStream(fos,true);
            if(ps != null) {
                System.setOut(ps);
            }

            for (int i = 0; i < 255; i++) {
                System.out.println((char)i);
                if(i % 50 == 0) {
                    System.out.println();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                ps.close();
            }
        }

    }

8 随机存取文件流 RandomAccessFile

RandomAccessFile 随机存取文件流
直接继承Object类,并实现了DataInput DataOutput接口,也就意味着这个类既可以读也可以写

RandomAccessFile支持随机访问的方式,程序可以直接跳到文件任意地方读写,支持只访问文件部分内容,可以向已存在的文件后面追加

RandomAccessFile对象包含一个记录指针,用以存储当前读写的位置,可以自由移动指针。

long getFilePointer()  获取文件记录指针的位置
void seek(long pos)    将文件记录指针定位到pos位置

创建RandomAccessFile类需要制定mode参数,访问模式
r : 以只读方式打开
rw: 打开以便读取和写入
wrd:打开以便读取和写入,同步文件内容更新
rws:打开以便读取和写入,同步文件内容和元数据更新

如果是r只读,不会创建文件,而是会去读取一个已经存在的文件
如果是读取的文件不存在就会出现异常,如果rw,会去创建文件,如果存在就不会创建
 

  /**
     * 覆盖里面额内容从下标0开始
     */
    @Test
    public void test02() {

        RandomAccessFile raf2 = null;
        try {

            raf2 = new RandomAccessFile(new File("random.txt"),"rw");
            //从下标3的字符也就是从第四个字符开始覆盖
            raf2.seek(3);
            raf2.write("666".getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            try {
                if (raf2 != null) {
                    raf2.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * 文件的复制
     */
    @Test
    public void test01() {
        RandomAccessFile raf1 = null;
        RandomAccessFile raf2 = null;
        try {
             raf1 = new RandomAccessFile(new File("寒烟柔.jpg"),"r");
             raf2 = new RandomAccessFile(new File("寒烟柔RandomAccessFile.jpg"),"rw");
            byte[] bytes = new byte[10];

            int len ;
            while((len = raf1.read(bytes)) != -1) {
                raf2.write(bytes,0,len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (raf1 != null) {
                    raf1.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (raf2 != null) {
                    raf2.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

9 对象流

对象流的使用
* ObjectInputStream ObjectOutputStream
*
* 作用:用于存储和读取基本数据类型或者对象的处理流,它的强大之处是可以把java
* 中对象写入到数据源中,也能把对象从数据源中读取出来
*
* 1 序列化 :用ObjectOutputStream类保存基本数据类型或对象的机制
* 2 反序列化: 用ObjectInputStream 类读取基本数据类型或对象的机制
*
*  注意:
*  ObjectInputStream和ObjectOutputStream
*  不能序列化static和transient修饰的成员变量
*
*
* 对象序列化机制允许把内存中的java对象转化成平台无关的二进制流,从而允许
* 把这种二进制流持久化的保存到磁盘中,或者通过网络将这种二进制流传输到
* 另一个网络节点。当其他程序获取这种二进制流就可以恢复成原来的java对象
*
* 序列化的好处在于可将任何实现Serializable接口的对象转化为字节数据,使其
* 在保存和传输中可以还原
*
* 序列化是RMI过程的参数和返回值必须实现的机制,而rmi是javaee的基础,因此序列化机制
* 是javaEE平台的基础
*
* 如果需要让某个对象支持序列化则必须让对象所属类及属性是可序列化的。为了
* 让某个类是可序列化的,该类必须实现如下两个接口之一,否则会抛出NotSerializableException异常
* Serializable   Externalizable

凡是实现Serializable接口的的类都都有一个表示序列化版本标识的静态变量
privae static final long serialVersionUID

serialVersionUID 用来表示类的不同版本之间兼容性,简而言之,其目的是以序列化对象进行的版本控制,有关各个版本反序列化时是否兼容如果类没有定义这个静态变量,它的值运行时环境根据类的内部细节动态成成,若类
实例变量发生修改,serialVersionUID也可能发生改变,故需要显示声明。

简单讲java序列化机制是通过运行时判断类的serialVersionUID来检测版本一致性。在进行反序列化时候jvm会把传来的字节流的serialVersionUID 与本地的相应实体类的serialVersionUID进行比较,如果相同就认为一致,可进行反序列化,否则出现序列化版本不一致的异常(InvalidCastException)


除了当前类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。默认情况下基本数据类型是可序列化的。


 

9.1 code

/**
     * 序列化  ObjectOutputStream
     */
    @Test
    public void test01(){
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream("object.dat"));
            objectOutputStream.writeObject(new String ("我爱北京天安门"));

            objectOutputStream.writeObject(new Person("小明",22));
            objectOutputStream.flush();

        } catch (IOException e) {
        } finally {
            try {
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 反序列化  ObjectInputStream
     */

    @Test
    public void test02() {

        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(new File("object.dat")));

            String s = (String) objectInputStream.readObject();

            Person person = (Person) objectInputStream.readObject();
            System.out.println(s);
            System.out.println(person);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void test03() {

        Person person = new Person("张三",22);
        byte[] bytes = SerializationUtils.serialize(person);

        Person  o = (Person) SerializationUtils.deserialize(bytes);
        System.out.println("序列化前:"+person);
        System.out.println("序列化后"+o);


    }

10 访问数组流

ByteArrayOutputStream ByteArrayInputStream 不需要关闭流,即使关闭了,它们对应的方法还是可以使用,因为它们是内存读写流,不同于指向硬盘的流,它内部是使用字节数组读/写内存的,这个字节数组是它的成员变量,当这个数组不再使用变成垃圾的时候,Java的垃圾回收机制会将它回收。所以不需要关流。 

一个一个字符读。所有不会有乱码 

 @Test
    public void test05() {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("hello.txt");
            String context = "";
            byte[] buffer = new byte[10];
            int len;
            while((len = fis.read(buffer)) !=-1) { // 一个一个字节读就会有问题
                context += new String(buffer);
            }
            System.out.println(context);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

@Test
    public void test03() {
        String s = "你好,北京欢迎你! nice to meet you ";

        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            byte[] buf = new byte[10];
            int len ;
            while((len = bais.read(buf)) !=-1) {
                baos.write(buf,0,len);
            }

            String b = baos.toString();
            System.out.println(b);

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

 @Test
    public void test02() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            baos.write("你好呀".getBytes());

            String s = baos.toString();
            System.out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
    }

// 会产生乱码,读取10个字节组成字符,可能读到中文的几个字节没法组成一个字符所有有乱码
    @Test
    public void test01() {

        try {
            String b = "afwfwfwfwfffwfwfwafwfwfw中fwfffwfw中国fwfwfbcfwjefi中owfjwfgjfwfbcfwjefiowfjwfgj";
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(b.getBytes());
            byte[] buf = new byte[10];
            int len;
            String sb = "";
            while((len = byteArrayInputStream.read(buf)) != -1) {
                sb += new String(buf,0,len);
            }
            System.out.println(sb);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

//        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();



    }

    private String readStringFromInputStream(FileInputStream fis) throws IOException {

        //方式一 可能出现乱码
//        String context = "";
//        byte[] buffer = new byte[1024];
//        int len;
//        while((len = fis.read(buffer)) !=-1) {
//            context += new String(buffer);
//        }
//        return context;

        //方式二 BufferedReader
//        BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
//        char[] buf = new char[10]; // 一个字符字符所有不会乱码
//        int len ;
//        String str = "";
//        while ((len=reader.read(buf)) !=-1) {
//            str += new String(buf,0,len);
//        }
//        return str;

//        方式三 避免出现乱码
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[10];
        int len ;
        while((len=fis.read(buffer)) !=-1) {
            // 写到ByteArrayOutputStream 里面的数组中,所以最后返回单额就是toString返回
            baos.write(buffer,0,len);
        }
//        baos.toString("urf-8");
        return baos.toString();

    }

 @Test
    public void testString() {
        BufferedReader reader = null;
        try {
            FileInputStream fis = new FileInputStream("hello.txt");
            reader = new BufferedReader(new InputStreamReader(fis));
            char[] buf = new char[10];
            int len ;
            String str = "";
            while ((len=reader.read(buf)) !=-1) {
                str += new String(buf,0,len); //一个一个字符读。所有不会有乱码
            }
            System.out.println(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
@Test
    public void test04() {
        ObjectOutputStream objectOutputStream = null;

        try {
            Person person = new Person("张三",22);

            //序列化
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(person);
            oos.flush();

            byte[] bytes = baos.toByteArray();

            //反序列化
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            Person  object = (Person) ois.readObject();

            System.out.println(object);
            // 结果name属性没有序列化,因为用transient修饰
            //Person{name='null', age=22}

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

public class Person implements Serializable {

    private static final long serialVersionUID = 8834973776217191519L;
    private transient String name;

    private int age;

    public Person() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

十五、网络通信

 数据传输的例子

 

1、网络编程中两个主要问题


1 如何准确定位网络上一台或多台主机(ip),定位主机上特定的应用(port)
2 找到主机后如何可靠搞笑的进行数据传输


2、网络编程中两个要素


 1 对应问题一:ip和端口
 2 对应问题二:提供网络通信协议:tcp/ip参考模型(应用层,传输层,网络层,物理+数据链路) 

3、网络通信协议

osi参考模型 应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
tcp/ip参考模型:应用层,传输层,网络层,物理+数据链路层

4、 IP地址:inetAddress

唯一的标识internett上计算机(通信实体)
本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost
IP地址分类1:IPV4和IPV6
    IPV4:4个字节组成,4个0-255个,大概42亿,30亿都在北美,亚洲4亿,2011年已经用尽,以点分十进制标识,如192.168.0.1
    IPV6:128位(16个字节),写成8个无符号整数,每个整数都用4个十六进制位标识,数之间用冒号分开比如:  3ffe:3201:1401:1280:c8ff,fe4d:db39:1984
    
IP地址分类2:公网地址(万维网使用)和私有地址(局域网)
                192.168开头的就是私有地址,范围192.168.0.0-192.168.255.255专门组织机构内部使用
特点:不易记忆


域名:www.baidu.com
如何获取InetAddress实例:两个方法getByname() getLocalhost()
    两个常用的方法 :getHostName() getHostAddress()

/*
        IP 定位到主机 InetAddress

        getAllByName
        getByName

        getHostName
        getHostAddress
     */
    @Test
    public void test01() {
        try {
            InetAddress[] allByName = InetAddress.getAllByName("127.0.0.1");///127.0.0.1
            InetAddress localhost = InetAddress.getByName("localhost");//localhost/127.0.0.1
            InetAddress byName = InetAddress.getByName("www.baidu.com");//www.baidu.com/180.101.49.11
            InetAddress byName1 = InetAddress.getByName("www.atguigu.com");//www.atguigu.com/58.215.145.131

            Arrays.stream(allByName).forEach(System.out::println);
            System.out.println(localhost);
            System.out.println(byName);
            System.out.println(byName1);

            //getLocalHost
            InetAddress localHost = InetAddress.getLocalHost();//admin-yubin/169.254.208.80

            System.out.println(localHost);//

            //getHostName
            String hostName = byName.getHostName();//www.baidu.com
            //getHostAddress
            String hostAddress = byName.getHostAddress();//180.101.49.11

            System.out.println(hostName);
            System.out.println(hostAddress);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }


5、端口号

       标识正在计算机上运行的进程(程序)
        不同的进程有不同的端口号
        被规定为一个16位的整数:0-65535

端口分类:
     公认端口:0-1023      
          被预定义的服务器通信占用(如Http占用端口80,FTP占用端口21,Telnet占用端口23)
     注册端口:1024-49151   
         分配给用户进程或应用程序(如Tomcat占用8080,Mysql占用3306,
          oracle占用1521)
     动态/私有端口:49152-65535
     
  端口号与ip地址组得到一个网络套接字:Socket

6、网络协议

计算机网路中实现通信必须有一些约定,即通信协议,对速率,传输代码,代码结构,传输控制步骤,出错控制等制定标准。

    *问题:网络协议太复杂
        计算机网路通信涉及内容很多,比如制定源地址目标地址,加解密
        压缩,解压缩,差错控制,流量控制,路由控制,如何实现网络协议。
    通信协议分层思想
        在指定协议时,把复杂成分分解成一些简单的成分。再把他们组合起来。最
        常用的复合方式就是层次方式,即同层之间可以通信,上一层可以调用下一层,而与再下一层不发送关系,各层互相影响,利于系统开发和扩展。

TCP/IP协议族
    传输层协议有两个非常重要的协议。
        传输控制协议TCP (Transmission Controller Protocol))
        用户数据报协议UDP (User datagram Protocol)
  
  TCP/IP以其两个主要协议:传输控制协议(TCP)和网络互连协议(IP)而得名。实际上是一组协议。包括多个具有不同功能切相互关联的协议
  
  IP(Internet Protocol)协议是网络层主要协议,支持网络互连的数据通信。
  TCP/IP协议模型从更实用的角度出发,形成高效的四层体系结构,即物理链路层,,ip层,传输层和应用层。
        

  TCP协议:(比如打电话)
    使用TCP协议前,需先建立TCP连接,形成传输数据通道
    传输前采用“三次握手”方式,点对点通信是可靠的
    TCP协议进行通信的两个应用进程:客户端,服务端
    在连接中可进行大量数据传输
    传输完毕,需要释放已建立的连接,效率低
  UDP协议:(比如播放视频,发送短信,电报)
    将数据,源,目的地封装成数据包,不需要建立连接
    每个数据包大小限制为64kb
    发送不管对方是否准备好,接收方收到也不确认,故而不可靠
    可以广播发送
    发送数据结束时无需释放资源,开销小,速度快
    

UDP网络通信
类DatagramSocket和DatagramPacket 实现了基于UDP协议网络程序
UDP数据报通过数据套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够
安全送到目的地,也不能确定什么时候可以抵达

DatagramPacket 对象封装UDP数据报,在数据报中包含了发送端ip地址和端口
以及接收端ip和端口

UDP协议中每个数据报都给出完整的地息因此无需建立发送方和接收方的连接,如同快递一样。
 

/**
     * 获取端口号
     *
     * @param href 网址, ftp, http, nntp, ... 等等
     * @return
     * @throws IOException
     */
    public static int parsePort(String href) throws IOException {
        //
        URL url = new URL(href);
        // 端口号; 如果 href 中没有明确指定则为 -1
        int port = url.getPort();
        if (port < 0) {
            // 获取对应协议的默认端口号
            port = url.getDefaultPort();
        }
        return port;
    }
    /**
     * 获取Host部分
     *
     * @param href 网址, ftp, http, nntp, ... 等等
     * @return
     * @throws IOException
     */
    public static String parseHost(String href) throws IOException {
        //
        URL url = new URL(href);
        // 获取 host 部分
        String host = url.getHost();
        return host;
    }

TCP示例:客户端发送消息,服务端接收消息

 /**
     *CharArrayWriter
     */
    @Test
    public void server3() {
        Socket accept = null;
        InputStream is = null;
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8899);
            accept = serverSocket.accept();

            is = accept.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is,"utf-8"));
            CharArrayWriter charArrayWriter = new CharArrayWriter();
            String context = "";
            char[] chars = new char[10];
            int len;
            while((len=bufferedReader.read(chars))!=-1) {
                charArrayWriter.write(chars,0,len);
                context += new String(chars,0,len);
            }
            String s = charArrayWriter.toString();
            System.out.println(s);
            System.out.println(context);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (accept != null) {
                    accept.close();
                }
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }


    /**
     * ByteArrayOutputStream 不会出现乱码
     */
    @Test
    public void server2 () {
        Socket accept = null;
        InputStream is = null;
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8899);
            accept = serverSocket.accept();

            is = accept.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            byte[] bytes = new byte[12];

            int len;
            while((len=is.read(bytes))!=-1) {
                baos.write(bytes,0,len);
            }
            String s = baos.toString();
            System.out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (accept != null) {
                    accept.close();
                }
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }


    /**
     * bufferedReader 读取
     */
    @Test
    public void server() {
        BufferedReader bufferedReader = null;
        Socket accept = null;
        ServerSocket socket = null;
        try {
            socket = new ServerSocket(8899);
            accept = socket.accept();
            InetAddress inetAddress = accept.getInetAddress();
            System.out.println(inetAddress);
            String hostAddress = inetAddress.getHostAddress();
            String hostName = inetAddress.getHostName();
            System.out.println("收到客户端名成:"+hostName);
            System.out.println("收到客户端地址:"+hostAddress);
            InputStream inputStream = accept.getInputStream();

//         乱码,因为是字节读取
//        byte[] bytes = new byte[1024];
//        int len;
//        while((len=inputStream.read(bytes)) != -1) {
//            System.out.println(new String (bytes,0,len));
//        }

            bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));

            char[] chars = new char[10];
            int len;
            String context ="";
            while((len = bufferedReader.read(chars)) != -1) {
                context  += new String (chars,0,len);

            }
            System.out.println(context);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (accept != null) {
                    accept.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Test
    public void client() {
        Socket socket = null;
        OutputStream os = null;
        try {
            socket = new Socket(InetAddress.getByName("127.0.0.1"),8899);
            os = socket.getOutputStream();
            os.write("你好,我是客户端".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

TCP示例: 客户端发送图片给服务端,服务端将文件保存到本地

 @Test
    public void client() {
        Socket socket = null;
        OutputStream os = null;
        BufferedInputStream bis = null;
        try {
            socket = new Socket("127.0.0.1",8899);

            os = socket.getOutputStream();

            bis = new BufferedInputStream(new FileInputStream(new File("寒烟柔.jpg")));

            byte[] buf = new byte[1024];
            int len;

            while((len = bis.read(buf)) !=-1) {
                os.write(buf,0,len);
            }
            System.out.println("图片发送完毕!");
        } catch (IOException e) {

        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (socket != null) {
                    socket.close();
                }
                if (bis != null) {
                    bis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    @Test
    public void server() {

        ServerSocket ss = null;
        Socket socket = null;
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;
        try {
            ss = new ServerSocket(8899);
            socket = ss.accept();

            InputStream is = socket.getInputStream();

            bos = new BufferedOutputStream(new FileOutputStream(new File("server.jpg")));

            bis = new BufferedInputStream(is);

            byte[] bytes = new byte[1024];
            int len ;
            while((len = bis.read(bytes)) !=-1) {
                bos.write(bytes,0,len);
            }
        } catch (IOException e) {

        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (socket != null) {
                    socket.close();
                }
                if (ss != null) {
                    ss.close();
                }
                if (bis != null) {
                    bis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

TCP示例:从客户端发送的文件给服务端,服务端保存到本地,并返回“发送成功”给客户端

TCP例题
*          客户端发送内容给服务端,服务端将内容打印到控制台
*             客户端发送文件给服务端,服务端将文件保存到本地
*             从客户端发送的文件给服务端,服务端保存到本地,并返回“发送成功”给客户端,并关闭相应的连接。
*/

    @Test
    public void client() {
        Socket socket = null;
        OutputStream os = null;
        BufferedInputStream bis = null;
        InputStream is = null;
        try {
            socket = new Socket("127.0.0.1",8899);

            os = socket.getOutputStream();

            bis = new BufferedInputStream(new FileInputStream(new File("寒烟柔.jpg")));

            byte[] buf = new byte[1024];
            int len;

            while((len = bis.read(buf)) !=-1) {
                os.write(buf,0,len);
            }
            System.out.println("客户端发送图片完毕!");
            socket.shutdownOutput();

            is = socket.getInputStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] bytes = new byte[20];
            int ls ;
            while((ls=is.read(bytes))!=-1) {
                bos.write(bytes,0,ls);
            }

            System.out.println(bos.toString());
        } catch (IOException e) {

        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (socket != null) {
                    socket.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    @Test
    public void server() {

        ServerSocket ss = null;
        Socket socket = null;
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            ss = new ServerSocket(8899);
            socket = ss.accept();

            InputStream is = socket.getInputStream();

            bos = new BufferedOutputStream(new FileOutputStream(new File("server.jpg")));

            bis = new BufferedInputStream(is);

            byte[] bytes = new byte[1024];
            int len ;
            while((len = bis.read(bytes)) !=-1) {
                bos.write(bytes,0,len);
            }
            System.out.println("服务端图片已经保存成功到本地");
            //返回给客户端
            os = socket.getOutputStream();
            os.write("图片接收成功".getBytes());

        } catch (IOException e) {

        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (socket != null) {
                    socket.close();
                }
                if (ss != null) {
                    ss.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

UDP示例: UDP 的网络编程


    /**
     * 发送端
     */
    @Test
    public void send()  {
        DatagramSocket datagramSocket  = null;
        try {
            datagramSocket = new DatagramSocket();
            String l = "你好,我是UDP客户端发送数据测试";
            byte[] buf =l.getBytes();
            InetAddress i = InetAddress.getLocalHost();
            DatagramPacket datagramPacket = new DatagramPacket(buf,0,buf.length,i,8899);

            datagramSocket.send(datagramPacket);
        } catch (IOException e) {
        } finally {
            datagramSocket.close();
        }

    }

    /**
     * 接收到端
     */
    @Test
    public void receiver(){
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket(8899);

            byte[] bytes = new byte[100];
            DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
            socket.receive(packet);

            System.out.println(new String(packet.getData(),0,packet.getLength()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            socket.close();
        }
    }

URL编程:通过地址可以获取网上上面的协议,地址,端口,参数等以及下载网络资源

 @Test
    public void test01() {

        URL url = null;
        try {
            url = new URL("https://goss.veer.com/creative/vcg/veer/800water/veer-306261164.jpg");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        String protocol = url.getProtocol();
        String host = url.getHost();
        int port = url.getPort();
        String query = url.getQuery();

        System.out.println("protocol:"+protocol);
        System.out.println("host:"+host);
        System.out.println("port:"+port);
        System.out.println("query:"+query);
        InputStream is = null;
        FileOutputStream fos = null;
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            is = connection.getInputStream();
            fos = new FileOutputStream(new File("Into the Battlefield.jpg"));
            byte[] bytes = new byte[1024];
            int len;
            while((len=is.read(bytes)) != -1) {
                fos.write(bytes,0,len);
            }

            if (connection != null) {
                connection.disconnect();
            }
            System.out.println("下载完成");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                if (is != null) {
                    is.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

十六、常用类

1 String 

  //intern方法就是返回的是常量池中的内容,不管之前是在堆空间还是常量池中
        String s8 = s5.intern();


  @Test
    public void test01() {
        String s1 = "JAVAEE";
        String s2 = "JAVAEE";

        String s3 = new String("JAVAEE");
        String s4 = new String("JAVAEE");

        System.out.println(s1==s2); // true
        System.out.println(s1==s3); // false
        System.out.println(s1==s4); // false

        System.out.println(s1.equals(s3)); // true

        System.out.println();

    }

    @Test
    public void test02() {

        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE"+"hadoop";

        // 有变量的拼接就不是字面量,而是在堆中开辟空间,就是new的构造出来的
        String s5 = s1+"hadoop";
        String s6 = "javaEE"+s2;
        String s7 = s1+s2;

        System.out.println(s3==s4);// true
        System.out.println(s3==s5);// false
        System.out.println(s3==s6);// false
        System.out.println(s3==s7);// false
        System.out.println(s5==s6);// false
        System.out.println(s5==s7);// false
        System.out.println(s6==s7);// false

        //intern方法就是返回的是常量池中的内容,不管之前是在堆空间还是常量池中
        String s8 = s5.intern();// 返回值得到的s8使用的常量值是已经存在的javaEEhadoop
        System.out.println(s3==s8); // true
    }
 String str = new String("goot");
    char[]  ch = {'t','e','s','t'};
    public void   change(String str,char[] ch){
        str = "test ok";
        ch[0]='b';

    }
    @Test
    public void test03() {
        stringTest test = new stringTest();
        test.change(test.str,test.ch);

        System.out.println(test.str);//good
        System.out.println(test.ch); // best
    }

 字符串内存结构笔记,final修饰的是常量,final 修饰的String是在常量池中 ,都是在方法区内

 @Test
    public void test09() {
        String s1= "javaEEhadoop";
        String s2 = "javaEE";
        String s3 = s2+"hadoop";
        System.out.println(s1==s3);// false


        final String s4 = "javaEE";  //常量,在常量池中
        String s5 = s4+"hadoop";
        System.out.println(s1 == s5); // true
    }

    /**
     * String和byte[] 转化
     */
    @Test
    public void test08() {

        String s = "abcd123中国";
        //默认编码集是utf-8
        System.out.println(Charset.defaultCharset());

        byte[] bytes = s.getBytes(Charset.defaultCharset());
        String s1 = Arrays.toString(bytes);
        System.out.println(s1);

        String s2 = new String(bytes);
        System.out.println(s2);
    }

    /*
     String 与char[]之间转换
     */
    @Test
    public void test07(){
        String a = "123abc";
        char[] chars = a.toCharArray();

        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }

        CharSequence charSequence = a.subSequence(0, 3);
        System.out.println(charSequence);

        char[] arr = {'f','a','l','s','e'};

        String s = new String(arr);
        System.out.println(s);
    }

1.1 内存结构划分jvm

1.2 String 常用方法

@Test
    public void test06() {

        String s1 = "北京尚硅谷北京";
        String s2 = s1.replace('北', '东');//东京尚硅谷东京
        System.out.println(s2);

        String s3 = s1.replace("北京", "上海");//上海尚硅谷上海
        System.out.println(s3);

        String str = "12hello34world56java789mysql1415";
        //把字符串中数字替换成,逗号,,,如果结果中开头和结尾有逗号的话就去掉
        String all = str.replaceAll("\\d+", ",")
                .replaceAll("^,|,$", "");//hello,world,java,mysql
        System.out.println(all);

        String  s6 = "123242";
        System.out.println(s6.matches("\\d+"));

        String s7 = "123";
        int i = Integer.parseInt(s7);
        System.out.println(i);
    }

    @Test
    public void test05() {

        String s1 = "helloworld";

        System.out.println(s1.endsWith("ld"));
        System.out.println(s1.startsWith("hello"));

        System.out.println(s1.contains("wo"));

        int or = s1.indexOf("or");
        System.out.println(or);

        int or1 = s1.indexOf("or", 2);
        System.out.println(or1);
    }


    @Test
    public void test04() {
        String s = "helloworld";
        String s1 = "";
        String s2 = " ";
        System.out.println(s.isEmpty());
        System.out.println(s1.isEmpty());
        System.out.println(s2.isEmpty());

        String s3 = "abc";
        String s4 = "abd";
         System.out.println(s3.compareTo(s4));
        String s5 = s3.substring(1);
        System.out.println(s5);



    }

    @Test
    public void test01() {
        String s1 = "JAVAEE";
        String s2 = "JAVAEE";

        String s3 = new String("JAVAEE");
        String s4 = new String("JAVAEE");

        System.out.println(s1==s2); // true
        System.out.println(s1==s3); // false
        System.out.println(s1==s4); // false

        System.out.println(s1.equals(s3)); // true

        System.out.println();

    }

    @Test
    public void test02() {

        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE"+"hadoop";

        // 有变量的拼接就不是字面量,而是在堆中开辟空间,就是new的构造出来的
        String s5 = s1+"hadoop";
        String s6 = "javaEE"+s2;
        String s7 = s1+s2;

        System.out.println(s3==s4);// true
        System.out.println(s3==s5);// false
        System.out.println(s3==s6);// false
        System.out.println(s3==s7);// false
        System.out.println(s5==s6);// false
        System.out.println(s5==s7);// false
        System.out.println(s6==s7);// false

        //intern方法就是返回的是常量池中的内容,不管之前是在堆空间还是常量池中
        String s8 = s5.intern();// 返回值得到的s8使用的常量值是已经存在的javaEEhadoop
        System.out.println(s3==s8); // true
    }

    String str = new String("goot");
    char[]  ch = {'t','e','s','t'};
    public void   change(String str,char[] ch){
        str = "test ok";
        ch[0]='b';

    }
    @Test
    public void test03() {
        stringTest test = new stringTest();
        test.change(test.str,test.ch);

        System.out.println(test.str);//good
        System.out.println(test.ch); // best
    }

1.3 String的几个基本算法问题:

* 1 模拟一个trim方法,去除字符串两端的空格  charAt 然后截取
*
* 2 将一个字符串进行反转 ,将字符串中指定部分反转 比如String abcdefg 转为 abfedcg
*
* 3 获取一个字符串在另一个字符串中出现的次数,比如ab在 abkkcadkabkebfkabkskab
*
* 4 获取两个字符串中最大相同子串,
* 比如:String str = "abcdwerthelloyuiodef"; String str2 = "cvhellobnm";
* -- 提示:将短的那个串进行长度一次递减的子串与长串比较,(在循环中比较,减少字符后的内容左侧向右侧移动一个个比较)
* 5 对字符串中字符进行自然顺序排序
*
* -- 提示:字符串转字符数组,排序后再转成字符串

 /**
     * 5 对字符串中字符进行自然顺序排序
     */
    @Test
    public void tst13 () {
        String s = "edcba";
        String s1 = sortString(s);
        System.out.println(s1);
    }

    /**
     * 冒泡排序将字符串中每个字符排序,按照自然排序
     * @param str sortString
     * @return
     */
    private String sortString(String str) {
        if(str == null) {
            return null;
        }
        char[] chars = str.toCharArray();

        // 外层循环控制次数:   循环完一次后将这一轮最大的放在最后的
        for (int i = 0; i < chars.length-1; i++) {
            // 内层循环比较数据: 内存恶鬼 循环就是将 比较数据
            for(int j =0;j<chars.length-1-i;j++) {
                if(chars[j]>chars[j+1]) {
                    char temp = chars[j];
                    chars[j] = chars[j+1];
                    chars[j+1] = temp;
                }
            }
        }
        return new String(chars);
    }


    /**
     * 4 获取两个字符串中最大相同子串,
     *      *    比如:String str = "abcdwerthelloyuiodef"; String str2 = "cvhellobnm";
     *      *  -- 提示:将短的那个串进行长度一次递减的子串与长串比较
     */

    @Test
    public void test12() {

        String str1 = "abcdwerthelloyuiodef";
        String str2 = "cvhellobnm";
        String s = searchKeyWord(str1, str2);
        System.out.println(s);
    }


    private String searchKeyWord(String str,String key) {
//        String str1 = "abcdwerthelloyuiodef";
//        String str2 = "cvhellobnm";

        if(str != null && key != null) {
            int i1 = str.length();
            int i2 = key.length();

            String mainString = i1 >= i2 ? str:key;
            String subString = i2 <= i1 ? key:str;
            System.out.println("长的一段长度:"+mainString);
            System.out.println("短的一段长度:"+subString);

            int length = subString.length();

            for (int i = 0; i < length ; i++) {
                for(int x =0,y=length-i;y<=length;x++,y++) {
                    String subStr = subString.substring(x, y);
                    System.out.println(subStr);
                    if(mainString.contains(subStr)) {
                        return subStr;
                    }
                }
            }
        }


        return null;
    }

    @Test
    public void test11() {
//        3 获取一个字符串在另一个字符串中出现的次数,比如ab在 abkkcadkabkebfkabkskab
        String s1 = "abkkcadkabkebfkabkskab";
        String s2 = "ab";
        Integer integer = countNum(s1, s2);
        System.out.println(integer);

    }

    private Integer countNum(String src,String reg) {
        int count = 0;
        int index = 0;

        index = src.indexOf(reg,index);
        while(true) {
            // 0
            // 0+end
            // end + end


            if(index>-1) {
                count++;
                index = src.indexOf(reg,index+reg.length());
            }else {
                break;
            }
        }
        return count;
    }



    @Test
    public void receiveString() {
        String s = "abcdefg" ;
        //方式一
        String reverse = reverse(s, 2, 5);
        System.out.println(reverse);
//        方式二
        String s1 = receString(s,1,6);
        System.out.println(s1);
    }

    private String reverse(String str ,int start,int end) {
        char[] arr = str.toCharArray();
        System.out.println(arr);
        for(int x=start,y=end;x<y;x++,y--) {
            char tem  = arr[x];
            arr[x] = arr[y];
            arr[y] = tem;
        }


        return  new String(arr);
    }

    /**
     * 2 将一个字符串进行反转 ,将字符串中指定部分反转 比如String abcdefg  转为 abfedcg
     * @param str
     * @param start
     * @param end
     * @return
     */
    private String receString(String str,int start,int end) {
        String startString = str.substring(0,start+1);
        String endString = str.substring(end);
        String tempString = str.substring(start,end);

        String nweStr = "";
        char[] chars = tempString.toCharArray();
        for (int i = chars.length-1; i >= 0 ; i--) {
            nweStr+=chars[i];
        }
        return startString+nweStr+endString;
    }

    /**
     * 1 模拟一个trim方法,去除字符串两端的空格
     *
     * 2 将一个字符串进行反转 ,将字符串中指定部分反转 比如String abcdefg  转为 abfedcg
     *
     * 3 获取一个字符串在另一个字符串中出现的次数,比如ab在 abkkcadkabkebfkabkskab
     *
     * 4 获取两个字符串中最大相同子串,
     *    比如:String str = "abcdwerthelloyuiodef"; String str2 = "cvhellobnm";
     *  -- 提示:将端的那个串进行长度一次递减的子串与长串比较
     *  5 对字符串中字符进行自然顺序排序
     *
     *  -- 提示:字符串转字符数组,排序后再转成字符串
     */
    @Test
    public void test10() {

        String s  = "   aaa  bbb  b jelwfjw   ";
//        String s1 = s.replaceAll("^' '| ' '$", "");
        String s1 = trimString(s);

        System.out.println("----"+s1+"----");


    }

/**
     * 模拟String的trim方法
     *
     * @param str
     * @return
     */
    private String trimString(String str) {
       String result=  str.substring(1);

       if(str.isEmpty()) {
           return str;
       }
       int start=0,end =str.length()-1;
       while(start<end && str.charAt(start)== ' ') {
           start++;
       }

        while(start<end && str.charAt(end)== ' ') {
            end--;
        }
       return str.substring(start,end);
    }


 @Test
    public void test09() {
        String s1= "javaEEhadoop";
        String s2 = "javaEE";
        String s3 = s2+"hadoop";
        System.out.println(s1==s3);// false


        final String s4 = "javaEE";  //常量,在常量池中
        String s5 = s4+"hadoop";
        System.out.println(s1 == s5); // true
    }

    /**
     * String和byte[] 转化
     */
    @Test
    public void test08() {

        String s = "abcd123中国";
        //默认编码集是utf-8
        System.out.println(Charset.defaultCharset());

        //编码
        byte[] bytes = s.getBytes(Charset.defaultCharset());
        String s1 = Arrays.toString(bytes);
        System.out.println(s1);

        //解码
        String s2 = null;
        try {
            s2 = new String(bytes,"utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(s2);
    }

    /*
     String 与char[]之间转换
     */
    @Test
    public void test07(){
        String a = "123abc";
        char[] chars = a.toCharArray();

        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }

        CharSequence charSequence = a.subSequence(0, 3);
        System.out.println(charSequence);

        char[] arr = {'f','a','l','s','e'};

        String s = new String(arr);
        System.out.println(s);
    }


    @Test
    public void test06() {

        String s1 = "北京尚硅谷北京";
        String s2 = s1.replace('北', '东');//东京尚硅谷东京
        System.out.println(s2);

        String s3 = s1.replace("北京", "上海");//上海尚硅谷上海
        System.out.println(s3);

        String str = "12hello34world56java789mysql1415";
        //把字符串中数字替换成,逗号,,,如果结果中开头和结尾有逗号的话就去掉
        String all = str.replaceAll("\\d+", ",")
                .replaceAll("^,|,$", "");//hello,world,java,mysql
        System.out.println(all);

        String  s6 = "123242";
        System.out.println(s6.matches("\\d+"));

        String s7 = "123";
        int i = Integer.parseInt(s7);
        System.out.println(i);
    }

    @Test
    public void test05() {

        String s1 = "helloworld";

        System.out.println(s1.endsWith("ld"));
        System.out.println(s1.startsWith("hello"));

        System.out.println(s1.contains("wo"));

        int or = s1.indexOf("or");
        System.out.println(or);

        int or1 = s1.indexOf("or", 2);
        System.out.println(or1);
    }


    @Test
    public void test04() {
        String s = "helloworld";
        String s1 = "";
        String s2 = " ";
        System.out.println(s.isEmpty());
        System.out.println(s1.isEmpty());
        System.out.println(s2.isEmpty());

        String s3 = "abc";
        String s4 = "abd";
         System.out.println(s3.compareTo(s4));
        String s5 = s3.substring(1);
        System.out.println(s5);

    }

    @Test
    public void test01() {
        String s1 = "JAVAEE";
        String s2 = "JAVAEE";

        String s3 = new String("JAVAEE");
        String s4 = new String("JAVAEE");

        System.out.println(s1==s2); // true
        System.out.println(s1==s3); // false
        System.out.println(s1==s4); // false

        System.out.println(s1.equals(s3)); // true

        System.out.println();

    }

    @Test
    public void test02() {

        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE"+"hadoop";

        // 有变量的拼接就不是字面量,而是在堆中开辟空间,就是new的构造出来的
        String s5 = s1+"hadoop";
        String s6 = "javaEE"+s2;
        String s7 = s1+s2;

        System.out.println(s3==s4);// true
        System.out.println(s3==s5);// false
        System.out.println(s3==s6);// false
        System.out.println(s3==s7);// false
        System.out.println(s5==s6);// false
        System.out.println(s5==s7);// false
        System.out.println(s6==s7);// false

        //intern方法就是返回的是常量池中的内容,不管之前是在堆空间还是常量池中
        String s8 = s5.intern();// 返回值得到的s8使用的常量值是已经存在的javaEEhadoop
        System.out.println(s3==s8); // true
    }



    String str = new String("goot");
    char[]  ch = {'t','e','s','t'};


    public void   change(String str,char[] ch){
        str = "test ok";
        ch[0]='b';

    }
    @Test
    public void test03() {
        stringTest test = new stringTest();
        test.change(test.str,test.ch);

        System.out.println(test.str);//good
        System.out.println(test.ch); // best
    }

2 StringBuilder,StringBuffer

2.1 面试题:StringBuilder,StringBuffer,String异同的

String:不可变字符序列    底层都是用char[]存储
StringBuffer:可变字符序列 线程安全 底层都是用char[]存储
StringBuilder:可变字符序列 线程不安全 底层都是用char[]存储
    


扩容问题:如果添加的数组底层数组盛不下,那就需要扩容底层数组
        默认情况扩容为原来的容量的2倍+2,同时将原来数组中元素复制到新的数组中。
        指导意义,在开发过程中,建议大家使用StringBuffer(int capacity)

2.2 StringBuffer StringBuilder常用方法

StringBuffer append(xxx)        
StringBuffer delete(int start,int end)//左闭右开
StringBuffer replace(int start,int end ,String str)//左闭右开
StringBuffer insert(int offset,xxx)
StringBuffer reverse()
indexOf(String str)
subString(int start,int end)//左闭右开
length()
charAt(int n)
setCharAt(int n,char char)

2.3 总结


    增:append 
    删:delete  deleteCharAt
    改 setCharAt   replace
    查  charAt
    插: insert
    长度  length()
    遍历       
    
    效率StringBuilder>StringBuffer>String 
    

十七、日期和时间

1 jkd1.8以前的日期和时间

java.util.Date类
    --java.sql.Date类
 1 两个构造器

Date date = new Date(1601019014355L);
Date date = new Date(); //创建了当前时间的

 2 两个方法
    toString()//Fri Sep 25 15:28:46 CST 2020
    getTime() // 1601019013355
    
    java.sql.Date 对应数据库中的时间
    
    SimpleDateFormat日期格式化
    
    Calender:日历类
        实例化:Calender.getInstance()
                调用子类GregorianCalendar构造器
        常用方法:
        一个Calender的实例是系统时间的抽象表示,通过Thread类的对象调用start方法
        get(int field)方法来获取想要的时间细细,比如ticket就是共享数据
        YEAR,MONTH,DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND
        

 @Test
    public void test01() {
        //实例化日历
        Calendar instance = Calendar.getInstance();

         // 常用方法
        //获取我们要的数据,比如
        int i = instance.get(Calendar.HOUR);
        System.out.println(i);
        instance.set(Calendar.HOUR,6);
        System.out.println(instance.get(Calendar.HOUR));

        instance.add(Calendar.HOUR,3);
        System.out.println(instance.get(Calendar.HOUR));

        Date time = instance.getTime();
        System.out.println(time);

        instance.setTime(new Date());
        System.out.println(instance);


    }


        public void set(int field,int value);
        public void add(int filed,int value);
        public final Date getTimt();
        public final void setTime(Date date);
        
        注意:获取月份时候,是0-11
            星期是周日是1 周六是7
            
joda-time jar包,如果jdk不是8版本也可以用新的日期时间

2 jkd1.8以后的日期和时间

LocalDate

LocalTime

LocalDateTime
Instant:时间线上的瞬时点,这可能用来记录应用程序中的时间戳

在处理时间和日期的时候,我们通常想到年月日时分秒,然后这只是时间的一个模型。
而面向人人的,第二种通用模型面型机器。或者说是连续的。在此模型中
时间线中的一个点表示为一个很大的数。这有利于计算机处理
        
        
ZoneId:包含所有时区信息,一个时区的id
ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,比如ticket就是共享数据    
    2007-12-03T10:15:30+01:00 Europe/Paris
     其中每个时区都对应着ID,地区ID都为{区域/城市}格式,
Clock:使用时区提供对当前即时,日期和时间的访问时钟
Duration:持续时间,用于计算两个时间间隔
Period:日期间隔,用于计算两个日期间隔
TemoralAdjuster:时间矫正器,有时我们可能需要获取例如:将日期调整为到“下一个工作日”等操作
TemploralAdjusters:该类通过静态方法(firstDayOfXXX/lastDayOfXXXX/nexxxx)
 提供了大量常用的TemporalAdjuster的实现
 

  @Test
    public void test05() {
        Set<String> availableZoneIds =
                ZoneId.getAvailableZoneIds();
        int size = availableZoneIds.size();
        System.out.println(size);
//        availableZoneIds.forEach(System.out::println);
        LocalDateTime now = LocalDateTime.now(ZoneId.of("US/Pacific"));
        System.out.println(now);
        ZonedDateTime zonedDateTime = now.atZone(ZoneId.of("Asia/Shanghai"));
        System.out.println(now);
        System.out.println(zonedDateTime);
//        2020-10-08T23:12:06.269
//        2020-10-08T23:12:06.269
//        2020-10-08T23:12:06.269+08:00[Asia/Shanghai] 这个时间还是now的时间,但是后面会多个时区并且标明跟UTC相差几个时区

    }

    @Test
    public void test04() {
        ZoneOffset zoneOffset = ZoneOffset.ofHours(8);//偏移量
        Instant instant = Instant.now();
        OffsetDateTime offsetDateTime = instant.atOffset(zoneOffset);

        LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("US/Pacific"));

        LocalDateTime now2 = LocalDateTime.now();
        System.out.println(now2);
        ZonedDateTime zonedDateTime = now2.atZone(ZoneId.of("Asia/Shanghai"));//这个时间还是now2的时间,但是后面会多个时区并且标明跟UTC相差几个时区
        System.out.println(now2);
        System.out.println(zonedDateTime);

    }

    /**
     * DateTimeFormatter
     */
    @Test
    public void test03() {
        DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;


        // datetime 适用于 SHORT LONG MEDIUM
        DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        // date 适用于 FULL SHORT LONG MEDIUM
        DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
        DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        //格式化
        String format = formatter.format(LocalDateTime.now());
        System.out.println(format);

        TemporalAccessor parse = formatter.parse(format);
        System.out.println(parse);

        String format1 = formatter1.format(LocalDateTime.now());
        System.out.println(format1);
    }


    @Test
    public void test02() {
        // 时间线上的瞬时点
        Instant now = Instant.now();//本初子午线对应的时间时间
        System.out.println(now);
        //指定时区偏移量
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));

        System.out.println(offsetDateTime);
        long epochMilli = now.toEpochMilli();
        System.out.println(epochMilli);


        //指定时间的时间戳
        Instant instant = Instant.ofEpochMilli(81653551);
        System.out.println(instant);



    }
    @Test
    public void test01() {
        //now  获取当前时间
        LocalDate date1 = LocalDate.now();
        LocalDateTime date2 = LocalDateTime.now();
        LocalTime date3 = LocalTime.now();

        System.out.println(date1);
        System.out.println(date2);
        System.out.println(date3);


        // of  设置指定日期时间,没有偏移量
        LocalDateTime of = LocalDateTime.of(2020,1,22,8,23,5);
        System.out.println(of);

        //getXX 获取

        System.out.println(date2.getDayOfWeek());

        //with 设置时间  体现不可变,只有返回值是改了后的,原来的值是不变的
        LocalDateTime dateTime = date2.withDayOfMonth(3);
        System.out.println(dateTime);


        //加  plus
        LocalDateTime dateTime1 = date2.plusHours(2);
        System.out.println(dateTime1);


        // 减 minus
        LocalDateTime dateTime2 = date2.minusHours(2);
        System.out.println(dateTime2);
        LocalDateTime localDateTime = date2.minusYears(1);
        System.out.println(localDateTime);

    }

十八、java比较器 自然排序Comparable 或者 定制Comparator
 


 正常情况下只能进行比较== !=  不能使用大于小于但是在开发中需要对多个对象进行排序
 
 使用两个接口中的一个:自然排序Comparable 或者 定制Comparator
 
 当元素类型没有实现java.lang.Comparable接口而又不方便修改代码 或者实现Comparable接口的排序规则不适合当前操作,那么可以考虑用Comparator的对象来排序,强行对多个对象进行整体排序的比较重写Compare(Object o1,Object o2)方法比较o1和o2大小。如返回的正整数表示o1大于o2,如果返回0则表示相等,如果返回-1表示o1小于o2可以将Comparator传递给sort方法比如(Collectors.sort或者Arrays.sort) 从而允许排序上实现精确控制。还可以使用Comparator来控制某些数据接口(比如有序Set和有序映射)的顺序,或者为那些没有自然排序的对象Collection提供排序。
 

1 comparable自然排序

 @Test
    public void test02() {
        Goods[] goods = new Goods[5];

        goods[0] = new Goods("xiaomi",22.0);
        goods[1] = new Goods("huawei",52.0);
        goods[2] = new Goods("meizu",11.00);
        goods[3] = new Goods("huashuo",88.0);
        goods[4] = new Goods("yijia",52.0);
        Arrays.sort(goods);
        System.out.println(Arrays.toString(goods));
    }

public class Goods implements Comparable {

    private String name;
    private Double prise;

    public Goods(String name, Double prise) {
        this.name = name;
        this.prise = prise;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrise() {
        return prise;
    }

    public void setPrise(Double prise) {
        this.prise = prise;
    }

    /**
     * 自然排序:
     * 指明按照价格从小到大排序
     *  价格相等则再按照名称从高到低
     * @param o
     * @return
     */
    @Override
    public int compareTo(Object o) {
        if(o instanceof Goods) {
            Goods g = (Goods) o;
            if(this.prise>g.getPrise()) {
                return 1;
            }else if(this.prise<g.getPrise()) {
                return -1;
            }else {
                return -this.name.compareTo(g.getName());
            }
        }

        throw new RuntimeException("当前不是商品");
    }

    @Override
    public String toString() {
        return "Goods{" +
                "name='" + name + '\'' +
                ", prise=" + prise +
                '}';
    }
}

2 comparator

@Test
    public void test3() {
        Goods[] goods = new Goods[5];

        goods[0] = new Goods("xiaomi",22.0);
        goods[1] = new Goods("huawei",52.0);
        goods[2] = new Goods("meizu",11.00);
        goods[3] = new Goods("huashuo",88.0);
        goods[4] = new Goods("yijia",52.0);

        Arrays.sort(goods,(o1,o2)->{
            if(o1.getPrise()>o2.getPrise()) {
                return 1;
            }else if(o1.getPrise()<o2.getPrise()) {
                return -1;
            }else {
                return o1.getName().compareTo(o2.getName());
            }
        });
        System.out.println(Arrays.toString(goods));
    }

十九、常用类 System,Math,BigInteger,BigDecimal

1 System

 /**
     * System
     */
    
    @Test
    public void test6() {
        String jversion = System.getProperty("java.version");
        System.out.println(jversion);

        String jhome = System.getProperty("java.home");
        System.out.println(jhome);

        String oversion = System.getProperty("os.version");
        System.out.println(oversion);
        String ohome = System.getProperty("os.name");
        System.out.println(ohome);

        String uname = System.getProperty("user.name");
        System.out.println(uname);

        String uhome = System.getProperty("user.home");
        System.out.println(uhome);
        String udir = System.getProperty("user.dir");
        System.out.println(udir);
    }

1.8.0_191
C:\Program Files\Java\jdk1.8.0_191\jre
6.1
Windows 7
admin
C:\Users\admin
G:\ideaIU-2018.1.4.win\IdeaProjects\fileIO

2 Math

abs  绝对值
 acos asin atan cos sin tan 三角函数
 sqrt 平方根
 pow(double a,double b) a的b此幂
 log 自然数
 exp e为底指数
 max(double a,double b) 
 min(double a,double b) 
 random() 返回0.0到1.0的随机数
 long round(double a) double型整数a转化为long型(四舍五入)

 toDegrees (double angrad) 弧度-》角度
 toRadians(double angdeg) 角度-》弧度

3  BigInteger,BigDecimal


    @Test
    public void test7(){
        BigInteger bigInteger = new BigInteger("3232323233333333333333333322222222222222222253233432232");
        System.out.println(bigInteger);

        BigDecimal bd1 = new BigDecimal("1332333.254221");
        BigDecimal bd2 = new BigDecimal("22");
        System.out.println(bd1);
        System.out.println(bd2);

//        BigDecimal divide = bd1.divide(bd2);
        BigDecimal divide1 = bd1.divide(bd2, BigDecimal.ROUND_HALF_UP);
        BigDecimal divide2 = bd1.divide(bd2, 13, BigDecimal.ROUND_HALF_UP);
//        System.out.println(divide);
        System.out.println(divide1);
        System.out.println(divide2);

    }

BigDecimal中的divide主要就是用来做除法的运算。其中有这么一个方法.

        public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode)

    第一个参数是除数,第二个参数代表保留几位小数,第三个代表的是使用的模式。

    BigDecimal.ROUND_DOWN:直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2

    BigDecimal.ROUND_UP:直接进位,比如1.21如果保留1位小数,得到的就是1.3

    BigDecimal.ROUND_HALF_UP:四舍五入,2.35保留1位,变成2.4

    BigDecimal.ROUND_HALF_DOWN:四舍五入,2.35保留1位,变成2.3

    后边两种的区别就是如果保留的位数的后一位如果正好是5的时候,一个舍弃掉,一个进位。

注意

看如下案例:

        BigDecimal d1 = new BigDecimal (45);    //45除以7=6.428571428571429

        BigDecimal d2 = new BigDecimal (7); 

        d1.divide(d2,5,BigDecimal.ROUND_UP);//得到的结果就是6.42858,直接进位

        但是要注意的点在这里

        就是

         System.out.println(d1.divide(d2,3,BigDecimal.ROUND_HALF_UP));//

         System.out.println(d1.divide(d2,3,BigDecimal.ROUND_HALF_DOWN));//

        上面的代码意思是结果保留3位,第四位是5,

        如果我们按照上面的理解,得到的结果应该一个是6.429,一个是6.428

        但是实际的运行结果都是6.429 。这里要注意,这个怎么看呢,如要注意,这两个的本质都是四舍五入,如果你的结果总位数超过了你要保留的位数,都是按照四舍五入。

        那么什么时候才按照进位和设为进行运算呢,只有你的结果的位数恰好比要保留的位数多一位,并且最后一位是恰好是5,才按照之前的规则进行运算。

二十、集合

1 Collection 和Collections

2 List

ArrayList: 线程不安全,数组,适合查找,可自动扩容50%

       三个构造器,无参,容量,Collection接口,transient Object[] elementData;不被序列化。

LinkedList:线程不安全,链表,适合插入,删除

Vector:   线程安全,数组,适合查找,可自动扩容100%

3 Set

HashSet:内部new了一个hashMap,添加时key放数据,value放一个内部定义的final的Object对象,线程不安全,可以存储null         值,但是只能添加一个null值。

LinkedHashSet:内部new了一个linkHashMap,添加时key放数据,value放一个内部定义的final的Object对象,遍历时有序, 可以按 照添加顺序遍历,查找更快

TreeSet:内部new了一个TreeMap,添加时key放数据,value放一个内部定义的final的Object对象.可以按照添加对象的指定属性进行排序。:自然排序和定制排序,实现Comparable接口或者Comparator接口

 //面试题
@Test
    public void test7() {
        Set set = new HashSet();
        User u1 = new User("AA", 1001);
        User u2 = new User("BB", 1002);

        set.add(u1);
        set.add(u2);


        u1.setName("CC");
        set.remove(u1);  // 先判断有没有这值再删除  通过hashcode然后根据hash值找到位子,然后看是否有值  这里改了值可能算出来的位置不在那里了
        // [User{name='CC', age=1001}, User{name='BB', age=1002}]
        System.out.println(set);

        set.add(new User("CC",1001));
        System.out.println(set); //[User{name='CC', age=1001}, User{name='CC', age=1001}, User{name='BB', age=1002}]
        set.add(new User("AA",1001));
        System.out.println(set); // [User{name='CC', age=1001}, User{name='CC', age=1001}, User{name='AA', age=1001}, User{name='BB', age=1002}]


    }

 @Test
    public void test6() {
        List<int[]> arr1 = Arrays.asList(new int[]{123, 456});
        System.out.println(arr1.size());// 1

        List<Integer> arr2 = Arrays.asList(new Integer[]{123, 46});
        System.out.println(arr2.size()); // 2

        集合转数组:toArray
    }
    /*
       定制排序
     */
    @Test
    public void test() {
        Comparator comparator = 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.compare(u1.getAge(),u2.getAge());
               }else {
                   throw new RuntimeException("输入的类型不匹配");
               }
            }
        };

        Set set = new TreeSet(comparator);
        set.add(new User("jack",22));
        set.add(new User("marry",45));
        set.add(new User("cathy",22));
        set.add(new User("kathrina",56));
        set.add(new User("rry",87));
        set.add(new User("rry",33));

        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }


    /**
     *  重写hashCode 和equal
     *  还需要重写compareTo方法
     */
    @Test
    public void test4() {
        Set set = new TreeSet();
        set.add(new User("jack",22));
        set.add(new User("marry",45));
        set.add(new User("cathy",22));
        set.add(new User("kathrina",56));
        set.add(new User("rry",87));
        set.add(new User("rry",33));

        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    /**
     * treeSet  不能添加不同类的值,需要添加相同类的对象才可以。
     *
     */
    @Test
    public void test3() {
        // 自然排序
        Set set = new TreeSet();
        set.add(22);
        set.add(11);
        set.add(55);
        set.add(77);
        set.add(21);
        set.add(34);

        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test02() {
        // 遍历有序 以按照添加顺序遍历,查找更快
        Set set = new LinkedHashSet();
        set.add("AA");
        set.add("BB");
        set.add(123);
        set.add(456);
        set.add("CC");
        set.add("CC");
        set.add(new Person("aa",22));
        set.add(new Person("aa",22));

        System.out.println(set);// 只添加了一个CC  不可重复

        // 遍历无需,但是每次遍历出来的额顺序一样,无需不代表随机
        for (Object o :set) {
            System.out.println(o);
        }

    }

    /**
     *Set 无序性  和不可重复性
     *  无序性 :不等同于随机性,以hashset为例说明,存储的数据在数组中并非按照数组索引添加。而是根据数据的hash值决定的。
     *
     *  不可重复性: 保证添加的元素按照equal方法判断时候不能返回true,即相同的只能添加一个
     *   |-----HashSet
     *       |—----LinkHashSet
     *   |----TreeSet
     *
     */
    @Test
    public void test01() {
        Set set = new HashSet();
        set.add("AA");
        set.add("BB");
        set.add(123);
        set.add(456);
        set.add("CC");
        set.add("CC");
        set.add(new Person("aa",22));
        set.add(new Person("aa",22));

        System.out.println(set);// 只添加了一个CC  不可重复

        // 遍历无需,但是每次遍历出来的额顺序一样,无需不代表随机
        for (Object o :set
             ) {
            System.out.println(o);
        }


    }

4 Map

HashTable 和 HashMap 是 Map 的实现类   
HashTable 是线程安全的,不能存储 null 值   
HashMap 不是线程安全的,可以存储 null 值  

TreeMap可以保证顺序,HashMap不保证顺序,即为无序的。

linkedHashMap:保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。


Map:双列数据,存储key-value 对的数据
        |---HashMap:作为map的主要实现类,线程不安全,效率高,存储null的key和value
            |---LinkedHashMap:保证在遍历map元素时候,可以按照添加的顺序实现遍历。
                原因:在原有的HashMap底层结构基础上,添加一对指针,指向前一个和后一个元素,对于频繁的遍历操作,此类执行效率高于HashMap
        |---TreeMap:保证按照添加的key-value对象排序,实现排序遍历,此时考虑key的自然排序和定制排序,底层是用红黑树
        
        |---Hashtable:作为古老的实现类,线程安全,效率低,不能存储null的keyhevalue    


HashMap底层实现源码:jdk7为例
    hashMap map= new HashMap();
    在实例化后底层创建了长度16的一维数组Entry[] table
      
      map.put(key1,value1)
      首先调用key1所在类的hashCode方法计算key1的hash值,此hash值经过某种算法后得到在entry数组中的位子,
      如果此位置上数据为空,此时key-value添加成功
      如果此位置上有值(意味着此位置上存在一个或者多个数据((链表方式))比较key的hash值:
        如果key1的hash与已经存在的数据的key的hash值都不同,则此时 key-value添加成功
        如果key1的hash值与已经存在的数据key的hash值相同,则比较equals
            如果equals返回false,则添加key-value成功
            如果equals返回true,则value1替换原来的值。
            
            补充:添加成功的数据相同位置的会以链表的形式存储
            在不断添加过程中,会涉及到扩容的问题,当超出临界值(且要存放的位置非空)默认扩容为原来的2倍。并将原来的值复制。
            
        jdk8 相较于jdk7在底层实现方式的不同
        :1 new HashMap:在底层没有创建创建一个16长度的数组
        2 jdk8底层数组是Node[] 而非Entry[]
        3 首次调用put方法时候,底层创建16长度的数组
        4 jkd7底层只有数组+链表,jdk8底层是数据+链表+红黑数
          当数组的某个索引位置上元素以链表形式存在的个数大于8个,并且数组长度大于64,则此索引位置上的所有数据改为使用红黑树。
          
默认加载因子:0.75
临界值:16*0.75=12
默认初始化容量:16
最大支持容量:2^30
 8 链表长度超过的限制
 64 底层数组长度超过的条件
 6
 
 LinkHashMap底层实现原理(了解)
 
 Object put(Object key,Object value)
 void putAll(Map m)
 Object remove(Object key)
 void clear()
 Object get(Object key)
 boolean containsKey(Object key)
 boolean containsValue(Object value)
 int size()
 boolean isEmpty()
 boolean equals(Object obj) 判断当前map和参数对象的object是否相等
 
 遍历map
 Set keySet
 Collection values()
 Set entrySet 
 
 以及迭代器
 
 
 TreeMap两种添加方法:
    向TreeMap中添加key-value要求key必须由同一个类创建的对象
    因为要按照key进行排序:自然排序 定制排序
    

@Test
    public void test5() {
        FileInputStream fis = null;
        System.out.println("8888");
        try {
            fis = new FileInputStream(new File("fileIO/src/main/resources/jdbc.properties"));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] bytes = new byte[4];
            int len ;
            while((len=fis.read(bytes)) !=-1) {
                baos.write(bytes,0,len);
            }
            System.out.println("******");
            String s = baos.toString("utf-8");
            System.out.println(s);
        } catch (Exception e) {

        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
//            Class<?> aClass = Class.forName("java.lang.String");
        }

    }

    @Test
    public void test4() throws Exception {
        Properties properties = new Properties();
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");

        properties.load(in);



        String jdbcName = properties.getProperty("jdbcName");
        System.out.println(jdbcName);


    }
    @Test
    public void test3() {
        // key应该是由同个类
        TreeMap<String,String> map = new TreeMap<>();

    }

    /**
     * 常用方法:
     * put
     * putAll
     * remove
     * clear
     *
     */
    @Test
    public void test2() {
        HashMap map = new HashMap();
        map.put(123,"AA");
        map.put(456,"bb");
        map.put(null,"CC");


        boolean b = map.containsKey(123);
        boolean cc = map.containsValue("CC");
        int size = map.size();
        boolean empty = map.isEmpty();
        boolean equals = map.equals(new HashMap());
    }

    @Test
    public void test1() {
        HashMap map = new HashMap();
        map.put(123,"AA");
        map.put(456,"bb");
        map.put(null,"CC");

        map.put(123,"DD");

        map.remove(null);

        System.out.println(map);
        map.clear();
        System.out.println(map.size());
    }

21 java8 9 10 11 新特性 

java8 看专递

java9 


of 与get搭配使用
ofNullable 与orElse 搭配使用
isPresent 判断是有有数据,有则true,否则false


java9新特性
1 模块化
2 jshell 可以在窗口写代码,定义类,参数和方法等 执行方法
3 接口私有方法 
4 砖石操作符<>  9以前匿名内部类new的时候不能用
  Comparator<Integer> comparator = new Comparator<>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return 0;
            }
        }
5 try写的优化
    java8可以实现资源自动关闭,但是要求执行后必须关闭的资源必须放在try子句中初始化。
    
    java9中可以初始化在外面。在try定义变量就可以。

InputStreamReader isr = new InputStreamReader(System.in);
        OutputStreamWriter osw = new OutputStreamWriter(System.out);
        try (isr;osw){
            char[] buffs = new char[1024];
            int len;
            while((len=isr.read(buffs)) != -1) {
                String str = new String(buffs, 0, len);
                System.out.println(str);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
6 string 底层用字节byte


7 集合创建只读集合of
8 Steam API

* Stream API新增四个方法
     * 
     * takeWhile  返回开头开始按照指定规则尽量多的元素,,有一个不满足就不走后面的了
     * dropWhile  与takeWhile相反,从头开始按照指定规则删除,一旦不满足就定制,后面的全部要
     * ofNullable  一个null,一个参数,java8的of不能放一个null
     * iterate 重载方法


9 Optional 可以获取流点stream  


    @Test
    public void test1() {

        InputStreamReader isr = new InputStreamReader(System.in);
        OutputStreamWriter osw = new OutputStreamWriter(System.out);
        try (isr;osw){
            char[] buffs = new char[1024];
            int len;
            while((len=isr.read(buffs)) != -1) {
                String str = new String(buffs, 0, len);
                System.out.println(str);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Test
    public void test2() {
        // jdk 8
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        List<String> strings = Collections.unmodifiableList(list);

        // jdk 9
        List<String> strings1 = Collections.unmodifiableList(Arrays.asList("a", "b", "c"));
        Set<String> strings2 = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));

        Map<Object, Object> map = Collections.unmodifiableMap(new HashMap<>() {
            {
                put("a", 1);
                put("b", 2);
                put("c", 3);
            }
        });

        Map<Object, Object> map2 = new HashMap<>() {
            {
                put("a", 1);
                put("b", 2);
                put("c", 3);
            }
        };

        map.forEach((x,y) -> System.out.println(x+","+y));

        map2.forEach((x,y) -> System.out.println(x+","+y));

        Map<String, String> map1 = Map.of("k1", "2", "k2", "4");

        Map<String, String> entries = Map.ofEntries(Map.entry("ka", "b"), Map.entry("kb", "bb"));



    }

    /**
     * 集合工厂方法:创建只读集合
     */
    @Test
    public void test4() {
        // 不能添加
        List<Integer> list = List.of(1,34, 6);
        System.out.println(list);

        // 不能添加
        Set<Integer> set1 = Set.of(2, 4, 5, 61);

        // 不能添加
        Map<String, Integer> map = Map.of("k1", 1, "k21", 21);

        Map<String, Integer> map2 = Map.ofEntries(Map.entry("k1", 22), Map.entry("k2", 23));

    }

    @Test
    public void test5() {

        try (InputStream in = this.getClass().getClassLoader().getResourceAsStream("hello.txt");
             FileOutputStream out = new FileOutputStream("src\\hello2.txt")){
            in.transferTo(out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Stream API新增四个方法
     *
     * takeWhile  返回开头开始按照指定规则尽量多的元素,,有一个不满足就不走后面的了
     * dropWhile  与takeWhile相反,从头开始按照指定规则删除,一旦不满足就定制,后面的全部要
     * ofNullable  一个null,一个参数,java8的of不能放一个null
     * iterate 重载方法
     */
    @Test
    public void test6() {
        List<Integer> list = List.of(22, 44, 55, 66, 77, 88, 1, 2, 4, 5, 6, 9, 56);
        list.stream()
                .takeWhile(x->x<60)
                .forEach(System.out::println);

        list.stream()
                .dropWhile(x->x<60)
                .forEach(System.out::println);

        Stream<Integer> integerStream = Stream.of(1, 2, 3, null);
        integerStream.forEach(System.out::println);
/// java.lang.NullPointerException: Cannot read the array length because "array" is null
//        Stream<Object> objectStream = Stream.of(null);
//        System.out.println(objectStream);

        Stream<Object> objectStream = Stream.ofNullable(null);
        long count = objectStream.count();
        System.out.println(count);//  0

        // iterate 重载方法
        Stream<Integer> iterate = Stream.iterate(0, x -> x < 100, y -> y + 1);
        iterate.forEach(System.out::println);
    }


    @Test
    public void test7() {
        List<String> list = List.of("TOM", "jerry", "marry");

        Optional<List<String>> strings = Optional.ofNullable(list);
        Stream<List<String>> stream = strings.stream();
       
        stream.flatMap(x->x.stream()).forEach(System.out::println);
    }

 java10 新特性:局部变量类型推断var

java11 新特性


10 java11 新特性 String新增的方法

 isBlank()
 strip()
 stripTrailing()
 stripLeading()
 repeat(n)
 lines().count() 行数
 
 11 Optional 新增方法
  boolean isEmpty() 判断值是否为空 与isPresent相反 
  ifPresentOrElse(Consumer<? super T> action,Runnable emptyAction)
    value非空,执行参数1功能,参数为空执行参数2的功能
  
  Optional<T> or(Suppler<? extends Optional<? extends T>> suppler)
    value非空,返会对应Optional,value为空返回形参封装的Optional

  Stream<T stream()  value非空返回仅包含此value值的stream,否则返回一个空的Stream
  
  T orElseThrow() value非空返回value,否则抛出异常
  
  
 12 java11局部变量类型推断升级
 
 使用var的好处在使用lambda表达式时候给参数加上注解
 Consumer<String> con = (@Deprecated var t)->System.out.println(t.toUpperCase());

12 全新httpClient 客户端api
   
   HttpClient client = HttpClient.newHttpClient();
   HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test")).build();
   HttpResponse.BodyHandler<String>  responseBodyHandler = httpResponse.BodyHandlers.ofString();
   HttpResponse<String> response  = client.send(request,responseBodyHandler);
   String body = response.body();
   
   
 13 java11 更简化的编译运行程序 java hello.java  不用javac编译了,只能执行第一个类的main方法 
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值