程序、进程、线程

程序(program)

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

进程(process)

是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期

如:运行中的QQ,运行中的MP3播放器

程序是静态的,进程是动态的

进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

线程(thread)

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

若一个进程同一时间并行执行多个线程,就是支持多线程的

线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小

一个进程中的多个线程共享相同的内存单元/内存地址空间,它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gumfhVT6-1631633504567)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818100245564.png)]

一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。

并行与并发

**并行:**多个CPU同时执行多个任务。比如:多个人同时做不同的事。

**并发:**一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事。

线程的创建

方式一(继承于Thread类)

  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中
  3. 创建Thread类的子类的对象
  4. 通过此对象调用start()
package com.wdl.java;//1. 创建一个继承于Thread类的子类
class MyThread extends Thread {//2. 重写Thread类的run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}public class ThreadTest {public static void main(String[] args) {//3. 创建Thread类的子类的对象MyThread t1 = new MyThread();//4.通过此对象调用start():①启动当前线程 ② 调用当前线程的run()t1.start();//问题一:我们不能通过直接调用run()的方式启动线程。相当于直接调用run方法
//        t1.run();//问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。会报IllegalThreadStateException
//        t1.start();//我们需要重新创建一个线程的对象MyThread t2 = new MyThread();t2.start();//如下操作仍然是在main线程中执行的。for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i + "***********main()************");}}}}

方式二(实现Runnable接口)

  1. 创建一个实现了Runnable接口的类
  2. 实现类去实现Runnable中的抽象方法:run()
  3. 创建实现类的对象
  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  5. 通过Thread类的对象调用start()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWAIBSwL-1631633504571)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818132818836.png)]

package com.wdl.java;//1. 创建一个实现了Runnable接口的类
class MThread implements Runnable{//2. 实现类去实现Runnable中的抽象方法:run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}public class ThreadTest1 {public static void main(String[] args) {//3. 创建实现类的对象MThread mThread = new MThread();//4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象Thread t1 = new Thread(mThread);t1.setName("线程1");//5. 通过Thread类的对象调用start():① 启动线程 ②调用当前线程的run()-->调用了Runnable类型的target的run()t1.start();//再启动一个线程,遍历100以内的偶数Thread t2 = new Thread(mThread);t2.setName("线程2");t2.start();}}

比较

这两种方式调用的都是Thread类里面的start方法

开发中:优先选择:实现Runnable接口的方式
原因:1. 实现的方式没有类的单继承性的局限性

    2. 实现的方式更适合来处理多个线程有共享数据的情况。联系:public class Thread implements Runnable相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnuIdr54-1631633504574)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818134045566.png)]

方式三(实现Callable接口)—JDK5.0新增

如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?

  1. call()可以有返回值的。
  2. call()可以抛出异常,被外面的操作捕获,获取异常的信息
  3. Callable是支持泛型的

1.创建一个实现Callable的实现类

2.实现call方法,将此线程需要执行的操作声明在call()中
3.创建Callable接口实现类的对象

4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象

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

6.获取Callable中call方法的返回值

package com.wdl.java;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;//1.创建一个实现Callable的实现类
class NumThread implements Callable{//2.实现call方法,将此线程需要执行的操作声明在call()中@Overridepublic Object call() throws Exception {int sum = 0;for (int i = 1; i <= 100; i++) {if(i % 2 == 0){System.out.println(i);sum += i;}}return sum;}
}public class ThreadNew {public static void main(String[] args) {//3.创建Callable接口实现类的对象NumThread numThread = new NumThread();//4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象FutureTask futureTask = new FutureTask(numThread);//5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()new Thread(futureTask).start();try {//6.获取Callable中call方法的返回值//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。Object sum = futureTask.get();System.out.println("总和为:" + sum);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}}

方式四(使用线程池)

好处:
1.提高响应速度(减少了创建新线程的时间)
2.降低资源消耗(重复利用线程池中线程,不需要每次都创建)
3.便于线程管理
corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间后会终止

面试题:创建多线程有几种方式?四种!

package com.wdl.java;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;class NumberThread implements Runnable{@Overridepublic void run() {for(int i = 0;i <= 100;i++){if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ": " + i);}}}
}class NumberThread1 implements Runnable{@Overridepublic void run() {for(int i = 0;i <= 100;i++){if(i % 2 != 0){System.out.println(Thread.currentThread().getName() + ": " + i);}}}
}public class ThreadPool {public static void main(String[] args) {//1. 提供指定线程数量的线程池ExecutorService service = Executors.newFixedThreadPool(10);ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;//设置线程池的属性
//        System.out.println(service.getClass());
//        service1.setCorePoolSize(15);
//        service1.setKeepAliveTime();//2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象service.execute(new NumberThread());//适合适用于Runnableservice.execute(new NumberThread1());//适合适用于Runnable//        service.submit(Callable callable);//适合使用于Callable//3.关闭连接池service.shutdown();}}

Thread中的常用方法

  1. start():启动当前线程;调用当前线程的run()
  2. run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
  3. currentThread():静态方法,返回执行当前代码的线程
  4. getName():获取当前线程的名字
  5. setName():设置当前线程的名字
  6. yield():释放当前cpu的执行权
  7. join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才
    结束阻塞状态。
  8. stop():已过时。当执行此方法时,强制结束当前线程。
  9. sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前
    线程是阻塞状态。
  10. isAlive():判断当前线程是否存活

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FNzooGX-1631633504587)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818135537808.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0geVAYW4-1631633504588)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818135617523.png)]

package com.wdl.java;class HelloThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){//                try {//                    sleep(10);
//                } catch (InterruptedException e) {//                    e.printStackTrace();
//                }System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);}//            if(i % 20 == 0){//                yield();
//            }}}public HelloThread(String name){super(name);}
}public class ThreadMethodTest {public static void main(String[] args) {HelloThread h1 = new HelloThread("Thread:1");//        h1.setName("线程一");//设置分线程的优先级h1.setPriority(Thread.MAX_PRIORITY);h1.start();//给主线程命名Thread.currentThread().setName("主线程");Thread.currentThread().setPriority(Thread.MIN_PRIORITY);for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);}//            if(i == 20){//                try {//                    h1.join();
//                } catch (InterruptedException e) {//                    e.printStackTrace();
//                }
//            }}//        System.out.println(h1.isAlive());}
}

线程优先级

MAX_PRIORITY:10
MIN _PRIORITY:1
NORM_PRIORITY:5 -->默认优先级
2.如何获取和设置当前线程的优先级:
getPriority():获取线程的优先级
setPriority(int p):设置线程的优先级
说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下
被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。

线程的生命周期

新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态

**就绪:**处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源

**运行:**当就绪的线程被调度并获得CPU资源时,便进入运行状态, run()方法定义了线程的操作和功能

**阻塞:**在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态

**死亡:**线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRZ558SB-1631633504589)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818153521684.png)]

线程安全问题解决(线程同步)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ddcUJjA4-1631633504590)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210818161532498.png)]

方式一(同步代码块)

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

说明:1.操作共享数据的代码,即为需要被同步的代码。 -->不能包含代码多了,也不能包含代码少了。
2.共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。
3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。
要求:多个线程必须要共用同一把锁。
补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。

package com.atguigu.java;class Window1 implements Runnable{private int ticket = 100;
//    Object obj = new Object();
//    Dog dog = new Dog();@Overridepublic void run() {//        Object obj = new Object();while(true){synchronized (this){//此时的this:唯一的Window1的对象   //方式二:synchronized (dog) {if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;} else {break;}}}}
}public class WindowTest1 {public static void main(String[] args) {Window1 w = new Window1();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}}class Dog{}
package com.atguigu.java;class Window2 extends Thread{private static int ticket = 100;private static Object obj = new Object();@Overridepublic void run() {while(true){//正确的
//            synchronized (obj){synchronized (Window2.class){//Class clazz = Window2.class,Window2.class只会加载一次//错误的方式:this代表着t1,t2,t3三个对象
//              synchronized (this){if(ticket > 0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + ":卖票,票号为:" + ticket);ticket--;}else{break;}}}}
}public class WindowTest2 {public static void main(String[] args) {Window2 t1 = new Window2();Window2 t2 = new Window2();Window2 t3 = new Window2();t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

方式二(同步方法)

如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

关于同步方法的总结:

  1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。
  2. 非静态的同步方法,同步监视器是:this
    静态的同步方法,同步监视器是:当前类本身
package com.atguigu.java;class Window3 implements Runnable {private int ticket = 100;@Overridepublic void run() {while (true) {show();}}private synchronized void show(){//同步监视器:this//synchronized (this){if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;}//}}
}public class WindowTest3 {public static void main(String[] args) {Window3 w = new Window3();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}}
package com.atguigu.java;/*** 使用同步方法处理继承Thread类的方式中的线程安全问题** @author shkstart* @create 2019-02-15 上午 11:43*/
class Window4 extends Thread {private static int ticket = 100;@Overridepublic void run() {while (true) {show();}}private static synchronized void show(){//同步监视器:Window4.class//private synchronized void show(){ //同步监视器:t1,t2,t3。此种解决方式是错误的if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;}}
}public class WindowTest4 {public static void main(String[] args) {Window4 t1 = new Window4();Window4 t2 = new Window4();Window4 t3 = new Window4();t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

方式三(Lock锁)—JDK5.0新增

1. 面试题:synchronized 与 Lock的异同?相同:二者都可以解决线程安全问题不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())2.优先使用顺序:
Lock
同步代码块(已经进入了方法体,分配了相应资源)
同步方法(在方法体之外)
package com.atguigu.java1;import java.util.concurrent.locks.ReentrantLock;/*** 解决线程安全问题的方式三:Lock锁  --- JDK5.0新增** 1. 面试题:synchronized 与 Lock的异同?*   相同:二者都可以解决线程安全问题*   不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器*        Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())** 2.优先使用顺序:* Lock  同步代码块(已经进入了方法体,分配了相应资源)  同步方法(在方法体之外)***  面试题:如何解决线程安全问题?有几种方式* @author shkstart* @create 2019-02-15 下午 3:38*/
class Window implements Runnable{private int ticket = 100;//1.实例化ReentrantLockprivate ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while(true){try{//2.调用锁定方法lock()lock.lock();if(ticket > 0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":售票,票号为:" + ticket);ticket--;}else{break;}}finally {//3.调用解锁方法:unlock()lock.unlock();}}}
}public class LockTest {public static void main(String[] args) {Window w = new Window();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

死锁

死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

解决方法

专门的算法、原则

尽量减少同步资源的定义

尽量避免嵌套同步

线程通信

涉及到的三个方法:
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。

说明:
1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalMonitorStateException异常
3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。

package com.wdl.java;class Number implements Runnable{private int number = 1;private Object obj = new Object();@Overridepublic void run() {while(true){synchronized (obj) {obj.notify();if(number <= 100){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + number);number++;try {//使得调用如下wait()方法的线程进入阻塞状态obj.wait();} catch (InterruptedException e) {e.printStackTrace();}}else{break;}}}}
}public class CommunicationTest {public static void main(String[] args) {Number number = new Number();Thread t1 = new Thread(number);Thread t2 = new Thread(number);t1.setName("线程1");t2.setName("线程2");t1.start();t2.start();}
}

题目一

sleep() 和 wait()的异同?
1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2.不同点:

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

题目二

生产者/消费者

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

分析:

  1. 是否是多线程问题?是,生产者线程,消费者线程
  2. 是否有共享数据?是,店员(或产品)
  3. 如何解决线程的安全问题?同步机制,有三种方法
  4. 是否涉及线程的通信?是
package com.wdl.java;class Clerk{private int productCount = 0;//生产产品public synchronized void produceProduct() {if(productCount < 20){productCount++;System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品");notify();}else{//等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}//消费产品public synchronized void consumeProduct() {if(productCount > 0){System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品");productCount--;notify();}else{//等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}
}class Producer extends Thread{//生产者private Clerk clerk;public Producer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(getName() + ":开始生产产品.....");while(true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}clerk.produceProduct();}}
}class Consumer extends Thread{//消费者private Clerk clerk;public Consumer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(getName() + ":开始消费产品.....");while(true){try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}clerk.consumeProduct();}}
}public class ProductTest {public static void main(String[] args) {Clerk clerk = new Clerk();Producer p1 = new Producer(clerk);p1.setName("生产者1");Consumer c1 = new Consumer(clerk);c1.setName("消费者1");Consumer c2 = new Consumer(clerk);c2.setName("消费者2");p1.start();c1.start();c2.start();}
}

释放锁VS不释放锁

释放锁

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

●当前线程在同步代码块、同步方法中遇到break、retuIn终止 了该代码块、该方法的继续执行.

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

●当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁.

不释放锁

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

●线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。

➢应尽量避免使用suspend()和resume()来控制线程

String类

String:字符串,使用一对""引起来表示。1.String声明为final的,不可被继承2.String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小3.String内部定义了final char[] value用于存储字符串数据4.String:代表不可变的字符序列。简称:不可变性。体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。2. 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。3. 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。6.字符串常量池中是不会存储相同内容的字符串的。

内存解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mqVOZCMd-1631633504591)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819104409148.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IsAZLcj0-1631633504593)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819191150929.png)]

@Test
public void test1(){String s1 = "abc";//字面量的定义方式String s2 = "abc";s1 = "hello";System.out.println(s1 == s2);//比较s1和s2的地址值System.out.println(s1);//helloSystem.out.println(s2);//abcSystem.out.println("*****************");String s3 = "abc";s3 += "def";System.out.println(s3);//abcdefSystem.out.println(s2);System.out.println("*****************");String s4 = "abc";String s5 = s4.replace('a', 'm');System.out.println(s4);//abcSystem.out.println(s5);//mbc}

String实例化方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-syMPHsGA-1631633504594)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819191331939.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOMQPrSi-1631633504595)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819193017412.png)]

方式一:通过字面量定义的方法

方式二:通过new+构造器的方式

@Test
public void test2(){//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。String s1 = "javaEE";String s2 = "javaEE";//通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。String s3 = new String("javaEE");String s4 = new String("javaEE");System.out.println(s1 == s2);//trueSystem.out.println(s1 == s3);//falseSystem.out.println(s1 == s4);//falseSystem.out.println(s3 == s4);//falseSystem.out.println("***********************");Person p1 = new Person("Tom",12);Person p2 = new Person("Tom",12);System.out.println(p1.name.equals(p2.name));//trueSystem.out.println(p1.name == p2.name);//truep1.name = "Jerry";System.out.println(p2.name);//Tom
}

题目一

面试题:String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?

两个:

一个是堆空间中new结构,

另一个是char[]对应的常量池中的数据:“abc”

题目二

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZSHBQZGq-1631633504596)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819195437628.png)]

不同拼接方式对比

1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中

@Test
public void test3(){String s1 = "javaEE";String s2 = "hadoop";String s3 = "javaEEhadoop";String s4 = "javaEE" + "hadoop";//都在字符串常量池中String s5 = s1 + "hadoop";String s6 = "javaEE" + s2;String s7 = s1 + s2;System.out.println(s3 == s4);//trueSystem.out.println(s3 == s5);//falseSystem.out.println(s3 == s6);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s5 == s6);//falseSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//falseString s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”System.out.println(s3 == s8);//true}

题目一

1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中

@Test
public void test4(){String s1 = "javaEEhadoop";String s2 = "javaEE";String s3 = s2 + "hadoop";System.out.println(s1 == s3);//falsefinal String s4 = "javaEE";//s4:常量String s5 = s4 + "hadoop";System.out.println(s1 == s5);//true}

字符串常量池位置变化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BiVWMpSe-1631633504597)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825161855967.png)]

JDK1.7

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t84AwnOi-1631633504598)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819200443817.png)]

JDK1.8

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LWdcq1bk-1631633504598)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210819200508722.png)]

String的常用方法

int length():返回字符串的长度: return value.length
char charAt(int index): 返回某索引处的字符return value[index]
boolean isEmpty():判断是否是空字符串:return value.length == 0
String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
String trim():返回字符串的副本,忽略前导空白和尾部空白
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
int compareTo(String anotherString):比较两个字符串的大小
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索注:indexOf和lastIndexOf方法如果未找到都是返回-1替换:
String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
匹配:
boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
切片:
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
package com.atguigu.java;import org.junit.Test;/*** @author shkstart* @create 2019 上午 11:52*/
public class StringMethodTest {@Testpublic void test4(){String str1 = "北京尚硅谷教育北京";String str2 = str1.replace('北', '东');System.out.println(str1);System.out.println(str2);String str3 = str1.replace("北京", "上海");System.out.println(str3);System.out.println("*************************");String str = "12hello34world5java7891mysql456";//把字符串中的数字替换成,,如果结果中开头和结尾有,的话去掉String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");System.out.println(string);System.out.println("*************************");str = "12345";//判断str字符串中是否全部有数字组成,即有1-n个数字组成boolean matches = str.matches("\\d+");System.out.println(matches);String tel = "0571-4534289";//判断这是否是一个杭州的固定电话boolean result = tel.matches("0571-\\d{7,8}");System.out.println(result);System.out.println("*************************");str = "hello|world|java";String[] strs = str.split("\\|");for (int i = 0; i < strs.length; i++) {System.out.println(strs[i]);}System.out.println();str2 = "hello.world.java";String[] strs2 = str2.split("\\.");for (int i = 0; i < strs2.length; i++) {System.out.println(strs2[i]);}}@Testpublic void test3(){String str1 = "hellowworld";boolean b1 = str1.endsWith("rld");System.out.println(b1);boolean b2 = str1.startsWith("He");System.out.println(b2);boolean b3 = str1.startsWith("ll",2);System.out.println(b3);String str2 = "wor";System.out.println(str1.contains(str2));System.out.println(str1.indexOf("lol"));System.out.println(str1.indexOf("lo",5));String str3 = "hellorworld";System.out.println(str3.lastIndexOf("or"));System.out.println(str3.lastIndexOf("or",6));//什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?//情况一:存在唯一的一个str。情况二:不存在str}@Testpublic void test2() {String s1 = "HelloWorld";String s2 = "helloworld";System.out.println(s1.equals(s2));System.out.println(s1.equalsIgnoreCase(s2));String s3 = "abc";String s4 = s3.concat("def");System.out.println(s4);String s5 = "abc";String s6 = new String("abe");System.out.println(s5.compareTo(s6));//涉及到字符串排序String s7 = "北京尚硅谷教育";String s8 = s7.substring(2);System.out.println(s7);System.out.println(s8);String s9 = s7.substring(2, 5);System.out.println(s9);}@Testpublic void test1() {String s1 = "HelloWorld";System.out.println(s1.length());System.out.println(s1.charAt(0));System.out.println(s1.charAt(9));
//        System.out.println(s1.charAt(10));
//        s1 = "";System.out.println(s1.isEmpty());String s2 = s1.toLowerCase();System.out.println(s1);//s1不可变的,仍然为原来的字符串System.out.println(s2);//改成小写以后的字符串String s3 = "   he  llo   world   ";String s4 = s3.trim();System.out.println("-----" + s3 + "-----");System.out.println("-----" + s4 + "-----");}
}

String与char[]之间的转换

String --> char[]:调用String的toCharArray()
char[] --> String:调用String的构造器

@Test
public void test2(){String str1 = "abc123";  //题目: a21cb3char[] charArray = str1.toCharArray();for (int i = 0; i < charArray.length; i++) {System.out.println(charArray[i]);}char[] arr = new char[]{'h','e','l','l','o'};String str2 = new String(arr);System.out.println(str2);
}

String与byte[]之间的转换

编码:String --> byte[]:调用String的getBytes()
解码:byte[] --> String:调用String的构造器编码:字符串 -->字节  (看得懂 --->看不懂的二进制数据)解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 ---> 看得懂)说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。
    @Testpublic void test3() throws UnsupportedEncodingException {String str1 = "abc123中国";byte[] bytes = str1.getBytes();//使用默认的字符集,进行编码。System.out.println(Arrays.toString(bytes));byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码。System.out.println(Arrays.toString(gbks));System.out.println("******************");String str2 = new String(bytes);//使用默认的字符集,进行解码。System.out.println(str2);String str3 = new String(gbks);System.out.println(str3);//出现乱码。原因:编码集和解码集不一致!String str4 = new String(gbks, "gbk");System.out.println(str4);//没有出现乱码。原因:编码集和解码集一致!}

String与StringBuffer、StringBuilder之间的转换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qMOlgl6B-1631633504600)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825161808624.png)]

