Java常用API(三)

GUI

  • GUI:Graphical User Interface(用户图形接口)
  • Eclipse就是Java写的
  • 桌面应用一般用C++,C#或Delphi
  • Java的GUI操作类都在java.awt和java.swing中
  • awt:abstract window toolkit(抽象窗口工具包)。调用本地系统方法实现功能,显示效果为系统图形效果。重量级控件
  • swing:在awt基础上建立的图形界面系统,提供了更多组件,完全由java实现。增强了移植性。轻量级控件。
  • 继承关系图
    • Component:组件
      • Container:容器(能添加组件的组件)
        • Window:独立存在的一个页面
          • Frame:框架
          • Dialog:对话框
            • FileDialog:文件对话框
        • Panel:窗体中的一个一个部分
      • Button:按钮
      • Label:标签
      • Checkbox:复选框
      • TextComponent:文本组件
        • TextArea:文本域
        • TextField:文本框
    • 容器中的布局管理器
      • FlowLayout(流式布局管理器)
        • 从左向右的顺序,放不下就下一行
        • Panel默认布局管理器
      • BorderLayout(边界布局管理器)
        • 东南西北中
        • Frame默认的布局管理器
        • 没有指定东南西北,直接界面填充,下边的覆盖上边的
      • GridLayout(网格布局管理器)
        • 规矩的矩阵
      • CardLayout(卡片布局管理器)
        • 选项卡
      • GridBagLayout(网格包布局管理器)
        • 非规则的矩阵,可以占多个格子
      • 坐标式布局
        • 可以拖动到任何位置
  • JFrame
    • 特点
      • 用于创建一个框架实例。
    • 构造方法
      JFrame()                                               创建一个最初不可见的窗体
                                                             默认为边界布局。
      JFrame(窗口标题)                                        给窗体放一个标题
    • 常用方法
      setVisiable(boolean)                                      设置窗体是否可见
      setSize(int, int)                                         设置窗口宽高(px)
      setLocation(int, int)                                     设置窗口具体左上角的距离
      setBounds(int, int, int, int)                             设置距离和宽高
      setlayout(new FlowLayout())                               设置布局
      Component add(Component)                                  将组件添加到窗体中
    • 事件监听机制
      • 组成
        • 事件源(组件)
        • 事件(Event)
        • 监听器(Listener)
        • 事件处理(引发事件后的处理方式)
        • 处理流程
          • 事件源可以添加监听器来监听事件。通过addXxx方法
          • WindowListener监听WindowEvent。前缀有对应关系
          • WindowListener抽象方法太多,其子类WindowAdapter实现了所有其方法,但只实现为空。方便创建监听器对象,不必实现所有方法。
            • WindowAdapter是抽象类,但没有抽象方法,也就是不能创建对象,但是方便该接口创建对象
            • 使用匿名内部类即可。

 

  • JButton
    • 特点
      • 用于创建一个按钮。
      • 按钮添加MouseListener和ActionListener,ActionListener先触发
    • 包解释
      • awt:图形界面组件的包
      • event:监听事件或适配器的包
    • 小知识
      • 键盘的F1的F是function
      • 有些大型机的F到F24
    • 构造方法
      JButton()                                               创建一个按钮
      JButton(标题)                                           给按钮放一个标题
    • 简单窗体+监听器
              // 构造一个最初不可见的框架
              JFrame f = new JFrame();
              // f.setSize(500, 400);
              // f.setLocation(400, 300);
              f.setBounds(400, 200, 500, 400);
              f.setLayout(new FlowLayout());
              JButton button = new JButton("按钮");
              f.add(button);
              // 给窗体添加一个窗体监听器,监听器方法超过2个,所以有适配器来避免手动实现所有接口方法
              f.addWindowListener(new WindowAdapter() {
                  // 当点击了窗体的退出按钮,自动调用该方法。并将事件传递给e
                  public void windowClosing(WindowEvent e) {
                      // 退出虚拟机
                      System.exit(0);
                  }
              });
              // 给按钮加一个活动监听器,因为监听器只有1个方法,所以没有适配器
              button.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      System.exit(0);
                  }
              });
              f.setVisible(true);
    • 键盘+鼠标监听器的演示
      public class JFrameTest{
          // 将图形化界面涉及的所有组件用成员变量定义
          // 用来明确需要多少组件
          // 创建方法的时候再对组件初始化
          private JFrame f;
          private JTextField tf;
          private JButton but;
      
          public JFrameTest() {
              init();
          }
          
          /**
           * 组件初始化
           */
          private void init() {
              f = new JFrame("鼠标键盘监听");
              f.setBounds(400, 200, 500, 400);
              f.setLayout(new FlowLayout());
      
              tf = new JTextField(15);
              but = new JButton("一个按钮");
              f.add(tf);
              f.add(but);
      
              myEvent();
      
              f.setVisible(true);
          }
      
          private void myEvent() {
              // 窗体监听事件
              f.addWindowListener(new WindowAdapter() {
                  public void windowClosing(WindowEvent e) {
                      System.exit(0);
                  }
              });
      
              // 给按钮添加一个鼠标监听事件
              but.addMouseListener(new MouseAdapter() {
                  private int count = 1;
                  public void mouseEntered(MouseEvent e) {
                      tf.setText("" + count);
                      count ++;
                  }
                  public void mouseClicked(MouseEvent e) {
                      // 可以通过MouseEvent的各种方法来获取鼠标事件的信息
                      if (e.getClickCount() == 2) {
                          System.out.println("double click");
                      }
                      // System.out.println("1");
                  }
              });
      
              // 给按钮添加活动事件,活动事件比鼠标监听事件先触发
              but.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      System.out.println("2");
                  }
              });
      
              // 给文本框添加键盘监听事件
              tf.addKeyListener(new KeyAdapter() {
                  public void keyPressed(KeyEvent e) {
                      // 获取键代码的名称
                      System.out.println(KeyEvent.getKeyText(e.getKeyCode()));
                      if (!(e.getKeyCode() >= KeyEvent.VK_0 && e.getKeyCode() <= KeyEvent.VK_9)) {
                          // 消耗掉该数据,不进行默认操作
                          e.consume();
                      }
                      // 用来判断CTRL + 回车
                      if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER) {
                          System.out.println("CTRL + enter");
                      }
                  }
              });
              
          }
      
          public static void main(String[] args) throws IOException {
              new JFrameTest();
          }
      }

       

    • JFileChooser 文件对话框

    • JMenuBar 菜单条

    • JDialog  对话框

    • JScrollPane 添加带滚动条的面板。可以继续向里边添加组件。

