Java GUI

1.1画笔

import java.awt.*;

public class TestPaint {

    public static void main(String[]args){
// 调用PaintRun类里的方法,因为paint方法是继承于父类,所以无需调用,new时会自动调用
        new PaintRun().defaultstatus();

    }
}

class PaintRun extends Frame {
    public void defaultstatus(){

        this.setBounds(100,100,400,300);
        this.setVisible(true);
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(Color.RED);
        //设置颜色
        g.fillOval(110,110,100,100);
//        画一个实心的圆
    }
}

1.2鼠标监听事件 模仿画图

package Java_review;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
// 总体分三步,获取点,保存点,打印出点
public class TestMouseListener {
    public static void main(String[]args){
       MyFrame myFrame = new MyFrame("画图");
    }
}
class MyFrame extends Frame{
//    保存的点
  ArrayList points;

//    设置标题
    MyFrame(String title){
        super(title);
        this.setBounds(200,200,400,300);
        this.setVisible(true);
        points = new ArrayList<>();
        this.addMouseListener(new myMouse());
    }

    @Override
    public void paint(Graphics g) {
       /* Iterator iterator = points.iterator();

        while(iterator.hasNext())
        {
            Point point = (Point) iterator.next();
            g.setColor(Color.RED);

            g.fillOval(point.x,point.y,10,10);
        }*/
    for(int i = 0 ;i<points.size();i++)
    {

        Point point = (Point) points.get(i);
        g.setColor(Color.RED);

        g.fillOval(point.x,point.y,10,10);
    }
    }

//    添加点到界面上
    public  void addPaint(Point point){

        points.add(point);

    }

    private class myMouse extends MouseAdapter{

        @Override
        public void mousePressed(MouseEvent e) {
            MyFrame myPoint = (MyFrame) e.getSource();  //监听的时窗口所以把事件源强制转换为窗口
            Point point = new Point(e.getX(),e.getY()); //获取事件的坐标,不是窗口对象的坐标
            myPoint.addPaint(point);  //保存到点的集合里

          myPoint.repaint();  //刷新出新页面
        }
    }
}

1.3窗口监听

package jisuanqi;



import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TestFrameListrener {
    public static void main(String[]args){
        myFrame frame = new myFrame();

    }
}

class myFrame extends Frame
{
    public myFrame(){
        setBounds(100,100,300,300);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
                              @Override
                              public void windowOpened(WindowEvent e) {
                                  System.out.println("窗口已经打开");
                              }

                              @Override
                              public void windowActivated(WindowEvent e) {
                                  setTitle("窗口已被激活");
                              }
                          }

        );

    }

}

//System.exit(0) 才是正常关闭

1.4 键盘监听

package Java_review;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class TestkeyBoard {
    public static void main(String[]args){
        new MykeBoardFrame();
    }
}

class MykeBoardFrame extends Frame{
    public MykeBoardFrame(){

        setBounds(100,100,200,200);
        setVisible(true);
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                System.out.println(e.getKeyChar());

            }
        });
    }


}

贪吃蛇制作

帧,如果时间片足够小,就是动画,一秒30帧/60帧,连起来是动画,拆开就是静态的图片!

键盘监听

定时器Timer

URL url= ImageIcon.class.getResource("")//获取图片地址

ImageIcon是该类的名称

再ImageIcon 名称 = new ImageIcon(URL)

把图片加载进来

步骤

1.定义数据

2.画上去

3.监听事件

键盘

事件

2.1 游戏运行界面(主界面)

package Java_review.snake;

import javax.swing.*;

//画出游戏的主界面类
public class GameStart {
    public static void main(String[] args){
        JFrame frame = new JFrame();

        frame.setBounds(10,10,900,720);

        frame.setResizable(false); //使窗口大小无法改变

        frame.setVisible(true);

        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        frame.add(new GamePanel());


    }
}

2.2游戏面板(都是在这上面画)

package Java_review.snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

//做该游戏的面板
public class GamePanel extends JPanel implements KeyListener, ActionListener {
    //定义蛇的数据结构
    int length;//蛇的长度
    int[] snakeX = new int[600];//蛇的x坐标 25*25
    int[] snakeY = new int[500];//蛇的y坐标 25*25
    // 食物坐标
    int foodx;
    int foody;

    Random random =new Random();
    String fx;//方向
//定时器 ms为单位
    Timer timer = new Timer(100,this);
    boolean isStart;//游戏状态

    int score;

    boolean isFail;// 判断游戏是否失败
    //构造器
    public GamePanel()
    {
        init();
        //获取焦点事件
        this.setFocusable(true);
        this.addKeyListener(this);//加入键盘监听
        timer.start();//游戏一开始就要启动定时器
    }
//初始化方法
    public void init(){
        length = 3;
        snakeX[0] =100;snakeY[0] =100;//脑袋坐标
        snakeX[1] =75;snakeY[1] =100;//第一节身体坐标
        snakeX[2] =50;snakeY[2] =100;//第二节身体坐标,接下来依次类推
        fx = "R";//初始方向向右
        //游戏当前的状态,开始,停止
        isStart = false;//初始化为暂停

        foodx = 25 + 25*random.nextInt(34);//34是最大的边界了

        foody = 75 + 25*random.nextInt(24);//食物的坐标是随机的

        isFail = false;//初始化为不失败

        score = 0;
    }




