Java笔记(韩顺平Java基础21-24章)

Java学习笔记(第 21章 P662-P684)(第22章 P685-P710)(第23章P711-P730)(第24章P731-P820)

第21章 网络编程

网络的相关概念

  • 网络通信
    在这里插入图片描述
  • 网络
    在这里插入图片描述
  • ip地址
    在这里插入图片描述
  • ipv4地址分类
    在这里插入图片描述
    在这里插入图片描述
  • 域名
    在这里插入图片描述
  • 网络通信协议
    在这里插入图片描述
    在这里插入图片描述
  • 网络通信协议
    在这里插入图片描述
  • TCP 和 UDP
    在这里插入图片描述

InetAddress类

  • 相关方法
    在这里插入图片描述
  • 应用案例 API_.java
package com.hspedu.api;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 演示INetAddress 类的使用
 */
@SuppressWarnings({"all"})
public class API_ {
    public static void main(String[] args) throws UnknownHostException {

        //1.获取本机的InetAddress 对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost);  //DESKTOP-V8DCRH9/192.168.0.10

        //2. 根据指定主机名 获取 InetAddress对象
        InetAddress host1 = InetAddress.getByName("DESKTOP-V8DCRH9");
        System.out.println("host1=" + host1);   //DESKTOP-V8DCRH9/192.168.0.10

        //3. 根据域名返回 InetAddress对象, 比如 www.baidu.com 对应
        InetAddress host2 = InetAddress.getByName("www.baidu.com");
        System.out.println("host2=" + host2);   //www.baidu.com/39.156.66.18

        //4. 通过 InetAddress 对象, 获取对应的地址
        String hostAddress = host2.getHostAddress();    //IP 39.156.66.18
        System.out.println("host2 对应的ip = " + hostAddress); //39.156.66.18

        //5. 通过 InetAddress 对象, 获取对应的主机名/或者是域名
        String hostName = host2.getHostName();
        System.out.println("host2对应的主机名/域名=" + hostName);   //www.baidu.com
    }
}

Socket

  • 基本介绍
    在这里插入图片描述
    示意图:
    在这里插入图片描述

TCP网络通信编程

  • 基本介绍
    在这里插入图片描述在这里插入图片描述
  • 应用案例1(使用字节流)
    SocketTCP01Server.java
    SocketTCP01Client.java
    在这里插入图片描述

SocketTCP01Server.java

package com.hspedu.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
* 服务端
*/
public class SocketTCP01Server {
   public static void main(String[] args) throws IOException {
       //思路
       //1. 在本机 的9999端口监听,等待连接
       //  细节: 要求在本机没有其他服务监听9999
       //  细节: 这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
       ServerSocket serverSocket = new ServerSocket(9999);
       System.out.println("服务端, 在9999端口监听, 等待连接..");
       //2. 当没有客户端连接9999端口时, 程序会阻塞, 等待连接
       //   如果有客户端连接, 则会返回Socket对象, 程序继续
       Socket socket = serverSocket.accept();

       System.out.println("服务端 socket =" + socket.getClass());
       //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
       InputStream inputStream = socket.getInputStream();
       //4. IO读取
       byte[] buf = new byte[1024];
       int readLen = 0;
       while((readLen = inputStream.read(buf)) != -1){
           System.out.println(new String(buf, 0, readLen));  //根据读取到的实际长度, 显示内容。
       }
       //5. 关闭流和socket
       inputStream.close();
       socket.close();
       serverSocket.close();   //关闭
   }
}

SocketTCP01Client.java

package com.hspedu.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
* 客户端, 发送 "hello, sever" 给服务器
*/
public class SocketTCP01Client {
   public static void main(String[] args) throws IOException {
       //思路
       //1. 连接服务端(ip , 端口)
       //解读: 连接本机的 9999端口, 如果连接成功, 返回Socket对象
       Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
       System.out.println("客户端 socket返回=" + socket.getClass());
       //2. 连接上后, 生成Socket, 通过socket.getOutputStream()
       //  得到 和 socket对象关联的输出流对象
       OutputStream outputStream = socket.getOutputStream();

       //3. 通过输出流, 写入数据到 数据通道
       outputStream.write("hello, server".getBytes());
       //4. 关闭流对象和socket, 必须关闭
       outputStream.close();
       socket.close();
       System.out.println("客户端退出.....");
   }
}

  • 应用案例2(使用字节流)

SocketTCP02Server.java
SocketTCP02Client.java
在这里插入图片描述
SocketTCP02Server.java

package com.hspedu.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端
 */
@SuppressWarnings({"all"})
public class SocketTCP02Server {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 在本机 的9999端口监听,等待连接
        //  细节: 要求在本机没有其他服务监听9999
        //  细节: 这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端, 在9999端口监听, 等待连接..");
        //2. 当没有客户端连接9999端口时, 程序会阻塞, 等待连接
        //   如果有客户端连接, 则会返回Socket对象, 程序继续
        Socket socket = serverSocket.accept();

        System.out.println("服务端 socket =" + socket.getClass());
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while((readLen = inputStream.read(buf)) != -1){
            System.out.println(new String(buf, 0, readLen));  //根据读取到的实际长度, 显示内容。
        }
        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, client".getBytes());
        //  设置结束标记
        socket.shutdownOutput();

        //6. 关闭流和socket
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();   //关闭
    }
}

SocketTCP02Client.java

package com.hspedu.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 客户端, 发送 "hello, sever" 给服务器
 */
@SuppressWarnings({"all"})
public class SocketTCP02Client {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 连接服务端(ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功, 返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后, 生成Socket, 通过socket.getOutputStream()
        //  得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();

        //3. 通过输出流, 写入数据到 数据通道
        outputStream.write("hello, server".getBytes());
        //   设置写入结束标记
        socket.shutdownOutput();

        //4. 获取和socket关联的输入流, 读取数据(字节), 并显示
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while((readLen = inputStream.read(buf)) != -1){
            System.out.println(new String(buf, 0, readLen));
        }

        //5. 关闭流对象和socket, 必须关闭
        inputStream.close();
        outputStream.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}