网络编程

  • 网络模型
    • OSI:Open System Interconnection 开放系统互联参考模型
    • TCP/IP参考模型
    • 物理层:网线是物理层介质。
    • 数据链路层:将物理层接收的数据进行MAC地址封装与解封装。该层数据叫帧。设备是交换机,交换机每个口都有MAC地址。
    • 网络层:对数据链路层数据进行IP地址封装。该层数据是数据包。设备是路由器。
    • 传输层:定义传输协议和端口号。发送数据规则。TCP,UDP等。该层数据叫段。
    • 会话层:建立会话
    • 表示层:进行数据的解析,加密解密,压缩解压
    • 应用层:计算机的应用软件
  • 网络通讯要素
    • IP地址
      • 127.0.0.1 本地回环地址。访问本机使用
      • 192.168.1.100 局域网内可以互相访问
    • 端口号
      • 同一个计算机的不同应用程序标识。标识进程的逻辑地址
      • 端口号在0-65535.0-1024通常为保留端口,不要用。
      • 防火墙:禁用进来和出去的端口就无法进行数据交互了。
    • 传输协议
      • 传输协议就是传输规则
      • 传输层的两种协议UDP(数据报文协议),TCP(传输控制协议)
        • UDP将数据,源地址,目的地址封装到数据包。不需要建立连接,速度快,不可靠协议,无法知道是否到达。数据包大小限制在64K。类似快递。对讲机,QQ,在线视频使用UDP,可能丢失一些数据,但是速度快。
        • TCP建立连接后才数据通讯。通过三次握手完成连接。是可靠协议,对方断开不传输数据,不丢包。必须建立连接。效率低。类似打电话。下载用的就是TCP。
        • UDP可能丢包,但是速度快。TCP速度较慢,但是不会丢包。
  • Java网络编程的包是net包
  • InetAddress

    • 特点

      • 表示网络的IP地址。在网际层

      • 没有构造函数,使用静态方法返回对象。

    • 小知识

      • DNS:(Domain Name System)域名解析服务器,进行域名与IP对应关系的记录

        • 先请求域名,域名从DNS服务器中找到对应IP返回自己的主机,自己根据该IP访问域名所属网站。

        • 域名解析顺序:本地hosts->互联网

      • 局域网的某台机器装一个DNS服务器软件,配置好域名解析,然后本地DNS指向该机器的IP,访问网址的时候就会自动从这台DNS服务器进行域名查询。

      • cmd输入start可以开一个新窗口

      • C类地址,P前三字段都是网络位,IP的第四个字段为0是网络位,相当于网段,ip地址从1-254有效,255是广播字段,会把消息广播到网段中所有IP中。可用于群聊

    • 常用方法

      InetAddress getLocalHost()                                          返回本地主机ip地址对象
      InetAddress getByName("DESKTOP-G8GJS0I")                            根据主机名获取ip地址对象
      InetAddress getByName("192.168.120.124")                            根据IP获取ip地址对象
      InetAddress getByName("www.baidu.com")                              根据域名获取ip地址对象
      InetAddress[] getAllByName()                                        获取主机的IP地址数组。有的主机IP地址不唯一。可能有服务器集群。
      String getHostAddress()                                             获取主机地址
      String getHostName()                                                获取主机名。找不到主机名就返回IP

       

 

  • UDP传输流程
    • DatagramSocket创建数据包套接字对象
    • DatagramPacket创建发送或接收数据包对象
    • 使用DatagramSocket发送或接收数据包
    • 关闭socket流
  • TCP传输流程
    • Socket
      • 实现客户端套接字
      • 术语叫做套接字,是为网络服务提供的一种机制
      • 可以理解为通讯的端点,数据在Socket中进行IO传递。需要通信两端都有Socket
      • TCP客户端创建的过程
        • 创建Socket对象,并指定要连接的IP与Port,明确目的主机
        • 如果连接建立成功,就形成了一个数据传输通道(socket流)。可以从该Socket对象获取输入输出流对象进行数据传输。
        • 使用输出流写出数据或使用输入流写入数据
        • 关闭Socket流
          • 这里可以不用关闭,服务器端会统一关闭,但是需要给服务器端发送结束标记,否则服务器端也不会关。
    • ServerSocket
      • 实现服务端套接字
      • TCP服务端创建的过程
        • 创建ServerSocket对象
        • 给服务端提供一个监听端口,否则客户端无法连接
        • 获取连接过来的客户端Socket对象,并获取其输入流或输出流对象
        • 使用输出流写出数据或使用输入流写入数据
        • 关闭资源
          • 需要关闭客户端,服务端如果需要一直进行服务提供则可以不用关闭。
  • DatagramSocket
    • 特点
      • 用于表示发送和接收数据报包的套接字
    • 构造方法
      DatagramSocket()                                                创建一个数据报包套接字对象。用于发送数据包,默认绑定任意可用端口
      DatagramSocket(int)                                             创建一个带端口的数据报包套接字对象。用于接收数据包

       

    • 常用方法
      close()                                                    关闭套接字
      send(DatagramPacket)                                       发送数据报包
      receive(DatagramPacket)                                    接收数据报包。阻塞式方法。接收到数据就可以走他下边的代码了。

 

 

  • DatagramPacket
    • 特点
      • 表示数据报包,实现无连接的投递服务。不对包投递做出保证。
      • 包含包中的数据,目的地址,源地址。所以封装对象更方便。
    • 构造方法
      DatagramPacket(byte[], int, InetAddress, int)                   创建一个发送数据报包套接字对象,需要指定字节数组,发送长度,IP和端口
                                                                      发送包有目的地址,接收包不需要地址
    • 常用方法
      byte[] getData()                                          获取接收的数据
      int getPort()                                             获取发送端端口
      InetAddress getAddress()                                  获取发送端IP对象
      int getLength()                                           获取发送数据的长度
    • 发送接收端小示例(可以使用多线程来进行同时发送和接收)
          // 发送端代码
          public void udpSend() throws IOException {
              /**
               * 1 创建UDP的socket
               * 2 组包
               * 3 发包
               * 4 关服务
               */
              System.out.println("发送端启动");
              DatagramSocket ds = new DatagramSocket();
              String sendData = "UDP传输演示";
              byte[] sendDataBinary = sendData.getBytes();
              InetAddress ip = InetAddress.getByName("127.0.0.1");
              DatagramPacket dp = new DatagramPacket(sendDataBinary, sendDataBinary.length, ip, 10000);
              ds.send(dp);
              ds.close();
          }
          // 接收端代码
          public void updReceive() throws IOException {
              /**
               * 1 建立UDP的socket
               * 2 接收UDP的包。使用数据包接收
               * 3 解包查看
               * 4 关闭socket
               */
              System.out.println("接收端启动");
              DatagramSocket ds = new DatagramSocket(10000);
              byte[] buf = new byte[1024];
              DatagramPacket dp = new DatagramPacket(buf, buf.length);
              ds.receive(dp);
              System.out.println(new String(dp.getData(), 0, dp.getLength()));
              System.out.println(dp.getPort());
              System.out.println(dp.getAddress().getHostAddress());
              ds.close();
          }

       

    • 使用多线程开启聊天室
      // 线程开启
      public static void chatroomDemo() throws SocketException {
          DatagramSocket senderSocket = new DatagramSocket(10001);
          DatagramSocket receiverSocket = new DatagramSocket(10002);
          ChatSender sender = new ChatSender(senderSocket);
          ChatReceiver receiver = new ChatReceiver(receiverSocket);
          new Thread(sender).start();
          new Thread(receiver).start();
      }
      
      // ChatSender
      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;
      
      public class ChatSender implements Runnable{
          private DatagramSocket ds;
      
          public ChatSender(DatagramSocket ds) {
              this.ds = ds;
          }
      
          public void run() {
              try {
                  System.out.println("发送端启动");
                  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                  String line = null;
                  while ((line = br.readLine()) != null) {
                      byte[] sendDataBinary = line.getBytes();
                      // InetAddress ip = InetAddress.getByName("127.0.0.255"); 255可以广播消息到该网段所有IP
                      InetAddress ip = InetAddress.getByName("127.0.0.1");
                      DatagramPacket dp = new DatagramPacket(sendDataBinary, sendDataBinary.length, ip, 10002);
                      ds.send(dp);
                      if ("over".equals(line))
                          break;
                  }
                  ds.close();
              } catch (Exception e) {
      
              }
          }
      }
      
      //ChatReceiver
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      
      public class ChatReceiver implements Runnable {
          private DatagramSocket ds;
          
          public ChatReceiver(DatagramSocket ds) {
              this.ds = ds;
          }
          public void run() {
              try {
                  System.out.println("接收端启动");
                  while (true) {
                      byte[] buf = new byte[1024];
                      DatagramPacket dp = new DatagramPacket(buf, buf.length);
                      ds.receive(dp);
                      String ip = dp.getAddress().getHostAddress() ;
                      String port = "" + dp.getPort();
                      String message = new String(dp.getData(), 0, dp.getLength(), "UTF-8");
                      System.out.println(ip + ":" + port + ":" + message);
                      if (message.equals("over"))
                          System.out.println(ip + "退出聊天室");
                  }
              } catch (Exception e) {
      
              }
          }
      }
  • Socket
    • 构造方法
      Socket()                                                 创建一个客户端未连接的套接字。可以使用connect方法连接
      Socket(InetAddress, port)                                创建一个流套接字并连接到指定IP和端口号
      Socket(String, port)                                     使用字符串来指定IP
    •  常用方法
      connect()                                                连接该socket到一个套接字地址
      InputStream getInputStream()                             获取输入流对象,用于读数据
      OutputStream getOutputStream()                           获取输出流对象,用于写数据
      shutdownInput()                                          给套接字的输入流置一个结束标记
      shutdownOutput()                                         给套接字的输出流置一个结束标记
       
    • 客户端给服务端发送数据,并接收服务端返回数据
              Socket socket = new Socket("127.0.0.1", 10001);
              OutputStream out = socket.getOutputStream();
              out.write("TCP演示".getBytes());
      
              InputStream input = socket.getInputStream();
              byte[] buf = new byte[1024];
              int len = input.read(buf);
              String text = new String(buf, 0, len);
              System.out.println(text);
              // 这里的关闭链接就相当于断开socket流连接。不关的话服务器关掉也行
              socket.close();
  • SocketAddress
    • 特点
      • 封装了IP + Port
  • ServerSocket
    • 构造方法
      ServerSocket()                                           创建一个服务端未连接的套接字
      Socket(port)                                             创建服务端套接字的时候初始化监听端口
    • 常用方法
      accept()                                                 获取客户端连接的Socket对象
    • 服务端接收客户端发送的数据,并给客户端返回数据
              ServerSocket ss = new ServerSocket(10001);
              Socket socket = ss.accept();// 阻塞式方法。如果没有进行Socket连接,这里一直等待
              InputStream input = socket.getInputStream();
              byte[] buf = new byte[1024];
              int len = input.read(buf);
              String ip = socket.getInetAddress().getHostAddress();
              String text = new String(buf, 0, len);
              System.out.println(ip + ":" + text);
      
              OutputStream out = socket.getOutputStream();
              out.write("收到".getBytes());
              
              socket.close();
              ss.close();
    • 创建英文大写转换服务器。
      // TransClient
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.Socket;
      import java.net.UnknownHostException;
      
      
      public class TransClient {
          public static void main(String[] args) throws UnknownHostException, IOException {
              Socket socket = new Socket("127.0.0.1", 10001);
              BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
              String line = null;
              // 用PrintWriter直接输出字符流,加true自动刷新
              PrintWriter pw = new PrintWriter(socket.getOutputStream());
              BufferedReader result = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              while ((line = br.readLine()) != null) {
                  if ("over".equals(line))
                      break;
                  // 将字节流输出,并加上换行
                  pw.print(line);
                  // 读入服务器返回的一行数据
                  System.out.println(result.readLine());
              }
              // 客户端进行了close,就会在流中植入结束标记-1,所以服务端判断没有数据,也会自动关闭
              // 最好给服务端发送一个结束标记,让服务端来关闭。
              socket.close();
          }
      }
      
      // TransServer
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      
      public class TransServer {
          public static void main(String[] args) throws IOException {
              ServerSocket ss = new ServerSocket(10001);
              Socket socket = ss.accept();
              BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              PrintWriter pw = new PrintWriter(socket.getOutputStream());
              String line = null;
              while((line = br.readLine()) != null) {
                  System.out.println(line);
                  String newLine = line.toUpperCase();
                  pw.print(newLine);
              }
              socket.close();
              ss.close();
          }
      }

       

    • TCP传输过程两端都在等,接收不到数据

      • 有阻塞式方法。数据留在了缓冲区,没有发出去。

        • 需要进行数据刷新

      • 没有读取到数据结束标记

        • 例如服务端使用readLine()读取客户端发送的数据,没有发送换行符,所以一直进行数据等待

    • 上传文本文件

      // UploadClient
      import java.io.BufferedReader;
      import java.io.FileReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.Socket;
      import java.net.UnknownHostException;
      
      
      public class UploadClient {
          public static void main(String[] args) throws UnknownHostException, IOException {
              System.out.println("client start");
              Socket socket = new Socket("127.0.0.1", 10001);
              BufferedReader br = new BufferedReader(new FileReader("Worker.java"));
              PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
              String line = null;
              // 客户端可以发送时间戳来当作结束标记。先发一个时间戳,服务端接收到存储好。然后客户端发送完再发相同的时间戳即可。
              // 也可以使用Socket的shutdownInput说shutdownOutput方法
              while ((line = br.readLine()) != null) {
                  pw.println(line);
              }
              // 传输给服务端结束标记
              socket.shutdownOutput();
              
              pw.println("over");
              BufferedReader result = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              System.out.println(line = result.readLine());
              br.close();
              socket.close();
          }
      }
      
      // UploadServer
      import java.io.BufferedReader;
      import java.io.FileWriter;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      
      public class UploadServer {
          public static void main(String[] args) throws IOException {
              System.out.println("server start");
              ServerSocket ss = new ServerSocket(10001);
              Socket socket = ss.accept();
              BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              PrintWriter pw = new PrintWriter(new FileWriter("server.txt"), true);
              String line = null;
              // 服务端需要使用结束标记来判断接收数据结束。
              // 或者客户端使用Socket的shutdownInput说shutdownOutput方法
              while ((line = br.readLine()) != null) {
                  pw.println(line);
              }
              PrintWriter returnStr = new PrintWriter(socket.getOutputStream());
              returnStr.println("success");
              System.out.println("server success");
              returnStr.flush();
              pw.close();
              socket.close();
              ss.close();
      
          }
      }
    • 服务端多线程上传图片

      // UploadPicClient
      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.net.Socket;
      import java.net.UnknownHostException;
      
      public class UploadPicClient {
          public static void main(String[] args) throws UnknownHostException, IOException {
              Socket socket = new Socket("127.0.0.1", 10001);
              BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.png"));
              BufferedOutputStream  bos = new BufferedOutputStream(socket.getOutputStream());
              byte[] buf = new byte[1024];
              int len = 0; 
              System.out.println("client start");
              while ((len = bis.read(buf)) != -1) {
                  bos.write(buf, 0, len);
                  bos.flush();
              }
              socket.shutdownOutput();
              InputStream is = socket.getInputStream();
              byte[] result = new byte[1024];
              int resultLength = is.read(result);
              System.out.println(new String(result, 0, resultLength));
              System.out.println("client finish");
              bis.close();
              socket.close();
      
              
          }
      }
      
      // UploadPicServer
      // 使用多线程是为了解决客户端请求服务端需要排队的问题。如果请求时间过长,会超时。
      import java.io.IOException;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      public class UploadPicServer {
          public static void main(String[] args) throws IOException {
              ServerSocket ss = new ServerSocket(10001);
              System.out.println("server start");
              
              while (true) {
                  Socket socket = ss.accept();
                  new Thread(new UploadTask(socket)).start();;
              }
      
              // ss.close();
          }
      }
      
      
      // UploadTask
      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.File;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.net.Socket;
      
      public class UploadTask implements Runnable {
          private Socket socket;
      
          public UploadTask(Socket socket) {
              this.socket = socket;
          }
      
          public void run() {
              BufferedOutputStream bos = null;
              int count = 0;
              try {
                  File dir = new File("C:\\pic");
                  if (!dir.exists()) {
                      dir.mkdirs();
                  }
                  File pic = new File(dir, socket.getInetAddress().getHostAddress() + ".png");
      
                  while (pic.exists()) {
                      pic = new File(dir, socket.getInetAddress().getHostAddress() + "(" + (++count) + ").png");
                  }
      
                  BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
                  bos = new BufferedOutputStream(new FileOutputStream(pic));
      
                  byte[] buf = new byte[1024];
                  int len = 0;
                  while ((len = bis.read(buf)) != -1) {
                      bos.write(buf, 0, len);
                      bos.flush();
                  }
      
                  PrintWriter pw = new PrintWriter(socket.getOutputStream());
                  pw.print("success");
                  pw.flush();
                  System.out.println("server finish");
              } catch (IOException e) {
      
              } finally {
                  try {
                      bos.close();
                  } catch (IOException e) {
                  }
                  try {
                      socket.close();
                  } catch (IOException e) {
                  }
              }
          }
          
      }

       

    • 小知识
      • 无限循环不要怕,主要是因为循环中有阻塞方法,资源没进来就进行等待。不耗费CPU
      • 如果判断一次,使用if,如果判断多次,使用while
      • HTTP是应用层规则。是一种通讯协议,通讯规则。
      • 192.168.1.100(自己的主机地址)和127.0.0.1都可以访问本地主机
      • C/S需要做客户端和服务端
        • 开发成本较高,维护比较麻烦。
        • 可以在本地分担一部分运算。例如杀毒就不适合使用B/S
        • 客户端游戏速度更快,效果更好。
      • B/S不需要做客户端,直接有浏览器就行
        • 开发成本较低,维护较简单。
        • 所有运算都在浏览器
      • 服务器端原理
        // 服务端多线程伪代码
        ServerSocket ss = new ServerSocket();
        while (true) {
            // 服务器端接收到一个客户端
            Socket socket = ss.accept();
            // 将客户端封装为一个线程执行任务
            new Thread(new Task(socket));
            // 主线程任务执行完,返回while重新执行,重新进行accept()获取。这样就可以并发处理多个客户端请求了。
            // 如果是单线程,原客户端任务没有执行完,新的客户端无法进行accept()获取,只能等待
        }
      • 常见客户端和服务端
        • 客户端

          • 浏览器

            • 早期浏览器都是IE内核,改了下外观。

            • IE是单窗口的,一个页面一个窗口。遨游将IE改为单窗口,多标签形式,切换更方便

            • 基于IE内核可能收费,所以后期基于webkit(开源免费)

        • 服务端

          • 服务器:可以对外提供服务的机器。

            • Oracle:数据库服务器

            • Tomcat:Web资源访问服务器。处理请求并给予应答。

              • 服务端的处理都需要实现Servlet(Server Applet)接口

              • 用于访问web应用(webapp)

            • 网络硬盘:存储服务器

      • 客户端和服务端原理

        • 服务端
          •  

            可以使用ServerSocket写一个服务端,浏览器访问该服务端,接收返回信息并解析。

          • 浏览器服务端小例子

                    ServerSocket ss = new ServerSocket(10001);
                    Socket socket = ss.accept();
                    String ip = socket.getInetAddress().getHostAddress();
                    System.out.println(ip);
                    InputStream is = socket.getInputStream();
                    byte[] buf = new byte[1024];
                    int len = is.read(buf);
                    System.out.println(new String(buf, 0, len));
                    PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
                    // 需要加上响应行,浏览器才可以解析
                    pw.println("HTTP/1.1 200  OK");
                    pw.println();
                    // 响应体前边加一个空行
                    pw.println("hello KnowServer");
                    socket.close();
                    ss.close();

             

          • 服务端发送的应答消息的含义

            HTTP/1.1 200  OK                                应答行:HTTP协议版本 应答状态码 应答状态描述信息
            Accept-Ranges: bytes                            (从这里开始都是应答消息头,键值对形式)
            ETag: W/"5-1597909615505"
            Last-Modified: Thu, 20 Aug 2020 07:46:55 GMT    资源最后修改时间。如果本地有缓存,请求的时候带上缓存中的这个键值对,服务端判断时间一致,返回一个状态码,不再返回响应体。速度会更快。
            Content-Type: text/html                         返回数据类型。
            Content-Length: 5                               返回数据的字节长度
            Date: Thu, 20 Aug 2020 07:47:54 GMT             
            Connection: close                               连接关闭
            
            hello                                           应答体和应答消息头之间也需要有空行
          • 常用状态码

            • 200 OK 请求成功
            • 404 not found 资源没有找到(输入不存在的网页也找不到)

        • 客户端

          • 使用Socket写一个客户端,使其访问Tomcat,接收返回信息并解析。

          • 浏览器客户端小例子

                    Socket socket = new Socket("127.0.0.1", 8080);
                    PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
                    // 添加请求行
                    pw.println("GET / HTTP/1.1");
                    // 添加请求头
                    pw.println("Accept: */*");
                    pw.println("Connection: close");
                    pw.println("Host: 127.0.0.1:8080");
                    // 这里没有请求体,有的话下边的换行是必须的
                    pw.println();
                    pw.println();
            
                    InputStream is = socket.getInputStream();
                    byte[] buf = new byte[1024];
                    int len = 0;
                    while ((len = is.read(buf)) != -1) {
                        System.out.println(new String(buf, 0, len));
                    }
            
                    socket.close();

             

          • 浏览器发送的请求消息的含义

            GET / HTTP/1.1                      请求行:请求方式 请求路径(这里是根目录) http协议版本。请求行是最主要的。
                                                GET请求的请求参数会在请求行获取到 /?user=qwe&pass=123
                                                POST请求的请求参数会在请求体中获取到 user=qwe&pass=123
            Host: 127.0.0.1:10001               获取主机名(从这里向下都是请求消息头,格式都是键值对。用于告诉服务器都允许什么应用程序解析)
            Connection: keep-alive              连接状态:保持存活
            Cache-Control: max-age=0
            Upgrade-Insecure-Requests: 1
            User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36  用来获取浏览器版本
            Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9   表示浏览器都支持解析什么数据。
            Sec-Fetch-Site: cross-site
            Sec-Fetch-Mode: navigate
            Accept-Encoding: gzip, deflate, br  表示浏览器支持的压缩方式。如果网页比较大,服务端会将网页压缩再发给浏览器。用于提高传输效率。
            Accept-Language: zh-CN,zh;q=0.9     表示浏览器都支持什么语言
            
            页面数据                             浏览器发送的请求体,请求体和请求头由空行隔开。HTTP请求规则。
          • GET提交和POST提交的区别
            • GET
              • 数据封装在请求行
              • 提交大量数据,地址栏有限,放不下
            • POST
              • 数据封装在请求体
              • 可以提交大量数据
  • URL
    • 特点
      • Uniform Resource Locator,统一资源定位符
      • 指向互联网资源的指针,资源可以是简单的文件或目录
      • 这是一个URL:http://www.lightly.com/project/index.html.可以参考
    • 构造方法
      URL(String)                                           创建一个带URL地址的URL对象
      URL(String protocol, String host, int port, String file)  指定协议,主机,端口,文件路径来创建URL对象
    • 常用方法
      String getProtocol()                                       获取协议名称
      String getHost()                                           获取主机名称
      int getPort()                                              获取端口
      String getPath()                                           获取路径名
      String getFile()                                           获取文件名,会有参数信息
      String getQuery()                                          获取查询部分
      InputStream openStream()                                   打开URL连接,返回从连接读入的InputStream,获取服务端返回的数据。只返回应答体。
                                                                 连上就相当于建立了Socket。
                                                                 底层调用了openConnection.getInputStream();
      URLConnection openConnection()                             获得URL连接器对象。可以连到统一资源定位符指向的资源。

       

  • URI
    • 特点
      • Uniform Resource Identifier,统一资源标识符
      • 包括URL和URN
      • 这是一个URI:http://www.lightly.com/project/index.html#intro.可以参考
  • URLConnection 
    • 特点
      • Java中内置的可以解析具体协议的对象+Socket
      • 只能获取该对象,不能进行实现。
    • 常用方法
      String getHeaderField(String)                               用键获取消息头对应键的值
      InputStream getInputStream()                                获取输入流
      OutputStream getOutputStream()                              获取输出流
       

