泛型

  • 泛型是JDK1.5提出的
  • 泛型类型必须是类,不能是基本数据类型
  • 没有指明,默认Object

    List、List

  • 如果一个泛型类中需要传递一个List

  • 如果List能作为List的父类
  • 创建一个List或List存放到List
  • 那么用get获取数据时,获取到的是Integer、float还是Number类型的,如果是这样还要进行类型转化
  • 这违背了定义泛型的初衷
  • 所以List和List不看做有父子关系

那么如果我们需要获取不同类型的数据,难道需要编写获取不同类型的方法吗?这违背了多态的特性
类型通配符<?>可以很好的解决这个问题

  1. public static void getData(Box<?> data) {
  2. System.out.println("data :" + data.getData());
  3. }

也可以通过<? extends Number> 与 <? super Number> 控制类型通配符的上限和下限

多线程

程序、进程、线程

  • 程序:一段静态代码
  • 进程:正在运行的一个程序
  • 线程:进程的进一步细化,程序内部的一条执行路径

    线程的创建

    继承Thread

    1. public class MyThread extends Thread{
    2. @Override
    3. public void run(){
    4. System.out.println("创建线程~启动线程调用run方法");
    5. }
    6. }

    实现Runnable接口

    1. public class Hello implements Runnable{
    2. @Override
    3. public void run(){
    4. System.out.println("实现Runnable接口");
    5. }
    6. }

    线程中常用方法

  • start():启动线程,执行run()

  • run():执行的操作在run()方法中
  • currentThread():静态方法,当前线程
  • getName():获取线程名
  • setName():设置线程名
  • yield():释放CPU使用权
  • join():线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态
  • stop():已过时,强制结束线程
  • sleep():休眠,进入阻塞,同步代码块中不会释放锁
  • isAlive():线程是否存活
  • getPriority():获取优先级 1~10,默认5
  • setPriority():设置优先级

    线程的同步

    同步代码块(synchronized)

    1. synchronized(对象/同步监视器){
    2. ...
    3. }

    同步方法(synchronized)

    1. public synchronized void show(String name){
    2. ...
    3. }

    Lock(锁)

  • jdk5.0开始,显示锁

  • java.util.concurrent.locks.Lock接口是控制多个线程进行共享资源的工具
  • ReentrantLock类实现了Lock,可以加锁,释放锁 ```java class A{ private final ReentrantLock lock = new ReentrantLock(); public void m(){
    1. lock.lock();
    2. try{
    3. //保证线程安全的代码
    4. }catch(){
    5. ...
    6. }finally{
    7. lock.unlock();
    8. }
    }

}

  1. <a name="E8E7v"></a>
  2. ### 单例模式(饿汉式,线程安全)
  3. ```java
  4. class Singleton{
  5. private Singleton(){}
  6. private static Singleton instance = null;
  7. public static Singleton getInstance(){
  8. if(instance == null){
  9. synchronized(Singleton.class){
  10. if(instance == null){
  11. instance = new Singleton();
  12. }
  13. }
  14. }
  15. return instance;
  16. }
  17. }