  • 应用案例3(使用字符流)
    在这里插入图片描述

SocketTCP03Server.java

package com.hspedu.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
* 服务端, 使用字符流方式读写
*/
@SuppressWarnings({"all"})
public class SocketTCP03Server {
   public static void main(String[] args) throws IOException {
       //思路
       //1. 在本机 的9999端口监听,等待连接
       //  细节: 要求在本机没有其他服务监听9999
       //  细节: 这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
       ServerSocket serverSocket = new ServerSocket(9999);
       System.out.println("服务端, 在9999端口监听, 等待连接..");
       //2. 当没有客户端连接9999端口时, 程序会阻塞, 等待连接
       //   如果有客户端连接, 则会返回Socket对象, 程序继续
       Socket socket = serverSocket.accept();

       System.out.println("服务端 socket =" + socket.getClass());
       //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
       InputStream inputStream = socket.getInputStream();
       //4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
       String s = bufferedReader.readLine();
       System.out.println(s);  //输出

       //5. 获取socket相关联的输出流
       OutputStream outputStream = socket.getOutputStream();
       //      使用字符输出流的方式回复信息
       BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
       bufferedWriter.write("hello client 字符流");
       bufferedWriter.newLine();   //插入一个换行符, 表示回复内容的结束
       bufferedWriter.flush(); //注意需要手动的刷新

       //6. 关闭流和socket
       bufferedWriter.close();
       bufferedReader.close();
       socket.close();
       serverSocket.close();   //关闭
   }
}

SocketTCP03Client.java

package com.hspedu.socket;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 客户端, 发送 "hello, sever" 给服务器, 使用字符流
 */
@SuppressWarnings({"all"})
public class SocketTCP03Client {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 连接服务端(ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功, 返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后, 生成Socket, 通过socket.getOutputStream()
        //  得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();

        //3. 通过输出流, 写入数据到 数据通道, 使用字符流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello, server 字符流");
        bufferedWriter.newLine();   //插入一个换行符, 表示写入的内容结束, 注意, 要求对方使用readLine()!!!!
        bufferedWriter.flush(); //  如果使用的字符流, 需求手动刷新, 否则数据不会写入数据通道


        //4. 获取和socket关联的输入流, 读取数据(字节), 并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 关闭流对象和socket, 必须关闭
        bufferedReader.close();     //关闭外层流
        bufferedWriter.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}

  • 应用案例4 TCPFileUploadServer.java TCPFileUploadClient.java

在这里插入图片描述
TCPFileUploadServer.java

package com.hspedu.upload;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 文件上传的服务器
 */
public class TCPFileUploadServer {
    public static void main(String[] args) throws Exception {

        //1. 服务端在本机监听8888端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端在8888端口监听....");
        //2. 等待连接
        Socket socket= serverSocket.accept();

        //3. 读取客户端发送的数据
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //4. 将得到bytes数组, 写入到指定的路径, 就得到一个文件了
        String destFilePath = "src\\th.jpg";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
        bos.write(bytes);
        bos.close();

        // 向客户端回复 "收到图片"
        // 通过socket 获取到输出流(字符)
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        writer.write("收到图片");
        writer.flush();    //把内容刷新到数据通道
        socket.shutdownOutput();    //设置写入结束标记

        //关闭其他资源
        writer.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}

TCPFileUploadClient.java

package com.hspedu.upload;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 文件上传的客户端
 */
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {

        //客户端连接服务器8888, 得到Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        //创建读取磁盘文件的输入流
        String filePath = "e:\\th.jpg";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));

        //bytes 就是filePath对应的字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);

        //通过socket获取到输出流, 将bytes数据发送到服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        bos.write(bytes);   //将文件对应的字节数组内容, 写入到数据通道
        bis.close();
        socket.shutdownOutput();    //设置写入数据的结束标记

        //====接收从服务端回复的消息

        InputStream inputStream = socket.getInputStream();
        //使用StreamUtils 的方法, 直接将inputStream 读取到的内容 转成字符串
        String s = StreamUtils.streamToString(inputStream);
        System.out.println(s);

        //关闭相关的流
        inputStream.close();
        bos.close();
        socket.close();
    }
}

StreamUtils.java

package com.hspedu.upload;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
	/**
	 * 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
	 * @param is
	 * @return
	 * @throws Exception
	 */
	public static byte[] streamToByteArray(InputStream is) throws Exception{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
		byte[] b = new byte[1024];//字节数组
		int len;
		while((len=is.read(b))!=-1){//循环读取
			bos.write(b, 0, len);//把读取到的数据,写入bos	
		}
		byte[] array = bos.toByteArray();//然后将bos 转成字节数组
		bos.close();
		return array;
	}
	/**
	 * 功能:将InputStream转换成String
	 * @param is
	 * @return
	 * @throws Exception
	 */
	
	public static String streamToString(InputStream is) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder builder= new StringBuilder();
		String line;
		while((line=reader.readLine())!=null){		//当读取到 null时, 就表示结束
			builder.append(line+"\r\n");
		}
		return builder.toString();
		
	}

}


  • netstat 指令
    在这里插入图片描述
  • TCP网络通讯不为人知的秘密
    在这里插入图片描述在这里插入图片描述

UDP网络通信编程【了解

  • 基本介绍
    在这里插入图片描述
  • 基本流程
    在这里插入图片描述
    在这里插入图片描述
  • 应用案例
    在这里插入图片描述在这里插入图片描述

UDPReceiverA.java

package com.hspedu.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * UDP接收端
 */