StringBuffer(线程安全)和StringBuilder(线程不安全)

String、StringBuffer、StringBuilder三者的异同?
String:不可变的字符序列;底层使用char[]存储
StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储源码分析:
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的数组。
System.out.println(sb1.length());//
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];//问题1. System.out.println(sb2.length());//3
//问题2. 扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组中。指导意义:开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
@Test
public void test1(){StringBuffer sb1 = new StringBuffer("abc");sb1.setCharAt(0,'m');System.out.println(sb1);StringBuffer sb2 = new StringBuffer();System.out.println(sb2.length());//0
}

StringBuffer的常用方法

StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse() :把当前字符序列逆转
public int indexOf(String str)
public String substring(int start,int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串
public int length()
public char charAt(int n )
public void setCharAt(int n ,char ch)总结:增:append(xxx)删:delete(int start,int end)改:setCharAt(int n ,char ch) / replace(int start, int end, String str)查:charAt(int n )插:insert(int offset, xxx)长度:length();*遍历:for() + charAt() / toString()

题目一

获取两个字符串中最大相同子串。比如:

str1 = “abcwerthelloyuiodefabcdef”;str2 = “cvhellobnm”
提示:将短的那个串进行长度依次递减的子串与较长的串比较。

package com.wdl.java;import org.junit.Test;import java.util.Arrays;/*** @author shkstart* @create 2019 上午 10:42*/
public class StringDemo2 {/*获取两个字符串中最大相同子串。比如:str1 = "abcwerthelloyuiodefabcdef";str2 = "cvhellobnm"提示:将短的那个串进行长度依次递减的子串与较长的串比较。*///前提:两个字符串中只有一个最大相同子串public String getMaxSameString(String str1,String str2){if(str1 != null && str2 != null){String maxStr = (str1.length() >= str2.length())? str1 : str2;String minStr = (str1.length() < str2.length())? str1 : str2;int length = minStr.length();for(int i = 0;i < length;i++){for(int x = 0,y = length - i;y <= length;x++,y++){String subStr = minStr.substring(x,y);if(maxStr.contains(subStr)){return subStr;}}}}return null;}// 如果存在多个长度相同的最大相同子串// 此时先返回String[],后面可以用集合中的ArrayList替换,较方便public String[] getMaxSameString1(String str1, String str2) {if (str1 != null && str2 != null) {StringBuffer sBuffer = new StringBuffer();String maxString = (str1.length() > str2.length()) ? str1 : str2;String minString = (str1.length() > str2.length()) ? str2 : str1;int len = minString.length();for (int i = 0; i < len; i++) {for (int x = 0, y = len - i; y <= len; x++, y++) {String subString = minString.substring(x, y);if (maxString.contains(subString)) {sBuffer.append(subString + ",");}}
//                System.out.println(sBuffer);if (sBuffer.length() != 0) {break;}}String[] split = sBuffer.toString().replaceAll(",$", "").split("\\,");return split;}return null;}@Testpublic void testGetMaxSameString(){String str1 = "abcwerthello1yuiodefabcdef";String str2 = "cvhello1bnmabcdef";String[] maxSameStrings = getMaxSameString1(str1, str2);System.out.println(Arrays.toString(maxSameStrings));}}

IDEA中Debug调试

package com.wdl.java;import org.junit.Test;/*** @author shkstart* @create 2019 上午 11:23*/
public class IDEADebug {@Testpublic void testStringBuffer(){String str = null;StringBuffer sb = new StringBuffer();sb.append(str);//System.out.println(sb.length());//4System.out.println(sb);//"null"StringBuffer sb1 = new StringBuffer(str);//抛异常NullPointerExceptionSystem.out.println(sb1);//}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8fDNYuW-1631633504601)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825195941061.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CT2ddURR-1631633504602)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825195911767.png)]

JDK8之前的日期时间API

System类

System类中的currentTimeMillis()

@Test
public void test1(){long time = System.currentTimeMillis();//返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。//称为时间戳System.out.println(time);
}

java.util.Date类|—java.sql.Date类

1.两个构造器的使用>构造器一:Date():创建一个对应当前时间的Date对象>构造器二:创建指定毫秒数的Date对象
2.两个方法的使用>toString():显示当前的年、月、日、时、分、秒>getTime():获取当前Date对象对应的毫秒数。(时间戳)3. java.sql.Date对应着数据库中的日期类型的变量>如何实例化>如何将java.util.Date对象转换为java.sql.Date对象
 @Testpublic void test2(){//构造器一:Date():创建一个对应当前时间的Date对象Date date1 = new Date();System.out.println(date1.toString());//Sat Feb 16 16:35:31 GMT+08:00 2019System.out.println(date1.getTime());//1550306204104//构造器二:创建指定毫秒数的Date对象Date date2 = new Date(155030620410L);System.out.println(date2.toString());//创建java.sql.Date对象java.sql.Date date3 = new java.sql.Date(35235325345L);System.out.println(date3);//1971-02-13//如何将java.util.Date对象转换为java.sql.Date对象//情况一:
//        Date date4 = new java.sql.Date(2343243242323L);
//        java.sql.Date date5 = (java.sql.Date) date4;//情况二:Date date6 = new Date();java.sql.Date date7 = new java.sql.Date(date6.getTime());}

SimpleDateFormat

SimpleDateFormat对日期Date类的格式化和解析
1.两个操作:
1.1 格式化:日期 —>字符串
1.2 解析:格式化的逆过程,字符串 —> 日期
2.SimpleDateFormat的实例化

package com.wdl.java;import org.junit.Test;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;/*** jdk 8之前的日期时间的API测试* 1. System类中currentTimeMillis();* 2. java.util.Date和子类java.sql.Date* 3. SimpleDateFormat* 4. Calendar** @author shkstart* @create 2019 上午 11:35*/
public class DateTimeTest {/*SimpleDateFormat的使用:SimpleDateFormat对日期Date类的格式化和解析1.两个操作:1.1 格式化:日期 --->字符串1.2 解析:格式化的逆过程,字符串 ---> 日期2.SimpleDateFormat的实例化*/@Testpublic void testSimpleDateFormat() throws ParseException {//实例化SimpleDateFormat:使用默认的构造器SimpleDateFormat sdf = new SimpleDateFormat();//格式化:日期 --->字符串Date date = new Date();System.out.println(date);String format = sdf.format(date);System.out.println(format);//解析:格式化的逆过程,字符串 ---> 日期String str = "19-12-18 上午11:43";Date date1 = sdf.parse(str);System.out.println(date1);//*************按照指定的方式格式化和解析:调用带参的构造器*****************
//        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa");SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//格式化String format1 = sdf1.format(date);System.out.println(format1);//2019-02-18 11:48:27//解析:要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现),//否则,抛异常Date date2 = sdf1.parse("2020-02-18 11:48:27");System.out.println(date2);}/*练习一:字符串"2020-09-08"转换为java.sql.Date练习二:"三天打渔两天晒网"   1990-01-01  xxxx-xx-xx 打渔?晒网?举例:2020-09-08 ? 总天数总天数 % 5 == 1,2,3 : 打渔总天数 % 5 == 4,0 : 晒网总天数的计算?方式一:( date2.getTime() - date1.getTime()) / (1000 * 60 * 60 * 24) + 1方式二:1990-01-01  --> 2019-12-31  +  2020-01-01 -->2020-09-08*/@Testpublic void testExer() throws ParseException {String birth = "2020-09-08";SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");Date date = sdf1.parse(birth);
//        System.out.println(date);java.sql.Date birthDate = new java.sql.Date(date.getTime());System.out.println(birthDate);}/*Calendar日历类(抽象类)的使用*/@Testpublic void testCalendar(){//1.实例化//方式一:创建其子类(GregorianCalendar)的对象//方式二:调用其静态方法getInstance()Calendar calendar = Calendar.getInstance();
//        System.out.println(calendar.getClass());//2.常用方法//get()int days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//set()//calendar可变性calendar.set(Calendar.DAY_OF_MONTH,22);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);//add()calendar.add(Calendar.DAY_OF_MONTH,-3);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);//getTime():日历类---> DateDate date = calendar.getTime();System.out.println(date);//setTime():Date ---> 日历类Date date1 = new Date();calendar.setTime(date1);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);}
}

题目一

字符串"2020-09-08"转换为java.sql.Date

 @Testpublic void testExer() throws ParseException {String birth = "2020-09-08";SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");Date date = sdf1.parse(birth);
//        System.out.println(date);java.sql.Date birthDate = new java.sql.Date(date.getTime());System.out.println(birthDate);}

题目二

“三天打渔两天晒网” 1990-01-01 xxxx-xx-xx 打渔?晒网?

举例:2020-09-08 ? 总天数

总天数 % 5 == 1,2,3 : 打渔
总天数 % 5 == 4,0 : 晒网

总天数的计算?
方式一:( date2.getTime() - date1.getTime()) / (1000 * 60 * 60 * 24) + 1
方式二:1990-01-01 --> 2019-12-31 + 2020-01-01 -->2020-09-08

Calendar日历类

注意:

获取月份时:一月是0,二月是1,以此类推,12月是11

获取星期时:周日是1,周二是2 , 。。。。周六是7

    /*Calendar日历类(抽象类)的使用*/@Testpublic void testCalendar(){//1.实例化//方式一:创建其子类(GregorianCalendar)的对象//方式二:调用其静态方法getInstance()Calendar calendar = Calendar.getInstance();
//        System.out.println(calendar.getClass());//2.常用方法//get()int days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//set()//calendar可变性calendar.set(Calendar.DAY_OF_MONTH,22);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);//add()calendar.add(Calendar.DAY_OF_MONTH,-3);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);//getTime():日历类---> DateDate date = calendar.getTime();System.out.println(date);//setTime():Date ---> 日历类Date date1 = new Date();calendar.setTime(date1);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);}

JDK8中新日期时间API

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jCrLNXXp-1631633504603)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826205046528.png)]

以前日期API中的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6j418vqZ-1631633504604)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825213456127.png)]

时间偏移量问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Easeccus-1631633504605)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825213413524.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nc5k6XHQ-1631633504605)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825213523996.png)]

LocalData、LocalTime、Localdatetime

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2sA1PeI-1631633504606)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210825215216186.png)]

/*
LocalDate、LocalTime、LocalDateTime 的使用
说明:1.LocalDateTime相较于LocalDate、LocalTime,使用频率要高2.类似于Calendar*/
@Test
public void test1(){//now():获取当前的日期、时间、日期+时间LocalDate localDate = LocalDate.now();LocalTime localTime = LocalTime.now();LocalDateTime localDateTime = LocalDateTime.now();System.out.println(localDate);System.out.println(localTime);System.out.println(localDateTime);//of():设置指定的年、月、日、时、分、秒。没有偏移量LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);System.out.println(localDateTime1);//getXxx():获取相关的属性System.out.println(localDateTime.getDayOfMonth());System.out.println(localDateTime.getDayOfWeek());System.out.println(localDateTime.getMonth());System.out.println(localDateTime.getMonthValue());System.out.println(localDateTime.getMinute());//体现不可变性//withXxx():设置相关的属性LocalDate localDate1 = localDate.withDayOfMonth(22);System.out.println(localDate);System.out.println(localDate1);LocalDateTime localDateTime2 = localDateTime.withHour(4);System.out.println(localDateTime);System.out.println(localDateTime2);//不可变性LocalDateTime localDateTime3 = localDateTime.plusMonths(3);System.out.println(localDateTime);System.out.println(localDateTime3);LocalDateTime localDateTime4 = localDateTime.minusDays(6);System.out.println(localDateTime);System.out.println(localDateTime4);
}

Instant

Instant的使用
类似于 java.util.Date类

/*
Instant的使用
类似于 java.util.Date类*/
@Test
public void test2(){//now():获取本初子午线对应的标准时间Instant instant = Instant.now();System.out.println(instant);//2019-02-18T07:29:41.719Z//添加时间的偏移量OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));System.out.println(offsetDateTime);//2019-02-18T15:32:50.611+08:00//toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数  ---> Date类的getTime()long milli = instant.toEpochMilli();System.out.println(milli);//ofEpochMilli():通过给定的毫秒数,获取Instant实例  -->Date(long millis)Instant instant1 = Instant.ofEpochMilli(1550475314878L);System.out.println(instant1);
}

DateTimeFormatter

   /*DateTimeFormatter:格式化或解析日期、时间类似于SimpleDateFormat*/@Testpublic void test3(){//        方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIMEDateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;//格式化:日期-->字符串LocalDateTime localDateTime = LocalDateTime.now();String str1 = formatter.format(localDateTime);System.out.println(localDateTime);System.out.println(str1);//2019-02-18T15:42:18.797//解析:字符串 -->日期TemporalAccessor parse = formatter.parse("2019-02-18T15:42:18.797");System.out.println(parse);//        方式二:
//        本地化相关的格式。如:ofLocalizedDateTime()
//        FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTimeDateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);//格式化String str2 = formatter1.format(localDateTime);System.out.println(str2);//2019年2月18日 下午03时47分16秒//      本地化相关的格式。如:ofLocalizedDate()
//      FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDateDateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);//格式化String str3 = formatter2.format(LocalDate.now());System.out.println(str3);//2019-2-18//       重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");//格式化String str4 = formatter3.format(LocalDateTime.now());System.out.println(str4);//2019-02-18 03:52:09//解析TemporalAccessor accessor = formatter3.parse("2019-02-18 03:52:09");System.out.println(accessor);}

其它API

ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris

ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。

(其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等 )

Clock:使用时区提供对当前即时、日期和时间的访问的时钟。

​ 持续时间:Duration,用于计算两个“时间”间隔

​ 日期间隔:Period,用于计算两个“日期”间隔

TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。

TemporalAdjusters : 该类通过静态方法

(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用

TemporalAdjuster 的实现

与传统日期处理的转换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMoTw3Ql-1631633504607)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826200406231.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2M2y7rOq-1631633504608)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826000451862.png)]

Java比较器

一、说明:Java中的对象,正常情况下,只能进行比较:== 或 != 。不能使用 > 或 < 的
但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。
如何实现?使用两个接口中的任何一个:Comparable 或 Comparator
二、Comparable接口与Comparator的使用的对比:
Comparable接口的方式一旦一定,保证Comparable接口实现类的对象在任何位置都可以比较大小。
Comparator接口属于临时性的比较。

自然排序java.lang.Comparable

Comparable接口的使用举例:  自然排序
1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。
2.像String、包装类重写compareTo()方法以后,进行了从小到大的排列
3. 重写compareTo(obj)的规则:如果当前对象this大于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回负整数,如果当前对象this等于形参对象obj,则返回零。
4. 对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。在compareTo(obj)方法中指明如何排序
package com.wdl.java;import org.junit.Test;import java.util.Arrays;
import java.util.Comparator;public class CompareTest {@Testpublic void test1(){String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};//Arrays.sort(arr);System.out.println(Arrays.toString(arr));}@Testpublic void test2(){Goods[] arr = new Goods[5];arr[0] = new Goods("lenovoMouse",34);arr[1] = new Goods("dellMouse",43);arr[2] = new Goods("xiaomiMouse",12);arr[3] = new Goods("huaweiMouse",65);arr[4] = new Goods("microsoftMouse",43);Arrays.sort(arr);System.out.println(Arrays.toString(arr));}}
package com.wdl.java;/*** 商品类* @author shkstart* @create 2019 下午 4:52*/
public class Goods implements  Comparable{private String name;private double price;public Goods() {}public Goods(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "Goods{" +"name='" + name + '\'' +", price=" + price +'}';}//指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从高到低排序@Overridepublic int compareTo(Object o) {//        System.out.println("**************");if(o instanceof Goods){Goods goods = (Goods)o;//方式一:if(this.price > goods.price){return 1;}else if(this.price < goods.price){return -1;}else{//                return 0;return -this.name.compareTo(goods.name);}//方式二:
//           return Double.compare(this.price,goods.price);}
//        return 0;throw new RuntimeException("传入的数据类型不一致!");}
}

定制排序java.util.Comparator

1.背景:
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,
或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,
那么可以考虑使用 Comparator 的对象来排序
2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2;
如果返回0,表示相等;
返回负整数,表示o1小于o2。

@Testpublic void test3(){String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};Arrays.sort(arr,new Comparator(){//按照字符串从大到小的顺序排列@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof String && o2 instanceof  String){String s1 = (String) o1;String s2 = (String) o2;return -s1.compareTo(s2);}
//                return 0;throw new RuntimeException("输入的数据类型不一致");}});System.out.println(Arrays.toString(arr));}@Testpublic void test4(){Goods[] arr = new Goods[6];arr[0] = new Goods("lenovoMouse",34);arr[1] = new Goods("dellMouse",43);arr[2] = new Goods("xiaomiMouse",12);arr[3] = new Goods("huaweiMouse",65);arr[4] = new Goods("huaweiMouse",224);arr[5] = new Goods("microsoftMouse",43);Arrays.sort(arr, new Comparator() {//指明商品比较大小的方式:按照产品名称从低到高排序,再按照价格从高到低排序@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Goods && o2 instanceof Goods){Goods g1 = (Goods)o1;Goods g2 = (Goods)o2;if(g1.getName().equals(g2.getName())){return -Double.compare(g1.getPrice(),g2.getPrice());}else{return g1.getName().compareTo(g2.getName());}}throw new RuntimeException("输入的数据类型不一致");}});System.out.println(Arrays.toString(arr));}

System、Math、BigInteger、BigDecimal类

System类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AegY3qUo-1631633504609)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826191700840.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYlSq3IN-1631633504610)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826191850855.png)]

package com.wdl.java;import org.junit.Test;import java.math.BigDecimal;
import java.math.BigInteger;/*** 其他常用类的使用* 1.System* 2.Math* 3.BigInteger 和 BigDecimal** @author shkstart* @create 2019 下午 6:23*/
public class OtherClassTest {@Testpublic void test1() {String javaVersion = System.getProperty("java.version");System.out.println("java的version:" + javaVersion);String javaHome = System.getProperty("java.home");System.out.println("java的home:" + javaHome);String osName = System.getProperty("os.name");System.out.println("os的name:" + osName);String osVersion = System.getProperty("os.version");System.out.println("os的version:" + osVersion);String userName = System.getProperty("user.name");System.out.println("user的name:" + userName);String userHome = System.getProperty("user.home");System.out.println("user的home:" + userHome);String userDir = System.getProperty("user.dir");System.out.println("user的dir:" + userDir);}}

Math类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ex6akohJ-1631633504611)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826192904236.png)]

BigInteger类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DrfLhSJZ-1631633504612)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826193126947.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQPD0FiO-1631633504613)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826193136594.png)]