    //绘制面板,游戏中的所有东西,都是有这个画笔来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏操作
//绘制静态面板
        this.setBackground(Color.white);//背景色为白色
        Data.headerIcon.paintIcon(this,g,25,11);//将头部画到面板上(这个就是面板上画图标的方法,this就是加入该面板容器)
        g.fillRect(25,75,850,600); //画出黑色的游戏面板,切记画笔是用g来画

        //把小蛇画上去,头部需要判断
        if(fx.equals("R")){
        Data.rightIcon.paintIcon(this,g,snakeX[0],snakeY[0]);//向右
        }
        else if (fx.equals("up")){
            Data.upIcon.paintIcon(this,g,snakeX[0],snakeY[0]);//向上
        }
        else if (fx.equals("L")){
            Data.leftIcon.paintIcon(this,g,snakeX[0],snakeY[0]);//向左
        }
        else if (fx.equals("down")){
            Data.downIcon.paintIcon(this,g,snakeX[0],snakeY[0]);
        }

        //把食物放上去
        Data.foodIcon.paintIcon(this,g,foodx,foody);//把食物放上去

        //画积分和长度
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("长度:"+length,600,35);
        g.drawString("积分:"+score,600,50);

        for (int i = 1; i < length; i++) {
            //用循环来画身体
            Data.bodyIcon.paintIcon(this,g,snakeX[i],snakeY[i]);//画身体
        }

        //游戏状态
        if(isStart == false)
        {
            g.setColor(Color.white);
            //设置字体
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            //打印字体
            g.drawString("按下空格开始游戏",300,350);
        }