反射

  • 含义
    • 运行状态中,对任意一个类(class文件)都能知道这个类的所有属性和方法
    • 对任意一个对象,都能够调用它的任意一个方法和属性
    • 这种动态获取的信息及动态调用对象的方法的功能叫做java的反射机制。
    • 可以理解为对类的解剖。
  • 应用场景
    • 对指定名称的字节码文件加载并获取其内容进行调用
      • 例如Tomcat中自己实现了Servlet,需要Tomcat运行自己的程序,只需要把自己的程序配置到web.xml,Tomcat就可以执行了。Tomcat就动态的获取了这个类的信息。这里用了反射。
      • 用户不用创建对象,把自己的类放到配置文件里就可以运行了。
  • 作用
    • 大大提高了程序扩展性
  • 小知识
    • 学习框架需要知道框架是做什么的,需要知道配置文件怎么配置,需要知道常见对象怎么用即可。
      • 也可以了解下框架的底层原理
    • 反射所有的对象都在java.lang.reflect包下(反射包),用于解析类成员对象
  • Class
    • 含义
      • 描述字节码文件的类,用来获取字节码文件的内容(名称,字段,构造函数,一般函数)
    • 作用
      • 用于获取字节码文件的所有内容。反射就是依靠该类完成的。
    • 获取字节码的方式
      • Object类的getClass方法。用的时候需要明确具体的类并创建对象
        Worker worker = new Worker("name", 12);
        Class clazz = worker.getClass();
      • 使用任意类的class静态属性
        Class clazz = Worker.class;
      • 通过给定类的字符串名称获取类,更具扩展性。使用Class类的方法。反射主要方式。知道类名字即可。

        // 从当前根目录找,需要写类的全名
        Class clazz = Class.forName("ml.lightly.bixiangdong.Worker");
        Object obj = clazz.newInstance();
    • 早期和现在创建对象比较

      • 早期:new的时候,根据类名称找到该类的字节码文件,加载到内存,创建该字节码文件对象,然后根据字节码文件对象创建该类对象

      • 现在:forName()会找到类文件,并加载到内存,产生Class对象,然后newInstance(),创建该类对象

    • 常用方法

      Class forName(name)                                      获取某个类名的Class对象
      Object newInstance()                                     创建获取的类的空参对象。没有空参构造函数抛出异常。
                                                               一般被反射的类都有空参构造函数。
      Constructor<?>[] getDeclaredConstructors()               获取所有构造函数,包括私有
      Constructor<?>[] getConstructors()                       获取所有公共构造函数
      Constructor<?> getConstructor(参数列表)                   获取指定参数列表的公共构造函数。任何数据类型都可以被.class描述
                                                               getConstructor(String.class, int.class)
      Field[] getFields()                                      获取所有的公共字段。因为字段有字段修饰符,类型,字段的值,所以被封装为Field对象
      Field getFields(String)                                  获取指定键的公共字段   
      Field[] getDeclaredFields()                              获取所有字段,包括私有字段     
      Field getDeclaredField(String)                           获取指定键的字段,包括私有字段      
      Method[] getMethods()                                    获取某类的所有公有方法,包括继承的
      Method[] getDeclaredMethods()                            只获取属于该类的所有方法,包括私有方法   
      Method getMethod(方法名, 参数列表)                       获取某个方法,需要传入参数列表,没有参数列表传入null,有的话传入xx.class
    • 小例子

              Class clazz = Class.forName("ml.lightly.bixiangdong.Worker");
              // 获取无参构造函数。如果没有无参构造函数,抛出异常
              // Object obj = clazz.newInstance();
              // 获取指定构造函数对象
              Constructor constructor = clazz.getConstructor(String.class, int.class);
              // 根据指定构造函数对象创建实例
              Worker worker = (Worker)constructor.newInstance("xia", 12);
              // 获取类的某个字段。该方法可以获取私有字段
              Field ageField = clazz.getDeclaredField("age");
              // 对于私有字段的访问需要使用这个方法取消权限限制
              ageField.setAccessible(true);
              // 用于为某个对象设置该字段的值
              ageField.set(worker, 25);
              // 获取某对象该字段的值
              Object obj = ageField.get(worker);
              System.out.println(obj);
              // 获取某类的某个方法,因为有重载,所以需要传入参数列表。有参数传入xx.class,没有传入null
              Method setAgeMethod = clazz.getMethod("setAge", int.class);
              // 传入相应对象和参数列表,执行方法,并返回相应数据
              setAgeMethod.invoke(worker, 23);
              // 获取某类的某个方法,因为有重载,所以需要传入参数列表。有参数传入xx.class,没有传入null
              Method method = clazz.getMethod("getAge", null);
              // 传入相应对象和参数列表,执行方法,并返回相应数据
              Integer age = (Integer)method.invoke(worker, null);
              System.out.println(age);

       

    • 电脑运行

      • 对于接口的修改。适用于不修改代码,但是可以运行新的设备

        // pci.properties
        pci0=SoundCard
        
        // 反射Demo
        import java.io.File;
        import java.io.FileInputStream;
        import java.util.Properties;
        
        public class ReflectDemo {
            public static void main(String[] args) throws Exception {
                MainBoard mb = new MainBoard();
                // 主板运行
                mb.run();
                File config = new File("pci.properties");
                Properties prop = new Properties();
                // 读取配置文件
                FileInputStream fis = new FileInputStream(config);
                prop.load(fis);
                for (int i = 0; i < prop.size(); i++) {
                    // 获取配置文件中的设备
                    String pciName = "ml.lightly.bixiangdong." + prop.getProperty("pci" + i);
                    // 获取该设备
                    Class clazz = Class.forName(pciName);
                    // 因为设备有统一的接口,所以可以同该接口进行统一操作
                    PCI p = (PCI)clazz.newInstance();
                    // 运行该设备
                    mb.usePCI(p);
                }
            }
        }
        
        // 主板
        class MainBoard {
            public void run() {
                System.out.println("main board run");
            }
            // 用于接口操作
            public void usePCI(PCI p) {
                if (p != null) {
                    p.open();
                    p.close();
                }
            }
        }
        
        // 统一规则
        interface PCI{
            public void open();
            public void close();
        }
        
        // 后期添加设备
        class SoundCard implements PCI{
            public void open() {
                System.out.println("SoundCard  open");
            }
            public void close() {
                System.out.println("SoundCard  close");
            }
        }
    • 小知识

      • 接口的使用

        • 定义好规则,后期设备通过该规则扩充,前期设备只操作这个规则即可。但是如果代码写好,后期扩展也是需要再去修改新添加的设备。

          public class Main {
              public static void main(String[] args) {
                  MainBoard mb = new MainBoard();
                  // 后期需要修改新添加的设备
                  mb.usePCI(new SoundCard());
              }
          }
          class MainBoard {
              public void run() {
                  System.out.println("main board run");
              }
              // 用于接口操作
              public void usePCI(PCI p) {
                  if (p != null) {
                      p.open();
                      p.close();
                  }
              }
          }
          
          // 统一规则
          interface PCI{
              public void open();
              public void close();
          }
          
          // 后期添加设备
          class SoundCard implements PCI{
              public void open() {
                  System.out.println("SoundCard  open");
              }
              public void close() {
                  System.out.println("SoundCard  close");
              }
          }

           

  • Constructor

    • 特点
      • 是获取的Class的构造器组成的对象
    • 常用方法

       

      Object newInstance(参数列表)                                使用该构造器创建对象。传入相应的参数。

       

  • Field

    • 特点
      • 是获取的Class的字段组成的对象
    • 常用方法

      setAccessible(boolean)                            对私有字段的访问取消权限检查。暴力访问
      Object get(Object)                                获取传入对象的该字段的值。私有字段需要设置setAccessible(true)
      set(Object, Object)                               给某个对象的该字段设置值。
  • Method
    • 特点
      • 是获取的Class的方法组成的对象
    • 常用方法
       Object invoke(Object, Object)                            运行某方法,需要传入运行对象和参数列表。没有参数列表传null,有参数列表传相应的参数值。

       