BigDecimal类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kp2puDc1-1631633504615)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826193932704.png)]

    @Testpublic void test2() {BigInteger bi = new BigInteger("1243324112234324324325235245346567657653");BigDecimal bd = new BigDecimal("12435.351");BigDecimal bd2 = new BigDecimal("11");System.out.println(bi);
//         System.out.println(bd.divide(bd2));System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));System.out.println(bd.divide(bd2, 25, BigDecimal.ROUND_HALF_UP));}

枚举

枚举类的属性

枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰,枚举类的使用 private final 修饰的属性应该在构造器中为其赋值

若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的传入参数

枚举类的使用

1.枚举类的理解:类的对象只有有限个,确定的。我们称此类为枚举类

2.当需要定义一组常量时,强烈建议使用枚举类

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

方式一:jdk5.0之前,自定义枚举类

package com.wdl.java;/*** Enum类中的常用方法:*    values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。*    valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。*    toString():返回当前枚举类对象常量的名称** 使用enum关键字定义的枚举类实现接口的情况*   情况一:实现接口,在enum类中实现抽象方法*   情况二:让枚举类的对象分别实现接口中的抽象方法** @author shkstart* @create 2019 上午 10:17*/
public class SeasonTest {public static void main(String[] args) {Season spring = Season.SPRING;System.out.println(spring);}}
//自定义枚举类
class Season{//1.声明Season对象的属性:private final修饰private final String seasonName;private final String seasonDesc;//2.私有化类的构造器,并给对象属性赋值private Season(String seasonName,String seasonDesc){this.seasonName = seasonName;this.seasonDesc = seasonDesc;}//3.提供当前枚举类的多个对象:public static final的public static final Season SPRING = new Season("春天","春暖花开");public static final Season SUMMER = new Season("夏天","夏日炎炎");public static final Season AUTUMN = new Season("秋天","秋高气爽");public static final Season WINTER = new Season("冬天","冰天雪地");//4.其他诉求1:获取枚举类对象的属性public String getSeasonName() {return seasonName;}public String getSeasonDesc() {return seasonDesc;}//4.其他诉求1:提供toString()@Overridepublic String toString() {return "Season{" +"seasonName='" + seasonName + '\'' +", seasonDesc='" + seasonDesc + '\'' +'}';}
}

方式二:jdk5.0,可以使用enum关键字定义枚举类

说明:定义的枚举类默认继承于java.lang.Enum类

package com.wdl.java;/*** 使用enum关键字定义枚举类* 说明:定义的枚举类默认继承于java.lang.Enum类** @author shkstart* @create 2019 上午 10:35*/
public class SeasonTest1 {public static void main(String[] args) {Season1 summer = Season1.SUMMER;//toString():返回枚举类对象的名称System.out.println(summer.toString());//        System.out.println(Season1.class.getSuperclass());System.out.println("****************");//values():返回所有的枚举类对象构成的数组Season1[] values = Season1.values();for(int i = 0;i < values.length;i++){System.out.println(values[i]);values[i].show();}System.out.println("****************");Thread.State[] values1 = Thread.State.values();for (int i = 0; i < values1.length; i++) {System.out.println(values1[i]);}//valueOf(String objName):返回枚举类中对象名是objName的对象。Season1 winter = Season1.valueOf("WINTER");//如果没有objName的枚举类对象,则抛异常:IllegalArgumentException
//        Season1 winter = Season1.valueOf("WINTER1");System.out.println(winter);winter.show();}
}interface Info{void show();
}//使用enum关键字枚举类
enum Season1 implements Info{//1.提供当前枚举类的对象,多个对象之间用","隔开,末尾对象";"结束SPRING("春天","春暖花开"){@Overridepublic void show() {System.out.println("春天在哪里?");}},SUMMER("夏天","夏日炎炎"){@Overridepublic void show() {System.out.println("宁夏");}},AUTUMN("秋天","秋高气爽"){@Overridepublic void show() {System.out.println("秋天不回来");}},WINTER("冬天","冰天雪地"){@Overridepublic void show() {System.out.println("大约在冬季");}};//2.声明Season对象的属性:private final修饰private final String seasonName;private final String seasonDesc;//2.私有化类的构造器,并给对象属性赋值private Season1(String seasonName,String seasonDesc){this.seasonName = seasonName;this.seasonDesc = seasonDesc;}//4.其他诉求1:获取枚举类对象的属性public String getSeasonName() {return seasonName;}public String getSeasonDesc() {return seasonDesc;}
//    //4.其他诉求1:提供toString()
//
//    @Override
//    public String toString() {//        return "Season1{" +
//                "seasonName='" + seasonName + '\'' +
//                ", seasonDesc='" + seasonDesc + '\'' +
//                '}';
//    }//    @Override
//    public void show() {//        System.out.println("这是一个季节");
//    }
}

Enum类的主要方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dd4RfkgS-1631633504616)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826220628731.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6PohHcA-1631633504617)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210826220418803.png)]

注解

生成文档相关的注解

@author 标明开发该类模块的作者,多个作者之间使用,分割

@version 标明该类模块的版本

@see 参考转向,也就是相关主题

@since 从哪个版本开始增加的

@param 对方法中某参数的说明,如果没有参数就不能写

@return 对方法返回值的说明,如果方法的返回值类型是void就不能写

@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写

其中

@param @return 和 @exception 这三个标记都是只用于方法的。

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

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

@exception的格式要求:@exception 异常类型 异常说明

@param和@exception可以并列多个

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

@Override: 限定重写父类方法, 该注解只能用于方法

@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择

@SuppressWarnings: 抑制编译器警告

跟踪代码依赖性,实现替代配置文件功能

Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署。

自定义注解

如何自定义注解:参照@SuppressWarnings定义

  • ① 注解声明为:@interface
  • ② 内部定义成员,通常使用value表示
  • ③ 可以指定成员的默认值,使用default定义
  • ④ 如果自定义注解没有成员,表明是一个标识作用。

如果注解有成员,在使用注解时,需要指明成员的值。
自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
自定义注解通过都会指明两个元注解:Retention、Target

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZSwHgQG-1631633504618)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210827145736203.png)]

package com.wdl.java;import org.junit.Test;import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Date;public class AnnotationTest {public static void main(String[] args) {Person p = new Student();p.walk();Date date = new Date(2020, 10, 11);System.out.println(date);@SuppressWarnings("unused")int num = 10;//        System.out.println(num);@SuppressWarnings({ "unused", "rawtypes" })ArrayList list = new ArrayList();}@Testpublic void testGetAnnotation(){Class clazz = Student.class;Annotation[] annotations = clazz.getAnnotations();for(int i = 0;i < annotations.length;i++){System.out.println(annotations[i]);}}
}//jdk 8之前的写法:
//@MyAnnotations({@MyAnnotation(value="hi"),@MyAnnotation(value="hi")})
@MyAnnotation(value="hi")
@MyAnnotation(value="abc")
class Person{private String name;private int age;public Person() {}@MyAnnotationpublic Person(String name, int age) {this.name = name;this.age = age;}@MyAnnotationpublic void walk(){System.out.println("人走路");}public void eat(){System.out.println("人吃饭");}
}interface Info{void show();
}class Student extends Person implements Info{@Overridepublic void walk() {System.out.println("学生走路");}@Overridepublic void show() {}
}class Generic<@MyAnnotation T>{public void show() throws @MyAnnotation RuntimeException{ArrayList<@MyAnnotation String> list = new ArrayList<>();int num = (@MyAnnotation int) 10L;}}
package com.wdl.java;import java.lang.annotation.*;import static java.lang.annotation.ElementType.*;/*** @author shkstart* @create 2019 上午 11:56*/
@Inherited
@Repeatable(MyAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
public @interface MyAnnotation {String value() default "hello";
}

jdk中基本的四个元注解

JDK 的元 Annotation 用于修饰其他 Annotation 定义

JDK5.0提供了4个标准的meta-annotation类型,分别是:

Retention

Target

Documented

Inherited

元数据的理解:String name = “atguigu”;

jdk 提供的4种元注解
元注解:对现有的注解进行解释说明的注解
Retention:指定所修饰的 Annotation 的生命周期:SOURCE\CLASS(默认行为)\RUNTIME
只有声明为RUNTIME生命周期的注解,才能通过反射获取。
Target:用于指定被修饰的 Annotation 能用于修饰哪些程序元素
出现的频率较低
Documented:表示所修饰的注解在被javadoc解析时,保留下来。
Inherited:被它修饰的 Annotation 将具有继承性。

Retention

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PWQDhGZJ-1631633504619)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210827152233646.png)]

Target

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k2MGQEMo-1631633504620)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210827152743972.png)]

Documented

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7OBXTOC7-1631633504621)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210827154428239.png)]

Inherited

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bukxiXFb-1631633504622)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210827154510564.png)]

jdk 8 中注解的新特性

可重复注解

① 在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class
② MyAnnotation的Target和Retention等元注解与MyAnnotations相同。

类型注解

ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如:泛型声明)。
ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。

集合

数组存储数据的优缺点

数组在存储多个数据方面的特点:> 一旦初始化以后,其长度就确定了。> 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。比如:String[] arr;int[] arr1;Object[] arr2;
数组在存储多个数据方面的缺点:> 一旦初始化以后,其长度就不可修改。> 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。> 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用> 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

Collection接口继承树

  |----Collection接口:单列集合,用来存储一个一个的对象|----List接口:存储有序的、可重复的数据。  -->“动态”数组|----ArrayList、LinkedList、Vector|----Set接口:存储无序的、不可重复的数据   -->高中讲的“集合”|----HashSet、LinkedHashSet、TreeSet

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1CWqJ2y1-1631633504624)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210829162427543.png)]

Map接口继承树

   |----Map接口:双列集合,用来存储一对(key - value)一对的数据   -->高中函数:y = f(x)|----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zpqe4qym-1631633504625)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210829162542735.png)]

Collection接口中常用方法

public class CollectionTest {@Testpublic void test1(){Collection coll = new ArrayList();//add(Object e):将元素e添加到集合coll中coll.add("AA");coll.add("BB");coll.add(123);//自动装箱coll.add(new Date());//size():获取添加的元素的个数System.out.println(coll.size());//4//addAll(Collection coll1):将coll1集合中的元素添加到当前的集合中Collection coll1 = new ArrayList();
//        System.out.println(coll1.size());coll1.add(456);coll1.add("CC");coll.addAll(coll1);System.out.println(coll.size());//6System.out.println(coll);//clear():清空集合元素coll.clear();
//        System.out.println(coll.size());//isEmpty():判断当前集合是否为空System.out.println(coll.isEmpty());}}
package com.wdl.java;import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;/*** Collection接口中声明的方法的测试** 结论:* 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().** @author shkstart* @create 2019 上午 10:04*/
public class CollectionTest {@Testpublic void test1(){Collection coll = new ArrayList();coll.add(123);coll.add(456);
//        Person p = new Person("Jerry",20);
//        coll.add(p);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//1.contains(Object obj):判断当前集合中是否包含obj//我们在判断时会调用obj对象所在类的equals()。逐个进行比较直到找到为止,找不到返回falseboolean contains = coll.contains(123);System.out.println(contains);System.out.println(coll.contains(new String("Tom")));
//        System.out.println(coll.contains(p));//trueSystem.out.println(coll.contains(new Person("Jerry",20)));//false -->true//2.containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中。Collection coll1 = Arrays.asList(123,4567);System.out.println(coll.containsAll(coll1));}@Testpublic void test2(){//3.remove(Object obj):从当前集合中移除obj元素。Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);coll.remove(1234);System.out.println(coll);coll.remove(new Person("Jerry",20));System.out.println(coll);//4. removeAll(Collection coll1):差集:从当前集合中移除coll1中所有的元素。Collection coll1 = Arrays.asList(123,456);coll.removeAll(coll1);System.out.println(coll);}@Testpublic void test3(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//5.retainAll(Collection coll1):交集:获取当前集合和coll1集合的交集,并返回给当前集合
//        Collection coll1 = Arrays.asList(123,456,789);
//        coll.retainAll(coll1);
//        System.out.println(coll);//6.equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同。Collection coll1 = new ArrayList();coll1.add(456);coll1.add(123);coll1.add(new Person("Jerry",20));coll1.add(new String("Tom"));coll1.add(false);System.out.println(coll.equals(coll1));}@Testpublic void test4(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//7.hashCode():返回当前对象的哈希值System.out.println(coll.hashCode());//8.集合 --->数组:toArray()Object[] arr = coll.toArray();for(int i = 0;i < arr.length;i++){System.out.println(arr[i]);}//拓展:数组 --->集合:调用Arrays类的静态方法asList()List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});System.out.println(list);List arr1 = Arrays.asList(new int[]{123, 456});System.out.println(arr1.size());//1List arr2 = Arrays.asList(new Integer[]{123, 456});System.out.println(arr2.size());//2//9.iterator():返回Iterator接口的实例,用于遍历集合元素。放在IteratorTest.java中测试}
}

Iterator迭代器接口

集合元素的遍历操作,使用迭代器Iterator接口
1.内部的方法:hasNext() 和 next()
2.集合对象每次调用iterator()方法都得到一个全新的迭代器对象,
默认游标都在集合的第一个元素之前。
3.内部定义了remove(),可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfdYLWbx-1631633504626)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210829192319042.png)]

package com.wdl.java;import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public class IteratorTest {@Testpublic void test1(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);Iterator iterator = coll.iterator();//方式一:
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        //报异常:NoSuchElementException
//        System.out.println(iterator.next());//方式二:不推荐
//        for(int i = 0;i < coll.size();i++){//            System.out.println(iterator.next());
//        }//方式三:推荐hasNext():判断是否还有下一个元素while(iterator.hasNext()){//next():①指针下移 ②将下移以后集合位置上的元素返回System.out.println(iterator.next());}}@Testpublic void test2(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//错误方式一:
//        Iterator iterator = coll.iterator();
//        while((iterator.next()) != null){//            System.out.println(iterator.next());
//        }//错误方式二://集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。while (coll.iterator().hasNext()){System.out.println(coll.iterator().next());}}//测试Iterator中的remove()//如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,// 再调用remove都会报IllegalStateException。@Testpublic void test3(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//删除集合中"Tom"Iterator iterator = coll.iterator();while (iterator.hasNext()){//            iterator.remove();Object obj = iterator.next();if("Tom".equals(obj)){iterator.remove();
//                iterator.remove();}}//遍历集合iterator = coll.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}}
}

增强for循环(jdk 5.0 新增)

jdk 5.0 新增了foreach循环,用于遍历集合、数组

package com.wdl.java;import org.junit.Test;import java.util.ArrayList;
import java.util.Collection;/*** jdk 5.0 新增了foreach循环,用于遍历集合、数组** @author shkstart* @create 2019 上午 11:24*/
public class ForTest {@Testpublic void test1(){Collection coll = new ArrayList();coll.add(123);coll.add(456);coll.add(new Person("Jerry",20));coll.add(new String("Tom"));coll.add(false);//for(集合元素的类型 局部变量 : 集合对象)//内部仍然调用了迭代器。for(Object obj : coll){System.out.println(obj);}}@Testpublic void test2(){int[] arr = new int[]{1,2,3,4,5,6};//for(数组元素的类型 局部变量 : 数组对象)for(int i : arr){System.out.println(i);}}//练习题@Testpublic void test3(){String[] arr = new String[]{"MM","MM","MM"};//        //方式一:普通for赋值
//        for(int i = 0;i < arr.length;i++){//            arr[i] = "GG";
//        }//方式二:增强for循环for(String s : arr){s = "GG";}for(int i = 0;i < arr.length;i++){System.out.println(arr[i]);}}
}

jdk8.0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTD6mAPp-1631633504627)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831101050254.png)]

Collection子接口之一:List接口

1. List接口框架|----Collection接口:单列集合,用来存储一个一个的对象|----List接口:存储有序的、可重复的数据。  -->“动态”数组,替换原有的数组|----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储|----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储|----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储2. ArrayList的源码分析:2.1 jdk 7情况下ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementDatalist.add(123);//elementData[0] = new Integer(123);...list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)2.2 jdk 8中ArrayList的变化:ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没有创建长度为10的数组list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]...后续的添加和扩容操作与jdk 7 无异。2.3 小结:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。3. LinkedList的源码分析:LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为nulllist.add(123);//将123封装到Node中,创建了Node对象。其中,Node定义为:体现了LinkedList的双向链表的说法private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}}4. Vector的源码分析:jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。在扩容方面,默认扩容为原来的数组长度的2倍。面试题:ArrayList、LinkedList、Vector三者的异同?同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据不同:见上5. List接口中的常用方法void add(int index, Object ele):在index位置插入ele元素
boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
Object get(int index):获取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出现的位置
int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
Object remove(int index):移除指定index位置的元素,并返回此元素
Object set(int index, Object ele):设置指定index位置的元素为ele
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合总结:常用方法
增:add(Object obj)
删:remove(int index) / remove(Object obj)
改:set(int index, Object ele)
查:get(int index)
插:add(int index, Object ele)
长度:size()
遍历:① Iterator迭代器方式② 增强for循环③ 普通的循环
package com.wdl.java;import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;public class ListTest {@Testpublic void test3(){ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");//方式一:Iterator迭代器方式Iterator iterator = list.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}System.out.println("***************");//方式二:增强for循环for(Object obj : list){System.out.println(obj);}System.out.println("***************");//方式三:普通for循环for(int i = 0;i < list.size();i++){System.out.println(list.get(i));}}@Testpublic void test2(){ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");list.add(new Person("Tom",12));list.add(456);//int indexOf(Object obj):返回obj在集合中首次出现的位置。如果不存在,返回-1.int index = list.indexOf(4567);System.out.println(index);//int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置。如果不存在,返回-1.System.out.println(list.lastIndexOf(456));//Object remove(int index):移除指定index位置的元素,并返回此元素Object obj = list.remove(0);System.out.println(obj);System.out.println(list);//Object set(int index, Object ele):设置指定index位置的元素为elelist.set(1,"CC");System.out.println(list);//List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的左闭右开区间的子集合List subList = list.subList(2, 4);System.out.println(subList);System.out.println(list);}@Testpublic void test1(){ArrayList list = new ArrayList();list.add(123);list.add(456);list.add("AA");list.add(new Person("Tom",12));list.add(456);System.out.println(list);//void add(int index, Object ele):在index位置插入ele元素list.add(1,"BB");System.out.println(list);//boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来List list1 = Arrays.asList(1, 2, 3);list.addAll(list1);
//        list.add(list1);System.out.println(list.size());//9//Object get(int index):获取指定index位置的元素System.out.println(list.get(0));}}

注意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JboqO3OJ-1631633504628)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210830151311484.png)]

Collection子接口之二:Set接口

1. Set接口的框架:
|----Collection接口:单列集合,用来存储一个一个的对象|----Set接口:存储无序的、不可重复的数据   -->高中讲的“集合”|----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值|----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历对于频繁的遍历操作,LinkedHashSet效率高于HashSet.|----TreeSet:可以按照添加对象的指定属性,进行排序。1. Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。2. 要求:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
 一、Set:存储无序的、不可重复的数据以HashSet为例说明:1. 无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。2. 不可重复性:保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一个。二、添加元素的过程:以HashSet为例:我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:如果此位置上没有其他元素,则元素a添加成功。 --->情况1如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:如果hash值不相同,则元素a添加成功。--->情况2如果hash值相同,进而需要调用元素a所在类的equals()方法:equals()返回true,元素a添加失败equals()返回false,则元素a添加成功。--->情况2对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。jdk 7 :元素a放到数组中,指向原来的元素。jdk 8 :原来的元素在数组中,指向元素a总结:七上八下HashSet底层:数组+链表的结构。
package com.wdl.java;import org.junit.Test;import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;public class SetTest {@Testpublic void test1(){Set set = new HashSet();set.add(456);set.add(123);set.add(123);set.add("AA");set.add("CC");set.add(new User("Tom",12));set.add(new User("Tom",12));set.add(129);Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}@Testpublic void test2(){Set set = new LinkedHashSet();set.add(456);set.add(123);set.add(123);set.add("AA");set.add("CC");set.add(new User("Tom",12));set.add(new User("Tom",12));set.add(129);Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

LinkedHashSet VS HashSet

LinkedHashSet的使用
LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个
数据和后一个数据。
优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EARUPtm5-1631633504629)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210830174952026.png)]