        if(isFail)
        {

            g.setColor(Color.red);
            //设置字体
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            //打印字体
            g.drawString("失败!按下空格重新开始",300,350);
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
//以键盘按压来实现
    @Override
    public void keyPressed(KeyEvent e) {
        int keyword = e.getKeyCode();
        if(keyword==KeyEvent.VK_SPACE)
        {   if(isFail){
            isFail = false;
            //重新开始游戏
            init();
        }
        else
        {isStart = !isStart;} //取反来控制游戏的开始和暂停
            repaint();//刷新页面,其实就是重新执行paint这个画笔,在这就是paintComponent这个方法重新执行
        }
        //小蛇移动,上下左右
        if(keyword == KeyEvent.VK_UP)
        {
            fx = "up";
        } else if (keyword == KeyEvent.VK_DOWN) {
            fx = "down";
        } else if (keyword == KeyEvent.VK_LEFT) {
            fx ="L";
        } else if (keyword == KeyEvent.VK_RIGHT) {
            fx = "R";
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
//事件监听,需要通过固定事件来判断,1s=10次
    @Override
    public void actionPerformed(ActionEvent e) {


        if(isStart && isFail == false){//让小蛇动起来

            //判断食物是否被吃
            if(snakeX[0] == foodx && snakeY[0] == foody)
            {
                length++; //长度加1
                score = score+10;
                //重新生成食物
                foodx = 25 + 25*random.nextInt(34);//34是最大的边界了

                foody = 75 + 25*random.nextInt(24);//食物的坐标是随机的

                //不用担心生成长度的坐标,他就是原先的最后一节的坐标,被下面一个判断自动推演了
            }
            //向右移,身体先动,后一节到前一节的位置,第一节到原先头部
            for(int i =length-1;i>0;i--)
            { snakeX[i] = snakeX[i-1];
                snakeY[i] = snakeY[i-1];

            }

            //头部的方向需要判断
            if(fx.equals("R"))
            {snakeX[0] = snakeX[0]+25;//头部向右移动,身体是后一节跟着前一节
            //边界判断
            if(snakeX[0]>850)
            {
                snakeX[0] = 25;
            }}
            else if (fx.equals("L")){

                snakeX[0] = snakeX[0]-25;//头部向右移动,身体是后一节跟着前一节
                //边界判断
                if(snakeX[0]<25)
                {
                    snakeX[0] = 850;
                }

            } else if (fx.equals("down")) {
                snakeY[0] = snakeY[0]+25;//头部向右移动,身体是后一节跟着前一节
                //边界判断
                if(snakeY[0]>650)
                {
                    snakeY[0] = 75;
                }
            } else if (fx.equals("up")) {
                snakeY[0] = snakeY[0]-25;//头部向右移动,身体是后一节跟着前一节
                //边界判断
                if(snakeY[0]<75)
                {
                    snakeY[0] = 650;
                }
            }

            //判断游戏是否失败
            for(int i = 1;i<length;i++)
            {
                if(snakeX[i] == snakeX[0] && snakeY[i] == snakeY[0])
                {
                    isFail = true;
                }
            }

            repaint();//刷新
        }
        timer.start();//定时器启动
    }
}


//键盘监听器,直接在内部类实现

2.3 数据中心(用来导入图标这类东西)

package Java_review.snake;

import javax.swing.*;
import java.net.URL;
//全部设为公有静态,便于外部调用
public class Data {
    //获取图标的地址
    public static URL body = Data.class.getResource("static/body.png");
    public static URL down = Data.class.getResource("static/down.png");
    public static URL food = Data.class.getResource("static/food.png");
    public static URL header = Data.class.getResource("static/1.png");
    public static URL left = Data.class.getResource("static/left.png");
    public static URL right = Data.class.getResource("static/right.png");
    public static URL up = Data.class.getResource("static/up.png");

    //获取图标
    public static ImageIcon bodyIcon = new ImageIcon(body);
    public static ImageIcon downIcon = new ImageIcon(down);
    public static ImageIcon foodIcon = new ImageIcon(food);
    public static ImageIcon headerIcon = new ImageIcon(header);
    public static ImageIcon leftIcon = new ImageIcon(left);
    public static ImageIcon rightIcon = new ImageIcon(right);
    public static ImageIcon upIcon = new ImageIcon(up);

}

通信协议

协议:约定,就好比现在说的普通话

网络通信协议:速率,传输码率,代码结构,传输控制......

问题;非常的复杂

大事化小:分层!

TCP/IP协议族

重要:

TCP:用户传输协议

UDP:用户数据报协议

3.1TCP

3.1.1 TCP实现聊天

必须先开服务端再开客户端,不然会连接失败

客户端

1.连接服务器Socket

2.发送消息

package Java_review;

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

//客户端
public class TcpClientDemo01 {
    public static void main(String[]args){
        //1.要知道服务器的地址
        try {
            InetAddress serverIp = InetAddress.getByName("127.0.0.1");
            //2.端口号
            int port =9999;

            //3.创建链接
            Socket socket = new Socket(serverIp,port);

            //4.发送消息
            OutputStream outputStream = socket.getOutputStream();

            outputStream.write("你好,我要和你交流".getBytes());

        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
//最后应该再finally里关闭接口,这里没有写,能接收到消息但是会报错

服务端

1.建立服务端口ServerSocket

2.等待用户的链接accept

3.接收用的信息

package Java_review;

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

//服务端
public class TcpServerDemo01 {public static void main(String[]args){
    //1.我得有一个地址和端口
    try {
        ServerSocket serverSocket = new ServerSocket(9999);
    //2.等待客户端链接过来
        Socket socket = serverSocket.accept();

        //3.读取客户端的消息

        InputStream inputStream = socket.getInputStream();

        //4.读出来
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            String msg = new String(buffer, 0, len);
            System.out.println(msg);


        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
}
//管道流( 把接收到的写进管道里同意输出)
/*
*  ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) != -1){
                 baos.write(buffer,0,len);


        }System.out.println(baos.toString());
*
**/

3.1.2 TCP文件上传

客户端

package Java_review;

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

public class TcpClientDemo02 {
    public static void main(String[]args) throws IOException {
        //1.创建Socket
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),1111);
        //2.发送文件
        OutputStream outputStream =socket.getOutputStream();
        //3.导入要发送的文件,并发送
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\86187\\IdeaProjects\\untitled1\\src\\Java_review\\1.txt");

        int len;

        byte[] buffer0 = new byte[1024];

        while ((len=fileInputStream.read(buffer0))!=-1)
        {
            outputStream.write(buffer0,0,len);
        }
        //通知服务器,我已经传输完了
        socket.shutdownOutput();//我已经结束了out传输
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024];

        while ((len = inputStream.read(buffer))!=-1)
        {
            String msg = new String(buffer,0,len);
            System.out.println(msg);
        }

        //5.关闭
        inputStream.close();
        fileInputStream.close();
        outputStream.close();
        socket.close();
    }
}

服务端

package Java_review;

import jdk.net.Sockets;

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

public class TcpServerDemo02 {
    public static void main(String[]args) throws IOException {
        //1.创建SocketServer端口
        ServerSocket serverSocket = new ServerSocket(1111);
        //2.创建接收socket
        Socket socket =serverSocket.accept();
        //3.创建接接收字符流和文件
        FileOutputStream fos =new FileOutputStream("2.txt");
        InputStream inputStream = socket.getInputStream();
        byte[] buffer =new byte[1024];
        int len;
        while((len = inputStream.read(buffer))!= -1)
        {
            fos.write(buffer,0,len);
        }
        //4.告诉客户端发送完毕
        OutputStream outputStream = socket.getOutputStream();
       outputStream.write("我已经接收完毕你可以断开连接了!".getBytes());



        //5.关闭
        outputStream.close();
        fos.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }

}

读入时牢记这个格式

 //4.读出来
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            String msg = new String(buffer, 0, len);
            System.out.println(msg);


        }

3.2UDP

发短信:不需要连接,需要知道对方地址

没有客户端和服务端,只是报文传输,都可以接收和发送

互为服务器和客户端

3.2.1 UDP消息发送

DataGramPackage类

发送消息(发送端):

package Java_review;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpClientDemo01 {
    public static void main(String[]args) throws IOException {
        //1.创建Socket
        DatagramSocket datagramSocket = new DatagramSocket();

        //创建发送的字符

        Scanner scanner =new Scanner(System.in);


        String msg = scanner.next();
        //要发送的主机地址
        InetAddress IP = InetAddress.getByName("localhost");
        //2.创建包 参数列表(发送的信息(比特的形式),信息的比特长度,目的地址,目的端口)
        DatagramPacket  packet =new DatagramPacket(msg.getBytes(),msg.getBytes().length,IP,9090);
        //3.发送包
        datagramSocket.send(packet);
        //4.关闭流
        datagramSocket.close();
    }
}

接收端:

package Java_review;

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

public class UdpServerDemo01 {
    public static void main(String[]args) throws IOException {
        //1.创建端口
        DatagramSocket socket =new DatagramSocket(9090);

        //2.接收数据包

        byte[] buffer = new byte[1024];

        DatagramPacket packet =new DatagramPacket(buffer,0,buffer.length);

        socket.receive(packet);

        //3.解包,输出包里的内容

        System.out.println(new String(packet.getData(),0,(packet.getLength())));

        //4.关闭流

        socket.close();
    }
}

循环发送消息

package Java_review.UDPChat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
//循环发送
public class UdpReceiveDemo01 {
    public static void main(String[]args) throws IOException {
        DatagramSocket socket =new DatagramSocket();
//准备数据,从屏幕读入数据与Scanner类似
        //循环输入
        while (true){
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        String msg = reader.readLine();

        byte[] buffer = new byte[1024];

        buffer = msg.getBytes();
        //传输的是比特流
        DatagramPacket packet =new DatagramPacket(buffer,0,buffer.length,new InetSocketAddress("localhost",9090));

        socket.send(packet);

        if(msg.equals("bye")){
            break;
        }
        }

        socket.close();

    }
}

循环接收

package Java_review.UDPChat;

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

public class UdpSenderDemo01 {
    public static void main(String[]args) throws IOException {
        DatagramSocket socket = new DatagramSocket(9090);

        byte[] buffer = new byte[1024];
        //创建空包用来接收
        DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);

        //装包和解包 循环接收
       while (true) {
           socket.receive(packet);
           String msg = new String(packet.getData(), 0, packet.getLength());

           if (msg.equals("bye")) {
               break;
           } else {
               System.out.println(msg);
           }
       }
       socket.close();
    }



}

3.2.2UDP多线程聊天(可以互相发和接收)

两个人都可以是发送方,也都可以是接收方

发送的线程

package Java_review.UDPChat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class TalkSender implements Runnable{
    DatagramSocket socket;
    DatagramPacket packet;

    private int toPort;

    private int myPort;

    private  String IP;


   public TalkSender(int toPort,int myPort,String IP) throws SocketException {
       socket = new DatagramSocket();
       this.myPort = myPort;
       this.toPort = toPort;
       this.IP = IP;

   }


    @Override
    public void run() {

//准备数据,从屏幕读入数据与Scanner类似
        //循环输入
        while (true){
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

            String msg = null;
            try {
                msg = reader.readLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            byte[] buffer = new byte[1024];

            buffer = msg.getBytes();
            //传输的是比特流
            packet =new DatagramPacket(buffer,0,buffer.length,new InetSocketAddress(this.IP,this.toPort));

            try {
                socket.send(packet);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            if(msg.equals("bye")){
                break;
            }
        }

        socket.close();

    }
    }


接收的线程

package Java_review.UDPChat;

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

public class TalkReceiver implements Runnable{
    private int myPort;

    private String name;

    byte[] buffer;

    DatagramSocket socket;

    public TalkReceiver(int myPort,String name) throws SocketException {
        this.name = name;
        socket = new DatagramSocket(myPort);
    }

    @Override
    public void run() {


        buffer = new byte[1024];
        //创建空包用来接收
        DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);

        //装包和解包 循环接收
        while (true) {
            try {
                socket.receive(packet);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            String msg = new String(packet.getData(), 0, packet.getLength());

            if (msg.equals("bye")) {
                break;
            } else {
                System.out.println(this.name+":"+msg);
            }
        }
        socket.close();
    }

}


然后在其他类里开启这两个线程即可

3.3URL

统一资源定位符:定位资源的,定位互联网上的某一个资源

DNS域名解析

协议://ip地址:端口

从http链接上下载资源

package Java_review;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class UrlDown {
    public static void main(String[]args) throws IOException {
       //下载地址
        URL url =new URL("https://cn.bing.com/sa/simg/Flag_Feedback.png");
        //连接到这个资源

        HttpURLConnection connection = (HttpURLConnection)url.openConnection();

        InputStream inputStream = connection.getInputStream();

        byte[] buffer = new byte[1024];

        int len;

        FileOutputStream fileOutputStream =new FileOutputStream("1.png");

    while ((len = inputStream.read(buffer))!=-1)
    {
        fileOutputStream.write(buffer,0,len);
    }
//断开连接
    fileOutputStream.close();
    inputStream.close();
    connection.disconnect();
    }
}

多线程

线程调度不一定立即执行,由cpu安排调度,交替执行的

4.1.继承Thread类(重点)

继承Threa类,重写run方法,通过调用start来实现

package Java_review;
//切记 是交替执行
public class ThreadTest extends Thread{
    @Override
    public void run() {
        for (int i = 0; i <300 ; i++) {
            System.out.println("吃饭"+i);
        }
    }

    public static void main(String[]args)
    {//主线程
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();

        for (int i = 0; i <300 ; i++) {
            System.out.println("玩手机"+i);
        }


    }
}

多线程网图下载

package Java_review;
import org.apache.commons.io.*;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

public class TestThread2 extends Thread{
    private String url;

    private String name;

    public TestThread2(String url,String name)
    {
        this.url =url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownLoad webDownLoad = new WebDownLoad();

        try {
            webDownLoad.downLoad(this.url,this.name);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("下载了文件:"+this.name);
    }

    public static void main(String[]args){
        //创建三个线程
        TestThread2 t1= new TestThread2("https://cn.bing.com/rp/yb75_iNlGYFD_4DQkyJGECm831o.png","1,png");
        TestThread2 t2 = new TestThread2("https://cn.bing.com/rp/C0MOC1lJM5OgbhfViNCsS5p0Syo.png","2.png");
        TestThread2 t3 = new TestThread2("https://cn.bing.com/sa/simg/Flag_Feedback.png","3.png");

        //开启线程
        t1.start();
        t2.start();
        t3.start();
        
        //输出结果说明线程是交替工作不是按顺序的
    }
}

//下载器
class WebDownLoad
{//下载方法
    public void downLoad(String url,String name) throws IOException {

        FileUtils.copyURLToFile(new URL(url),new File(name));
    }

}

4.2.实现Runnable接口(重点)

多个线程操作同一个对象

package Java_review;
//通过Runnable接口来实现
public class TestRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我在学习"+i);
        }

    }

    public static void main(String[]args){
        //创建类实例
        TestRunnable runnable = new TestRunnable();
        //创建一个Thread类,传入实现Runnable的类作为参数
        Thread thread = new Thread(runnable);
        thread.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("吃饭"+i);
        }


    }
}

龟兔赛跑(共享同一条赛道,所以用Runnable来实现 通过传参)

package Java_review;
//龟兔赛跑
public class TestRunnable3 implements Runnable{
    private String winner ; //胜利者


    @Override
    public void run() {
        //跑同一个赛道
        for (int i = 1; i <=100; i++) {
            if(Thread.currentThread().getName().equals("兔子")){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            if(!isGameOver(i))//调用判断游戏是否结束
            {
                System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");}
            else {break;}
        }


    }

    //用来判断游戏是否结束的方法
    public Boolean isGameOver(int step){
        if(winner != null)
        {
            return true;
        }
        if(step >= 100)
        {
            winner = Thread.currentThread().getName();
            System.out.println("winner is "+winner);
            return true;
        }

        return false;

    }
    public static void main(String[]args){
    TestRunnable3 testRunnable3 = new TestRunnable3();
    new Thread(testRunnable3,"兔子").start();
    new Thread(testRunnable3,"乌龟").start();

    }
}

4.3.实现Callable接口(了解)

1.需要返回值类型

2.重写call方法,抛出异常

3.创建执行任务

4.提交执行

5.获取结果

6.关闭服务

好处:1.可以定义返回值 2.可以抛出异常

4.4 静态代理

真实对象和代理对象要实现同一个接口

代理对象要代理真实对象

好处:代理对象可以做很多真实对象做不了的事

​ 真实对象可以专注做某一件事

package Java_review;

public class StaticProxy {
    public static void main(String[] args) {
        Company company =new Company(new My());
        company.happyMerry();
    }
}
//接口
interface Merry{
      default void happyMerry(){};
}
//真实对象
class My implements Merry{


    @Override
    public void happyMerry() {
        System.out.println("结婚");

    }
}
//代理对象
class Company implements Merry{
    private Merry target;
public Company(Merry target){
    this.target = target;
}
    @Override
    public void happyMerry() {
    before();
    this.target.happyMerry();
    after();
    }

    private void after() {
        System.out.println("婚后");
    }

    private void before() {
        System.out.println("婚前");
    }
}

4.5Lambda表达式

用来简化只有一个方法的接口

函数式接口(只有一个方法)

Lambda是函数式编程

如:like = ()->{代码块};

如下列代码来简化

package Java_review;

public class TestLambda {
    public static void main(String[] args) {
        //如此重写方法(lambda方式)
        Love a = ()->{
            System.out.println("爱你");
        };
        //然后调用方法
        a.love();
}

}

interface Love {
    void love();
}

上面的表达式还可以简化:可以去掉参数类型以及参数的小括号,还可以去掉花括号

切记去掉花括号的前提是只有一句代码,如果有多句,不可以去掉花括号

多个括号也可以去掉参数类型,要去掉就都去掉,必须加上括号

4.6五大状态即一些方法

1.创建

2.就绪

3.运行

4.阻塞

5.死亡

setPriority()更改线程优先级

4.6.1线程停止

//测试stop //1.建议线程正常停止-->利用次数,不建议死循环 //2.剪易使用标志位-->设置一个标志位 //3.不要使用stop或者destory等过时或者JDK

package Java_review;
//测试stop
//1.建议线程正常停止-->利用次数,不建议死循环
//2.剪易使用标志位-->设置一个标志位
//3.不要使用stop或者destory等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{
private boolean flag =true;
    public static void main(String[] args) {
      TestStop threadTest = new TestStop();
        for (int i = 0; i < 100; i++) {
            new Thread(threadTest).start();
            
        }


     threadTest.stop1();

    }


    @Override
    public void run() {
        while (flag)
        {
            System.out.println("zaiyux");
        }
    }

    public void stop1(){
        this.flag=false;
    }
}

4.6.2线程休眠(sleep)

sleep

package Java_review;
//放大问题的发生性
public class TestSleep implements Runnable {
    private int ticket = 100;
    @Override
    public void run() {
        while (true)
        {
            if(ticket <= 1){break;}

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //得到线程的名字
            System.out.println(ThreadTest.currentThread().getName()+"拿到了第"+--ticket+"张票");

        }
    }
    public static void main(String[]args){

        TestSleep runnable2 = new TestSleep();

        Thread thread1 = new Thread(runnable2,"小李");
        Thread thread2 = new Thread(runnable2, "小明");
        Thread thread3 = new Thread(runnable2, "小鹏");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

倒计时(其中包含打印当前系统时间)

package Java_review;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;

public class tenDown implements Runnable{
    @Override
    public void run() {
        int num =11;
        while (num-->1){
            System.out.println(num);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) {
        tenDown ten =new tenDown();
        new Thread(ten).start();
//打印系统时间
        Date starttime = new Date(System.currentTimeMillis());//获取系统当前时间
        while (true)
        {
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(starttime));//打印当前系统时间
                starttime = new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

4.6.3线程礼让(yield)

礼让线程,让运行暂停但不阻塞

重新成为就绪态

礼让不一定成功(看cpu心情)

package Java_review;

public class TestYield {
    public static void main(String[] args) {
    MyYield myYield =new MyYield();

    new Thread(myYield,"a").start();
    new Thread(myYield,"b").start();

    }
}

class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }
}

4.6.4线程强制执行(Join)

插队 VIP

少用,会造成线程阻塞

package Java_review;

public class JoinTest implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 500; i++) {
            System.out.println("VIP来了");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        JoinTest joinTest =new JoinTest();
        Thread thread =new Thread(joinTest);
        thread.start();

        for (int i = 0; i < 1000; i++) {
            if(i==200)
            {
                thread.join();//插队
            }
            System.out.println("main在执行");
        }
    }
}

4.7观测线程状态

使用thread.getState来获取状态

TERMINATED是死亡状态

package Java_review;
//观察测试线程的状态
public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
            System.out.println("sjdalk");
        });

        //观察线程状态
        Thread.State state = thread.getState();
        System.out.println(state);

        //启动线程
        thread.start();
        state = thread.getState();//更新状态
        System.out.println(state);

//线程只能启动一次,执行完就死亡了
        //一直监视
        while (state != Thread.State.TERMINATED)
        {   Thread.sleep(100);
            state = thread.getState();//更新状态
            System.out.println(state);
        }
    }
}