正则

  • 作用
    • 主要操作字符串
  • 特点
    • 通过特定符号体现
    • 简化了,阅读性变差。
  • 正则表达式常用符号
    /**
      * 大括号控制次数,中括号控制数据范围,小括号用于符号封装(会对加了小括号的每个封装体从1进行编号,没有加括号就是第0组)
      * (.)\\1+   在java里,括号封装了一个匹配模式,这是第一组模式,正则中用1来标识,但不是普通1,所以加转义符号来标识第一组,然后+就是用来对第一组进行操作的符号
      * ^ 非,作用于后边的第一个控制范围  
      * - 用于数据范围  
      * && 与,用于交集
      */
    
    字符
    x                              表示随意地一个字符
    \\                             反斜杠
    
    字符类
    [abc]                          某一位上只能是a或b或c
    [^abc]                         某一位上是除了a或b或c的任意字符
    [a-zA-Z]                       所有字母
    [a-z[A-Z]]                     所有字母,可以多加一个中括号
    [a-d&&c-e]                     获取交集cd
    [a-z&&[^bc]]                   获取a-d里边不包含bc的,等同[ad-z]
    
    预定义字符类(已经定义好的字符含义)
    .                              该位可以是任意字符
    \d                             表示数字,等同[0-9]
    \D                             表示非数字,等同[^0-9]
    \s                             表示空白字符,等同[ \t\n\x0b\f\r]
    \S                             表示非空白字符,等同[^\s]
    \w                             表示数字字母下划线,等同[0-9a-z_A-Z]
    \W                             表示非数字字母下划线,等同[^\w]
    
    边界匹配
    ^                              放在最开始,表示行的开头
    $                              放在最后,表示行的结尾
    \b                             表示单词边界,每个单词中间都有空格,空格就是边界
    
    数量词
    x?                             随意字符跟一个问号,表示这个字符出现0或1次
    x*                             随意字符跟一个星号,表示这个字符出现0或多次
    x+                             随意字符跟一个加号,表示这个字符出现1或多次
    x{n}                           随意字符跟一个大括号和次数,表示这个字符出现n次
    x{n,}                          随意字符跟一个大括号和次数和逗号,表示这个字符出现至少n次
    x{n,m}                         随意字符跟一个大括号和次数,逗号,次数,表示这个字符出现至少n次,至多出现m次
    
    逻辑运算符
    xy                             x字符后边跟一个y字符
    x|y                            x或y
    (x)                            作为捕获组,第一个左括号是第一组,第二个左括号是第二组,用数字标识(数字不是普通的数字字符,所以需要转义)
                                   组0代表整个表达式
                                   (x)\\1+  第一组的匹配模式出现1次或多次
    
    引用
    \组号                           用于匹配捕获组

     

  • 正则表达式对字符串的常用操作
    • 匹配
              // 匹配手机号码
              String tel = "18024726182";
              // 第一位固定为1,第二位固定为[3586],剩下的都是[0-9]总长度为11,
              String regex = "1[3456789]\\d{9}";\\ [0-9]可以用\\d代表.java的\d是转移字符,这里需要普通符号,所以用\\d
              System.out.println(tel.matches(regex));
      • 匹配手机号练习
    • 切割

              // 切割空格字符
              String nameStr = "easul     xiaoqiang   zhaoliu";
              String regex = "\\s+";
              String[] results = nameStr.split(regex);
              for (String result :results)
                  System.out.println(result);
      
              // 用.进行切割
              nameStr = "easul.xiaoqiang.zhaoliu";
              // 正则中.表示任意字符,这里如果要当作普通字符,需要进行转义
              regex = "\\.";
              results = nameStr.split(regex);
              for (String result :results)
                  System.out.println(result);
      
              // 切叠词
              nameStr = "easultttttxiaoqiangnnnnnnnnzhaoliu";
              regex = "(.)\\1+";
              results = nameStr.split(regex);
              for (String result :results)
                  System.out.println(result);

       

    • 替换
              // 将叠词替换为一个字符
              String str = "asdffffffffasdfafdasdf";
              String regex = "(.)\\1+";
              str = str.replaceAll(regex, "#");
              System.out.println(str);
      
              // 让第二个参数使用第一个参数的正则,使用$符号.$n就是匹配第几组
              // 这里输出后第二个参数每次只获取第一个参数的一个字符
              String str = "asdvvvgggggasdfafdasdf";
              String regex = "(.)\\1+";
              str = str.replaceAll(regex, "$1");
              System.out.println(str);
      
              // 手机号隐藏中间四位.正则分组,用$n在替换的字符串中代表第几组
              String tel = "15878783928";
              String regex = "(\\d{3})\\d{4}(\\d{4})";
              tel = tel.replaceAll(regex, "$1****$2");
              System.out.println(tel);

       

    • 获取
              /**
               * 正则的获取常规操作.只能通过Pattern和Matcher获取
               *
               * 将正则规则进行对象封装
               * 通过正则对象的matcher方法与字符串关联,获取字符串操作匹配对象Matcher
               * 通过Matcher匹配器对象对字符串操作
               */       
              // 获取三个字母组成的单词
              String str = "da jia hao, ming tian bu fang jia";
              String regex = "\\b[a-z]{3}\\b";
              // 将正则规则进行对象封装
              Pattern p = Pattern.compile(regex);
              // 通过正则对象的matcher方法与字符串关联,获取字符串操作匹配对象Matcher
              Matcher m = p.matcher(str);
              // 通过Matcher匹配器对象对字符串操作
              while (m.find()) {
                  System.out.println(m.group());
              }

       

  • 小例子
    • 简单QQ号校验
              /**
               * 需求:对QQ号校验
               * 要求:长度为5-10位,0不能开头,只能是数字
               * 思路:
               * 1 先判断长度,然后判断字符串是不是0开头,然后打散字符串,判断每一位是不是数字(这里也可以将字符串转为long型,用异常判断)
               * 2 正则
               */
              String qq = "123456789";
              // 正则底层对应了代码
              // 大括号控制次数,中括号放数据范围
              String regex = "[1-9][0-9]{4,9}";
              System.out.println(qq.matches(regex));

       

    • 治疗口吃
              // 治疗口吃
              String str = "我我我...我我我我我我我要...要要要要要要要...要要要要要要要......学学学学学学学学..学学编编编编编....编编编编编编编编...编...程程程程程....程程程程程...程程程程程程..";
              // 1 替换掉点
              String regex = "\\.+";
              str = str.replaceAll(regex, "");
              // 2 替换掉叠词
              regex = "(.)\\1+";
              str = str.replaceAll(regex, "$1");
              System.out.println(str);

       

    • 对IP地址排序
              // 因为是字符串排序,所以正常排序和字符串排序结果不同.所以可以想到每个都补成3位,然后按照字符串顺序排序.
              String ipStr = "192.168.10.34 127.0.0.1 3.3.3.3  105.70.11.55";
              
              // 每一段都加两个0
              String regex = "(\\d+)";
              ipStr = ipStr.replaceAll(regex, "00$1");
              // 每一段都保留三位数字
              regex = "0*(\\d{3})";
              ipStr = ipStr.replaceAll(regex, "$1");
      
              regex = "\\s+";
              String[] ipArr = ipStr.split(regex);
      
              TreeSet<String> ts = new TreeSet<String>();
              for (String ip : ipArr) {
                  ts.add(ip);
              }
      
              for (String ip : ts) {
                  // 输出的时候,因为有0,至少要保留一位数字,所以用了\d+
                  System.out.println(ip.replaceAll("0*(\\d+)", "$1"));
              }
    • 对邮件地址校验
              // 可以用于关键字屏蔽.
              String mail = "asdf@qq.com.cn";
              // 在这里如果只有一个组,可以不写组号
              String regex = "[\\w]+@[\\w-&&[^_]]+(\\.[a-zA-Z]{2,3}){1,3}";
              boolean b = mail.matches(regex);
              System.out.println(b);
    • 爬虫:获取互联网中符合指定规则的数据.百度早期爬keywords,现在爬内容
              // 爬取邮箱地址
              // 读取源文件,本地文件
              BufferedReader br = new BufferedReader(new FileReader("mail.html"));
              // 爬取网络内容
              // URL url = new URL("网络地址");
              BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
              // 对读取的数据进行规则的匹配.从中获取符合规则的数据
              String mailRegex = "\\w+@\\w+(\\.\\w+){1,2}";
              List<String> list = new ArrayList<String>();
              Pattern p = Pattern.compile(mailRegex);
              String line = null;
              while ((line = br.readLine()) != null) {
                  Matcher m = p.matcher(line);
                  while (m.find()) {
                      // 将符合规则的数据存储到集合
                      list.add(m.group());
                  }
              }
      
              for (String mail : list) {
                  System.out.println(mail);
              }
          }
  • String的正则方法
    boolean matches(String regex)                               检查字符串是否匹配该正则
    String[] split(String regex)                                将字符串按正则切割为字符串数组
    String replaceAll(String regex, String replacement)         使用replacement替换符合正则的部分.第二个参数想要用第一个参数的正则内容,可以用$表示
                                                                replaceAll("(.)\\1+", "$1") $n就是匹配第n组
                                                                这里就可以在第二个参数获取第一个参数匹配的一个字符了.
    

     

  • Pattern
    • 含义
      • 正则表达式的对象形式.
    • 作用
      • 用于正则表达式的封装,存在于java.util.regex包中.
    • 常用方法
      Pattern complie(regex)                                      将正则封装为正则对象
      Matcher matcher(String)                                     将正则与要操作的字符串关联,返回匹配器对象

       

  • Matcher
    • 含义
      • 匹配器
    • 作用
      • 使用正则对象的匹配器对象操作字符串
      • 匹配结果留在匹配器中
    • 常用方法
      Boolean find()                                            查找与该模式匹配的字符串的下一个子序列.查找一次,匹配一次.
      boolean matches()                                         判断正则与整个字符串是否存在匹配
      String group()                                            返回匹配的子序列.需要先find才能获取
      String group(int)                                         返回指定组匹配的子序列.需要先find才能获取
      String replaceAll(String replacement)                     对正则在字符串中匹配的地方修改为replacement,返回修改字符串
      int start()                                               返回匹配的子序列的第一个字符下标
      int end()                                                 返回匹配的子序列的最后一个字符的后一个下标

       

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值