hashCode()重写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMuLzD3i-1631633504630)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210830172947631.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3NAFonip-1631633504631)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210830171646714.png)]

TreeSet

1.向TreeSet中添加的数据,要求是相同类的对象。
2.两种排序方式:自然排序(实现Comparable接口) 和 定制排序(Comparator)
3.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0.不再是equals().
4.定制排序中,比较两个对象是否相同的标准为:compare()返回0.不再是equals().

底层采用红黑树

package com.wdl.java;import org.junit.Test;import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;/*** @author shkstart* @create 2019 下午 4:59*/
public class TreeSetTest {@Testpublic void test1(){TreeSet set = new TreeSet();//失败:不能添加不同类的对象
//        set.add(123);
//        set.add(456);
//        set.add("AA");
//        set.add(new User("Tom",12));//举例一:
//        set.add(34);
//        set.add(-34);
//        set.add(43);
//        set.add(11);
//        set.add(8);//举例二:set.add(new User("Tom",12));set.add(new User("Jerry",32));set.add(new User("Jim",2));set.add(new User("Mike",65));set.add(new User("Jack",33));set.add(new User("Jack",56));Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}@Testpublic void test2(){Comparator com = new Comparator() {//按照年龄从小到大排列@Overridepublic 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("输入的数据类型不匹配");}}};TreeSet set = new TreeSet(com);set.add(new User("Tom",12));set.add(new User("Jerry",32));set.add(new User("Jim",2));set.add(new User("Mike",65));set.add(new User("Mary",33));set.add(new User("Jack",33));set.add(new User("Jack",56));Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}}

题目一

重写equals

删除时候先比较hashcode然后再比较equals

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJ9pHHLt-1631633504632)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831112051344.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-84oV5Bq2-1631633504633)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831112506717.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KZtJYdj-1631633504634)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831112747078.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gabmFrLG-1631633504635)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831112809516.png)]

Map接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KlgaJrsS-1631633504636)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831134801284.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dlUMtT2U-1631633504637)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831142810557.png)]

一、Map的实现类的结构:|----Map:双列数据,存储key-value对的数据   ---类似于高中的函数:y = f(x)|----HashMap:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value|----LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap。|----TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序底层使用红黑树|----Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value|----Properties:常用来处理配置文件。key和value都是String类型HashMap的底层:数组+链表  (jdk7及之前)数组+链表+红黑树 (jdk 8)面试题:1. HashMap的底层实现原理?2. HashMap 和 Hashtable的异同?3. CurrentHashMap 与 Hashtable的异同?(暂时不讲)二、Map结构的理解:Map中的key:无序的、不可重复的,使用Set存储所有的key  ---> key所在的类要重写equals()和hashCode() (以HashMap为例)Map中的value:无序的、可重复的,使用Collection存储所有的value --->value所在的类要重写equals()一个键值对:key-value构成了一个Entry对象。Map中的entry:无序的、不可重复的,使用Set存储所有的entry三、HashMap的底层实现原理?以jdk7为例说明:HashMap map = new HashMap():在实例化以后,底层创建了长度是16的一维数组Entry[] table。...可能已经执行过多次put...map.put(key1,value1):首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。如果此位置上的数据为空,此时的key1-value1添加成功。 ----情况1如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较:如果equals()返回false:此时key1-value1添加成功。----情况3如果equals()返回true:使用value1替换value2。补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。jdk8 相较于jdk7在底层实现方面的不同:1. new HashMap():底层没有创建一个长度为16的数组2. jdk 8底层的数组是:Node[],而非Entry[]3. 首次调用put()方法时,底层创建长度为16的数组4. jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。4.1 形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素)4.2 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储。DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75threshold:扩容的临界值,=容量*填充因子:16 * 0.75 => 12TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64四、LinkedHashMap的底层实现原理(了解)源码中:static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;//能够记录添加的元素的先后顺序Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}}五、Map中定义的方法:添加、删除、修改操作:Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中void putAll(Map m):将m中的所有key-value对存放到当前map中Object remove(Object key):移除指定key的key-value对,并返回valuevoid clear():清空当前map中的所有数据元素查询的操作:Object get(Object key):获取指定key对应的valueboolean containsKey(Object key):是否包含指定的keyboolean containsValue(Object value):是否包含指定的valueint size():返回map中key-value对的个数boolean isEmpty():判断当前map是否为空boolean equals(Object obj):判断当前map和参数对象obj是否相等元视图操作的方法:Set keySet():返回所有key构成的Set集合Collection values():返回所有value构成的Collection集合Set entrySet():返回所有key-value对构成的Set集合总结:常用方法:* 添加:put(Object key,Object value)* 删除:remove(Object key)* 修改:put(Object key,Object value)* 查询:get(Object key)* 长度:size()* 遍历:keySet() / values() / entrySet()
package com.wdl.java;import org.junit.Test;import java.util.*;public class MapTest {/*元视图操作的方法:Set keySet():返回所有key构成的Set集合Collection values():返回所有value构成的Collection集合Set entrySet():返回所有key-value对构成的Set集合*/@Testpublic void test5(){Map map = new HashMap();map.put("AA",123);map.put(45,1234);map.put("BB",56);//遍历所有的key集:keySet()Set set = map.keySet();Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}System.out.println();//遍历所有的value集:values()Collection values = map.values();for(Object obj : values){System.out.println(obj);}System.out.println();//遍历所有的key-value//方式一:entrySet()Set entrySet = map.entrySet();Iterator iterator1 = entrySet.iterator();while (iterator1.hasNext()){Object obj = iterator1.next();//entrySet集合中的元素都是entryMap.Entry entry = (Map.Entry) obj;System.out.println(entry.getKey() + "---->" + entry.getValue());}System.out.println();//方式二:Set keySet = map.keySet();Iterator iterator2 = keySet.iterator();while(iterator2.hasNext()){Object key = iterator2.next();Object value = map.get(key);System.out.println(key + "=====" + value);}}/*元素查询的操作:Object get(Object key):获取指定key对应的valueboolean containsKey(Object key):是否包含指定的keyboolean containsValue(Object value):是否包含指定的valueint size():返回map中key-value对的个数boolean isEmpty():判断当前map是否为空boolean equals(Object obj):判断当前map和参数对象obj是否相等*/@Testpublic void test4(){Map map = new HashMap();map.put("AA",123);map.put(45,123);map.put("BB",56);// Object get(Object key)System.out.println(map.get(45));//containsKey(Object key)boolean isExist = map.containsKey("BB");System.out.println(isExist);isExist = map.containsValue(123);System.out.println(isExist);map.clear();System.out.println(map.isEmpty());}/*添加、删除、修改操作:Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中void putAll(Map m):将m中的所有key-value对存放到当前map中Object remove(Object key):移除指定key的key-value对,并返回valuevoid clear():清空当前map中的所有数据*/@Testpublic void test3(){Map map = new HashMap();//添加map.put("AA",123);map.put(45,123);map.put("BB",56);//修改map.put("AA",87);System.out.println(map);Map map1 = new HashMap();map1.put("CC",123);map1.put("DD",123);map.putAll(map1);System.out.println(map);//remove(Object key)Object value = map.remove("CC");System.out.println(value);System.out.println(map);//clear()map.clear();//与map = null操作不同System.out.println(map.size());System.out.println(map);}@Testpublic void test2(){Map map = new HashMap();map = new LinkedHashMap();map.put(123,"AA");map.put(345,"BB");map.put(12,"CC");System.out.println(map);}@Testpublic void test1(){Map map = new HashMap();
//        map = new Hashtable();map.put(null,123);}
}

HashMap源码中重要常量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y6RC6aKn-1631633504638)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831164008817.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nSvaEFVw-1631633504639)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831213921636.png)]

LinkedHashMap底层

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UKW0VTR3-1631633504640)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831172739730.png)]

Properties

package com.wdl.java;import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;/*** @author shkstart* @create 2019 下午 4:07*/
public class PropertiesTest {//Properties:常用来处理配置文件。key和value都是String类型public static void main(String[] args)  {FileInputStream fis = null;try {Properties pros = new Properties();fis = new FileInputStream("jdbc.properties");pros.load(fis);//加载流对应的文件String name = pros.getProperty("name");String password = pros.getProperty("password");System.out.println("name = " + name + ", password = " + password);} catch (IOException e) {e.printStackTrace();} finally {if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
}

Collections工具类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsHh907L-1631633504642)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831200111824.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olOAgzEu-1631633504643)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831200227836.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FaP5q6zw-1631633504644)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831200252999.png)]

package com.wdl.java;import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** Collections:操作Collection、Map的工具类*** 面试题:Collection 和 Collections的区别?*** @author shkstart* @create 2019 下午 4:19*/
public class CollectionsTest {/*
reverse(List):反转 List 中元素的顺序
shuffle(List):对 List 集合元素进行随机排序
sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
Object min(Collection)
Object min(Collection,Comparator)
int frequency(Collection,Object):返回指定集合中指定元素的出现次数
void copy(List dest,List src):将src中的内容复制到dest中
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值*/@Testpublic void test2(){List list = new ArrayList();list.add(123);list.add(43);list.add(765);list.add(-97);list.add(0);//报异常:IndexOutOfBoundsException("Source does not fit in dest")
//        List dest = new ArrayList();
//        Collections.copy(dest,list);//正确的:List dest = Arrays.asList(new Object[list.size()]);System.out.println(dest.size());//list.size();Collections.copy(dest,list);System.out.println(dest);/*Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题*///返回的list1即为线程安全的ListList list1 = Collections.synchronizedList(list);}@Testpublic void test1(){List list = new ArrayList();list.add(123);list.add(43);list.add(765);list.add(765);list.add(765);list.add(-97);list.add(0);System.out.println(list);//        Collections.reverse(list);
//        Collections.shuffle(list);
//        Collections.sort(list);
//        Collections.swap(list,1,2);int frequency = Collections.frequency(list, 123);System.out.println(list);System.out.println(frequency);}}

泛型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nczR0FQs-1631633504645)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831214750116.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOsM7glW-1631633504645)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831215316655.png)]

1.jdk 5.0新增的特性
2.在集合中使用泛型:总结:① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。② 在实例化集合类时,可以指明具体的泛型类型③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。比如:add(E e)  --->实例化以后:add(Integer e)④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换⑤ 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
3.如何自定义泛型结构:泛型类、泛型接口;泛型方法。见 GenericTest1.java
package com.wdl.java;import org.junit.Test;import java.util.*;public class GenericTest {//在集合中使用泛型之前的情况:@Testpublic void test1(){ArrayList list = new ArrayList();//需求:存放学生的成绩list.add(78);list.add(76);list.add(89);list.add(88);//问题一:类型不安全
//        list.add("Tom");for(Object score : list){//问题二:强转时,可能出现ClassCastExceptionint stuScore = (Integer) score;System.out.println(stuScore);}}//在集合中使用泛型的情况:以ArrayList为例@Testpublic void test2(){ArrayList<Integer> list =  new ArrayList<Integer>();list.add(78);list.add(87);list.add(99);list.add(65);//编译时,就会进行类型检查,保证数据的安全
//        list.add("Tom");//方式一:
//        for(Integer score : list){//            //避免了强转操作
//            int stuScore = score;
//
//            System.out.println(stuScore);
//
//        }//方式二:Iterator<Integer> iterator = list.iterator();while(iterator.hasNext()){int stuScore = iterator.next();System.out.println(stuScore);}}//在集合中使用泛型的情况:以HashMap为例@Testpublic void test3(){//        Map<String,Integer> map = new HashMap<String,Integer>();//jdk7新特性:类型推断Map<String,Integer> map = new HashMap<>();map.put("Tom",87);map.put("Jerry",87);map.put("Jack",67);//        map.put(123,"ABC");//泛型的嵌套Set<Map.Entry<String,Integer>> entry = map.entrySet();Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();while(iterator.hasNext()){Map.Entry<String, Integer> e = iterator.next();String key = e.getKey();Integer value = e.getValue();System.out.println(key + "----" + value);}}}

类型推断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0x3lqBHX-1631633504646)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831221749741.png)]

自定义泛型类、接口、方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iVcb9nBq-1631633504647)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210831223515304.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4YrDH06E-1631633504648)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901095259666.png)]

泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
换句话说,泛型方法所属的类是不是泛型类都没有关系。
泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。

package com.wdl.java;import org.junit.Test;import java.util.ArrayList;
import java.util.List;/** 如何自定义泛型结构:泛型类、泛型接口;泛型方法。** 1. 关于自定义泛型类、泛型接口:**** @author shkstart* @create 2019 上午 11:09*/
public class GenericTest1 {@Testpublic void test1(){//如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型//要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。Order order = new Order();order.setOrderT(123);order.setOrderT("ABC");//建议:实例化时指明类的泛型Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");order1.setOrderT("AA:hello");}@Testpublic void test2(){SubOrder sub1 = new SubOrder();//由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。sub1.setOrderT(1122);SubOrder1<String> sub2 = new SubOrder1<>();sub2.setOrderT("order2...");}@Testpublic void test3(){ArrayList<String> list1 = null;ArrayList<Integer> list2 = new ArrayList<Integer>();//泛型不同的引用不能相互赋值。
//        list1 = list2;Person p1 = null;Person p2 = null;p1 = p2;}//测试泛型方法@Testpublic void test4(){Order<String> order = new Order<>();Integer[] arr = new Integer[]{1,2,3,4};//泛型方法在调用时,指明泛型参数的类型。List<Integer> list = order.copyFromArrayToList(arr);System.out.println(list);}
}
package com.wdl.java;import java.util.ArrayList;
import java.util.List;/*** 自定义泛型类* @author shkstart* @create 2019 上午 11:05*/
public class Order<T> {String orderName;int orderId;//类的内部结构就可以使用类的泛型T orderT;public Order(){//编译不通过
//        T[] arr = new T[10];//编译通过T[] arr = (T[]) new Object[10];}public Order(String orderName,int orderId,T orderT){this.orderName = orderName;this.orderId = orderId;this.orderT = orderT;}//如下的三个方法都不是泛型方法public T getOrderT(){return orderT;}public void setOrderT(T orderT){this.orderT = orderT;}@Overridepublic String toString() {return "Order{" +"orderName='" + orderName + '\'' +", orderId=" + orderId +", orderT=" + orderT +'}';}//静态方法中不能使用类的泛型。
//    public static void show(T orderT){//        System.out.println(orderT);
//    }public void show(){//编译不通过
//        try{//
//
//        }catch(T t){//
//        }}//泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。//换句话说,泛型方法所属的类是不是泛型类都没有关系。//泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。public static <E>  List<E> copyFromArrayToList(E[] arr){ArrayList<E> list = new ArrayList<>();for(E e : arr){list.add(e);}return list;}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLOk8UCA-1631633504649)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901095347579.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sWkFkgqo-1631633504649)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901100734231.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBX54YYO-1631633504650)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901101149106.png)]

泛型类和泛型方法的使用场景

package com.wdl.java1;/*** @author shkstart* @create 2019 上午 11:54*/
public class Customer { //此类对应数据库中的customers表
}
package com.wdl.java1;/*** @author shkstart* @create 2019 上午 11:55*/
public class CustomerDAO extends DAO<Customer>{//只能操作某一个表的DAO
}
package com.wdl.java1;import java.util.List;/*** @author shkstart* @create 2019 上午 11:50** DAO:data(base) access object*/
public class DAO<T> {//表的共性操作的DAO//添加一条记录public void add(T t){}//删除一条记录public boolean remove(int index){return false;}//修改一条记录public void update(int index,T t){}//查询一条记录public T getIndex(int index){return null;}//查询多条记录public List<T> getForList(int index){return null;}//泛型方法//举例:获取表中一共有多少条记录?获取最大的员工入职时间?public <E> E getValue(){return null;}}
package com.wdl.java1;import org.junit.Test;import java.util.List;/*** @author shkstart* @create 2019 上午 11:57*/
public class DAOTest {@Testpublic void test1(){CustomerDAO dao1 = new CustomerDAO();dao1.add(new Customer());List<Customer> list = dao1.getForList(10);StudentDAO dao2 = new StudentDAO();Student student = dao2.getIndex(1);}
}

泛型在继承方面的体现和通配符的使用

package com.wdl.java2;import org.junit.Test;import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;/**** 1. 泛型在继承方面的体现*** 2. 通配符的使用** @author shkstart* @create 2019 下午 2:13*/
public class GenericTest {/*1. 泛型在继承方面的体现虽然类A是类B的父类,但是G<A> 和G<B>二者不具备子父类关系,二者是并列关系。补充:类A是类B的父类,A<G> 是 B<G> 的父类*/@Testpublic void test1(){Object obj = null;String str = null;obj = str;Object[] arr1 = null;String[] arr2 = null;arr1 = arr2;//编译不通过
//        Date date = new Date();
//        str = date;List<Object> list1 = null;List<String> list2 = new ArrayList<String>();//此时的list1和list2的类型不具有子父类关系//编译不通过
//        list1 = list2;/*反证法:假设list1 = list2;list1.add(123);导致混入非String的数据。出错。*/show(list1);show1(list2);}public void show1(List<String> list){}public void show(List<Object> list){}@Testpublic void test2(){AbstractList<String> list1 = null;List<String> list2 = null;ArrayList<String> list3 = null;list1 = list3;list2 = list3;List<String> list4 = new ArrayList<>();}/*2. 通配符的使用通配符:?类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是:G<?>*/@Testpublic void test3(){List<Object> list1 = null;List<String> list2 = null;List<?> list = null;list = list1;list = list2;//编译通过
//        print(list1);
//        print(list2);//List<String> list3 = new ArrayList<>();list3.add("AA");list3.add("BB");list3.add("CC");list = list3;//添加(写入):对于List<?>就不能向其内部添加数据。//除了添加null之外。
//        list.add("DD");
//        list.add('?');list.add(null);//获取(读取):允许读取数据,读取的数据类型为Object。Object o = list.get(0);System.out.println(o);}public void print(List<?> list){Iterator<?> iterator = list.iterator();while(iterator.hasNext()){Object obj = iterator.next();System.out.println(obj);}}/*3.有限制条件的通配符的使用。? extends A:G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类? super A:G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类*/@Testpublic void test4(){List<? extends Person> list1 = null;List<? super Person> list2 = null;List<Student> list3 = new ArrayList<Student>();List<Person> list4 = new ArrayList<Person>();List<Object> list5 = new ArrayList<Object>();list1 = list3;list1 = list4;
//        list1 = list5;//        list2 = list3;list2 = list4;list2 = list5;//读取数据:list1 = list3;Person p = list1.get(0);//编译不通过//Student s = list1.get(0);list2 = list4;Object obj = list2.get(0);编译不通过
//        Person obj = list2.get(0);//写入数据://编译不通过
//        list1.add(new Student());//编译通过list2.add(new Person());list2.add(new Student());}}

题目一

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YSVsnH2O-1631633504651)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901162152399.png)]

IO流

File类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sfk2uwjN-1631633504653)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901150425798.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PDtbweKB-1631633504654)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901150710131.png)]

常用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RA46G23A-1631633504655)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901152209975.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWnTYgoE-1631633504656)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901152226341.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7MZxdt8-1631633504657)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901152648366.png)]