4.8线程优先级

getPriority(),setPriority(int x)

优先级默认是5,范围为1-10 越大越优先,不在该范围内会报错!!!

优先级高的不一定先调用!!!只是可能性更大

package Java_review;
//测试线程优先级
public class TestPriority {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+"优先级为:"+Thread.currentThread().getPriority());

        MyPriority myPriority =new MyPriority();

        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        t1.setPriority(10);
        t2.setPriority(9);
        t3.setPriority(8);
        t4.setPriority(7);

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

    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"优先级为:"+Thread.currentThread().getPriority());
    }
}

4.9守护线程

setDaemon(boolean)

线程分为用户线程和守护线程

虚拟机不必等待守护线程结束,用户线程结束,守护线程就会结束,虚拟机关闭需要时间,默认的线程是用户线程,即setDaemon()默认为false

4.10线程同步

同一个对象被多个线程同时操作会造成很多问题

形成条件:队列+锁

syncharoniized,当一个线程获得对象的排他锁,独占资源,其他线程必须等待,但也会存在其他问题,下文再说,总体来说是安全的

4.10.1 三大不安全案例

不安全的购票系统

package Java_review;

public class UnsafaBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket,"小李").start();
        new Thread(buyTicket,"妮妮").start();
        new Thread(buyTicket,"黄牛").start();
    }
}
class BuyTicket implements Runnable{
    //票
    private int ticketnum = 10;
    boolean flag = true;
    @Override
    public void run() {
        //买票
        while (flag)
        {
            buy();
        }
    }