@SuppressWarnings({"all"})
public class UDPReceiverA {
    public static void main(String[] args) throws IOException {
        //1. 创建一个 DatagramSocket 对象, 准备在9999接收数据
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 构建一个 DatagramPacket 对象, 准备接收数据
        //    在前面讲解UDP协议时, 老师说过一个数据包最大 64K
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3. 调用接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //老师提示: 当有数据包发送到 本机的9999端口时, 就会接收到数据
        //    如果没有数据包发送到 本机的9999端口, 就会阻塞等待.
        System.out.println("接收端A 等待接收数据..");
        socket.receive(packet);

        //4. 可以把packet 进行拆包, 取出数据, 并显示.
        int length = packet.getLength();    //实际接收到的数据字节长度
        byte[] data = packet.getData();     //接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //===回复信息给B端

        //将需要发送的数据, 封装到 DatagramPacket对象
        data = "好的, 明天见".getBytes();//InetAddress.getByName("192.168.0.10")

        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.10"), 9998);

        socket.send(packet);    //发送

        //5. 关闭资源
        socket.close();
        System.out.println("A端退出...");
    }
}

UDPSenderB.java

package com.hspedu.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 发送端 B ====> 也可以接收数据
 */
@SuppressWarnings({"all"})
public class UDPSenderB {
    public static void main(String[] args) throws IOException {

        //1.创建 DatagramSocket 对象, 准备在9998端口 接收数据
        DatagramSocket socket = new DatagramSocket(9998);

        //2. 将需要发送的数据, 封装到 DatagramPacket对象
        byte[] data = "hello 明天吃火锅~".getBytes();    //InetAddress.getByName("192.168.0.10")

        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.10"), 9999);

        socket.send(packet);

        //3.=== 接收从A端回复的信息
        //(1)    构建一个 DatagramPacket 对象, 准备接收数据
        //    在前面讲解UDP协议时, 老师说过一个数据包最大 64K
        byte[] buf = new byte[1024];
        packet = new DatagramPacket(buf, buf.length);
        //(2)   调用接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //老师提示: 当有数据包发送到 本机的9998端口时, 就会接收到数据
        //    如果没有数据包发送到 本机的9998端口, 就会阻塞等待.
        socket.receive(packet);

        //(3) 可以把packet 进行拆包, 取出数据, 并显示.
        int length = packet.getLength();    //实际接收到的数据字节长度
        data = packet.getData();     //接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //关闭资源
        socket.close();
        System.out.println("B端退出");
    }
}

第22章 多用户即时通信系统

没有做出如下的界面, 但实现了相对应的功能(代码较多先不粘贴在这里(准备后来放入github中))

QQ聊天项目演示

  • 项目QQ演示
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

项目开发流程

  • 为什么选择这个项目
    在这里插入图片描述
  • 项目开发流程
    在这里插入图片描述
  • 需求分析
    在这里插入图片描述
  • 界面设计
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • 功能实现-用户登录
    在这里插入图片描述在这里插入图片描述
  • 功能实现 - 拉去在线用户列表
    在这里插入图片描述
  • 功能实现-无异常退出
    在这里插入图片描述
  • 功能实现-私聊
    在这里插入图片描述在这里插入图片描述
  • 功能实现-群聊
    在这里插入图片描述
  • 功能说明-发文件
    在这里插入图片描述
    在这里插入图片描述
  • 功能实现-服务器推送新闻
    在这里插入图片描述在这里插入图片描述
  • 多用户即时通信系统
    在这里插入图片描述

第23章 反射(reflection)

一个需求引出反射

  • 快速入门
    在这里插入图片描述

ReflectionQuestion.java

package com.hspedu.reflection.question;

import com.hspedu.Cat;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 反射问题的引入
 */
@SuppressWarnings({"all"})
public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        //根据配置文件 re.properties 指定信息, 创建Cat对象并调用方法hi

        //传统方式 new 对象 -> 调用方法
        //Cat cat = new Cat();
        //cat.hi(); ===> cat.cry() 修改源码完成类其他函数的调用

        //我们尝试做一做 -> 明白反射

        //1. 使用Properties 类, 可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();  //"com.hspedu.Cat"
        String methodName = properties.get("method").toString();    //"hi"
        System.out.println("classfullpath=" + classfullpath);
        System.out.println("method=" + methodName);

        //2. 创建对象 , 传统的方法, 行不通 => 反射机制
        //new classfullpath();  错,类型为String不是类路径

        //3. 使用反射机制解决
        //(1) 加载类, 返回Class类型的对象cls
        Class cls = Class.forName(classfullpath);
        //(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例
        Object o = cls.newInstance();
        System.out.println("o的运行类型=" + o.getClass());   //运行类型
        //(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName "hi" 的方法对象
        //      即: 在反射中, 可以把方法视为对象 (万物皆对象)
        Method method1 = cls.getMethod(methodName);
        //(4) 通过method1 调用方法: 即通过方法对象来实现调用方法
        System.out.println("======================");
        method1.invoke(o);  //传统方法 对象方法() , 反射机制 方法. invoke(对象)

    }
}

反射机制

  • Java Reflection
    在这里插入图片描述

  • Java反射机制原理示意图
    在这里插入图片描述

  • Java反射机制可以完成
    在这里插入图片描述

  • 反射相关的主要类
    在这里插入图片描述

Reflection01.java

package com.hspedu.reflection.question;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;