package com.wdl.java3;import org.junit.Test;import java.io.File;
import java.io.IOException;
import java.util.Date;/*** File类的使用** 1. File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)* 2. File类声明在java.io包下* 3. File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,*    并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。* 4. 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点".***** @author shkstart* @create 2019 下午 4:05*/
public class FileTest {/*1.如何创建File类的实例File(String filePath)File(String parentPath,String childPath)File(File parentFile,String childPath)2.相对路径:相较于某个路径下,指明的路径。绝对路径:包含盘符在内的文件或文件目录的路径3.路径分隔符windows:\\unix:/*/@Testpublic void test1(){//构造器1File file1 = new File("hello.txt");//相对于当前moduleFile file2 =  new File("D:\\workspace_idea1\\JavaSenior\\day08\\he.txt");System.out.println(file1);System.out.println(file2);//构造器2:File file3 = new File("D:\\workspace_idea1","JavaSenior");System.out.println(file3);//构造器3:File file4 = new File(file3,"hi.txt");System.out.println(file4);}/*
public String getAbsolutePath():获取绝对路径
public String getPath() :获取路径
public String getName() :获取名称
public String getParent():获取上层文件目录路径。若无,返回null
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值如下的两个方法适用于文件目录:
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组*/@Testpublic void test2(){File file1 = new File("hello.txt");File file2 = new File("d:\\io\\hi.txt");System.out.println(file1.getAbsolutePath());System.out.println(file1.getPath());System.out.println(file1.getName());System.out.println(file1.getParent());System.out.println(file1.length());System.out.println(new Date(file1.lastModified()));System.out.println();System.out.println(file2.getAbsolutePath());System.out.println(file2.getPath());System.out.println(file2.getName());System.out.println(file2.getParent());System.out.println(file2.length());System.out.println(file2.lastModified());}@Testpublic void test3(){File file = new File("D:\\workspace_idea1\\JavaSenior");String[] list = file.list();for(String s : list){System.out.println(s);}System.out.println();File[] files = file.listFiles();for(File f : files){System.out.println(f);}}/*public boolean renameTo(File dest):把文件重命名为指定的文件路径比如:file1.renameTo(file2)为例:要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。*/@Testpublic void test4(){File file1 = new File("hello.txt");File file2 = new File("D:\\io\\hi.txt");boolean renameTo = file2.renameTo(file1);System.out.println(renameTo);}/*
public boolean isDirectory():判断是否是文件目录
public boolean isFile() :判断是否是文件
public boolean exists() :判断是否存在
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏*/@Testpublic void test5(){File file1 = new File("hello.txt");file1 = new File("hello1.txt");System.out.println(file1.isDirectory());System.out.println(file1.isFile());System.out.println(file1.exists());System.out.println(file1.canRead());System.out.println(file1.canWrite());System.out.println(file1.isHidden());System.out.println();File file2 = new File("d:\\io");file2 = new File("d:\\io1");System.out.println(file2.isDirectory());System.out.println(file2.isFile());System.out.println(file2.exists());System.out.println(file2.canRead());System.out.println(file2.canWrite());System.out.println(file2.isHidden());}/*创建硬盘中对应的文件或文件目录
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs() :创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,一并创建删除磁盘中的文件或文件目录
public boolean delete():删除文件或者文件夹删除注意事项:Java中的删除不走回收站。*/@Testpublic void test6() throws IOException {File file1 = new File("hi.txt");if(!file1.exists()){//文件的创建file1.createNewFile();System.out.println("创建成功");}else{//文件存在file1.delete();System.out.println("删除成功");}}@Testpublic void test7(){//文件目录的创建File file1 = new File("d:\\io\\io1\\io3");boolean mkdir = file1.mkdir();if(mkdir){System.out.println("创建成功1");}File file2 = new File("d:\\io\\io1\\io4");boolean mkdir1 = file2.mkdirs();if(mkdir1){System.out.println("创建成功2");}//要想删除成功,io4文件目录下不能有子目录或文件File file3 = new File("D:\\io\\io1\\io4");file3 = new File("D:\\io\\io1");System.out.println(file3.delete());}
}

相对路径VS绝对路径

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kEGzm0FM-1631633504658)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901165426342.png)]

流的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mYxRk3RO-1631633504660)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901170634525.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfvY8L8Q-1631633504661)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901171052095.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sqw1IEgI-1631633504662)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901171531625.png)]

文件流

注意:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lVQZSTdB-1631633504663)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901175620985.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5yuuZunE-1631633504664)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901175210809.png)]

字符流

package com.wdl.java;import org.junit.Test;import java.io.*;/**** 一、流的分类:* 1.操作数据单位:字节流、字符流* 2.数据的流向:输入流、输出流* 3.流的角色:节点流、处理流** 二、流的体系结构* 抽象基类         节点流(或文件流)                               缓冲流(处理流的一种)* InputStream     FileInputStream   (read(byte[] buffer))        BufferedInputStream (read(byte[] buffer))* OutputStream    FileOutputStream  (write(byte[] buffer,0,len)  BufferedOutputStream (write(byte[] buffer,0,len) / flush()* Reader          FileReader (read(char[] cbuf))                 BufferedReader (read(char[] cbuf) / readLine())* Writer          FileWriter (write(char[] cbuf,0,len)           BufferedWriter (write(char[] cbuf,0,len) / flush()**** @author shkstart* @create 2019 上午 10:40*/
public class FileReaderWriterTest {public static void main(String[] args) {File file = new File("hello.txt");//相较于当前工程System.out.println(file.getAbsolutePath());File file1 = new File("day09\\hello.txt");System.out.println(file1.getAbsolutePath());}/*将day09下的hello.txt文件内容读入程序中,并输出到控制台说明点:1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-12. 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理3. 读入的文件一定要存在,否则就会报FileNotFoundException。*/@Testpublic void testFileReader(){FileReader fr = null;try {//1.实例化File类的对象,指明要操作的文件File file = new File("hello.txt");//相较于当前Module//2.提供具体的流fr = new FileReader(file);//3.数据的读入//read():返回读入的一个字符。如果达到文件末尾,返回-1//方式一:
//        int data = fr.read();
//        while(data != -1){//            System.out.print((char)data);
//            data = fr.read();
//        }//方式二:语法上针对于方式一的修改int data;while((data = fr.read()) != -1){System.out.print((char)data);}} catch (IOException e) {e.printStackTrace();} finally {//4.流的关闭操作
//            try {//                if(fr != null)
//                    fr.close();
//            } catch (IOException e) {//                e.printStackTrace();
//            }//或if(fr != null){try {fr.close();} catch (IOException e) {e.printStackTrace();}}}}//对read()操作升级:使用read的重载方法@Testpublic void testFileReader1()  {FileReader fr = null;try {//1.File类的实例化File file = new File("hello.txt");//2.FileReader流的实例化fr = new FileReader(file);//3.读入的操作//read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1char[] cbuf = new char[5];int len;while((len = fr.read(cbuf)) != -1){//方式一://错误的写法
//                for(int i = 0;i < cbuf.length;i++){//                    System.out.print(cbuf[i]);
//                }//正确的写法
//                for(int i = 0;i < len;i++){//                    System.out.print(cbuf[i]);
//                }//方式二://错误的写法,对应着方式一的错误的写法
//                String str = new String(cbuf);
//                System.out.print(str);//正确的写法String str = new String(cbuf,0,len);System.out.print(str);}} catch (IOException e) {e.printStackTrace();} finally {if(fr != null){//4.资源的关闭try {fr.close();} catch (IOException e) {e.printStackTrace();}}}}/*从内存中写出数据到硬盘的文件里。说明:1. 输出操作,对应的File可以不存在的。并不会报异常2.File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。File对应的硬盘中的文件如果存在:如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容*/@Testpublic void testFileWriter() {FileWriter fw = null;try {//1.提供File类的对象,指明写出到的文件File file = new File("hello1.txt");//2.提供FileWriter的对象,用于数据的写出fw = new FileWriter(file,false);//3.写出的操作fw.write("I have a dream!\n");fw.write("you need to have a dream!");} catch (IOException e) {e.printStackTrace();} finally {//4.流资源的关闭if(fw != null){try {fw.close();} catch (IOException e) {e.printStackTrace();}}}}@Testpublic void testFileReaderFileWriter() {FileReader fr = null;FileWriter fw = null;try {//1.创建File类的对象,指明读入和写出的文件File srcFile = new File("hello.txt");File destFile = new File("hello2.txt");//不能使用字符流来处理图片等字节数据
//            File srcFile = new File("爱情与友情.jpg");
//            File destFile = new File("爱情与友情1.jpg");//2.创建输入流和输出流的对象fr = new FileReader(srcFile);fw = new FileWriter(destFile);//3.数据的读入和写出操作char[] cbuf = new char[5];int len;//记录每次读入到cbuf数组中的字符的个数while((len = fr.read(cbuf)) != -1){//每次写出len个字符fw.write(cbuf,0,len);}} catch (IOException e) {e.printStackTrace();} finally {//4.关闭流资源//方式一:
//            try {//                if(fw != null)
//                    fw.close();
//            } catch (IOException e) {//                e.printStackTrace();
//            }finally{//                try {//                    if(fr != null)
//                        fr.close();
//                } catch (IOException e) {//                    e.printStackTrace();
//                }
//            }//方式二:try {if(fw != null)fw.close();} catch (IOException e) {e.printStackTrace();}try {if(fr != null)fr.close();} catch (IOException e) {e.printStackTrace();}}}}

字节流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rvKiUk7g-1631633504665)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210901210159711.png)]

package com.wdl.java;import org.junit.Test;import java.io.*;/*** 测试FileInputStream和FileOutputStream的使用** 结论:* 1. 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理* 2. 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理**** @author shkstart* @create 2019 下午 2:13*/
public class FileInputOutputStreamTest {//使用字节流FileInputStream处理文本文件,可能出现乱码。@Testpublic void testFileInputStream() {FileInputStream fis = null;try {//1. 造文件File file = new File("hello.txt");//2.造流fis = new FileInputStream(file);//3.读数据byte[] buffer = new byte[5];int len;//记录每次读取的字节的个数while((len = fis.read(buffer)) != -1){String str = new String(buffer,0,len);System.out.print(str);}} catch (IOException e) {e.printStackTrace();} finally {if(fis != null){//4.关闭资源try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}/*实现对图片的复制操作*/@Testpublic void testFileInputOutputStream()  {FileInputStream fis = null;FileOutputStream fos = null;try {//File srcFile = new File("爱情与友情.jpg");File destFile = new File("爱情与友情2.jpg");//fis = new FileInputStream(srcFile);fos = new FileOutputStream(destFile);//复制的过程byte[] buffer = new byte[5];int len;while((len = fis.read(buffer)) != -1){fos.write(buffer,0,len);}} catch (IOException e) {e.printStackTrace();} finally {if(fos != null){//try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}//指定路径下文件的复制public void copyFile(String srcPath,String destPath){FileInputStream fis = null;FileOutputStream fos = null;try {//File srcFile = new File(srcPath);File destFile = new File(destPath);//fis = new FileInputStream(srcFile);fos = new FileOutputStream(destFile);//复制的过程byte[] buffer = new byte[1024];int len;while((len = fis.read(buffer)) != -1){fos.write(buffer,0,len);}} catch (IOException e) {e.printStackTrace();} finally {if(fos != null){//try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}@Testpublic void testCopyFile(){long start = System.currentTimeMillis();String srcPath = "C:\\Users\\Administrator\\Desktop\\01-视频.avi";String destPath = "C:\\Users\\Administrator\\Desktop\\02-视频.avi";//        String srcPath = "hello.txt";
//        String destPath = "hello3.txt";copyFile(srcPath,destPath);long end = System.currentTimeMillis();System.out.println("复制操作花费的时间为:" + (end - start));//618}}

处理流之一:缓存流

package com.wdl.java;import org.junit.Test;import java.io.*;/*** 处理流之一:缓冲流的使用** 1.缓冲流:* BufferedInputStream* BufferedOutputStream* BufferedReader* BufferedWriter** 2.作用:提供流的读取、写入的速度*   提高读写速度的原因:内部提供了一个缓冲区** 3. 处理流,就是“套接”在已有的流的基础上。** @author shkstart* @create 2019 下午 2:44*/
public class BufferedTest {/*实现非文本文件的复制*/@Testpublic void BufferedStreamTest() throws FileNotFoundException {BufferedInputStream bis = null;BufferedOutputStream bos = null;try {//1.造文件File srcFile = new File("爱情与友情.jpg");File destFile = new File("爱情与友情3.jpg");//2.造流//2.1 造节点流FileInputStream fis = new FileInputStream((srcFile));FileOutputStream fos = new FileOutputStream(destFile);//2.2 造缓冲流bis = new BufferedInputStream(fis);bos = new BufferedOutputStream(fos);//3.复制的细节:读取、写入byte[] buffer = new byte[10];int len;while((len = bis.read(buffer)) != -1){bos.write(buffer,0,len);//                bos.flush();//刷新缓冲区}} catch (IOException e) {e.printStackTrace();} finally {//4.资源关闭//要求:先关闭外层的流,再关闭内层的流if(bos != null){try {bos.close();} catch (IOException e) {e.printStackTrace();}}if(bis != null){try {bis.close();} catch (IOException e) {e.printStackTrace();}}//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
//        fos.close();
//        fis.close();}}//实现文件复制的方法public void copyFileWithBuffered(String srcPath,String destPath){BufferedInputStream bis = null;BufferedOutputStream bos = null;try {//1.造文件File srcFile = new File(srcPath);File destFile = new File(destPath);//2.造流//2.1 造节点流FileInputStream fis = new FileInputStream((srcFile));FileOutputStream fos = new FileOutputStream(destFile);//2.2 造缓冲流bis = new BufferedInputStream(fis);bos = new BufferedOutputStream(fos);//3.复制的细节:读取、写入byte[] buffer = new byte[1024];int len;while((len = bis.read(buffer)) != -1){bos.write(buffer,0,len);}} catch (IOException e) {e.printStackTrace();} finally {//4.资源关闭//要求:先关闭外层的流,再关闭内层的流if(bos != null){try {bos.close();} catch (IOException e) {e.printStackTrace();}}if(bis != null){try {bis.close();} catch (IOException e) {e.printStackTrace();}}//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
//        fos.close();
//        fis.close();}}@Testpublic void testCopyFileWithBuffered(){long start = System.currentTimeMillis();String srcPath = "C:\\Users\\Administrator\\Desktop\\01-视频.avi";String destPath = "C:\\Users\\Administrator\\Desktop\\03-视频.avi";copyFileWithBuffered(srcPath,destPath);long end = System.currentTimeMillis();System.out.println("复制操作花费的时间为:" + (end - start));//618 - 176}/*使用BufferedReader和BufferedWriter实现文本文件的复制*/@Testpublic void testBufferedReaderBufferedWriter(){BufferedReader br = null;BufferedWriter bw = null;try {//创建文件和相应的流br = new BufferedReader(new FileReader(new File("dbcp.txt")));bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));//读写操作//方式一:使用char[]数组
//            char[] cbuf = new char[1024];
//            int len;
//            while((len = br.read(cbuf)) != -1){//                bw.write(cbuf,0,len);
//    //            bw.flush();
//            }//方式二:使用StringString data;while((data = br.readLine()) != null){//方法一:
//                bw.write(data + "\n");//data中不包含换行符//方法二:bw.write(data);//data中不包含换行符bw.newLine();//提供换行的操作}} catch (IOException e) {e.printStackTrace();} finally {//关闭资源if(bw != null){try {bw.close();} catch (IOException e) {e.printStackTrace();}}if(br != null){try {br.close();} catch (IOException e) {e.printStackTrace();}}}}}

图片加密与解密

package com.atguigu.exer;import org.junit.Test;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;/*** @author shkstart* @create 2019 下午 4:08*/
public class PicTest {//图片的加密@Testpublic void test1() {FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("爱情与友情.jpg");fos = new FileOutputStream("爱情与友情secret.jpg");byte[] buffer = new byte[20];int len;while ((len = fis.read(buffer)) != -1) {//字节数组进行修改//错误的//            for(byte b : buffer){//                b = (byte) (b ^ 5);//            }//正确的for (int i = 0; i < len; i++) {buffer[i] = (byte) (buffer[i] ^ 5);}fos.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}//图片的解密@Testpublic void test2() {FileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("爱情与友情secret.jpg");fos = new FileOutputStream("爱情与友情4.jpg");byte[] buffer = new byte[20];int len;while ((len = fis.read(buffer)) != -1) {//字节数组进行修改//错误的//            for(byte b : buffer){//                b = (byte) (b ^ 5);//            }//正确的for (int i = 0; i < len; i++) {buffer[i] = (byte) (buffer[i] ^ 5);}fos.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}
}

统计字符出现的次数

package com.atguigu.exer;import org.junit.Test;import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;/*** 练习3:获取文本上字符出现的次数,把数据写入文件** 思路:* 1.遍历文本每一个字符* 2.字符出现的次数存在Map中** Map<Character,Integer> map = new HashMap<Character,Integer>();* map.put('a',18);* map.put('你',2);** 3.把map中的数据写入文件** @author shkstart* @create 2019 下午 3:47*/
public class WordCount {/*说明:如果使用单元测试,文件相对路径为当前module如果使用main()测试,文件相对路径为当前工程*/@Testpublic void testWordCount() {FileReader fr = null;BufferedWriter bw = null;try {//1.创建Map集合Map<Character, Integer> map = new HashMap<Character, Integer>();//2.遍历每一个字符,每一个字符出现的次数放到map中fr = new FileReader("dbcp.txt");int c = 0;while ((c = fr.read()) != -1) {//int 还原 charchar ch = (char) c;// 判断char是否在map中第一次出现if (map.get(ch) == null) {map.put(ch, 1);} else {map.put(ch, map.get(ch) + 1);}}//3.把map中数据存在文件count.txt//3.1 创建Writerbw = new BufferedWriter(new FileWriter("wordcount.txt"));//3.2 遍历map,再写入数据Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();for (Map.Entry<Character, Integer> entry : entrySet) {switch (entry.getKey()) {case ' ':bw.write("空格=" + entry.getValue());break;case '\t'://\t表示tab 键字符bw.write("tab键=" + entry.getValue());break;case '\r'://bw.write("回车=" + entry.getValue());break;case '\n'://bw.write("换行=" + entry.getValue());break;default:bw.write(entry.getKey() + "=" + entry.getValue());break;}bw.newLine();}} catch (IOException e) {e.printStackTrace();} finally {//4.关流if (fr != null) {try {fr.close();} catch (IOException e) {e.printStackTrace();}}if (bw != null) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}}}
}

处理流之二:转换流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-THRQOywD-1631633504667)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902095432370.png)]

字符编码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqixB0aV-1631633504667)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902102550527.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m2kWAuZW-1631633504668)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902103723248.png)]

其他流

package com.wdl.java;import org.junit.Test;import java.io.*;/*** 其他流的使用* 1.标准的输入、输出流* 2.打印流* 3.数据流** @author shkstart* @create 2019 下午 6:11*/
public class OtherStreamTest {/*1.标准的输入、输出流1.1System.in:标准的输入流,默认从键盘输入System.out:标准的输出流,默认从控制台输出1.2System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。1.3练习:从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入“e”或者“exit”时,退出程序。方法一:使用Scanner实现,调用next()返回一个字符串方法二:使用System.in实现。System.in  --->  转换流 ---> BufferedReader的readLine()*/public static void main(String[] args) {BufferedReader br = null;try {InputStreamReader isr = new InputStreamReader(System.in);br = new BufferedReader(isr);while (true) {System.out.println("请输入字符串:");String data = br.readLine();if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {System.out.println("程序结束");break;}String upperCase = data.toUpperCase();System.out.println(upperCase);}} catch (IOException e) {e.printStackTrace();} finally {if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}/*2. 打印流:PrintStream 和PrintWriter2.1 提供了一系列重载的print() 和 println()2.2 练习:*/@Testpublic void test2() {PrintStream ps = null;try {FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)ps = new PrintStream(fos, true);if (ps != null) {// 把标准输出流(控制台输出)改成文件System.setOut(ps);}for (int i = 0; i <= 255; i++) { // 输出ASCII字符System.out.print((char) i);if (i % 50 == 0) { // 每50个数据一行System.out.println(); // 换行}}} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (ps != null) {ps.close();}}}/*3. 数据流3.1 DataInputStream 和 DataOutputStream3.2 作用:用于读取或写出基本数据类型的变量或字符串练习:将内存中的字符串、基本数据类型的变量写出到文件中。注意:处理异常的话,仍然应该使用try-catch-finally.*/@Testpublic void test3() throws IOException {//1.DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));//2.dos.writeUTF("刘建辰");dos.flush();//刷新操作,将内存中的数据写入文件dos.writeInt(23);dos.flush();dos.writeBoolean(true);dos.flush();//3.dos.close();}/*将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。注意点:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!*/@Testpublic void test4() throws IOException {//1.DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));//2.String name = dis.readUTF();int age = dis.readInt();boolean isMale = dis.readBoolean();System.out.println("name = " + name);System.out.println("age = " + age);System.out.println("isMale = " + isMale);//3.dis.close();}}

装饰设计模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BeKXL64K-1631633504669)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902115209770.png)]

对象流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFOapnoy-1631633504670)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902121432265.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VGjpAgGU-1631633504672)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902121526250.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2CQC6or5-1631633504673)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902131709165.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0mh7VulP-1631633504673)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902132557440.png)]