    private void buy(){
        if(ticketnum <= 0){
            flag = false;
            return;
        }
        else
        {
            System.out.println(Thread.currentThread().getName()+"买到了"+"第"+ticketnum--+"张票");
        }

    }
}

不安全的银行

package Java_review;

public class UnsafeBank {
    public static void main(String[] args) {
        Account man = new Account("结婚基金",100);
        Drawing drawing =new Drawing(man,100,"小李");
        Drawing drawing1 =new Drawing(man,50,"妮妮");
        drawing1.start();
        drawing.start();

    }
}
//账户
class Account{
    //卡名
    String name;
    //余额
    int price;



    public Account(String name, int price) {
        this.name = name;
        this.price = price;
    }
}

class Drawing extends Thread{
    Account account;//账户
    //要取多少钱
    int drawingMoney;

    //现在手里有多少钱
    int nowMoney;

    public void setAccount(Account account) {
        this.account = account;
    }

    public void setDrawingMoney(int drawingMoney) {
        this.drawingMoney = drawingMoney;
    }

    public void setNowMoney(int nowMoney) {
        this.nowMoney = nowMoney;
    }

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;

    }
//取钱
    @Override
    public void run() {
if(account.price < drawingMoney){
    System.out.println(Thread.currentThread().getName()+"余额不足");

    return;
}
else {//取完后的余额
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    account.price=account.price-drawingMoney;
    nowMoney = nowMoney+drawingMoney;
    System.out.println(Thread.currentThread().getName()+"手里金额为"+nowMoney+"卡里余额为:"+account.price);
}
    }
}