@SuppressWarnings({"all"})
public class Reflection01 {
   public static void main(String[] args) throws Exception {

       //1. 使用Properties 类, 可以读写配置文件
       Properties properties = new Properties();
       properties.load(new FileInputStream("src\\re.properties"));
       String classfullpath = properties.get("classfullpath").toString();  //"com.hspedu.Cat"
       String methodName = properties.get("method").toString();    //"hi"


       //2. 使用反射机制解决
       //(1) 加载类, 返回Class类型的对象cls
       Class cls = Class.forName(classfullpath);
       //(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例
       Object o = cls.newInstance();
       System.out.println("o的运行类型=" + o.getClass());   //运行类型
       //(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName "hi" 的方法对象
       //      即: 在反射中, 可以把方法视为对象 (万物皆对象)
       Method method1 = cls.getMethod(methodName);
       //(4) 通过method1 调用方法: 即通过方法对象来实现调用方法
       System.out.println("======================");
       method1.invoke(o);  //传统方法 对象方法() , 反射机制 方法. invoke(对象)

       //java.lang.reflect.Field: 代表类的成员变量, Field对象表示某个类的成员变量
       //得到name字段
       //getField不能得到私有的属性
       Field nameField = cls.getField("age");   //
       System.out.println(nameField.get(o));   //传统写法 对象,成员变量 , 反射 : 成员变量.get(对象)

       //java.lang.reflect.Constructor: 代表类的构造方法, Constructor对象表示构造器
       Constructor constructor = cls.getConstructor(); //()中可以指定构造器参数类型, 返回无参构造器
       System.out.println(constructor);    //Cat()


       Constructor constructor2 = cls.getConstructor(String.class);//这里传入的String.class 就是String类的Class对象
       System.out.println(constructor2);   //Cat(String name)
   }
}

Cat.class

package com.hspedu;

/**
 * @author zt
 * @version 1.0
 */
public class Cat {

    private String name = "招财猫";
    public int age = 10; //public 的

    public Cat() {}    //无参构造器

    public Cat(String name) {
        this.name = name;
    }

    public void hi() {  //常见方法
        System.out.println("hi " + name);
    }

    public void cry() { //常用方法
        System.out.println(name + "喵喵叫..");
    }
}

  • 反射优点和缺点
    在这里插入图片描述

Reflection02.java

package com.hspedu.reflection;

import com.hspedu.Cat;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 测试反射调用的性能, 和优化方案
 */
public class Reflection02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        m1();
        m2();
        m3();
    }

    //传统方法来调用hi

    public static void m1() {

        Cat cat = new Cat();
        long start = System.currentTimeMillis();
        for(int i = 0; i < 900000000; i++){
            cat.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法来调用hi(m1()调用) 耗时=" + (end - start));
    }

    //反射机制调用方法hi
    public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        Class cls = Class.forName("com.hspedu.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        long start = System.currentTimeMillis();
        for(int i = 0; i < 900000000; i++){
            hi.invoke(o);   //反射调用方法
        }
        long end = System.currentTimeMillis();
        System.out.println("反射方式来调用hi(m2()调用) 耗时=" + (end - start));
    }

    //反射调用优化 + 关闭访问检查
    public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        Class cls = Class.forName("com.hspedu.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        hi.setAccessible(true); //在反射调用方法时, 取消访问检查
        long start = System.currentTimeMillis();
        for(int i = 0; i < 900000000; i++){
            hi.invoke(o);   //反射调用方法
        }
        long end = System.currentTimeMillis();
        System.out.println("优化反射方式来调用hi(m3()调用) 耗时=" + (end - start));
    }

}

结果:
速度:普通调用>反射优化(关闭访问检查)>反射

  • 反射调用优化-关闭访问检查
    在这里插入图片描述在这里插入图片描述

Class类

  • 基本介绍
    在这里插入图片描述在这里插入图片描述
    Class01.java
package com.hspedu.reflection.class_;

import com.hspedu.Cat;

/**
 * 对Class类特点的梳理
 */
@SuppressWarnings({"all"})
public class Class01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //看看Class类图
        //1. Class也是类, 因此也继承Object类
        //Class
        //2. Class类对象不是new出来的, 而是系统创建的
        //(1) 传统new对象
        /*  ClassLoader类
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                    return loadClass(name, false);
                }
         */
        //Cat cat = new Cat();
        //(2) 反射方式, 刚才没有debug到 ClassLoader类的 loadClass, 原因是, 我没有注销Cat cat = new Cat();
        //已经进行了类的加载
        /*
                ClassLoader类, 仍然是通过 ClassLoader类加载Cat类的 Class对象
                public Class<?> loadClass(String name) throws ClassNotFoundException {
                        return loadClass(name, false);
                    }
         */
        Class cls1 = Class.forName("com.hspedu.Cat");

        //3. 对于某个类的Class类对象, 在内存中只有一份, 因为类只加载一次
        Class cls2 = Class.forName("com.hspedu.Cat");
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        Class cls3 = Class.forName("com.hspedu.Dog");
        System.out.println(cls3.hashCode());
    }
}

  • Class类的常用方法
    在这里插入图片描述
    应用实例: Class02.java
package com.hspedu.reflection.class_;

import com.hspedu.Car;

import java.lang.reflect.Field;

/**
 * 演示Class类的常用方法
 */
public class Class02 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {

        String classAllPath = "com.hspedu.Car";
        //1.    获取到Car类 对应的 Class对象
        //<?> 表示不确定的Java类型
        Class<?> cls = Class.forName(classAllPath);
        //2.    输出cls
        System.out.println(cls);       //显示cls对象, 是哪个类的Class对象 com.hspedu.car
        System.out.println(cls.getClass());     //输出cls运行类型 java.lang.Class
        //3.    得到包名
        System.out.println(cls.getPackage().getName()); //包名
        //4.     得到类名
        System.out.println(cls.getName());
        //5.    通过cls创建对象实例
        Car car = (Car)cls.newInstance();
        System.out.println(car);    //car.toString()
        //6. 通过反射获取属性 brand
        Field brand = cls.getField("brand");
        System.out.println(brand.get(car));     //宝马
        //7. 通过反射给属性赋值
        brand.set(car, "奔驰");
        System.out.println(brand.get(car));     //奔驰
        //8. 希望得到所有的属性(字段)
        System.out.println("=====所有的字段属性=====");
        Field[] fields = cls.getFields();
        for(Field f : fields){
            System.out.println(f.getName());    //名称
        }
    }
}

获取Class类对象

在这里插入图片描述在这里插入图片描述在这里插入图片描述
GetClass_.java

package com.hspedu.reflection.class_;

import com.hspedu.Car;

/**
 * 演示得到Class对象的各种方式(6)
 */