package com.wdl.java;import org.junit.Test;import java.io.*;/*** 对象流的使用* 1.ObjectInputStream 和 ObjectOutputStream* 2.作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。** 3.要想一个java对象是可序列化的,需要满足相应的要求。见Person.java** 4.序列化机制:* 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种* 二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。* 当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。** @author shkstart* @create 2019 上午 10:27*/
public class ObjectInputOutputStreamTest {/*序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去使用ObjectOutputStream实现*/@Testpublic void testObjectOutputStream(){ObjectOutputStream oos = null;try {//1.oos = new ObjectOutputStream(new FileOutputStream("object.dat"));//2.oos.writeObject(new String("我爱北京天安门"));oos.flush();//刷新操作oos.writeObject(new Person("王铭",23));oos.flush();oos.writeObject(new Person("张学良",23,1001,new Account(5000)));oos.flush();} catch (IOException e) {e.printStackTrace();} finally {if(oos != null){//3.try {oos.close();} catch (IOException e) {e.printStackTrace();}}}}/*反序列化:将磁盘文件中的对象还原为内存中的一个java对象使用ObjectInputStream来实现*/@Testpublic void testObjectInputStream(){ObjectInputStream ois = null;try {ois = new ObjectInputStream(new FileInputStream("object.dat"));Object obj = ois.readObject();String str = (String) obj;Person p = (Person) ois.readObject();Person p1 = (Person) ois.readObject();System.out.println(str);System.out.println(p);System.out.println(p1);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {if(ois != null){try {ois.close();} catch (IOException e) {e.printStackTrace();}}}}}
package com.wdl.java;import java.io.Serializable;/*** Person需要满足如下的要求,方可序列化* 1.需要实现接口:Serializable* 2.当前类提供一个全局常量:serialVersionUID* 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性*   也必须是可序列化的。(默认情况下,基本数据类型可序列化)*** 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量*** @author shkstart* @create 2019 上午 10:38*/
public class Person implements Serializable{public static final long serialVersionUID = 475463534532L;private String name;private int age;private int id;private Account acct;public Person(String name, int age, int id) {this.name = name;this.age = age;this.id = id;}public Person(String name, int age, int id, Account acct) {this.name = name;this.age = age;this.id = id;this.acct = acct;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", id=" + id +", acct=" + acct +'}';}public int getId() {return id;}public void setId(int id) {this.id = id;}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;}public Person(String name, int age) {this.name = name;this.age = age;}public Person() {}
}class Account implements Serializable{public static final long serialVersionUID = 4754534532L;private double balance;@Overridepublic String toString() {return "Account{" +"balance=" + balance +'}';}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}public Account(double balance) {this.balance = balance;}
}

随机访问文件流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AFUUfa9L-1631633504674)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902133653050.png)]

package com.wdl.java;import org.junit.Test;import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;/*** RandomAccessFile的使用* 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口* 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流** 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。*   如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)** 4. 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果** @author shkstart* @create 2019 上午 11:18*/
public class RandomAccessFileTest {@Testpublic void test1() {RandomAccessFile raf1 = null;RandomAccessFile raf2 = null;try {//1.raf1 = new RandomAccessFile(new File("爱情与友情.jpg"),"r");raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"),"rw");//2.byte[] buffer = new byte[1024];int len;while((len = raf1.read(buffer)) != -1){raf2.write(buffer,0,len);}} catch (IOException e) {e.printStackTrace();} finally {//3.if(raf1 != null){try {raf1.close();} catch (IOException e) {e.printStackTrace();}}if(raf2 != null){try {raf2.close();} catch (IOException e) {e.printStackTrace();}}}}@Testpublic void test2() throws IOException {RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");raf1.seek(3);//将指针调到角标为3的位置raf1.write("xyz".getBytes());//raf1.close();}/*使用RandomAccessFile实现数据的插入效果*/@Testpublic void test3() throws IOException {RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");raf1.seek(3);//将指针调到角标为3的位置//保存指针3后面的所有数据到StringBuilder中StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());byte[] buffer = new byte[20];int len;while((len = raf1.read(buffer)) != -1){builder.append(new String(buffer,0,len)) ;}//调回指针,写入“xyz”raf1.seek(3);raf1.write("xyz".getBytes());//将StringBuilder中的数据写入到文件中raf1.write(builder.toString().getBytes());raf1.close();//思考:将StringBuilder替换为ByteArrayOutputStream}
}

NIO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9uU3Putp-1631633504676)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902144935427.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uatnnndX-1631633504677)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902144942775.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RVksXLvJ-1631633504678)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902151620213.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gk5QaL6y-1631633504679)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902151714137.png)]

Path常用方法(File类的升级)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fUB4Ux9K-1631633504680)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902152204563.png)]

Files常用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJcQQzqt-1631633504680)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902152214451.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CZ7pVxOY-1631633504681)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902152226359.png)]

package com.atguigu.java;import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.*;
import java.util.Iterator;/*** Files工具类的使用:操作文件或目录的工具类* @author shkstart* @create 2019 下午 2:44*/
public class FilesTest {@Testpublic void test1() throws IOException{Path path1 = Paths.get("d:\\nio", "hello.txt");Path path2 = Paths.get("atguigu.txt");//        Path copy(Path src, Path dest, CopyOption … how) : 文件的复制//要想复制成功,要求path1对应的物理上的文件存在。path1对应的文件没有要求。
//      Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING);//        Path createDirectory(Path path, FileAttribute<?> … attr) : 创建一个目录//要想执行成功,要求path对应的物理上的文件目录不存在。一旦存在,抛出异常。Path path3 = Paths.get("d:\\nio\\nio1");
//      Files.createDirectory(path3);//     Path createFile(Path path, FileAttribute<?> … arr) : 创建一个文件//要想执行成功,要求path对应的物理上的文件不存在。一旦存在,抛出异常。Path path4 = Paths.get("d:\\nio\\hi.txt");
//      Files.createFile(path4);//      void delete(Path path) : 删除一个文件/目录,如果不存在,执行报错
//      Files.delete(path4);//      void deleteIfExists(Path path) : Path对应的文件/目录如果存在,执行删除.如果不存在,正常执行结束Files.deleteIfExists(path3);//     Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置//要想执行成功,src对应的物理上的文件需要存在,dest对应的文件没有要求。
//      Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE);//     long size(Path path) : 返回 path 指定文件的大小long size = Files.size(path2);System.out.println(size);}@Testpublic void test2() throws IOException{Path path1 = Paths.get("d:\\nio", "hello.txt");Path path2 = Paths.get("atguigu.txt");
//      boolean exists(Path path, LinkOption … opts) : 判断文件是否存在System.out.println(Files.exists(path2, LinkOption.NOFOLLOW_LINKS));//        boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录//不要求此path对应的物理文件存在。System.out.println(Files.isDirectory(path1, LinkOption.NOFOLLOW_LINKS));//       boolean isRegularFile(Path path, LinkOption … opts) : 判断是否是文件//     boolean isHidden(Path path) : 判断是否是隐藏文件//要求此path对应的物理上的文件需要存在。才可判断是否隐藏。否则,抛异常。
//      System.out.println(Files.isHidden(path1));//        boolean isReadable(Path path) : 判断文件是否可读System.out.println(Files.isReadable(path1));
//      boolean isWritable(Path path) : 判断文件是否可写System.out.println(Files.isWritable(path1));
//      boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在System.out.println(Files.notExists(path1, LinkOption.NOFOLLOW_LINKS));}/*** StandardOpenOption.READ:表示对应的Channel是可读的。* StandardOpenOption.WRITE:表示对应的Channel是可写的。* StandardOpenOption.CREATE:如果要写出的文件不存在,则创建。如果存在,忽略* StandardOpenOption.CREATE_NEW:如果要写出的文件不存在,则创建。如果存在,抛异常** @author shkstart 邮箱:shkstart@126.com* @throws IOException*/@Testpublic void test3() throws IOException{Path path1 = Paths.get("d:\\nio", "hello.txt");//     InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象InputStream inputStream = Files.newInputStream(path1, StandardOpenOption.READ);//       OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象OutputStream outputStream = Files.newOutputStream(path1, StandardOpenOption.WRITE,StandardOpenOption.CREATE);//        SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。SeekableByteChannel channel = Files.newByteChannel(path1, StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);//      DirectoryStream<Path>  newDirectoryStream(Path path) : 打开 path 指定的目录Path path2 = Paths.get("e:\\teach");DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path2);Iterator<Path> iterator = directoryStream.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}

第三方jar包实现数据读写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EUyUTLzB-1631633504682)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902152520413.png)]

package com.atguigu.java;import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;/*** @author shkstart* @create 2019 上午 11:58*/
public class FileUtilsTest {public static void main(String[] args) {File srcFile = new File("day10\\爱情与友情.jpg");File destFile = new File("day10\\爱情与友情2.jpg");try {FileUtils.copyFile(srcFile,destFile);} catch (IOException e) {e.printStackTrace();}}
}

网络编程

两个主要的问题

1.如何准确地定位网络上一台或多台主机;定位主机上的特定的应用

2.找到主机后如何可靠高效地进行数据传输

两个要素

1.通信双方地址

IP

端口号

2.一定的规则(即:网络通信协议。有两套参考模型)

OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广

TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

要素一:IP和端口号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WGegWUfo-1631633504684)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902155333200.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vakm7Za7-1631633504685)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902160215543.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qICHeqTb-1631633504686)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902160927577.png)]

要素二:网络通信协议

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eBN0S7J6-1631633504687)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902154628597.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOGq9Cfb-1631633504688)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902161843220.png)]

package com.wdl.java1;import java.net.InetAddress;
import java.net.UnknownHostException;/*** 一、网络编程中有两个主要的问题:* 1.如何准确地定位网络上一台或多台主机;定位主机上的特定的应用* 2.找到主机后如何可靠高效地进行数据传输** 二、网络编程中的两个要素:* 1.对应问题一:IP和端口号* 2.对应问题二:提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)*** 三、通信要素一:IP和端口号** 1. IP:唯一的标识 Internet 上的计算机(通信实体)* 2. 在Java中使用InetAddress类代表IP* 3. IP分类:IPv4 和 IPv6 ; 万维网 和 局域网* 4. 域名:   www.baidu.com   www.mi.com  www.sina.com  www.jd.com*            www.vip.com* 5. 本地回路地址:127.0.0.1 对应着:localhost** 6. 如何实例化InetAddress:两个方法:getByName(String host) 、 getLocalHost()*        两个常用方法:getHostName() / getHostAddress()** 7. 端口号:正在计算机上运行的进程。* 要求:不同的进程有不同的端口号* 范围:被规定为一个 16 位的整数 0~65535。** 8. 端口号与IP地址的组合得出一个网络套接字:Socket* @author shkstart* @create 2019 下午 2:30*/
public class InetAddressTest {public static void main(String[] args) {try {//File file = new File("hello.txt");InetAddress inet1 = InetAddress.getByName("192.168.10.14");System.out.println(inet1);InetAddress inet2 = InetAddress.getByName("www.atguigu.com");System.out.println(inet2);InetAddress inet3 = InetAddress.getByName("127.0.0.1");System.out.println(inet3);//获取本地ipInetAddress inet4 = InetAddress.getLocalHost();System.out.println(inet4);//getHostName()System.out.println(inet2.getHostName());//getHostAddress()System.out.println(inet2.getHostAddress());} catch (UnknownHostException e) {e.printStackTrace();}}}

TCP和UDP

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKCaTU52-1631633504689)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902162536536.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1rlamtvo-1631633504690)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902162711094.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K6yfsp7F-1631633504691)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902162746240.png)]

TCP

将数据显示在控制台上

package com.wdl.java1;import org.junit.Test;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;/*** 实现TCP的网络编程* 例子1:客户端发送信息给服务端,服务端将数据显示在控制台上** @author shkstart* @create 2019 下午 3:30*/
public class TCPTest1 {//客户端@Testpublic void client()  {Socket socket = null;OutputStream os = null;try {//1.创建Socket对象,指明服务器端的ip和端口号InetAddress inet = InetAddress.getByName("127.0.0.1");socket = new Socket(inet,8899);//2.获取一个输出流,用于输出数据os = socket.getOutputStream();//3.写出数据的操作os.write("你好,我是客户端mm".getBytes());} catch (IOException e) {e.printStackTrace();} finally {//4.资源的关闭if(os != null){try {os.close();} catch (IOException e) {e.printStackTrace();}}if(socket != null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}//服务端@Testpublic void server()  {ServerSocket ss = null;Socket socket = null;InputStream is = null;ByteArrayOutputStream baos = null;try {//1.创建服务器端的ServerSocket,指明自己的端口号ss = new ServerSocket(8899);//2.调用accept()表示接收来自于客户端的socketsocket = ss.accept();//3.获取输入流is = socket.getInputStream();//不建议这样写,可能会有乱码
//        byte[] buffer = new byte[1024];
//        int len;
//        while((len = is.read(buffer)) != -1){//            String str = new String(buffer,0,len);
//            System.out.print(str);
//        }//4.读取输入流中的数据baos = new ByteArrayOutputStream();byte[] buffer = new byte[5];int len;while((len = is.read(buffer)) != -1){baos.write(buffer,0,len);}System.out.println(baos.toString());System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据");} catch (IOException e) {e.printStackTrace();} finally {if(baos != null){//5.关闭资源try {baos.close();} catch (IOException e) {e.printStackTrace();}}if(is != null){try {is.close();} catch (IOException e) {e.printStackTrace();}}if(socket != null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}if(ss != null){try {ss.close();} catch (IOException e) {e.printStackTrace();}}}}}

将文件保存在本地

package com.wdl.java1;import org.junit.Test;import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;/**** 实现TCP的网络编程* 例题2:客户端发送文件给服务端,服务端将文件保存在本地。** @author shkstart* @create 2019 下午 3:53*/
public class TCPTest2 {/*这里涉及到的异常,应该使用try-catch-finally处理*/@Testpublic void client() throws IOException {//1.Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);//2.OutputStream os = socket.getOutputStream();//3.FileInputStream fis = new FileInputStream(new File("beauty.jpg"));//4.byte[] buffer = new byte[1024];int len;while((len = fis.read(buffer)) != -1){os.write(buffer,0,len);}//5.fis.close();os.close();socket.close();}/*这里涉及到的异常,应该使用try-catch-finally处理*/@Testpublic void server() throws IOException {//1.ServerSocket ss = new ServerSocket(9090);//2.Socket socket = ss.accept();//3.InputStream is = socket.getInputStream();//4.FileOutputStream fos = new FileOutputStream(new File("beauty1.jpg"));//5.byte[] buffer = new byte[1024];int len;while((len = is.read(buffer)) != -1){fos.write(buffer,0,len);}//6.fos.close();is.close();socket.close();ss.close();}
}

将文件保存在本地(并返回"发送成功")

package com.wdl.java1;import org.junit.Test;import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;/*** 实现TCP的网络编程* 例题3:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。* 并关闭相应的连接。* @author shkstart* @create 2019 下午 4:13*/
public class TCPTest3 {/*这里涉及到的异常,应该使用try-catch-finally处理*/@Testpublic void client() throws IOException {//1.Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);//2.OutputStream os = socket.getOutputStream();//3.FileInputStream fis = new FileInputStream(new File("beauty.jpg"));//4.byte[] buffer = new byte[1024];int len;while((len = fis.read(buffer)) != -1){os.write(buffer,0,len);}//关闭数据的输出socket.shutdownOutput();//5.接收来自于服务器端的数据,并显示到控制台上InputStream is = socket.getInputStream();ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] bufferr = new byte[20];int len1;while((len1 = is.read(buffer)) != -1){baos.write(buffer,0,len1);}System.out.println(baos.toString());//6.fis.close();os.close();socket.close();baos.close();}/*这里涉及到的异常,应该使用try-catch-finally处理*/@Testpublic void server() throws IOException {//1.ServerSocket ss = new ServerSocket(9090);//2.Socket socket = ss.accept();//3.InputStream is = socket.getInputStream();//4.FileOutputStream fos = new FileOutputStream(new File("beauty2.jpg"));//5.byte[] buffer = new byte[1024];int len;while((len = is.read(buffer)) != -1){fos.write(buffer,0,len);}System.out.println("图片传输完成");//6.服务器端给予客户端反馈OutputStream os = socket.getOutputStream();os.write("你好,美女,照片我已收到,非常漂亮!".getBytes());//7.fos.close();is.close();socket.close();ss.close();os.close();}
}

UDP

package com.wdl.java1;import org.junit.Test;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;/*** UDPd协议的网络编程* @author shkstart* @create 2019 下午 4:34*/
public class UDPTest {//发送端@Testpublic void sender() throws IOException {DatagramSocket socket = new DatagramSocket();String str = "我是UDP方式发送的导弹";byte[] data = str.getBytes();InetAddress inet = InetAddress.getLocalHost();DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);socket.send(packet);socket.close();}//接收端@Testpublic void receiver() throws IOException {DatagramSocket socket = new DatagramSocket(9090);byte[] buffer = new byte[100];DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);socket.receive(packet);System.out.println(new String(packet.getData(),0,packet.getLength()));socket.close();}
}

URL编程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r8fgIcvR-1631633504692)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902175219850.png)]