不安全的线程集合

package Java_review;

import java.util.ArrayList;

//不安全的线程(多个线程抢占一个集合空位造成覆盖,最后集合的大小小于10000个)
public class Unsafe {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList<>();

        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                arrayList.add(Thread.currentThread().getName());

            }).start();
        }
        System.out.println(arrayList.size());
    }
}

4.10.2同步方法 synchronized关键字

每个对象都加了一把锁,一个对象只有一个锁(切记)

两种方式

1.synchronized默认锁的是this

2.synchronized块:格式:

synchronized(被锁的对象){

把要执行的代码放在里面

}

4.11死锁

含义:多个线程互相抱着对方需要的资源,然后形成僵持

4.12Lock锁

可重入锁

格式如下

package Java_review;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock2 lock2 = new TestLock2();

        new Thread(lock2,"1").start();
        new Thread(lock2,"2").start();
        new Thread(lock2,"3").start();
    }

}

class TestLock2 implements Runnable{
    int ticknum = 10;
//定义lock锁
   private final ReentrantLock lock =new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try {lock.lock(); //上锁
                if (ticknum > 0) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread().getName() + "第" + ticknum--);
                } else {
                    break;
                }

            } finally {
                lock.unlock();//解锁
            }
        }

    }
}

4.13线程协作