public class GetClass_ {
    public static void main(String[] args) throws ClassNotFoundException {

        //1. Class.forName
        String classAllPath = "com.hspedu.Car"; //通过读取配置文件读取
        Class<?> cls1 = Class.forName(classAllPath);
        System.out.println(cls1);

        //2. 类名.class , 应用场景: 用于参数传递
        Class cls2 = Car.class;
        System.out.println(cls2);

        //3. 对象.getClass(), 应用场景, 有对象实例
        Car car = new Car();
        Class cls3 = car.getClass();
        System.out.println(cls3);

        //4. 通过类加载器【4种】来获取到类的Class对象
        //(1)先得到类加载器 car
        ClassLoader classLoader = car.getClass().getClassLoader();
        //(2)通过类加载器得到Class对象
        Class cls4 = classLoader.loadClass(classAllPath);
        System.out.println(cls4);

        //cls1 , cls2 , cls3 , cls4 其实是同一个对象
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        System.out.println(cls3.hashCode());
        System.out.println(cls4.hashCode());

        //5. 基本数据(int, char, boolean, float, double, byte, long, short) 按如下方式得到Class类对象
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        Class<Boolean> booleanClass = boolean.class;
        //底层是自动装箱(类转基本)
        System.out.println(integerClass);   //int

        //6. 基本数据类型对应的包装类, 可以通过 .TYPE 得到Class类对象
        Class<Integer> type1 = Integer.TYPE;
        Class<Character> type2 = Character.TYPE;    //其他包装类BOOLEAN, DOUBLE, LONG, BYTE等待
        System.out.println(type1);  //int

        System.out.println(integerClass.hashCode());
        System.out.println(type1.hashCode());
    }
}

哪些类型有Class对象

  • 如下类型有Class对象
    在这里插入图片描述
    应用实例 AllTypeClass.java
package com.hspedu.reflection.class_;

import java.io.Serializable;

/**
 * 演示哪些类型有Class对象
 */
public class AllTypeClass {
    public static void main(String[] args) {

        Class<String> cls1 = String.class;  //外部类
        Class<Serializable> cls2 = Serializable.class; //接口
        Class<Integer[]> cls3 = Integer[].class;  //数组
        Class<float[][]> cls4 = float[][].class;  //二维数组
        Class<Deprecated> cls5 = Deprecated.class;  //注解
        //枚举
        Class<Thread.State> cls6 = Thread.State.class;
        Class<Long> cls7 = long.class;  //基本数据类型
        Class<Void> cls8 = void.class;  //void数据类型
        Class<Class> cls9 = Class.class;    

        System.out.println(cls1);
        System.out.println(cls2);
        System.out.println(cls3);
        System.out.println(cls4);
        System.out.println(cls5);
        System.out.println(cls6);
        System.out.println(cls7);
        System.out.println(cls8);
        System.out.println(cls9);
    }
}

类加载

  • 基本说明
    在这里插入图片描述ClassLoad_.java
import java.util.*;
import java.lang.reflect.*;
public class ClassLoad_{

	public static void main(String[] args) throws Exception{

		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入key");
		String key = scanner.next();
		switch(key) {
			case "1" :
				Dog dog = new Dog();	//静态加载, 依赖性很强
				dog.cry();
				break;
			case "2" :
				//反射-> 动态加载
				Class cls = Class.forName("Person");	//加载Person类[动态加载]
				Object o = cls.newInstance();
				Method m = cls.getMethod("hi");
				m.invoke(o);
				System.out.println("ok");
				break;
			default:
				System.out.println("do nothing..");	
		}
	}
}

//因为new Dog() 是静态加载, 因此必须编写Dog
//Person类是动态加载, 所以, 没有编写Person类也不会报错, 只有当动态加载该类时, 才会报错
class Dog {
	public void cry() {
		System.out.println("小狗汪汪加...");
	}
}

class Person{
	public void hi() {
		System.out.println("小孩 hi");
	}
}
  • 类加载时机
    在这里插入图片描述
  • 类加载过程图
    在这里插入图片描述
  • 类加载各阶段完成任务
    在这里插入图片描述
  • 加载阶段
    在这里插入图片描述
  • 连接阶段- 验证
    在这里插入图片描述
  • 连接阶段 - 准备
    在这里插入图片描述
    ClassLoad02.java
   package com.hspedu.reflection.classload_;

/**
 * 说明一个类加载的连接阶段-准备
 */
public class ClassLoad02 {
    public static void main(String[] args) {

    }
}

class A {
    //属性-成员变量-字段
    //分析类加载的连接阶段-准备 属性是如何处理
    //1. n1 是实例属性, 不是静态变量, 因此在准备阶段, 是不会分配内存
    //2. n2 是静态变量, 分配内存 n2 是默认初始化 0, 而不是20
    //3. n3 是static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30
    public int n1 = 10;
    public static int n2 = 20;
    public static final int n3 = 30;
}
  • 连接阶段-解析
    在这里插入图片描述
  • Initialization(初始化)

在这里插入图片描述
ClassLoad03.java

package com.hspedu.reflection.classload_;

/**
 * 演示类加载-初始化阶段
 */
public class ClassLoad03 {
    public static void main(String[] args) throws ClassNotFoundException {
        //分析
        //1. 加载B类, 并生成 B的class对象
        //2. 链接 num = 0;
        //3. 初始化阶段
        //      依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并合并
        /*      //clinit收集
                clinit() {
                    System.out.println("B 静态代码块被执行");
                    //num = 300;
                    num = 100;
                }
                合并: num = 100
         */
        //4. "B() 构造器被执行"
        //new B();    //类加载
        //System.out.println(B.num);  //100, 如果直接使用类的静态属性, 也会导致类的加载

        //看看加载类的时候, 是有同步机制控制
        /*
            protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
        {
            //正因为有这个机制, 才能某个类在内存中, 只有一份Class对象
            synchronized (getClassLoadingLock(name)) {
            //....
            }
            }
         */
        B b = new B();
    }
}

