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();
}
Leave a reply