package com.wdl.java1;import java.net.MalformedURLException;
import java.net.URL;/*** URL网络编程* 1.URL:统一资源定位符,对应着互联网的某一资源地址* 2.格式:*  http://localhost:8080/examples/beauty.jpg?username=Tom*  协议   主机名    端口号  资源地址           参数列表** @author shkstart* @create 2019 下午 4:47*/
public class URLTest {public static void main(String[] args) {try {//            URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom");URL url = new URL("https://pics6.baidu.com/feed/bf096b63f6246b603d8cbf353ae91445500fa28f.jpeg?token=62351cd161af0d9f045ce6327f063e1a");//            public String getProtocol(  )     获取该URL的协议名System.out.println(url.getProtocol());
//            public String getHost(  )           获取该URL的主机名System.out.println(url.getHost());
//            public String getPort(  )            获取该URL的端口号System.out.println(url.getPort());
//            public String getPath(  )           获取该URL的文件路径System.out.println(url.getPath());
//            public String getFile(  )             获取该URL的文件名System.out.println(url.getFile());
//            public String getQuery(   )        获取该URL的查询名System.out.println(url.getQuery());} catch (MalformedURLException e) {e.printStackTrace();}}}
package com.wdl.java1;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;/*** @author shkstart* @create 2019 下午 4:54*/
public class URLTest1 {public static void main(String[] args) {HttpURLConnection urlConnection = null;InputStream is = null;FileOutputStream fos = null;try {//            URL url = new URL("http://localhost:8080/examples/beauty.jpg");URL url = new URL("https://pics6.baidu.com/feed/bf096b63f6246b603d8cbf353ae91445500fa28f.jpeg?token=62351cd161af0d9f045ce6327f063e1a");urlConnection = (HttpURLConnection) url.openConnection();urlConnection.connect();is = urlConnection.getInputStream();
//            fos = new FileOutputStream("day10\\beauty3.jpg");fos = new FileOutputStream("day10"+ File.separator +"beauty3.jpg");byte[] buffer = new byte[1024];int len;while((len = is.read(buffer)) != -1){fos.write(buffer,0,len);}System.out.println("下载完成");} catch (IOException e) {e.printStackTrace();} finally {//关闭资源if(is != null){try {is.close();} catch (IOException e) {e.printStackTrace();}}if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}if(urlConnection != null){urlConnection.disconnect();}}}
}

反射

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ii3m49bM-1631633504693)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902195925622.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0SvZ1YKz-1631633504695)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902200909552.png)]

反射操作所有构造器、属性、方法

package com.wdl.java;import org.junit.Test;import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;/*** @author shkstart* @create 2019 上午 10:38*/
public class ReflectionTest {//反射之前,对于Person的操作@Testpublic void test1() {//1.创建Person类的对象Person p1 = new Person("Tom", 12);//2.通过对象,调用其内部的属性、方法p1.age = 10;System.out.println(p1.toString());p1.show();//在Person类外部,不可以通过Person类的对象调用其内部私有结构。//比如:name、showNation()以及私有的构造器}//反射之后,对于Person的操作@Testpublic void test2() throws Exception{Class clazz = Person.class;//1.通过反射,创建Person类的对象Constructor cons = clazz.getConstructor(String.class,int.class);Object obj = cons.newInstance("Tom", 12);Person p = (Person) obj;System.out.println(p.toString());//2.通过反射,调用对象指定的属性、方法//调用属性Field age = clazz.getDeclaredField("age");age.set(p,10);System.out.println(p.toString());//调用方法Method show = clazz.getDeclaredMethod("show");show.invoke(p);System.out.println("*******************************");//通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性//调用私有的构造器Constructor cons1 = clazz.getDeclaredConstructor(String.class);cons1.setAccessible(true);Person p1 = (Person) cons1.newInstance("Jerry");System.out.println(p1);//调用私有的属性Field name = clazz.getDeclaredField("name");name.setAccessible(true);name.set(p1,"HanMeimei");System.out.println(p1);//调用私有的方法Method showNation = clazz.getDeclaredMethod("showNation", String.class);showNation.setAccessible(true);String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国")System.out.println(nation);}//疑问1:通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?//建议:直接new的方式。//什么时候会使用:反射的方式。 反射的特征:动态性//疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?//不矛盾。}

获取Class的实例的方式

   /*关于java.lang.Class类的理解1.类的加载过程:程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。2.换句话说,Class的实例就对应着一个运行时类。3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。*///获取Class的实例的方式(前三种方式需要掌握)@Testpublic void test3() throws ClassNotFoundException {//方式一:调用运行时类的属性:.classClass clazz1 = Person.class;System.out.println(clazz1);//方式二:通过运行时类的对象,调用getClass()Person p1 = new Person();Class clazz2 = p1.getClass();System.out.println(clazz2);//方式三:调用Class的静态方法:forName(String classPath)Class clazz3 = Class.forName("com.atguigu.java.Person");
//        clazz3 = Class.forName("java.lang.String");System.out.println(clazz3);System.out.println(clazz1 == clazz2);System.out.println(clazz1 == clazz3);//方式四:使用类的加载器:ClassLoader  (了解)ClassLoader classLoader = ReflectionTest.class.getClassLoader();Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");System.out.println(clazz4);System.out.println(clazz1 == clazz4);}//万事万物皆对象?对象.xxx,File,URL,反射,前端、数据库操作//Class实例可以是哪些结构的说明:@Testpublic void test4(){Class c1 = Object.class;Class c2 = Comparable.class;Class c3 = String[].class;Class c4 = int[][].class;Class c5 = ElementType.class;Class c6 = Override.class;Class c7 = int.class;Class c8 = void.class;Class c9 = Class.class;int[] a = new int[10];int[] b = new int[100];Class c10 = a.getClass();Class c11 = b.getClass();// 只要数组的元素类型与维度一样,就是同一个ClassSystem.out.println(c10 == c11);}

类的加载过程(了解)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ybgdD7C4-1631633504696)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902214915142.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRovUTT3-1631633504697)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902215320434.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DlCP5Ph8-1631633504697)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902215256319.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRZ6zdKV-1631633504698)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902215632303.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gx5Km10l-1631633504699)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210902220113067.png)]

package com.atguigu.java;import org.junit.Test;import java.io.InputStream;
import java.util.Properties;/*** 了解类的加载器* @author shkstart* @create 2019 下午 2:16*/
public class ClassLoaderTest {@Testpublic void test1(){//对于自定义类,使用系统类加载器进行加载ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();System.out.println(classLoader);//调用系统类加载器的getParent():获取扩展类加载器ClassLoader classLoader1 = classLoader.getParent();System.out.println(classLoader1);//调用扩展类加载器的getParent():无法获取引导类加载器//引导类加载器主要负责加载java的核心类库,无法加载自定义类的。ClassLoader classLoader2 = classLoader1.getParent();System.out.println(classLoader2);ClassLoader classLoader3 = String.class.getClassLoader();System.out.println(classLoader3);}/*Properties:用来读取配置文件。*/@Testpublic void test2() throws Exception {Properties pros =  new Properties();//此时的文件默认在当前的module下。//读取配置文件的方式一:
//        FileInputStream fis = new FileInputStream("jdbc.properties");
//        FileInputStream fis = new FileInputStream("src\\jdbc1.properties");
//        pros.load(fis);//读取配置文件的方式二:使用ClassLoader//配置文件默认识别为:当前module的src下ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();InputStream is = classLoader.getResourceAsStream("jdbc1.properties");pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");System.out.println("user = " + user + ",password = " + password);}}

创建运行时类的对象

package com.wdl.java;import org.junit.Test;import java.util.Random;/*** 通过发射创建对应的运行时类的对象** @author shkstart* @create 2019 下午 2:32*/
public class NewInstanceTest {@Testpublic void test1() throws IllegalAccessException, InstantiationException {Class<Person> clazz = Person.class;/*newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。要想此方法正常的创建运行时类的对象,要求:1.运行时类必须提供空参的构造器2.空参的构造器的访问权限得够。通常,设置为public。在javabean中要求提供一个public的空参构造器。原因:1.便于通过反射,创建运行时类的对象2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器*/Person obj = clazz.newInstance();System.out.println(obj);}//体会反射的动态性@Testpublic void test2(){for(int i = 0;i < 100;i++){int num = new Random().nextInt(3);//0,1,2String classPath = "";switch(num){case 0:classPath = "java.util.Date";break;case 1:classPath = "java.lang.Object";break;case 2:classPath = "com.atguigu.java.Person";break;}try {Object obj = getInstance(classPath);System.out.println(obj);} catch (Exception e) {e.printStackTrace();}}}/*创建一个指定类的对象。classPath:指定类的全类名*/public Object getInstance(String classPath) throws Exception {Class clazz =  Class.forName(classPath);return clazz.newInstance();}}

动态语言VS静态语言

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-57oMJ1CD-1631633504700)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903095851188.png)]

获取运行时类的完整结构

属性

package com.wdl.java2;import com.wdl.java1.Person;
import org.junit.Test;import java.lang.reflect.Field;
import java.lang.reflect.Modifier;/*** 获取当前运行时类的属性结构** @author shkstart* @create 2019 下午 3:23*/
public class FieldTest {@Testpublic void test1(){Class clazz = Person.class;//获取属性结构//getFields():获取当前运行时类及其父类中声明为public访问权限的属性Field[] fields = clazz.getFields();for(Field f : fields){System.out.println(f);}System.out.println();//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)Field[] declaredFields = clazz.getDeclaredFields();for(Field f : declaredFields){System.out.println(f);}}//权限修饰符  数据类型 变量名@Testpublic void test2(){Class clazz = Person.class;Field[] declaredFields = clazz.getDeclaredFields();for(Field f : declaredFields){//1.权限修饰符int modifier = f.getModifiers();System.out.print(Modifier.toString(modifier) + "\t");//2.数据类型Class type = f.getType();System.out.print(type.getName() + "\t");//3.变量名String fName = f.getName();System.out.print(fName);System.out.println();}}}

方法

package com.wdl.java2;import com.wdl.java1.Person;
import org.junit.Test;import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;/*** 获取运行时类的方法结构** @author shkstart* @create 2019 下午 3:37*/
public class MethodTest {@Testpublic void test1(){Class clazz = Person.class;//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法Method[] methods = clazz.getMethods();for(Method m : methods){System.out.println(m);}System.out.println();//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)Method[] declaredMethods = clazz.getDeclaredMethods();for(Method m : declaredMethods){System.out.println(m);}}/*@Xxxx权限修饰符  返回值类型  方法名(参数类型1 形参名1,...) throws XxxException{}*/@Testpublic void test2(){Class clazz = Person.class;Method[] declaredMethods = clazz.getDeclaredMethods();for(Method m : declaredMethods){//1.获取方法声明的注解Annotation[] annos = m.getAnnotations();for(Annotation a : annos){System.out.println(a);}//2.权限修饰符System.out.print(Modifier.toString(m.getModifiers()) + "\t");//3.返回值类型System.out.print(m.getReturnType().getName() + "\t");//4.方法名System.out.print(m.getName());System.out.print("(");//5.形参列表Class[] parameterTypes = m.getParameterTypes();if(!(parameterTypes == null && parameterTypes.length == 0)){for(int i = 0;i < parameterTypes.length;i++){if(i == parameterTypes.length - 1){System.out.print(parameterTypes[i].getName() + " args_" + i);break;}System.out.print(parameterTypes[i].getName() + " args_" + i + ",");}}System.out.print(")");//6.抛出的异常Class[] exceptionTypes = m.getExceptionTypes();
//            System.out.println("aaaa"+exceptionTypes);if(exceptionTypes.length > 0){System.out.print("throws ");for(int i = 0;i < exceptionTypes.length;i++){if(i == exceptionTypes.length - 1){System.out.print(exceptionTypes[i].getName());break;}System.out.print(exceptionTypes[i].getName() + ",");}}System.out.println();}}
}

构造器、父类、带泛型的父类

package com.wdl.java2;import com.wdl.java1.Person;
import org.junit.Test;import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;/*** @author shkstart* @create 2019 下午 4:19*/
public class OtherTest {/*获取构造器结构*/@Testpublic void test1(){Class clazz = Person.class;//getConstructors():获取当前运行时类中声明为public的构造器Constructor[] constructors = clazz.getConstructors();for(Constructor c : constructors){System.out.println(c);}System.out.println();//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器Constructor[] declaredConstructors = clazz.getDeclaredConstructors();for(Constructor c : declaredConstructors){System.out.println(c);}}/*获取运行时类的父类*/@Testpublic void test2(){Class clazz = Person.class;Class superclass = clazz.getSuperclass();System.out.println(superclass);}/*获取运行时类的带泛型的父类*/@Testpublic void test3(){Class clazz = Person.class;Type genericSuperclass = clazz.getGenericSuperclass();System.out.println(genericSuperclass);}/*获取运行时类的带泛型的父类的泛型代码:逻辑性代码  vs 功能性代码*/@Testpublic void test4(){Class clazz = Person.class;Type genericSuperclass = clazz.getGenericSuperclass();ParameterizedType paramType = (ParameterizedType) genericSuperclass;//获取泛型类型Type[] actualTypeArguments = paramType.getActualTypeArguments();
//        System.out.println(actualTypeArguments[0].getTypeName());System.out.println(((Class)actualTypeArguments[0]).getName());}/*获取运行时类实现的接口*/@Testpublic void test5(){Class clazz = Person.class;Class[] interfaces = clazz.getInterfaces();for(Class c : interfaces){System.out.println(c);}System.out.println();//获取运行时类的父类实现的接口Class[] interfaces1 = clazz.getSuperclass().getInterfaces();for(Class c : interfaces1){System.out.println(c);}}/*获取运行时类所在的包*/@Testpublic void test6(){Class clazz = Person.class;Package pack = clazz.getPackage();System.out.println(pack);}/*获取运行时类声明的注解*/@Testpublic void test7(){Class clazz = Person.class;Annotation[] annotations = clazz.getAnnotations();for(Annotation annos : annotations){System.out.println(annos);}}}

调用运行时类的指定结构

package com.wdl.java2;import com.wdl.java1.Person;
import org.junit.Test;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;/*** 调用运行时类中指定的结构:属性、方法、构造器** @author shkstart* @create 2019 下午 4:46*/
public class ReflectionTest {/*不需要掌握*/@Testpublic void testField() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//获取指定的属性:要求运行时类中属性声明为public//通常不采用此方法Field id = clazz.getField("id");/*设置当前属性的值set():参数1:指明设置哪个对象的属性   参数2:将此属性值设置为多少*/id.set(p,1001);/*获取当前属性的值get():参数1:获取哪个对象的当前属性值*/int pId = (int) id.get(p);System.out.println(pId);}/*如何操作运行时类中的指定的属性 -- 需要掌握*/@Testpublic void testField1() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性Field name = clazz.getDeclaredField("name");//2.保证当前属性是可访问的name.setAccessible(true);//3.获取、设置指定对象的此属性值name.set(p,"Tom");System.out.println(name.get(p));}/*如何操作运行时类中的指定的方法 -- 需要掌握*/@Testpublic void testMethod() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();/*1.获取指定的某个方法getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表*/Method show = clazz.getDeclaredMethod("show", String.class);//2.保证当前方法是可访问的show.setAccessible(true);/*3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参invoke()的返回值即为对应类中调用的方法的返回值。*/Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");System.out.println(returnValue);System.out.println("*************如何调用静态方法*****************");// private static void showDesc()Method showDesc = clazz.getDeclaredMethod("showDesc");showDesc.setAccessible(true);//如果调用的运行时类中的方法没有返回值,则此invoke()返回null
//        Object returnVal = showDesc.invoke(null);Object returnVal = showDesc.invoke(Person.class);System.out.println(returnVal);//null}/*如何调用运行时类中的指定的构造器*/@Testpublic void testConstructor() throws Exception {Class clazz = Person.class;//private Person(String name)/*1.获取指定的构造器getDeclaredConstructor():参数:指明构造器的参数列表*/Constructor constructor = clazz.getDeclaredConstructor(String.class);//2.保证此构造器是可访问的constructor.setAccessible(true);//3.调用此构造器创建运行时类的对象Person per = (Person) constructor.newInstance("Tom");System.out.println(per);}}

动态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UuW950w4-1631633504702)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903145732051.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQ6FJWxd-1631633504703)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903150759428.png)]

package com.wdl.java;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/**** 动态代理的举例** @author shkstart* @create 2019 上午 10:18*/interface Human{String getBelief();void eat(String food);}
//被代理类
class SuperMan implements Human{@Overridepublic String getBelief() {return "I believe I can fly!";}@Overridepublic void eat(String food) {System.out.println("我喜欢吃" + food);}
}class HumanUtil{public void method1(){System.out.println("====================通用方法一====================");}public void method2(){System.out.println("====================通用方法二====================");}}/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。*/class ProxyFactory{//调用此方法,返回一个代理类的对象。解决问题一public static Object getProxyInstance(Object obj){//obj:被代理类的对象MyInvocationHandler handler = new MyInvocationHandler();handler.bind(obj);return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);}}class MyInvocationHandler implements InvocationHandler{private Object obj;//需要使用被代理类的对象进行赋值public void bind(Object obj){this.obj = obj;}//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()//将被代理类要执行的方法a的功能就声明在invoke()中@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {HumanUtil util = new HumanUtil();util.method1();//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法//obj:被代理类的对象Object returnValue = method.invoke(obj,args);util.method2();//上述方法的返回值就作为当前类中的invoke()的返回值。return returnValue;}
}public class ProxyTest {public static void main(String[] args) {SuperMan superMan = new SuperMan();//proxyInstance:代理类的对象Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法String belief = proxyInstance.getBelief();System.out.println(belief);proxyInstance.eat("四川麻辣烫");System.out.println("*****************************");NikeClothFactory nikeClothFactory = new NikeClothFactory();ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);proxyClothFactory.produceCloth();}
}

AOP

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPCYNgO6-1631633504704)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903160736704.png)]

Java8新特性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8hv4UD8f-1631633504704)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903162716254.png)]

Lambda表达式

Lambda表达式的使用
1.举例: (o1,o2) -> Integer.compare(o1,o2);
2.格式:-> :lambda操作符 或 箭头操作符->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表)->右边:lambda体 (其实就是重写的抽象方法的方法体)
3. Lambda表达式的使用:(分为6种情况介绍)总结:->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return
4.Lambda表达式的本质:作为函数式接口的实例
5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解这样做可以检查它是否是一个函数式接口。
6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
package com.wdl.java1;import org.junit.Test;import java.util.Comparator;/*** Lambda表达式的使用举例** @author shkstart* @create 2019 上午 11:30*/
public class LambdaTest {@Testpublic void test1(){Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("我爱北京天安门");}};r1.run();System.out.println("***********************");Runnable r2 = () -> System.out.println("我爱北京故宫");r2.run();}@Testpublic void test2(){Comparator<Integer> com1 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1,o2);}};int compare1 = com1.compare(12,21);System.out.println(compare1);System.out.println("***********************");//Lambda表达式的写法Comparator<Integer> com2 = (o1,o2) -> Integer.compare(o1,o2);int compare2 = com2.compare(32,21);System.out.println(compare2);System.out.println("***********************");//方法引用Comparator<Integer> com3 = Integer :: compare;int compare3 = com3.compare(32,21);System.out.println(compare3);}}
package com.wdl.java1;import org.junit.Test;import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;public class LambdaTest1 {//语法格式一:无参,无返回值@Testpublic void test1(){Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("我爱北京天安门");}};r1.run();System.out.println("***********************");Runnable r2 = () -> {System.out.println("我爱北京故宫");};r2.run();}//语法格式二:Lambda 需要一个参数,但是没有返回值。@Testpublic void test2(){Consumer<String> con = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};con.accept("谎言和誓言的区别是什么?");System.out.println("*******************");Consumer<String> con1 = (String s) -> {System.out.println(s);};con1.accept("一个是听得人当真了,一个是说的人当真了");}//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”@Testpublic void test3(){Consumer<String> con1 = (String s) -> {System.out.println(s);};con1.accept("一个是听得人当真了,一个是说的人当真了");System.out.println("*******************");Consumer<String> con2 = (s) -> {System.out.println(s);};con2.accept("一个是听得人当真了,一个是说的人当真了");}@Testpublic void test4(){ArrayList<String> list = new ArrayList<>();//类型推断int[] arr = {1,2,3};//类型推断}//语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略@Testpublic void test5(){Consumer<String> con1 = (s) -> {System.out.println(s);};con1.accept("一个是听得人当真了,一个是说的人当真了");System.out.println("*******************");Consumer<String> con2 = s -> {System.out.println(s);};con2.accept("一个是听得人当真了,一个是说的人当真了");}//语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值@Testpublic void test6(){Comparator<Integer> com1 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);}};System.out.println(com1.compare(12,21));System.out.println("*****************************");Comparator<Integer> com2 = (o1,o2) -> {System.out.println(o1);System.out.println(o2);return o1.compareTo(o2);};System.out.println(com2.compare(12,6));}//语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略@Testpublic void test7(){Comparator<Integer> com1 = (o1,o2) -> {return o1.compareTo(o2);};System.out.println(com1.compare(12,6));System.out.println("*****************************");Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);System.out.println(com2.compare(12,21));}@Testpublic void test8(){Consumer<String> con1 = s -> {System.out.println(s);};con1.accept("一个是听得人当真了,一个是说的人当真了");System.out.println("*****************************");Consumer<String> con2 = s -> System.out.println(s);con2.accept("一个是听得人当真了,一个是说的人当真了");}}

函数式(Functional)接口

java内置的4大核心函数式接口
消费型接口 Consumer void accept(T t)
供给型接口 Supplier T get()
函数型接口 Function<T,R> R apply(T t)
断定型接口 Predicate boolean test(T t)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ug5LFM6-1631633504705)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903174116335.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7b9slRO-1631633504706)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903181349417.png)]