class B {
    static {
        System.out.println("B 静态代码块被执行");
        num = 300;
    }

    static int num = 100;
    public B() {    //构造器
        System.out.println("B() 构造器被执行");
    }
}

通过反射获取类的结构信息

  • 第一组:java.lang.Class类
    在这里插入图片描述
  • 第二组:java.lang.reflect.Field类
    在这里插入图片描述
  • 第三组:java.lang.reflect.Method类
    在这里插入图片描述
  • 第四组:java.lang.reflect.Constructor类
    在这里插入图片描述
    案例:
    ReflectionUtils.java
package com.hspedu.reflection;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 演示如何通过反射获取类的结构信息
 */
public class RefectionUtils {
    public static void main(String[] args) {

    }

    @Test
    public void api_02() throws ClassNotFoundException, NoSuchMethodException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.hspedu.reflection.Person");
        //getDeclaredFields:获取本类中所有属性
        //规定 说明: 默认修饰符 是0, public 是 1 , private 是 2 , protected 是 4 , static 是 8 , final 是 16
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性=" + declaredField.getName()
            + " 该属性的修饰符值=" + declaredField.getModifiers()
            + " 该属性的类型=" + declaredField.getType());
        }

        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法=" + declaredMethod.getName()
            + " 该方法的访问修饰符值=" + declaredMethod.getModifiers()
            + " 该方法返回类型" + declaredMethod.getReturnType());

            //输出当前这个方法的形参数组情况
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("该方法的形参类型=" + parameterType);
            }
        }

        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("=================");
            System.out.println("本类中所有构造器=" + declaredConstructor.getName());    //这里只是输出名

            Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("该构造器的形参类型=" + parameterType);
            }
        }

    }

        @Test
    //第一组方法API
    public void api_01() throws ClassNotFoundException, NoSuchMethodException {

        //得到Class对象
        Class<?> personCls = Class.forName("com.hspedu.reflection.Person");
        //getName: 获取全类名
        System.out.println(personCls.getName());    //com.hspedu.reflection.Person
        //getSimpleName: 获取简单类名
        System.out.println(personCls.getSimpleName());  //Person
        //getFields:获取所有public修饰的属性, 包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {    //增强for
            System.out.println("本类以及父类的public属性=" + field.getName());
        }
        //getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性=" + declaredField.getName());
        }
        //getMethods:获取所有public修饰的方法, 包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println("本类以及父类的public方法=" + method.getName());
        }
        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法=" + declaredMethod.getName());
        }
        //getConstructors: 获取所有public修饰的构造器, 包含本类
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("本类的构造器=" + constructor.getName());
        }
        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("本类中所有构造器=" + declaredConstructor.getName());    //这里只是输出名
        }
        //getPackage:以Package形式返回 包信息
        System.out.println(personCls.getPackage());   //com.hspedu.reflection
        //getSuperClass:以Class形式返回父类信息
        Class<?> superclass = personCls.getSuperclass();
        System.out.println("父类的class对象=" + superclass);
        //getInterfaces:以Class[]形式返回接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("接口信息=" + anInterface);
        }
        //getAnnotations:以Annotation[] 形式返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("注解信息=" + annotation);
        }
    }
}

class A {
    public String hobby;
    public void hi(){

    }
    public A(){

    }
}

interface IA {

}

interface IB {

}

@Deprecated
class Person extends A implements IA, IB {
    //属性
    public String name;
    protected static int age;   // 4 + 8 = 12
    String job;
    private double sal;

    //构造器
    public Person() {}
    public Person(String name)  {

    }
    //私有的
    private Person(String name, int age) {

    }
    //方法
    public void m1(String name, int age, double sal) {

    }

    protected String m2() {
        return null;
    }

    void m3() {

    }

    private void m4() {

    }
}

通过反射创建对象

在这里插入图片描述

  • 案例演示 com.hspedu.reflection
    ReflecCreateInstance.java
    测试1: 通过反射创建某类的对象, 要求该类中必须有public的无参构造
    测试2: 通过调用某个指定构造器的方式, 实现创建某类的对象

ReflecCreateInstance.java

package com.hspedu.reflection;

import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 演示通过反射机制创建实例
 */
public class ReflecCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        //1. 先获取到User类的Class对象
        Class<?> userClass = Class.forName("com.hspedu.reflection.User");
        //2. 通过public的无参构造器创建实例
        Object o = userClass.newInstance();
        System.out.println(o);
        //3. 通过public的有参构造器创建实例
        /*
            constructor 对象就是
            public User(String name) {//public的有参构造器
                this.name = name;
            }
         */
        //3.1 先得到对应构造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        //3.2 创建实例, 并传入实参
        Object hsp = constructor.newInstance("hsp");
        System.out.println("hsp=" + hsp);
        //4. 通过非public的有参构造器创建实例
        //4.1 得到private的构造器对象
        Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);
        //4.2 创建实例
        //暴破【暴力破解】 , 使用反射可以访问private构造器/方法/属性, 反射面前, 都是纸老虎
        constructor1.setAccessible(true);
        Object user2 = constructor1.newInstance(100, "张三丰");
        System.out.println("user2=" + user2);
    }
}

class User { //User类
    private int age = 10;
    private String name = "韩顺平教育";

    public User() {//无参 public
    }

    public User(String name) {//public的有参构造器
        this.name = name;
    }

    private User(int age, String name) {//private 有参构造器
        this.age = age;
        this.name = name;
    }

    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

通过反射访问类中的成员

  • 访问属性 ReflectAccessProperty.java

在这里插入图片描述
ReflectAccessProperty.java

package com.hspedu.reflection;

import java.lang.reflect.Field;

/**
 * 演示反射操作属性
 */
public class ReflecAccessProperty {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {

        //1. 得到Student类对应的 Class对象
        Class<?> stuClass = Class.forName("com.hspedu.reflection.Student");
        //2. 创建对象
        Object o = stuClass.newInstance();  //o 的运行类型就是Student
        System.out.println(o.getClass());   //Student
        //3. 使用反射得到age 属性对象
        Field age = stuClass.getField("age");
        age.set(o, 88); //通过反射来操作属性
        System.out.println(o);
        System.out.println(age.get(o)); //返回age属性的值

        //4. 使用反射操作name 属性
        Field name = stuClass.getDeclaredField("name");
        //对name 进行暴破, 可以操作private 属性
        name.setAccessible(true);
        //name.set(o, "老韩");
        name.set(null, "老韩~");  //因为name是static属性, 因此 o 也可以写出null
        System.out.println(o);  //获取属性值
        System.out.println(name.get(o)); //获取属性值
        System.out.println(name.get(null)); //获取属性值, 要求name是static
    }
}

class Student {//类
    public int age;
    private static String name;

    public Student() {//构造器
    }

    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }
}


  • 访问方法 ReflectAccessMethod.java
    在这里插入图片描述
    ReflectAccessMethod.java
package com.hspedu.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 演示通过反射调用方法
 */
public class ReflecAccessMethod {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        //1. 得到Boss类对应的Class对象
        Class<?> bossCls = Class.forName("com.hspedu.reflection.Boss");
        //2. 创建对象
        Object o = bossCls.newInstance();
        //3. 调用public的hi方法
        //Method hi = bossCls.getMethod("hi", String.class);  //上下两种方式皆可
        //3.1 得到hi方法对象
        Method hi = bossCls.getDeclaredMethod("hi", String.class);
        //3.2 调用
        hi.invoke(o, "韩顺平教育~");

        //4. 调用private static 方法
        //4.1 得到 say 方法对象
        Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
        //4.2 因为say方法是private, 所以需要暴破, 原理和前面的构造器和属性一样
        say.setAccessible(true);
        System.out.println(say.invoke(o, 100, "张三", '男'));
        //4.3 因为say方法是static的, 还可以这样调用 , 可以和传入null
        System.out.println(say.invoke(null, 200, "李四", '女'));

        //5. 在反射中, 如果方法有返回值, 统一返回Object , 但是他运行类型和方法定义的返回类型一致
        Object reVal = say.invoke(null, 300, "王五", '男');
        System.out.println("reVal 的运行类型" + reVal.getClass());   //String
        
    }
}

class Boss {    //类
    public int age;
    private static String name;

    public Boss() { //构造器
    }

    private static String say(int n, String s, char c) {    //静态方法
        return n + " " + s + " " + c;
    }

    public void hi(String s) {  //普通public方法
        System.out.println("hi " + s);
    }
}

第24章 零基础学MySQL(正在学习)

一个问题(引出概念)

在这里插入图片描述

解决之道(引出概念)

  • 解决之道-文件、数据库
    在这里插入图片描述
  • MySQL 数据库的安装和配置(安装演示)
    在这里插入图片描述在这里插入图片描述
  • 使用命令行窗口连接MySQL数据库[示意图]
    在这里插入图片描述
  • 操作示意图
    在这里插入图片描述

Navicat 安装和使用

  • 介绍 : 图形化MySQL管理软件
    在这里插入图片描述

  • 下载&安装&使用
    在这里插入图片描述

  • 演示: 使用Navicat 创建一个数据库 db01, 在db01创建一张表users, 保存3个用户

  • 老韩扩: 我使用命令行完成

SQLyog[SQLyog] 安装和使用

  • 介绍:图形化MySQL管理软件
    在这里插入图片描述
  • 下载&安装&使用
    在这里插入图片描述
  • 演示: 使用SQLyog创建一个数据库 db01, 在db01创建一张表user, 保存3个用户

数据库三层结构-破除MySQL神秘

在这里插入图片描述在这里插入图片描述

数据在数据库中的存储方式

在这里插入图片描述

SQL语句分类

在这里插入图片描述

创建数据库

在这里插入图片描述

查看、删除数据库

在这里插入图片描述

备份恢复数据库

在这里插入图片描述

备份恢复数据库的表

在这里插入图片描述

安装Ecshop数据库

在这里插入图片描述

创建表(按课程大纲顺序)

在这里插入图片描述

Mysql常用数据类型(列类型)

在这里插入图片描述

数值型(整数)的基本使用

在这里插入图片描述

  • 型如何定义一个无符号的整数
    在这里插入图片描述

数值型(bit)的使用

在这里插入图片描述

  • 数值型(小数)的基本使用
    在这里插入图片描述

字符串的基本使用

在这里插入图片描述

  • 字符串使用细节
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

日期类型的基本使用

在这里插入图片描述

创建表练习

在这里插入图片描述

修改表-基本介绍

在这里插入图片描述

修改表-课堂练习

在这里插入图片描述

数据库C[create]R[read]U[update]D[delete]语句

在这里插入图片描述

Insert语句

  • 使用INSERT语句向表中插入数据。 insert.sql

    在这里插入图片描述

  • 学员练习: 使用insert语句向表employee中插入2个员工的信息
    在这里插入图片描述
  • 细节说明 insertdetail.sql

update语句

  • 使用update语句修改表中数据
    在这里插入图片描述
  • 基本使用 update.sql
    在这里插入图片描述
  • 使用细节:
    在这里插入图片描述

delete语句

  • 使用delete语句删除表中数据
    在这里插入图片描述
  • 使用细节
    在这里插入图片描述

select语句

  • 基本语法
    在这里插入图片描述
  • 注意事项(创建测试表学生表)
    在这里插入图片描述
  • 课堂练习:select01.sql
    在这里插入图片描述
  • 使用表达式对查询的列进行运算
    在这里插入图片描述
  • 在select语句中可使用as语句
    在这里插入图片描述
  • 练习 select02.sql

在这里插入图片描述

  • 在where子句中经常使用的运算符

