当前位置:

首页 > 编程开发 > java如何实现联机五子棋

java如何实现联机五子棋

下面是客户端运行的效果:这里是代码包的结构:接着我来依次说下这些类所完成的功能Media包Media包:主要是放了五子棋的背景图片和播放音乐的类以及音乐内容播放音乐这个类是我从室友那拿的,所以我也不是很懂,瞄了一眼是用Applet完成的,只能处理.wav后缀的音乐Net包Net包:包含两个类,细心的小伙伴应该注意到客户端是没有主方法的。客户端中其实是包含与服务端进行通信的socket的,其中包含一些读和写的方法。服务端我采用的是线程池的方法来处理客户端的请求(线程池这部分我也不是特别了解,用起来和多线程感

本文目录

    下面是客户端运行的效果:

    java如何实现联机五子棋

    这里是代码包的结构:

    java如何实现联机五子棋

    接着我来依次说下这些类所完成的功能

    Media包

    Media包:主要是放了五子棋的背景图片和播放音乐的类以及音乐内容

    播放音乐这个类是我从室友那拿的,所以我也不是很懂,瞄了一眼是用Applet完成的,只能处理.wav后缀的音乐

    Net包

    Net包:包含两个类,细心的小伙伴应该注意到客户端是没有主方法的。客户端中其实是包含与服务端进行通信的socket的,其中包含一些读和写的方法。服务端我采用的是线程池的方法来处理客户端的请求(线程池这部分我也不是特别了解,用起来和多线程感觉差不多)。

    View包

    View包:包含四个类,分别是ChessBoard,ChessPanel,Pieces和WhoWin 类

    ChessBoard是一个包含Main方法的JFrame,命令面板和棋盘面板都是添加到这个JFrame中的。

    ChessPanel是一个棋盘面板,里面完成了如:画19*19的棋盘线条,加载背景图片,不停的接收来自服务端的消息并处理(把棋子加到面板),处理每次点击后添加棋子到面板并发送棋子到服务器,判断胜负并且给出提示消息。

    Pieces是一个棋子,其中有包含如颜色,棋子半径,棋子位置和命令(和前面的命令面板配合使用,默认是发送)等属性。

    WhoWin就是五子棋中判断谁输谁赢的部分。每下一步就需要判断。

    播放音乐的类:

    package Media.Music;
    import java.io.File;
    import java.io.IOException;
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.Clip;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    public class PlayMusic {
        private Clip clip;
        public PlayMusic(String filePath) throws LineUnavailableException, UnsupportedAudioFileException, IOException {
            File file = new File(filePath);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
            clip = AudioSystem.getClip();
            clip.open(audioInputStream);
        }
     
        public void play() {
            clip.setFramePosition(1);
            clip.start();
        }
     
        public void loop() {
            clip.loop(Clip.LOOP_CONTINUOUSLY);
        }
        public void stop() {
            clip.stop();
        }
    }

    TcpClient:

    package net;
    import view.Pieces;
    import java.io.*;
    import java.net.Socket;
    public class TcpClient{
        private Socket socket;
        private ObjectInputStream ois;
        private ObjectOutputStream oos;
        public TcpClient(Socket socket,ObjectInputStream ois,ObjectOutputStream oos){
            this.socket= socket;
            this.ois = ois;
            this.oos = oos;
        }
        public Socket getSocket() {
            return socket;
        }
     
        public void setSocket(Socket socket) {
            this.socket = socket;
        }
     
        public ObjectInputStream getOis() {
            return ois;
        }
     
        public void setOis(ObjectInputStream ois) {
            this.ois = ois;
        }
     
        public ObjectOutputStream getOos() {
            return oos;
        }
     
        public void setOos(ObjectOutputStream oos) {
            this.oos = oos;
        }
     
        public void send(Pieces pieces) throws IOException {
            oos.writeObject(pieces);
            System.out.println(socket+"向服务器发送消息");
        }
        public Pieces accept() throws IOException, ClassNotFoundException {
            Pieces pieces = (Pieces) ois.readObject();
            System.out.println(socket+"从服务器读取消息");
            return pieces;
        }
        public void close(){
            ;
        }
    }

    TcpServer:

    package net;
    import view.Pieces;
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.ArrayList;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class TcpServer {
        public static void main(String[] args) {
            // 保存客户端处理的线程
            ArrayList userList = new ArrayList<>();
            // 固定大小的线程池只支持两个线程,用来处理客户端
            ExecutorService es = Executors.newFixedThreadPool(2);
            try {
                ServerSocket server = new ServerSocket(10086);
                System.out.println("服务器已经启动,正在等待客户端连接......");
                while (true) {
                    //接收客户端的Socket,如果没有客户端连接就一直卡在这里
                    Socket socket = server.accept();
                    // 每来一个用户就创建一个线程
                    UserThread user = new UserThread(socket, userList);
                    // 开启线程
                    es.execute(user);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
     
    class UserThread implements Runnable {
        private Socket socket = null;
        private static ArrayList list; // 客户端线程集合
        private ObjectOutputStream oos;
        private ObjectInputStream ois;
        private boolean flag = true;// 标记
     
        public UserThread(Socket socket, ArrayList list) {
            this.socket = socket;
            this.list = list;
            list.add(this); // 把当前线程加入list中
        }
     
        @Override
        public void run() {
            UserThread user = null;
            try {
                System.out.println("客户端:" + socket.getInetAddress().getHostAddress() + "已经连接");
                ois = new ObjectInputStream(socket.getInputStream());
                oos = new ObjectOutputStream(socket.getOutputStream());
                while(true){
                    Pieces pieces = (Pieces) ois.readObject(); // 客户端发给服务端的消息,把他写到其它套接字中去
                    int size = list.size();
                    for (int i = 0; i < size; i++) {
                        user = list.get(i);
                        if (user.socket != socket) {
                            user.oos.writeObject(pieces);
                            System.out.println("从"+socket+"向"+user.socket+"发送消息");
                        }
                    }
                }
            } catch(SocketException e){ //  todo 客户端掉线后,移除客户端。没想好{1.从客户端列表移除当前元素,关闭当前:socket,通知另一方:这一方已经掉线,然后关闭这一方的socket}
                try {
                    int i = list.size();
                    if (i ==2){
                        list.remove(user);
                        System.out.println("已经删除了一个客户端");
                        list.get(0).oos.writeObject(new Pieces("对方掉线"));
                    }else if (i==1){
                        list.remove(0);
                        System.out.println("又移除了另一个客户端");
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    ChessBoard:

    /*
    * 1.变量值不变的问题
    * 2.输入输出流先后顺序的问题(socket阻塞)
    * 3.socket 短连接不关闭输入输出流,为何看起来就像长连接一样(长短连接的区别是什么)
    * */
    // todo 一个提示框
    package view;
    import Media.Music.PlayMusic;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    public class ChessBoard extends JFrame implements ActionListener {
        private JButton PlayMusic = new JButton("播放音乐");
        private ChessPanel chessPanel;
        private Panel CommandPanel = new Panel();
        private JButton reStart = new JButton("重新开始");
        private JButton fail = new JButton("认输");
        private JButton Regret = new JButton("悔棋");
        private String command=null; // 触发按钮后发送的命令
        private PlayMusic music = null;
        private int count = 1;
        //  todo 静态语句块
        {
            try {
                music = new PlayMusic("./src/Media/Music/bg3.wav");
            } catch (LineUnavailableException e) {
                e.printStackTrace();
            } catch (UnsupportedAudioFileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
     
        public ChessBoard() {
            this.setTitle("欢乐五子棋");
            chessPanel = new ChessPanel();
            this.add(chessPanel,BorderLayout.CENTER);
            reStart.addActionListener(this);
            fail .addActionListener(this);
            Regret.addActionListener(this);
            PlayMusic.addActionListener(this);
            CommandPanel.add(reStart);
            CommandPanel.add(fail);
            CommandPanel.add(Regret);
            CommandPanel.add(PlayMusic);
            this.add(CommandPanel,BorderLayout.SOUTH);
            this.setBounds(10, 10, 800, 800);
            this.setVisible(true);
            this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
        public static void main(String[] args) {
            ChessBoard Board = new ChessBoard();
     
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            if(e.getSource()==reStart){
                command ="重新开始";
                chessPanel.canPlay = true;
            }else if(e.getSource()==fail){
                command ="认输";
                JOptionPane.showMessageDialog(chessPanel,"It's a pity,you have fail the game!");
                chessPanel.canPlay = false;
            }else if (e.getSource()==Regret){
                command ="悔棋";
            }else if (e.getSource()==PlayMusic){
                // todo 播放音乐,单数次播放;
                if (count%2==1){
                    music.play();
                }else {
                    music.stop();
                }
                count++;
                command = null;
            }
            if(command!=null){
                Pieces pieces = new Pieces(command);
                try {
                    this.chessPanel.client.send(pieces);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
     
        }
    }

    ChessPanel:

    package view;
    // 五子棋面板,就是在这里面画图。
    // todo 背景图片 ,也许一个背景音乐
    import net.TcpClient;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.ConnectException;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.Iterator;
    public class ChessPanel extends JPanel implements MouseListener{
        // TODO 从服务器接收来的棋子 ,值不变有问题
    //   Pieces accept_pieces = new Pieces();
    //   Pieces send_pieces = new Pieces();
        whoWin ifWin =new whoWin() ; // 是否胜利
        TcpClient client = null; // 客户端
        boolean canPlay = true; // 是否能继续玩
        boolean isBlack = true; // 是否黑子,黑1,白2
        ArrayList allPieces = new ArrayList<>(); // 存储棋子对象,就是通过这个画图的
        int [][] allChess = new int[19][19];
        int PanelWidth;
        int PanelHeight;
        int width = 600;
        int height = 600;
        int temp = width / 18;
        int xbase,ybase;
        Image image = Toolkit.getDefaultToolkit().getImage("./src/Media/bg.jpeg"); // "./"表示当前项目下
        public ChessPanel(){
            this.addMouseListener(this);
            try {
                Socket socket = new Socket("172.27.29.190", 10086);
                //TODO 构建输出输入流,输入输出流问题,先输出后输入
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                client = new TcpClient(socket,ois,oos);
                new Thread(new getMessage()).start(); // 开启读取的线程
            } catch (ConnectException e){
                System.out.println("服务器拒绝连接!");
            } catch (IOException e) {
                e.printStackTrace();
            }catch(Exception e ){
                e.printStackTrace();
            }
        }
        // 画图部分
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            PanelWidth = this.getSize().width; // 这两步骤
            PanelHeight = this.getSize().height;
            xbase = (PanelWidth - width) / 2;
            ybase = (PanelHeight - height) / 2;
            Graphics2D g2d = (Graphics2D) g;
    //        this.setBackground(new Color(246, 186, 114));
            g2d.drawImage(image,0,0,this.getWidth(),this.getHeight(),this);
            int x1, y1, x2, y2;
            // 画线
            for (int i = 0; i < 19; i++) {
                if (i == 0 || i == 18) {
                    g2d.setStroke(new BasicStroke(3.0f));
                } else g2d.setStroke(new BasicStroke(1.0f));
                x1 = xbase + temp * i;
                y1 = ybase;
                y2 = ybase + 18 * temp;
                g2d.drawLine(x1, y1, x1, y2);
                x1 = xbase;
                y1 = ybase + temp * i;
                x2 = xbase + temp * 18;
                g2d.drawLine(x1, y1, x2, y1);
            }
            // 开始画棋子
            int radius ;
            int xPos,yPos;
            Iterator it = allPieces.iterator(); // 迭代器遍历arraylist
            while(it.hasNext()){
                Pieces pieces = (Pieces) it.next();
                radius  = pieces.getRadius();
                xPos = pieces.getxPos();
                yPos = pieces.getyPos();
                System.out.println(pieces.getColor()+","+pieces.getxPos()+","+pieces.getyPos());
                if (pieces.getColor() == 1){
                    g2d.setColor(Color.black);
                    g2d.fillOval(xPos*temp+xbase-radius/2,yPos*temp+ybase-radius/2,radius,radius);
                }
                else if (pieces.getColor() == 2) {
                    g2d.setColor(Color.white);
                    g2d.fillOval(xPos * temp + xbase - radius / 2, yPos * temp + ybase - radius / 2, radius, radius);
                }
            }
     
        }
     
        @Override
        public void mousePressed(MouseEvent e) {
            int x ,y ;
            if (canPlay) {
                x = e.getX();
                y = e.getY();
                //  判断鼠标点击位置
                if (x >= xbase & x <= (xbase + 18 * temp) & y >= ybase & y < (ybase + 18 * temp)) {
                    // 判断是不是下在空的位置
                    int tempX = (x - xbase) / temp, tempY = (y - ybase) / temp;
                    // todo 这里是关键判断这点坐标的数组下标是什么
                    if ((x - xbase) % temp > temp / 2) {
                        x = tempX + 1;
                    } else
                        x = tempX;
                    if ((y - ybase) % temp > temp / 2)
                        y = tempY + 1;
                    else
                        y = tempY;
                    // 先判断有没有棋子,处理没有棋子的情况
                    if (allChess[x][y] != 0) {
                           JOptionPane.showMessageDialog(this, "这里有棋子了");
                    } else {
                        Pieces send_pieces = new Pieces();
                        send_pieces.setxPos(x);
                        send_pieces.setyPos(y);
                        if (isBlack){
                            send_pieces.setColor(1);
                            allChess[x][y] = 1;
                            isBlack = false;
                        }
                        else{
                            send_pieces.setColor(2);
                            allChess[x][y]=2;
                            isBlack = true;
                        }
                        allPieces.add(send_pieces); // 向棋子队列加入当前棋子
                        canPlay = false;// canPlay在true情况下, 点击一次后不能点击了
                        this.repaint();
                        ifWin = new whoWin(allChess,x,y);
                        // 如果赢了,就不能玩了,并且给出提示消息,你赢了;
                        if(ifWin.isWin()){
                            canPlay = false;
                            JOptionPane.showMessageDialog(this,"Congratulations you have won tha game !");
                        }
                        try {
                            if (client!=null){
                                client.send(send_pieces);
                            }
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
     
            }
        }
     
        // 读取来自服务器端的信息
        class getMessage implements Runnable{
            private boolean flag = true;
            public void setFlag(boolean flag) {
                this.flag = flag;
            }
     
            @Override
            public void run() {
                // 循环读
                while(flag){
                    if(client!=null){
                        try {
                            Pieces accept_pieces = client.accept();
                            String command = accept_pieces.getCommand();
                            int color = accept_pieces.getColor();
                            switch (command){
                                case "发送":{
                                    canPlay = true;
                                    if (color == 1){
                                        isBlack = false;//对方为黑我为白
                                    }else{
                                        isBlack = true;
                                    }
                                    allPieces.add(accept_pieces);
                                    allChess[accept_pieces.getxPos()][accept_pieces.getyPos()]= accept_pieces.getColor();
                                    ChessPanel.this.repaint();
                                    ifWin.setY(accept_pieces.getyPos());
                                    ifWin.setX(accept_pieces.getxPos());
                                    ifWin.setAllChess(allChess);
                                    if(ifWin.isWin()){
                                        canPlay = false;
                                        JOptionPane.showMessageDialog(ChessPanel.this,"It's a pity you have fail the game!");
                                    }
                                    break;
                                }
                                case "悔棋":{
                                    int i = JOptionPane.showConfirmDialog(ChessPanel.this,"对方请求悔棋,是否同意!");
                                    // yes 0,no 1,cancel 2,closed -1
                                    Pieces pieces = new Pieces();
                                    if (i == 0){
                                        // 同意悔棋:1.同意对方悔棋
                                        pieces.setCommand("同意悔棋");
                                        // arraylist 去除末尾的两个值,对应allChess置0
                                        int size = allPieces.size();
                                        for (int j = 1;j<=2;j++){
                                            allChess[allPieces.get(size-j).getxPos()][allPieces.get(size-j).getyPos()]=0;
                                            allPieces.remove(size-j);
                                        }
                                        ChessPanel.this.repaint();
                                    }else if(i==1){
                                        pieces.setCommand("不同意悔棋");
                                    }
                                    client.send(pieces);
                                    break;
                                }
                                case "认输":{ // 不能继续玩下去,你已经胜利
                                    JOptionPane.showMessageDialog(ChessPanel.this,"对方认输");
                                    canPlay = false;
                                    JOptionPane.showMessageDialog(ChessPanel.this,"Congratulations you have won tha game !");
                                    break;
                                }
                                case "重新开始":{ // 是否同意重新开始
                                   int i = JOptionPane.showConfirmDialog(ChessPanel.this,"对方请求重新开始,是否同意");
                                    Pieces pieces = new Pieces();
                                    if(i == 0){// allChess 和 allPieces全部置0;
                                        pieces.setCommand("同意重新开始");
                                        int size = allPieces.size();
                                        System.out.println("arraylist 长度:"+size);
                                        for (int j = 0;j

    Pieces:

    package view;
     
    import java.io.Serializable;
    // 存储棋子的相关信息
    public class Pieces implements Serializable {
        private int radius = 16;
        private int color = 0;
        private int xPos ;
        private int yPos;
        private String command = "发送";
        public String getCommand() {
            return command;
        }
     
        public void setCommand(String command) {
            this.command = command;
        }
     
        public Pieces(int color, int xPos, int yPos){
            this.color = color;
            this.xPos = xPos;
            this.yPos = yPos;
        }
        public Pieces(){
     
        }
        public Pieces(String command){
            this.command = command;
        }
        public int getRadius() {
            return radius;
        }
     
        public void setRadius(int radius) {
            this.radius = radius;
        }
     
        public int getColor() {
            return color;
        }
     
        public void setColor(int color) {
            this.color = color;
        }
     
        public int getxPos() {
            return xPos;
        }
     
        public void setxPos(int xPos) {
            this.xPos = xPos;
        }
     
        public int getyPos() {
            return yPos;
        }
     
        public void setyPos(int yPos) {
            this.yPos = yPos;
        }
    }

    WhoWin:

    package view;
    public class whoWin { // 判断是谁赢了
        private int allChess[][] = new int[19][19];
        private int x = 0;
        private int y = 0;
        public whoWin(){
     
        }
        public whoWin(int allChess[][],int x,int y){
            this.allChess = allChess;
            this.x = x;
            this.y = y;
        }
     
        public void setAllChess(int allChess[][]){
            this.allChess = allChess;
        }
        public void setX(int x){
            this.x = x;
        }
        public void setY(int y ){
            this.y = y;
        }
        public boolean isWin() {
            int color = allChess[x][y];
            int count;
            count = this.Count(1, 0, color); // 对横方向的判断
            if (count >= 5) {
                return true;
            } else {
                count = this.Count(0, 1, color); // 对竖方向的判断
                if (count >= 5) {
                    return true;
                } else {
                    count = this.Count(1, 1, color); // 对左上方向的判断
                    if (count >= 5)
                        return true;
                    else {
                        count = this.Count(1, -1, color); // 对右上方向的判断
                        if (count >= 5)
                            return true;
                    }
                }
            }
            return false;
        }
        private int Count(int xChange, int yChange, int color) {
            int count = 1;
            int tempX = xChange, tempY = yChange;
            while (color == allChess[x + xChange][y + yChange]) {
                count++;
                if (xChange != 0) {
                    xChange++;
                }
                if (yChange != 0) {
                    if (yChange > 0)
                        yChange++;
                    else
                        yChange--;
                }
            }
            xChange = tempX;
            yChange = tempY;
            while (color == allChess[x - xChange][y - yChange]) {
                count++;
                if (xChange != 0)
                    xChange++;
                if (yChange != 0) {
                    if (yChange > 0)
                        yChange++;
                    else
                        yChange--;
                }
            }
            return count;
        }
    }
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。