package com.wdl.java1;import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;public class LambdaTest2 {@Testpublic void test1(){happyTime(500, new Consumer<Double>() {@Overridepublic void accept(Double aDouble) {System.out.println("学习太累了,去天上人间买了瓶矿泉水,价格为:" + aDouble);}});System.out.println("********************");happyTime(400,money -> System.out.println("学习太累了,去天上人间喝了口水,价格为:" + money));}public void happyTime(double money, Consumer<Double> con){con.accept(money);}@Testpublic void test2(){List<String> list = Arrays.asList("北京","南京","天津","东京","西京","普京");List<String> filterStrs = filterString(list, new Predicate<String>() {@Overridepublic boolean test(String s) {return s.contains("京");}});System.out.println(filterStrs);List<String> filterStrs1 = filterString(list,s -> s.contains("京"));System.out.println(filterStrs1);}//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定public List<String> filterString(List<String> list, Predicate<String> pre){ArrayList<String> filterList = new ArrayList<>();for(String s : list){if(pre.test(s)){filterList.add(s);}}return filterList;}}

方法引用、构造器、数组引用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S6oO2KCU-1631633504707)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903193809508.png)]

package com.wdl.java2;import org.junit.Test;import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;/*** 方法引用的使用** 1.使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!** 2.方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以*   方法引用,也是函数式接口的实例。** 3. 使用格式:  类(或对象) :: 方法名** 4. 具体分为如下的三种情况:*    情况1     对象 :: 非静态方法*    情况2     类 :: 静态方法**    情况3     类 :: 非静态方法** 5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的*    形参列表和返回值类型相同!(针对于情况1和情况2)** Created by shkstart.*/
public class MethodRefTest {// 情况一:对象 :: 实例方法//Consumer中的void accept(T t)//PrintStream中的void println(T t)@Testpublic void test1() {Consumer<String> con1 = str -> System.out.println(str);con1.accept("北京");System.out.println("*******************");PrintStream ps = System.out;Consumer<String> con2 = ps::println;con2.accept("beijing");}//Supplier中的T get()//Employee中的String getName()@Testpublic void test2() {Employee emp = new Employee(1001,"Tom",23,5600);Supplier<String> sup1 = () -> emp.getName();System.out.println(sup1.get());System.out.println("*******************");Supplier<String> sup2 = emp::getName;System.out.println(sup2.get());}// 情况二:类 :: 静态方法//Comparator中的int compare(T t1,T t2)//Integer中的int compare(T t1,T t2)@Testpublic void test3() {Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);System.out.println(com1.compare(12,21));System.out.println("*******************");Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(12,3));}//Function中的R apply(T t)//Math中的Long round(Double d)@Testpublic void test4() {Function<Double,Long> func = new Function<Double, Long>() {@Overridepublic Long apply(Double d) {return Math.round(d);}};System.out.println("*******************");Function<Double,Long> func1 = d -> Math.round(d);System.out.println(func1.apply(12.3));System.out.println("*******************");Function<Double,Long> func2 = Math::round;System.out.println(func2.apply(12.6));}// 情况三:类 :: 实例方法  (有难度)// Comparator中的int comapre(T t1,T t2)// String中的int t1.compareTo(t2)@Testpublic void test5() {Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc","abd"));System.out.println("*******************");Comparator<String> com2 = String :: compareTo;System.out.println(com2.compare("abd","abm"));}//BiPredicate中的boolean test(T t1, T t2);//String中的boolean t1.equals(t2)@Testpublic void test6() {BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);System.out.println(pre1.test("abc","abc"));System.out.println("*******************");BiPredicate<String,String> pre2 = String :: equals;System.out.println(pre2.test("abc","abd"));}// Function中的R apply(T t)// Employee中的String getName();@Testpublic void test7() {Employee employee = new Employee(1001, "Jerry", 23, 6000);Function<Employee,String> func1 = e -> e.getName();System.out.println(func1.apply(employee));System.out.println("*******************");Function<Employee,String> func2 = Employee::getName;System.out.println(func2.apply(employee));}}
package com.wdl.java2;import org.junit.Test;import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;/*** 一、构造器引用*      和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。*      抽象方法的返回值类型即为构造器所属的类的类型** 二、数组引用*     大家可以把数组看做是一个特殊的类,则写法与构造器引用一致。** Created by shkstart*/
public class ConstructorRefTest {//构造器引用//Supplier中的T get()//Employee的空参构造器:Employee()@Testpublic void test1(){Supplier<Employee> sup = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};System.out.println("*******************");Supplier<Employee>  sup1 = () -> new Employee();System.out.println(sup1.get());System.out.println("*******************");Supplier<Employee>  sup2 = Employee :: new;System.out.println(sup2.get());}//Function中的R apply(T t)@Testpublic void test2(){Function<Integer,Employee> func1 = id -> new Employee(id);Employee employee = func1.apply(1001);System.out.println(employee);System.out.println("*******************");Function<Integer,Employee> func2 = Employee :: new;Employee employee1 = func2.apply(1002);System.out.println(employee1);}//BiFunction中的R apply(T t,U u)@Testpublic void test3(){BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);System.out.println(func1.apply(1001,"Tom"));System.out.println("*******************");BiFunction<Integer,String,Employee> func2 = Employee :: new;System.out.println(func2.apply(1002,"Tom"));}//数组引用//Function中的R apply(T t)@Testpublic void test4(){Function<Integer,String[]> func1 = length -> new String[length];String[] arr1 = func1.apply(5);System.out.println(Arrays.toString(arr1));System.out.println("*******************");Function<Integer,String[]> func2 = String[] :: new;String[] arr2 = func2.apply(10);System.out.println(Arrays.toString(arr2));}
}

强大的StreamAPI

1. Stream关注的是对数据的运算,与CPU打交道集合关注的是数据的存储,与内存打交道
2.
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
3.Stream 执行流程
① Stream的实例化
② 一系列的中间操作(过滤、映射、...)
③ 终止操作
4.说明:
4.1 一个中间操作链,对数据源的数据进行处理
4.2 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

操作的三个步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NbFuZt1q-1631633504708)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903201350423.png)]

Stream的实例化

package com.wdl.java3;import com.wdl.java2.Employee;
import com.wdl.java2.EmployeeData;
import org.junit.Test;import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;public class StreamAPITest {//创建 Stream方式一:通过集合@Testpublic void test1(){List<Employee> employees = EmployeeData.getEmployees();//        default Stream<E> stream() : 返回一个顺序流Stream<Employee> stream = employees.stream();//        default Stream<E> parallelStream() : 返回一个并行流Stream<Employee> parallelStream = employees.parallelStream();}//创建 Stream方式二:通过数组@Testpublic void test2(){int[] arr = new int[]{1,2,3,4,5,6};//调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流IntStream stream = Arrays.stream(arr);Employee e1 = new Employee(1001,"Tom");Employee e2 = new Employee(1002,"Jerry");Employee[] arr1 = new Employee[]{e1,e2};Stream<Employee> stream1 = Arrays.stream(arr1);}//创建 Stream方式三:通过Stream的of()@Testpublic void test3(){Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);}//创建 Stream方式四:创建无限流@Testpublic void test4(){//      迭代
//      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)//遍历前10个偶数Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);//      生成
//      public static<T> Stream<T> generate(Supplier<T> s)Stream.generate(Math::random).limit(10).forEach(System.out::println);}}

Stream的中间操作

筛选与切片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjFT3sR3-1631633504709)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903203440132.png)]

映射

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-to5nkErT-1631633504710)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210903205058276.png)]

排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1sLRAYKO-1631633504711)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904191349474.png)]

package com.wdl.java3;import com.wdl.java2.Employee;
import com.wdl.java2.EmployeeData;
import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;/*** 测试Stream的中间操作** @author shkstart* @create 2019 下午 4:42*/
public class StreamAPITest1 {//1-筛选与切片@Testpublic void test1(){List<Employee> list = EmployeeData.getEmployees();
//        filter(Predicate p)——接收 Lambda , 从流中排除某些元素。Stream<Employee> stream = list.stream();//练习:查询员工表中薪资大于7000的员工信息stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);System.out.println();
//        limit(n)——截断流,使其元素不超过给定数量。list.stream().limit(3).forEach(System.out::println);System.out.println();//        skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补list.stream().skip(3).forEach(System.out::println);System.out.println();
//        distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素list.add(new Employee(1010,"刘强东",40,8000));list.add(new Employee(1010,"刘强东",41,8000));list.add(new Employee(1010,"刘强东",40,8000));list.add(new Employee(1010,"刘强东",40,8000));list.add(new Employee(1010,"刘强东",40,8000));//        System.out.println(list);list.stream().distinct().forEach(System.out::println);}//映射@Testpublic void test2(){//        map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。List<String> list = Arrays.asList("aa", "bb", "cc", "dd");list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);//        练习1:获取员工姓名长度大于3的员工的姓名。List<Employee> employees = EmployeeData.getEmployees();Stream<String> namesStream = employees.stream().map(Employee::getName);namesStream.filter(name -> name.length() > 3).forEach(System.out::println);System.out.println();//练习2:Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);streamStream.forEach(s ->{s.forEach(System.out::println);});System.out.println();
//        flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);characterStream.forEach(System.out::println);}//将字符串中的多个字符构成的集合转换为对应的Stream的实例public static Stream<Character> fromStringToStream(String str){//aaArrayList<Character> list = new ArrayList<>();for(Character c : str.toCharArray()){list.add(c);}return list.stream();}@Testpublic void test3(){ArrayList list1 = new ArrayList();list1.add(1);list1.add(2);list1.add(3);ArrayList list2 = new ArrayList();list2.add(4);list2.add(5);list2.add(6);//        list1.add(list2);list1.addAll(list2);System.out.println(list1);}//3-排序@Testpublic void test4(){//        sorted()——自然排序List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);list.stream().sorted().forEach(System.out::println);//抛异常,原因:Employee没有实现Comparable接口
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);//        sorted(Comparator com)——定制排序List<Employee> employees = EmployeeData.getEmployees();employees.stream().sorted( (e1,e2) -> {int ageValue = Integer.compare(e1.getAge(),e2.getAge());if(ageValue != 0){return ageValue;}else{return -Double.compare(e1.getSalary(),e2.getSalary());}}).forEach(System.out::println);}}

Stream的终止操作

匹配与查找

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z254O8WE-1631633504712)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904191825425.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzgkr9Ir-1631633504713)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904192620656.png)]

归约

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4kejUjZa-1631633504714)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904193606951.png)]

收集

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0OaJZquX-1631633504715)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904194928015.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TpicBaF2-1631633504716)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904195456441.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xq3isotb-1631633504717)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904202014657.png)]

package com.wdl.java3;import com.wdl.java2.Employee;
import com.wdl.java2.EmployeeData;
import org.junit.Test;import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** 测试Stream的终止操作** @author shkstart* @create 2019 下午 6:37*/
public class StreamAPITest2 {//1-匹配与查找@Testpublic void test1(){List<Employee> employees = EmployeeData.getEmployees();//        allMatch(Predicate p)——检查是否匹配所有元素。
//          练习:是否所有的员工的年龄都大于18boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);System.out.println(allMatch);//        anyMatch(Predicate p)——检查是否至少匹配一个元素。
//         练习:是否存在员工的工资大于 10000boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);System.out.println(anyMatch);//        noneMatch(Predicate p)——检查是否没有匹配的元素。
//          练习:是否存在员工姓“雷”boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));System.out.println(noneMatch);
//        findFirst——返回第一个元素Optional<Employee> employee = employees.stream().findFirst();System.out.println(employee);
//        findAny——返回当前流中的任意元素Optional<Employee> employee1 = employees.parallelStream().findAny();System.out.println(employee1);}@Testpublic void test2(){List<Employee> employees = EmployeeData.getEmployees();// count——返回流中元素的总个数long count = employees.stream().filter(e -> e.getSalary() > 5000).count();System.out.println(count);
//        max(Comparator c)——返回流中最大值
//        练习:返回最高的工资:Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());Optional<Double> maxSalary = salaryStream.max(Double::compare);System.out.println(maxSalary);
//        min(Comparator c)——返回流中最小值
//        练习:返回最低工资的员工Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(employee);System.out.println();
//        forEach(Consumer c)——内部迭代employees.stream().forEach(System.out::println);//使用集合的遍历操作employees.forEach(System.out::println);}//2-归约@Testpublic void test3(){//        reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T
//        练习1:计算1-10的自然数的和List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer sum = list.stream().reduce(0, Integer::sum);System.out.println(sum);//        reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
//        练习2:计算公司所有员工工资的总和List<Employee> employees = EmployeeData.getEmployees();Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);System.out.println(sumMoney.get());}//3-收集@Testpublic void test4(){//        collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
//        练习1:查找工资大于6000的员工,结果返回为一个List或SetList<Employee> employees = EmployeeData.getEmployees();List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());employeeList.forEach(System.out::println);System.out.println();Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());employeeSet.forEach(System.out::println);//        1.对象中的属性转map 通过Collectors.toMap
//        list.stream().collect(Collectors.toMap(Person::getId,Person::getName));
//        2.收集对象本身
//        list.stream().collect(Collectors.toMap(Person::getId,list->list)}
}

Optional类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yk4qiF5T-1631633504718)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904200642752.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOxzKM5h-1631633504719)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210904202036222.png)]

package com.wdl.java4;import org.junit.Test;import java.util.Optional;/*** Optional类:为了在程序中避免出现空指针异常而创建的。** 常用的方法:ofNullable(T t)*            orElse(T t)** @author shkstart* @create 2019 下午 7:24*/
public class OptionalTest {/*
Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):t可以为null*/@Testpublic void test1(){Girl girl = new Girl();
//        girl = null;//of(T t):保证t是非空的Optional<Girl> optionalGirl = Optional.of(girl);}@Testpublic void test2(){Girl girl = new Girl();
//        girl = null;//ofNullable(T t):t可以为nullOptional<Girl> optionalGirl = Optional.ofNullable(girl);System.out.println(optionalGirl);//orElse(T t1):如果单前的Optional内部封装的t是非空的,则返回内部的t.//如果内部的t是空的,则返回orElse()方法中的参数t1.Girl girl1 = optionalGirl.orElse(new Girl("赵丽颖"));System.out.println(girl1);}public String getGirlName(Boy boy){return boy.getGirl().getName();}@Testpublic void test3(){Boy boy = new Boy();boy = null;String girlName = getGirlName(boy);System.out.println(girlName);}//优化以后的getGirlName():public String getGirlName1(Boy boy){if(boy != null){Girl girl = boy.getGirl();if(girl != null){return girl.getName();}}return null;}@Testpublic void test4(){Boy boy = new Boy();boy = null;String girlName = getGirlName1(boy);System.out.println(girlName);}//使用Optional类的getGirlName():public String getGirlName2(Boy boy){Optional<Boy> boyOptional = Optional.ofNullable(boy);//此时的boy1一定非空Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));Girl girl = boy1.getGirl();Optional<Girl> girlOptional = Optional.ofNullable(girl);//girl1一定非空Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));return girl1.getName();}@Testpublic void test5(){Boy boy = null;boy = new Boy();boy = new Boy(new Girl("苍老师"));String girlName = getGirlName2(boy);System.out.println(girlName);}}

❤️ 爆肝一个月!JAVA零基础入门总结(下)❤️相关推荐

  1. 一篇文章让你从JAVA零基础入门`OOP`编程12.19

    一篇文章让你从JAVA零基础入门OOP编程 前言: 此文为玄子,复习ACCP-S1课程后,整理的文章,文中对知识点的解释仅为个人理解. 配套PPT,站点源码,等学习资料 一.预科 1.1 JAVA 介 ...

  2. 一篇文章让你从JAVA零基础入门`OOP`编程12.20

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(QQ_3336392096.png)] 一篇文章让你从JAVA零基础入门OOP编程 前言: 此文为玄子,复习ACCP-S1课程后, ...

  3. 一期完结《一篇文章让你从JAVA零基础入门`OOP`编程》12.21

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(QQ_3336392096.jpg)] 一篇文章让你从JAVA零基础入门OOP编程 前言: 此文为玄子,复习ACCP-S1课程后, ...

  4. java零基础入门的四大步骤

    对于许多想要转换到Java开发的初学者来说,如何学习Java是一个问题.在很多人眼里,程序员是高薪的代名词,所以他们吸引了很多想要转到Java开发的初学者.但是对于很多初学者来说,他们不知道从哪里开始 ...

  5. 【JAVA零基础入门系列】Day2 Java集成开发环境IDEA

    [JAVA零基础入门系列](已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day ...

  6. 【JAVA零基础入门系列】Day14 Java对象的克隆

    [JAVA零基础入门系列](已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day ...

  7. 阿里云【名师课堂】Java零基础入门24 ~ 26:方法的定义与使用

    阿里云[名师课堂]Java零基础入门24 ~ 26:方法的定义与使用 24:方法的基本定义 无返回值无参数 无返回值有参数 有返回值有参数 25:方法重载(重点) 26:方法递归调用 24:方法的基本 ...

  8. 视频教程-由浅入深Java零基础入门-Java

    由浅入深Java零基础入门 负责过多个软件项目的研发.设计和管理工作,拥有项目管理师认证.项目监理师中级认证.出版过的图书有<微信小程序开发图解案例教程><Axure RP8原型设计 ...

  9. 阿里云【名师课堂】Java零基础入门6:CLASSPATH环境属性

    阿里云[名师课堂]Java零基础入门6:CLASSPATH环境属性 一.具体内容 二.总结 一.具体内容 CLASSPATH指的是类的加载路径,是一个路径列表,用于搜索Java编译或者运行时所用到的类 ...

最新文章

  1. mongoDB 入门指南、示例
  2. codewars068 - Convert string to camel case
  3. 您如何重命名MongoDB数据库?
  4. MyEclipse8.5注册码 到2015年
  5. 年度最期待游戏废土2登陆Linux
  6. 特殊的求和(函数和循环)
  7. 关于压缩工具 7z(7-zip) 的选项 -u(更新压缩档案中的文件)的解读
  8. 基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中
  9. jQuery框架学习第十一天:实战jQuery表单验证及jQuery自动完成提示插件
  10. Linux学习之shell
  11. 一同事恶搞static
  12. matlab朴素贝叶斯手写数字识别_从“手写数字识别”学习分类任务
  13. boost准模板库内存管理中pool和object_pool的使用
  14. python中用箱线图分析异常值_[宜配屋]听图阁
  15. Java中OutOfMemoryError(内存溢出)的情况及解决办法
  16. javascript之querySelector和querySelectorAll
  17. android studio 4.0 去掉标题栏
  18. ISO/IEC 27701:2019(隐私信息安全管理扩展要求和指南)解读(二)
  19. java生成随机名字
  20. 操作日志 | 上证50是续命仙丹还是饮鸩毒药?

热门文章

  1. 将字符串添加负数_Go语言实现LeetCode算法:8 字符串转整数
  2. python unpack_ip地址处理每天10行python代码系列
  3. 笔记本电脑销量排名_网友总结京东笔记本销量,联想高居第一,华为表现很出色...
  4. word List 13
  5. XGBClassifier()特征选择
  6. 2019-03-11-算法-进化(求众数)
  7. cf1491C. Pekora and Trampoline
  8. P6669 [清华集训2016] 组合数问题
  9. CF 1529E. Trees of Tranquillity
  10. 牛客网 【每日一题】8月5日题目精讲—蓝魔法师