线程的通信

  • wait():线程阻塞,释放锁,进入等待
  • notify()/notifyAll():唤醒等待该对象监控权(锁)的一个/所有线程,有这个锁才能调用

    使用两个线程交替打印1~100

    1. //使用两个线程打印1~100,交替打印
    2. class Number implements Runnable{
    3. private int number = 1;
    4. private Object obj = new Object();
    5. @Override
    6. public void run(){
    7. while(true){
    8. synchronized(obj){
    9. obj.notify();
    10. if(number <= 100){
    11. try{
    12. Thread.sleep(10);
    13. }catch(InterruptedException e){
    14. e.printStackTrace();
    15. }
    16. System.out.println(Thread.currentThread().getName() + ":" + number);
    17. number++;
    18. try{
    19. //使这个线程进入阻塞:释放锁
    20. obj.wait();
    21. }catch(InterruptedException e){
    22. e.printStackTrace();
    23. }
    24. }else{
    25. break;
    26. }
    27. }
    28. }
    29. }
    30. }

    生产者消费者问题

    1. //生产者消费者问题
    2. class Clerk{
    3. private int productCount = 0;
    4. //生产产品
    5. public synchronized void produceProduct(){
    6. if(productCount < 20){
    7. productCount++;
    8. System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品");
    9. notify();
    10. }else{
    11. try{
    12. wait();
    13. }catch(InterruptedException e){
    14. e.printStackTrace();
    15. }
    16. }
    17. }
    18. //消费产品
    19. public synchronized void consumeProduct(){
    20. if(productCount > 0){
    21. System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品");
    22. productCount--;
    23. notify();
    24. }else{
    25. try{
    26. wait();
    27. }catch(InterruptedException e){
    28. e.printStackTrace();
    29. }
    30. }
    31. }
    32. }
    33. //生产者
    34. class Producer extends Thread{
    35. private Clerk clerk;
    36. public Producer(Clerk clerk){
    37. this.clerk = clerk;
    38. }
    39. @Override
    40. public void run(){
    41. System.out.println(getName() + ":开始生产产品.....");
    42. while(true){
    43. try{
    44. sleep(10);
    45. }catch(InterruptedException e){
    46. e.printStackTrace();
    47. }
    48. clerk.produceProduct();
    49. }
    50. }
    51. }
    52. //消费者
    53. class Consumer extends Thread{
    54. private Clerk clerk;
    55. public Consumer(Clerk clerk){
    56. this.clerk = clerk;
    57. }
    58. @Override
    59. public void run(){
    60. System.out.println(getName() + ":开始消费产品.....");
    61. while(true){
    62. try {
    63. Thread.sleep(20);
    64. } catch (InterruptedException e) {
    65. e.printStackTrace();
    66. }
    67. clerk.consumeProduct();
    68. }
    69. }
    70. }

    JDK5.0新增创建线程方式

    实现Callable接口

  1. 相比run()方法,可以有返回值
  2. 方法可以抛出异常
  3. 支持泛型的返回值
  4. 需要借助FutureTask类,比如获取返回结果 ```java //1.创建一个实现Callable的实现类 class NumThread implements Callable{ //2.实现call方法,将此线程需要执行的操作声明在call()中 @Override public Object call() throws Exception {
    1. int sum = 0;
    2. for (int i = 1; i <= 100; i++) {
    3. if(i % 2 == 0){
    4. System.out.println(i);
    5. sum += i;
    6. }
    7. }
    8. return sum;
    } } public class ThreadNew { public static void main(String[] args) {
    1. //3.创建Callable接口实现类的对象
    2. NumThread numThread = new NumThread();
    3. //4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
    4. FutureTask futureTask = new FutureTask(numThread);
    5. //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
    6. new Thread(futureTask).start();
    7. try {
    8. //6.获取Callable中call方法的返回值
    9. //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
    10. Object sum = futureTask.get();
    11. System.out.println("总和为:" + sum);
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. } catch (ExecutionException e) {
    15. e.printStackTrace();
    16. }
    }

}

  1. <a name="m1rSJ"></a>
  2. #### 线程池
  3. ![QQ截图20210722105014.png](https://cdn.nlark.com/yuque/0/2021/png/22164924/1626922257732-d68986ef-0fbc-4114-9070-72bf6d6beb99.png#clientId=u7ed34dea-9058-4&from=ui&id=ua58e7a2e&margin=%5Bobject%20Object%5D&name=QQ%E6%88%AA%E5%9B%BE20210722105014.png&originHeight=406&originWidth=847&originalType=binary&ratio=1&size=225850&status=done&style=none&taskId=ud88f225e-9cfa-4afc-89c6-8d71be29f56)![QQ截图20210722105035.png](https://cdn.nlark.com/yuque/0/2021/png/22164924/1626922257800-c6791fa8-b747-4c4e-860b-29d9c273bdde.png#clientId=u7ed34dea-9058-4&from=ui&id=u35c2fbb8&margin=%5Bobject%20Object%5D&name=QQ%E6%88%AA%E5%9B%BE20210722105035.png&originHeight=472&originWidth=881&originalType=binary&ratio=1&size=263737&status=done&style=none&taskId=u8c9a60bf-d9c5-47ef-833c-15258c9e912)
  4. <a name="jbAau"></a>
  5. ## Java输入输出流
  6. <a name="jAfEd"></a>
  7. ### 字节流
  8. <a name="NNAsu"></a>
  9. #### 字节输入流
  10. - InputStream接口(抽象基类)
  11. - FileInputStream文件输入流
  12. <a name="py48G"></a>
  13. #### 字节输出流
  14. - OutputStream接口(抽象基类)
  15. - FileOutputStream文件输出流
  16. <a name="snZqh"></a>
  17. #### 复制文件
  18. ```java
  19. public void copyFile(String srcPath,String destPath){
  20. FileInputStream = null;
  21. FileOutputStream = null;
  22. try{
  23. File src = new File("srcPath");
  24. File dest = new File("destPath");
  25. fis = new FileInputStream(src);
  26. fos = new FileOutputStream(dest);
  27. byte[] buf = new byte[1024];
  28. int len;
  29. while((len = fis.read(buf)) != -1){
  30. fos.write(buf, 0, len);
  31. }
  32. }catch(IOException e){
  33. e.printStackTrace();
  34. }finally{
  35. if(fis != null){
  36. try{
  37. fis.close();
  38. }catch (IOException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. if(fos != null){
  43. try{
  44. fos.close();
  45. }catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }
  50. }

字符流

字符输入流

  • Reader接口(抽象基类)
  • FileReader

    字符输出流

  • Writer接口(抽象基类)

  • FileWriter

    缓冲流

    提供流的读取、写入速度
    提高读写速度的原因:内部提供了一个缓冲区

  • BufferInputStream

  • BufferOutputStream
  • BufferReader
  • BufferWriter

    1. //实现文件复制的方法
    2. public void copyFileWithBuffered(String srcPath,String destPath){
    3. BufferedInputStream bis = null;
    4. BufferedOutputStream bos = null;
    5. try {
    6. //1.造文件
    7. File srcFile = new File(srcPath);
    8. File destFile = new File(destPath);
    9. //2.造流
    10. //2.1 造节点流
    11. FileInputStream fis = new FileInputStream((srcFile));
    12. FileOutputStream fos = new FileOutputStream(destFile);
    13. //2.2 造缓冲流
    14. bis = new BufferedInputStream(fis);
    15. bos = new BufferedOutputStream(fos);
    16. //3.复制的细节:读取、写入
    17. byte[] buffer = new byte[1024];
    18. int len;
    19. while((len = bis.read(buffer)) != -1){
    20. bos.write(buffer,0,len);
    21. }
    22. } catch (IOException e) {
    23. e.printStackTrace();
    24. } finally {
    25. //4.资源关闭
    26. //要求:先关闭外层的流,再关闭内层的流
    27. if(bos != null){
    28. try {
    29. bos.close();
    30. } catch (IOException e) {
    31. e.printStackTrace();
    32. }
    33. }
    34. if(bis != null){
    35. try {
    36. bis.close();
    37. } catch (IOException e) {
    38. e.printStackTrace();
    39. }
    40. }
    41. //说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
    42. // fos.close();
    43. // fis.close();
    44. }
    45. }

    处理流之转换流

  • InputStreamReader:将InputStream转换为Reader

  • OutputStreamWriter:将Writer转换为OutputStream

    对象序列化

    实现Serializable接口 ```java /**

    • 对象流的使用
    • 1.ObjectInputStream 和 ObjectOutputStream
    • 2.作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。 *
    • 3.要想一个java对象是可序列化的,需要满足相应的要求。见Person.java *
    • 4.序列化机制:
    • 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种
    • 二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。
    • 当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。

    *

    • @author shkstart
    • @create 2019 上午 10:27 */ public class ObjectInputOutputStreamTest {

      / 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去 使用ObjectOutputStream实现 / @Test public void testObjectOutputStream(){

      1. ObjectOutputStream oos = null;
      2. try {
      3. //1.
      4. oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
      5. //2.
      6. oos.writeObject(new String("我爱北京天安门"));
      7. oos.flush();//刷新操作
      8. oos.writeObject(new Person("王铭",23));
      9. oos.flush();
      10. oos.writeObject(new Person("张学良",23,1001,new Account(5000)));
      11. oos.flush();
      12. } catch (IOException e) {
      13. e.printStackTrace();
      14. } finally {
      15. if(oos != null){
      16. //3.
      17. try {
      18. oos.close();
      19. } catch (IOException e) {
      20. e.printStackTrace();
      21. }
      22. }
      23. }

      }

      / 反序列化:将磁盘文件中的对象还原为内存中的一个java对象 使用ObjectInputStream来实现 / @Test public void testObjectInputStream(){

      1. ObjectInputStream ois = null;
      2. try {
      3. ois = new ObjectInputStream(new FileInputStream("object.dat"));
      4. Object obj = ois.readObject();
      5. String str = (String) obj;
      6. Person p = (Person) ois.readObject();
      7. Person p1 = (Person) ois.readObject();
      8. System.out.println(str);
      9. System.out.println(p);
      10. System.out.println(p1);
      11. } catch (IOException e) {
      12. e.printStackTrace();
      13. } catch (ClassNotFoundException e) {
      14. e.printStackTrace();
      15. } finally {
      16. if(ois != null){
      17. try {
      18. ois.close();
      19. } catch (IOException e) {
      20. e.printStackTrace();
      21. }
      22. }
      23. }

      } }

  1. ```java
  2. /**
  3. * Person需要满足如下的要求,方可序列化
  4. * 1.需要实现接口:Serializable
  5. * 2.当前类提供一个全局常量:serialVersionUID
  6. * 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
  7. * 也必须是可序列化的。(默认情况下,基本数据类型可序列化)
  8. *
  9. *
  10. * 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
  11. *
  12. *
  13. * @author shkstart
  14. * @create 2019 上午 10:38
  15. */
  16. public class Person implements Serializable{
  17. public static final long serialVersionUID = 475463534532L;
  18. private String name;
  19. private int age;
  20. private int id;
  21. private Account acct;
  22. public Person(String name, int age, int id) {
  23. this.name = name;
  24. this.age = age;
  25. this.id = id;
  26. }
  27. public Person(String name, int age, int id, Account acct) {
  28. this.name = name;
  29. this.age = age;
  30. this.id = id;
  31. this.acct = acct;
  32. }
  33. @Override
  34. public String toString() {
  35. return "Person{" +
  36. "name='" + name + '\'' +
  37. ", age=" + age +
  38. ", id=" + id +
  39. ", acct=" + acct +
  40. '}';
  41. }
  42. public int getId() {
  43. return id;
  44. }
  45. public void setId(int id) {
  46. this.id = id;
  47. }
  48. public String getName() {
  49. return name;
  50. }
  51. public void setName(String name) {
  52. this.name = name;
  53. }
  54. public int getAge() {
  55. return age;
  56. }
  57. public void setAge(int age) {
  58. this.age = age;
  59. }
  60. public Person(String name, int age) {
  61. this.name = name;
  62. this.age = age;
  63. }
  64. public Person() {}
  65. }
  66. class Account implements Serializable{
  67. public static final long serialVersionUID = 4754534532L;
  68. private double balance;
  69. @Override
  70. public String toString() {
  71. return "Account{" +
  72. "balance=" + balance +
  73. '}';
  74. }
  75. public double getBalance() {
  76. return balance;
  77. }
  78. public void setBalance(double balance) {
  79. this.balance = balance;
  80. }
  81. public Account(double balance) {
  82. this.balance = balance;
  83. }
  84. }

随机存储文件流(RandomAccessFile类)

  • 可以当输入流也可以当输出流
  • 构造器
    • public RandomAccessFile(File file, String mode)
    • public RandomAccessFile(String name, String mode)
  • mode参数
    • r:只读
    • rw:读写
    • rwd:读写,同步文件内容更新
    • rws:读写,同步文件内容和元数据的更新
  • 文件不存在,创建;文件存在(默认覆盖)