生产者与消费者问题(重点,一定要记住)

管程法

package Java_review;
//生产者与消费者问题
public class TestPc {
    public static void main(String[] args) {
        ContainerTes containerTes = new ContainerTes();
        Customer customer = new Customer(containerTes);//将同一个缓冲池加入
        Productor productor =new Productor(containerTes);
        productor.start();
        customer.start();
}}

//消费者类
class Customer extends Thread{
ContainerTes containerTes = new ContainerTes();
public Customer(ContainerTes containerTes){

    this.containerTes = containerTes;
}
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            containerTes.pop();

        }
    }
}

//生产者类
class Productor extends Thread{
    ContainerTes containerTes = new ContainerTes();
    public Productor(ContainerTes containerTes){

        this.containerTes = containerTes;
    }
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            Chicken chicken = new Chicken(i);
            containerTes.push(chicken); //生产者把鸡加入

        }
    }
}

//产品类
class Chicken{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}

//缓冲区类
class ContainerTes {
    //缓冲池最多为10个
    Chicken [] chickens= new Chicken[10];
    private int counts = 0;//计数器

    //生产者生产的方法,要加锁
    public synchronized void push(Chicken chicken)
    {//先判断缓冲池是否已满
            if(counts==chickens.length-1)
            {
                //如果缓冲区满了,进入等待
                try {
                    //最后一个空位,这时就应该处理了,不然下面消费者会下标越界,因为不处理的话counts=10,下面就会越界
                    chickens[counts] = chicken;
                    System.out.println("生产者生产了第"+chicken.id+"只鸡");
                    this.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }


            }

            else //若是有空位,加入缓冲池
            {
                chickens[counts] = chicken;
                System.out.println("生产者生产了第"+chicken.id+"只鸡");
                counts++;//缓冲池加1
                this.notifyAll();//唤醒消费者来消费
            }

        }




    //消费者消费的方法,要加锁
    public synchronized Chicken pop(){


        //判断是否有资源,有的话取出
        if(counts == 0)
        {
            try {
                System.out.println("消费者消费了第"+chickens[counts].id+"只鸡");//数组等于一时是还有元素的,因为下标是从0开始的
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

            int x = counts;

            counts--;
           System.out.println("消费者消费了第"+chickens[x].id+"只鸡");
            this.notifyAll();//唤醒生产者来生产
            return chickens[x];//将吃了的取出来







    }

}


信号灯法

package Java_review;
//测试生产者消费者问题:信号灯法,通过flag来管控
public class Test2 {
    public static void main(String[] args) {
        Tv tv = new Tv();
        Watcher watcher = new Watcher(tv);
        Player player = new Player(tv);
        watcher.start();//启动线程
        player.start();

    }



}

//观众观看
class Watcher extends Thread{
    Tv tv = new Tv();
    public Watcher(Tv tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            tv.watch();
        }
    }
}

//演员表演
class Player extends Thread{
    Tv tv = new Tv();
    public Player(Tv tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(10); //睡眠一下,因为线程进入等待和唤醒是需要时间的,这中间的时间可能还在运行上面的线程到结束
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(i % 2 == 0){
                tv.play("天天向上");
            }
            else
            {
                tv.play("快乐大本营");
            }
        }
    }
}

//产品,也是一个池
class Tv {
    //标志位,用来管控,在这表示未完成表演的状态
    boolean flag = true;

    private String name;

    //演员的表演方法
    public synchronized void play(String name){
        //通过标志位来确定谁开始
        if(flag){
        //演员表演,观众等待
            this.name = name;

        System.out.println("演员在表演"+this.name+"这个节目");

        //表演完了,唤醒观众来观看
        this.notifyAll();
        //标志位取反
        this.flag = !this.flag;}
        else {
            //观众观看,演员等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }

    public synchronized void watch(){
        if(!flag){
            System.out.println("观众观看了"+this.name+"这个节目");
            //看完后唤醒演员来表演
            this.flag = !this.flag;
            this.notifyAll();
        }
        else
        { //若是没完成表演,那就等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }


    }


}

4.14 线程池

![f97cd2df31305803bced40eccd3ed65](C:\Users\86187\Documents\WeChat Files\wxid_8tdki3p9kc5q22\FileStorage\Temp\f97cd2df31305803bced40eccd3ed65.jpg)

线程池可以用来创建多个线程,通过上面的两个接口,线程池可以规定池内有多少个线程

package Java_review;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
    public static void main(String[] args) {
        //1.创建任务创建线程池
        //newFixedThreadPool 参数为线程池的大小:最多有几个线程
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());//相当于执行start()
        service.execute(new MyThread());
        service.execute(new MyThread());
        //2.关闭线程池
        service.shutdown();
    }

}

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println("这是我的线程池");
    }
}

注解和反射

注解就是带有@的那种

5.1注解

元注解