在这里插入图片描述

  • 使用where子句, 进行过滤查询 select03.sql
    在这里插入图片描述
  • 课堂练习
    在这里插入图片描述

  • 使用order by 子句排序查询结果

在这里插入图片描述

合计/统计函数

  • count
    在这里插入图片描述
  • sum
    在这里插入图片描述
  • avg
    在这里插入图片描述
  • max/min
    在这里插入图片描述
  • 使用group by子句对列进行分组[先创建测试表]
    在这里插入图片描述
  • 使用having子句对分组后的结果进行过滤
    在这里插入图片描述在这里插入图片描述

字符串相关函数

在这里插入图片描述

数学相关函数

在这里插入图片描述

时间日期相关函数 date.sql

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

加密和系统函数 pwd.sql

在这里插入图片描述

流程控制函数

在这里插入图片描述在这里插入图片描述

mysql表查询–加强

  • 介绍
    在这里插入图片描述
  • 分页查询
    在这里插入图片描述
  • 使用分组函数和分组子句 group by

在这里插入图片描述

  • 数据分组的总结
    在这里插入图片描述

mysql多表查询

  • 问题的引出(重点, 难点)
    在这里插入图片描述
  • 说明
    在这里插入图片描述
  • 多表查询练习 many_tab.sql
    在这里插入图片描述
  • 自连接
    在这里插入图片描述

mysql表子查询

  • 什么是子查询 subquery.sql
    子查询是指嵌入在其它sql语句中的select语句, 也叫嵌套查询

  • 单行子查询
    单行子查询是指只返回一行数据的子查询语句

  • 请思考: 如何显示与SMITH同一部门的所有员工?

  • 多行子查询
    在这里插入图片描述

  • 子查询当做临时表使用 练习题 subquery.sql
    在这里插入图片描述
  • 在多行子查询中使用all操作符
    在这里插入图片描述
  • 在多行子查询中使用any操作符
    在这里插入图片描述
  • 多列子查询 manycolumn.sql
    在这里插入图片描述
  • 在from子句中使用子查询 subquery03.sql
    在这里插入图片描述
  • 在from子句中使用子查询—课堂小练习
    在这里插入图片描述

表复制

  • 自我复制数据(蠕虫复制)
    在这里插入图片描述

合并查询

  • 介绍
    在这里插入图片描述在这里插入图片描述

mysql表外连接

  • 提出一个问题
    在这里插入图片描述
  • 外连接
    在这里插入图片描述
  • 课堂练习
    在这里插入图片描述

mysql约束

  • 基本介绍
    在这里插入图片描述
  • primary key(主键)-基本使用
    在这里插入图片描述
  • not null(非空)
    在这里插入图片描述
  • unique(唯一)
    在这里插入图片描述
  • foreign key(外键)
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • check
    在这里插入图片描述
  • 商店售货系统表设计案例
    在这里插入图片描述

自增长

  • 自增长基本介绍 一个问题
    在这里插入图片描述
  • 自增长使用细节
    在这里插入图片描述

mysql索引

  • 索引快速入门
    在这里插入图片描述
  • 索引的原理
    在这里插入图片描述
  • 索引的类型
    在这里插入图片描述
  • 索引使用
    在这里插入图片描述
  • 索引课堂练习
    在这里插入图片描述
  • 小结: 哪些列上适合使用索引
    在这里插入图片描述

mysql事物

  • 什么是事务
    在这里插入图片描述在这里插入图片描述
  • 事务和锁
    在这里插入图片描述
  • 回退事务
    在这里插入图片描述
  • 提交事务
    在这里插入图片描述
  • 事务细节讨论 transaction_detail.sql
    在这里插入图片描述

mysql事务隔离级别

  • 事务隔离级别介绍
    在这里插入图片描述
  • 查看事务隔离级别
    在这里插入图片描述
  • 事务隔离级别
    在这里插入图片描述
  • mysql的事务隔离级–案例
    在这里插入图片描述
  • 设置事务隔离级别
    在这里插入图片描述在这里插入图片描述

mysql事务ACID

  • 事务的acid特性
    在这里插入图片描述
  • 事务的课堂练习
    在这里插入图片描述

mysql表类型和存储引擎

  • 基本介绍
    在这里插入图片描述
  • 主要的存储引擎/表类型特点
    在这里插入图片描述
  • 细节说明
    这里重点介绍三种:MyISAM、InnoDB、MEMORY
    在这里插入图片描述
  • 三种存储引擎表使用案列
    在这里插入图片描述
  • 如何选择标的存储引擎
    在这里插入图片描述
  • 修改存储引擎
    在这里插入图片描述

视图(view)

  • 看一个需求
    在这里插入图片描述
  • 基本概念
    在这里插入图片描述在这里插入图片描述
  • 视图的基本使用

在这里插入图片描述

  • 完成前面提出的需求 view.sql
    在这里插入图片描述
  • 视图细节讨论
    在这里插入图片描述
  • 视图最佳实践
    在这里插入图片描述
  • 视图课堂练习

在这里插入图片描述

Mysql管理

  • Mysql用户
    在这里插入图片描述

  • 创建用户
    在这里插入图片描述

  • 删除用户
    在这里插入图片描述

  • 用户修改密码
    在这里插入图片描述

  • mysql中的权限
    在这里插入图片描述

  • 给用户授权
    在这里插入图片描述

  • 回收用户授权
    基本语法:
    revoke 权限列表 on 库.对象名 from “用户名”@“登录位置”

  • 权限生效指令
    如果权限没有生效, 可以执行下面命令
    基本语法:
    FLUSH PRIVIEGES;

  • 课堂练习题 grant.sql
    在这里插入图片描述

  • 细节说明 manage_detail.sql
    在这里插入图片描述

日期

第21章 2022年7月20日-2022年7月22日
第22章 2022年7月23日-2022年7月27日
第23章 2022年7月28日-2022年8月1日
第24章 2022年8月1日-长期(内容细致,长期消耗,慢慢看)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值