可以用来定义注解

//@Target 表示我们的注解可以用在那些地方

可以用枚举类型来表示多个作用范围

//@Retention表示我们的注解在什么地方还有效

runtime>class>sources

//@Documented 表示是否将我们的注解生成在JAVAdoc中

//@Inherited 子类可以继承父类的注解

用@interface 加名称来自定义一个注解

5.2反射

Java.Reflection

反着来,可以根据对象来反射得到类

Class本身也是一个类,对象只能由系统建立对象

5.2.1Class类的创建方式

方式一:通过对象获得

Class c1 = person.getClass();

方式二:forname获得

Class c2 = Class.forName(类的引用路径);

方式三:通过类名.class获得

Class c3 = 类名.class;

获得子类后,通过子类的方法可以获得父类对象!

5.2.2类的加载与ClassLoader的理解

加载:每个类生成了一个代表这个类的java.lang.Class对象

链接:将Java类的二进制代码合并到JVM的运行状态之中的过程

初始化:执行类构造器()方法的过程。就是收集类变量的赋值动作和静态代码块中的语句合并执行。

5.2.3 分析类的初始化

如果初始化一个类,他的父类没有被初始化,那一定会先初始化他的父类

主动引用(会引起初始化):1.new一个新对象

​ 2.反射也会产生主动引用

被动引用(不会引起初始化):1.创建静态域不会,如子类调用父类的静态变量

2.通过数组定义类引用

3.引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

package Java_review;

public class Test06 {

    static {
        System.out.println("Main被加载");

    }

    public static void main(String[] args) {
        //主动引用
        try {
            Class.forName("Java_review.Son");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
       
    }
}
class Father{
    int x =0 ;
    static {
        System.out.println("父类被加载");
    }
}
class Son extends Father{
    static {
        System.out.println("子类被加载");
    }
    static int m = 100;
    static final int M = 1;
}

5.2.4获取类的运行时结构

package Java_review;

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

//获得类的信息
public class Test07 {
    public static void main(String[] args) throws NoSuchFieldException {
        try {
            Class c1 = Class.forName("Java_review.User");
            //获得类的名字
            System.out.println(c1.getName());//获得包名+类名
            System.out.println(c1.getSimpleName());//获得类名
            //获得类的属性 只能获得public属性的
            Field name = c1.getDeclaredField("name");
            System.out.println(name);
            //获得类方法,可以获得指定的方法
            Method [] methods = c1.getMethods();
            for (int i = 0; i < methods.length; i++) {
                System.out.println("正常的"+methods[i]);
            }

            //获得构造器,也可以获得指定的
            Constructor []constructors = c1.getConstructors();
            for (int i = 0; i < constructors.length; i++) {
                System.out.println(constructors[i]);
            }

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }


    }
}

5.2.5动态创建对象,通过反射(重点)

package Java_review;

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

public class Test09 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得Class对象
       Class c1 = Class.forName("Java_review.User");
       //构造一个对象
        User user = (User)c1.newInstance(); //本质时是调用了无参构造
        System.out.println(user);

        //通过构造器创建对象,可以调用有参构造
        Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
        User user2 = (User)constructor.newInstance("李",18,23);
        System.out.println(user2);

        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method method = c1.getDeclaredMethod("setName", String.class);
        //invoke:激活的意思
        //(对象,“方法的值”)
        method.invoke(user3,"L");
        System.out.println(user3.getName());

        //通过反射操作属性
        User user4 = (User) c1.newInstance();

        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,我们需要关闭程序的安全检测,就是下面的setAccessible
        name.setAccessible(true);

        name.set(user4,"lijieru");
        
        System.out.println(user4.getName());

    }
}

5.2.6性能检测

普通>关闭检测的反射>反射

package Java_review;

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

public class Test10 {
    //普通方式调用
    public static void test01(){
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("01执行的时间为:"+(endTime-startTime)+"ms");
    }

    //反射方式调用

    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method method = c1.getDeclaredMethod("getName");
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            method.invoke(user);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("02执行的时间为:"+(endTime-startTime)+"ms");
    }

    //反射方式调用,关闭检测
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method method = c1.getDeclaredMethod("getName");
        method.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            method.invoke(user);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("03执行的时间为:"+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        test01();
        test02();
        test03();
    }
}

5.3 通过反射获得注解

先获取类对象,再转换类型(属性,方法,字段),再获取里面的信息

package Java_review;

import java.lang.annotation.*;
import java.lang.reflect.Field;

//练习反射操作注解
public class Test12 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
       Class c1 = Class.forName("Java_review.Student2");
        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();

        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解的value的值
        Table table = (Table)c1.getAnnotation(Table.class);
        String value = table.value();
        System.out.println(value);

        //通过注解获得属性的值
        Field f = c1.getDeclaredField("id");
        Field1 field1 = f.getAnnotation(Field1.class);
        System.out.println(field1.columnName()+field1.type()+field1.length());


    }
}
@Table("db_Student")
class Student2{
    @Field1(columnName = "db_id",type = "int",length = 10)
    private int id;
    @Field1(columnName = "db_age",type = "int",length = 10)
    private  int age;
    @Field1(columnName = "db_name",type = "String",length = 10)
    private String name;

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

    public int getId() {
        return id;
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setId(int id) {
        this.id = id;
    }

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

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

    @Override
    public String toString() {
        return "Java_review.Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}


//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field1{
    String columnName();
    String type();
    int length();
}