【Java应用】使用Java实现机器学习算法:聚类、分类、预测

article/2025/9/22 19:04:24

一、引言

1、机器学习算法概述

机器学习是一种人工智能技术,旨在通过使用数据和统计分析来让计算机系统自动改进性能。机器学习算法可分为三大类:聚类、分类和预测。聚类算法用于将数据集分成不同的群组;分类算法用于将数据分为不同的类别;预测算法用于预测未来事件或趋势。

机器学习算法广泛应用于各种领域,例如金融、医疗、教育、自然语言处理、计算机视觉等。随着数据量的不断增加和数据分析需求的不断提高,机器学习技术在各行各业都得到了广泛的应用。

2、Java语言在机器学习领域的优势

Java是一种广泛应用的编程语言,在机器学习领域也有其独特的优势。

  1. 广泛的使用:Java是一种广泛应用的编程语言,在各行各业都有广泛的应用。使用Java实现机器学习算法可以让更多的人参与到机器学习技术的研究和应用中来。
  2. 丰富的类库:Java语言有着丰富的类库,这些类库提供了许多机器学习所需的功能,如矩阵运算、数据处理、图形绘制等。这些类库可以大大简化机器学习算法的实现过程。
  3. 跨平台性:Java是一种跨平台的编程语言,可以在不同的操作系统和硬件平台上运行。这使得使用Java实现机器学习算法更具灵活性和可移植性。
  4. 安全性:Java语言有着高度的安全性,可以避免常见的安全漏洞和错误。这对于机器学习算法的实现和应用来说是非常重要的。
  5. 大型项目支持:Java语言适合开发大型项目,可以方便地管理大量的代码和数据。这对于大规模机器学习项目来说非常有用。

Java语言在机器学习领域有着独特的优势,可以帮助开发人员更加轻松地实现各种机器学习算法,并应用于不同的领域和行业中。

二、聚类算法

1、聚类算法概述

聚类算法是一种无监督学习算法,用于将数据集分成不同的群组。聚类算法通常基于相似性度量来决定数据点之间的距离,从而将数据点分成不同的群组。聚类算法在许多领域中都有广泛的应用,如市场营销、社交网络、天文学等。

2、K-Means算法

原理

K-Means算法是聚类算法中最常用的一种算法。K-Means算法的基本思想是将数据点分成K个群组,每个群组称为一个簇。K-Means算法通过最小化每个数据点到其所属簇中心的距离来确定簇中心,从而将数据点分成不同的簇。

K-Means算法的实现过程如下:

  1. 随机选择K个数据点作为初始簇中心。
  2. 将每个数据点分配给距离最近的簇中心。
  3. 根据簇中所有数据点的均值重新计算每个簇的中心。
  4. 重复第2和第3步,直到簇中心不再发生变化或达到最大迭代次数。

Java实现

下面是一个K-Means算法的Java实现示例,包括点(Point)、簇(Cluster)、以及主程序(KMeansDemo):

Point.java:
public class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double distanceTo(Point other) {
double dx = x - other.getX();
double dy = y - other.getY();
return Math.sqrt(dx * dx + dy * dy);
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}

Cluster.java:

import java.util.ArrayList;
import java.util.List;
public class Cluster {
private Point center;
private List<Point> points;
public Cluster(Point center) {
this.center = center;
this.points = new ArrayList<>();
}
public Point getCenter() {
return center;
}
public List<Point> getPoints() {
return points;
}
public void addPoint(Point point) {
points.add(point);
}
public void clearPoints() {
points.clear();
}
public void recalculateCenter() {
double sumX = 0;
double sumY = 0;
for (Point point : points) {
sumX += point.getX();
sumY += point.getY();
}
double centerX = sumX / points.size();
double centerY = sumY / points.size();
center = new Point(centerX, centerY);
}
@Override
public String toString() {
return "Cluster[center=" + center + ", points=" + points + "]";
}
}

KMeansDemo.java:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class KMeansDemo {
public static void main(String[] args) {
// 生成随机点
List<Point> points = generatePoints(100, 10, 10, 90, 90);
// 初始化K-Means算法
int k = 3;
KMeans kMeans = new KMeans(points, k);
// 运行K-Means算法
int maxIterations = 10;
kMeans.run(maxIterations);
// 打印结果
List<Cluster> clusters = kMeans.getClusters();
System.out.println("Points:");
for (Point point : points) {
System.out.println(point);
}
System.out.println("Clusters:");
for (Cluster cluster : clusters) {
System.out.println(cluster);
}
}
// 生成随机点
private static List<Point> generatePoints(int numPoints, double minX, double minY, double maxX, double maxY) {
List<Point> points = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < numPoints; i++) {
double x = minX + (maxX - minX) * random.nextDouble();
double y = minY + (maxY - minY) * random.nextDouble();
Point point = new Point(x, y);
points.add(point);
}
return points;
}
}

在运行KMeansDemo.java后,会生成100个随机点,然后使用K-Means算法将这些点分成3个簇,最后打印出每个簇的中心点和包含的点。

三、分类算法

1、分类算法概述

分类算法是机器学习领域中最常用的一种算法,它的主要任务是将数据集中的数据根据其特征分成不同的类别。分类算法可以应用于多种应用领域,例如垃圾邮件分类、图像识别、自然语言处理、医学诊断等。

下面是常见的分类算法概述:

  1. 决策树:决策树是一种基于树形结构的分类方法。它通过对数据进行逐步划分,最终生成一颗决策树,使得对新的数据进行分类时,可以根据其特征值在决策树上进行推理,从而确定其类别。
  2. 朴素贝叶斯:朴素贝叶斯是一种基于概率统计的分类方法。它假设所有特征之间相互独立,并且通过贝叶斯公式计算每个类别的概率,然后选择概率最大的类别作为分类结果。
  3. 支持向量机:支持向量机是一种基于最大间隔原则的分类方法。它通过寻找数据点中距离分类边界最近的点,从而确定分类边界,并使分类边界与不同类别的数据点之间的距离最大化,从而提高分类的准确性。
  4. k-近邻算法:k-近邻算法是一种基于距离度量的分类方法。它将新的数据点与已有数据集中的最近邻数据点进行比较,并根据最近邻数据点的类别确定新数据点的类别。
  5. 神经网络:神经网络是一种模拟人脑神经网络结构的分类方法。它通过训练神经网络模型,将输入数据与目标输出之间的映射关系进行建模,并通过反向传播算法不断调整网络权值,从而提高分类的准确性。

2、决策树算法

算法

算法中用到的公式包括:

熵的计算公式:

 

信息增益的计算公式:

 

Java实现

import java.util.*;
public class DecisionTree {
private Node root;
// 决策树节点
private static class Node {
private final String attribute; // 节点对应的属性
private final Map<String, Node> children; // 子节点
private final String result; // 叶节点对应的结果
// 内部类的构造函数
private Node(String attribute) {
this.attribute = attribute;
this.children = new HashMap<>();
this.result = null;
}
private Node(String result, boolean isLeaf) {
this.attribute = null;
this.children = null;
this.result = result;
}
private boolean isLeaf() {
return result != null;
}
}
// 训练决策树
public void train(List<Map<String, String>> data) {
List<String> attributes = new ArrayList<>(data.get(0).keySet()); // 获取数据中所有属性的列表
attributes.remove("label"); // 移除类别属性
root = buildTree(data, attributes);
}
// 递归地构建决策树
private Node buildTree(List<Map<String, String>> data, List<String> attributes) {
if (data.isEmpty()) {
return new Node(null, true);
}
// 所有样本属于同一类别
String firstClass = data.get(0).get("label");
boolean allSameClass = data.stream().allMatch(d -> d.get("label").equals(firstClass));
if (allSameClass) {
return new Node(firstClass, true);
}
// 没有属性可分裂
if (attributes.isEmpty()) {
return new Node(majorityClass(data), true);
}
// 选择最佳分裂属性
String splitAttribute = selectBestAttribute(data, attributes);
Node node = new Node(splitAttribute);
// 递归构建子节点
Map<String, List<Map<String, String>>> splits = splitData(data, splitAttribute);
for (Map.Entry<String, List<Map<String, String>>> entry : splits.entrySet()) {
String value = entry.getKey();
List<Map<String, String>> subset = entry.getValue();
List<String> remainingAttributes = new ArrayList<>(attributes);
remainingAttributes.remove(splitAttribute);
Node child = buildTree(subset, remainingAttributes);
node.children.put(value, child);
}
return node;
}
// 预测单个样本
public String predict(Map<String, String> instance) {
Node node = root;
while (!node.isLeaf()) {
String attribute = node.attribute;
String value = instance.get(attribute);
node = node.children.get(value);
}
return node.result;
}
// 获取数据集中类别最多的类
private String majorityClass(List<Map<String, String>> data) {
Map<String, Integer> counts = new HashMap<>();
for (Map<String, String> instance : data) {
String cls = instance.get("label");
counts.put(cls, counts.getOrDefault(cls, 0) + 1);
}
return Collections.max(counts.entrySet(), Map.Entry.comparingByValue()).getKey();
}
//
// 计算信息熵
private double entropy(List<Map<String, String>> data) {
int n = data.size();
if (n <= 1) {
return 0;
}
Map<String, Integer> counts = new HashMap<>();
for (Map<String, String> instance : data) {
String cls = instance.get("label");
counts.put(cls, counts.getOrDefault(cls, 0) + 1);
}
double entropy = 0;
for (int count : counts.values()) {
double p = (double) count / n;
entropy -= p * Math.log(p) / Math.log(2);
}
return entropy;
}
// 计算信息增益
private double informationGain(List<Map<String, String>> data, String attribute) {
double entropyBeforeSplit = entropy(data);
Map<String, List<Map<String, String>>> splits = splitData(data, attribute);
double entropyAfterSplit = 0;
int n = data.size();
for (List<Map<String, String>> subset : splits.values()) {
double p = (double) subset.size() / n;
entropyAfterSplit += p * entropy(subset);
}
return entropyBeforeSplit - entropyAfterSplit;
}
// 选择信息增益最大的属性
private String selectBestAttribute(List<Map<String, String>> data, List<String> attributes) {
String bestAttribute = null;
double maxInformationGain = -1;
for (String attribute : attributes) {
double informationGain = informationGain(data, attribute);
if (informationGain > maxInformationGain) {
maxInformationGain = informationGain;
bestAttribute = attribute;
}
}
return bestAttribute;
}
// 根据属性分裂数据
private Map<String, List<Map<String, String>>> splitData(List<Map<String, String>> data, String attribute) {
Map<String, List<Map<String, String>>> splits = new HashMap<>();
for (Map<String, String> instance : data) {
String value = instance.get(attribute);
List<Map<String, String>> subset = splits.getOrDefault(value, new ArrayList<>());
subset.add(instance);
splits.put(value, subset);
}
return splits;
}
public static void main(String[] args) {
// 训练集
List<Map<String, String>> data = new ArrayList<>();
// 添加训练数据
Map<String, String> instance1 = new HashMap<>();
instance1.put("outlook", "sunny");
instance1.put("temperature", "hot");
instance1.put("humidity", "high");
instance1.put("windy", "false");
instance1.put("label", "no");
data.add(instance1);
//自己编数据吧。。。
//构建决策树
DecisionTree decisionTree = new DecisionTree();
decisionTree.train(data);
// 进行预测
Map<String, String> instance = new HashMap<>();
instance.put("outlook", "sunny");
instance.put("temperature", "cool");
instance.put("humidity", "high");
instance.put("windy", "false");
String prediction = decisionTree.predict(instance);
System.out.println("Prediction: " + prediction);
}
}

四、预测算法

1、预测算法概述

预测算法是一种机器学习算法,用于预测未来的事件或趋势。这些算法基于历史数据和统计分析,从中学习并推断出可能的未来情况。以下是几种常见的预测算法:

  1. 线性回归:线性回归是一种用于建立线性模型的算法,它将自变量与因变量之间的关系拟合为一条直线。
  2. 逻辑回归:逻辑回归是一种分类算法,它将输入特征映射到输出类别的概率上。
  3. 决策树:决策树是一种基于树形结构的算法,它通过将样本分割成不同的子集,最终输出预测结果。
  4. 随机森林:随机森林是一种集成学习算法,它通过组合多个决策树来进行预测,从而提高预测精度和鲁棒性。
  5. 神经网络:神经网络是一种模拟人脑的算法,它通过训练多层神经元来学习输入和输出之间的非线性映射关系。

2、线性回归算法

算法

线性回归是一种用于建立线性模型的算法,它可以用于预测因变量和自变量之间的关系。该算法的基本原理是建立一个线性方程,通过寻找最佳拟合线,来解决回归问题。

下面是线性回归的基本原理:

  1. 线性方程:线性回归假设因变量y和自变量x之间存在一个线性关系。该关系可以表示为y = β0 + β1*x + ε,其中β0和β1是回归系数,ε是误差项。
  2. 最小二乘法:最小二乘法是一种常用的求解线性回归系数的方法。该方法的目标是最小化误差平方和,即找到最佳拟合线,使得所有数据点到该线的距离之和最小化。
  3. 模型评估:线性回归的模型评估通常使用R方值和均方误差(MSE)来衡量模型的准确性。R方值表示模型解释的变异性占总变异性的比例,而MSE则表示模型预测值和真实值之间的平均偏差程度。
  4. 多元线性回归:当自变量不止一个时,可以使用多元线性回归模型。该模型可以表示为y = β0 + β1x1 + β2x2 + ... + βn*xn + ε,其中x1, x2, ..., xn是自变量,β1, β2, ..., βn是回归系数,ε是误差项。

Java实现

以下是一个基于Java语言实现的线性回归算法的示例代码,其中使用最小二乘法求解回归系数,以预测房价为例:

import java.util.ArrayList;
import java.util.List;
public class LinearRegressionDemo {
public static void main(String[] args) {
// 创建训练数据
List<Double> x = new ArrayList<>();
List<Double> y = new ArrayList<>();
x.add(2.0); y.add(10.0);
x.add(4.0); y.add(20.0);
x.add(5.0); y.add(22.0);
x.add(7.0); y.add(30.0);
x.add(8.0); y.add(33.0);
// 训练模型
double[] coefficients = train(x, y);
// 预测房价
double price = predict(coefficients, 6.0);
System.out.println("预测房价:" + price);
}
// 训练模型
public static double[] train(List<Double> x, List<Double> y) {
int n = x.size();
double xSum = 0.0, ySum = 0.0, xySum = 0.0, xxSum = 0.0;
for (int i = 0; i < n; i++) {
xSum += x.get(i);
ySum += y.get(i);
xySum += x.get(i) * y.get(i);
xxSum += x.get(i) * x.get(i);
}
double xMean = xSum / n;
double yMean = ySum / n;
double beta1 = (xySum - n * xMean * yMean) / (xxSum - n * xMean * xMean);
double beta0 = yMean - beta1 * xMean;
double[] coefficients = new double[2];
coefficients[0] = beta0;
coefficients[1] = beta1;
return coefficients;
}
// 预测房价
public static double predict(double[] coefficients, double x) {
double beta0 = coefficients[0];
double beta1 = coefficients[1];
return beta0 + beta1 * x;
}
}

该示例代码中,train方法用于训练模型,使用最小二乘法求解回归系数;predict方法用于预测房价,根据已训练好的回归系数来计算预测值。最后,在main方法中,我们可以通过train方法训练模型,然后使用predict方法来预测房价。当然,这里的训练数据只是一个简单的示例,实际应用中需要更多和更准确的数据来训练和测试模型。

五、结论

Java在机器学习领域具有广泛的应用前景。

1、适合大型应用程序:Java具有卓越的内存管理和处理能力,这使得它非常适合处理大型数据集和复杂的机器学习算法。Java中的JVM和垃圾回收机制可以保证大型程序的性能和稳定性。

2、应用程序的开发和部署:Java具有良好的跨平台性,可以轻松地在不同的操作系统和设备上进行开发和部署。Java的许多机器学习框架也可以方便地进行部署和管理。

3、强大的机器学习库:Java生态系统中有很多强大的机器学习库,如Weka、DL4J、Mallet、H2O等,这些库提供了许多有用的工具和算法,以帮助开发人员轻松地实现机器学习应用程序。

4、Java与大数据:Java在大数据领域也非常流行,它可以轻松地与大数据框架(如Hadoop、Spark和Flink)和其他大数据技术(如Kafka和Cassandra)集成,以进行分布式数据处理和分析。

5、Java与云计算:Java的跨平台性和强大的内存管理使其成为云计算领域的首选语言之一。许多云服务提供商都支持Java应用程序的部署和运行,如AWS、Azure和Google Cloud。

因此,Java在机器学习领域具有广泛的应用前景,尤其是在大规模数据处理、云计算和大数据分析等方面。


http://chatgpt.dhexx.cn/article/97fyv8M8.shtml

相关文章

KL15和KL30

一、KL15节点方式 这是最直接和简单的方法&#xff0c;将所有CAN总线上的ECU电源都接在KL15上面。(KL15是当点火开关在ON上才接通蓄电池电源&#xff09; 缺点&#xff0c;无法适应所有的ECU&#xff1a; 1.可以断电关闭&#xff0c;比如座椅控制。 2.有些ECU在汽车到OFF档时…

KL15和KL30节点网络管理概念

一、KL15节点方式 这是最直接和简单的方法&#xff0c;将所有CAN总线上的ECU电源都接在KL15上面。(KL15是当点火开关在ON上才接通蓄电池电源&#xff09; 缺点&#xff0c;无法适应所有的ECU&#xff1a; 1.可以断电关闭&#xff0c;比如座椅控制。 2.有些ECU在汽车到OFF档时…

KL15 是什么?ACC,crank,on等

KL含义 KL is the abbreviation for klemme which is the German term for connector / connection.KL是“ klemme”的缩写&#xff0c;这是德语中连接器或连接的术语。 KL30 &#xff0c;通常表示电瓶的正极。positive KL31&#xff0c;通常表示电瓶的负极。negative KL15, 通…

CANoe串口控制电源

一、工具 CANoe12.0版本&#xff0c;VN1630A 可控制电源---固纬PSW 30-36 二、CAPL编写 1、在variables变量总定义串口的一些配置信息 这里定义的port_KL30和port_KL15具体的值可以去查看设备管理器连接的串口值是多少。 2、初始化串口定义 3、串口发送函数 一切定义配置…

MKS GEN_L V2.1 Klipper固件使用说明书

广州谦辉信息科技有限公司 MKS GEN_L V2.1 Klipper固件使用说明书 创客基地QQ群&#xff1a;489095605 232237692 邮箱&#xff1a;Huangkaidamakerbase.com.cn 文章目录 一、产品简述1.1特点优势1.2主板参数1.3接线图1.4尺寸图 二、固件下载、更新2.1固件下载2.2 使用Xloader更…

Vector - VT System - 板卡_VT7001

接上篇我们介绍完了背板VT8006和VT8012&#xff0c;今天我们来介绍下电源模块板卡VT7001&#xff0c;这个板卡是我们在不需要程控电源的时候依然能够实现精细化的电压、电流控制及检查的板卡&#xff0c;并且在脚本开发中无需考虑时延的一个模块。我们使用的大部分设备无论是继…

车载中电源的术语

文章目录 前言电源模式KLR模式KL30模式KL31模式KL15模式KL50模式 前言 ​ 对于车载测试来说&#xff0c;一般是很少进行电源测试&#xff0c;但是这并不代表着我们不用去了解&#xff0c;在面试中也会经常问到电源相关的一部分知识&#xff0c;所以还是有必要了解一下的 电源…

主动/被动唤醒源与网络主动/被动唤醒

1主动唤醒源/被动唤醒源 主动唤醒源&#xff1a;承担着主动唤醒网络责任的唤醒源&#xff0c;称为主动唤醒源。比如&#xff1a;KL15硬线&#xff0c;User请求&#xff0c;ERA信号等。 KL15硬线&#xff1a;通过KL15硬线方式唤醒网络&#xff0c;说明当前网络没有节点参与通信…

【车载】【汽车电源】简述汽车电源系统

一、汽车电源 一般来讲&#xff0c;传统能源汽车的电源主要来源于电池和发电机&#xff0c;电池为汽车启动提供能量来源&#xff0c;当汽车启动完成之后&#xff0c;汽车的发电机又会为电池充电。由于发电机和发动机是靠皮带连接的&#xff0c;所以广义上也称发动机发电。而发电…

AUTOSAR EcuM学习(一)

简介 ECU Manager(EcuM)的主要任务包括&#xff1a; 初始化(initializes)/反初始化(de-initializes)OS、SchM及BSW模块&#xff1b;执行ECU的关闭(SHUTDOWN)和睡眠(SLEEP)动作&#xff1b;处理唤醒(wakeup)事件并对唤醒源进行校验(wakeup validation)。 最初ECU的整个状态管理…

AUTOSAR EcuM学习(二)

前言 本文以一个简化的示例看下ECU唤醒休眠的执行流程&#xff0c;通常不同项目因需求不同流程处理都会有所不同&#xff0c;本示例只是其中一种&#xff0c;并不是标准普适的流程。假设ECU休眠采用的是MCU掉电方式&#xff0c;且只有两个唤醒源&#xff1a;CAN和KL15&#xf…

KL15含义-- 汽车钥匙孔挡位

KL含义 KL是德文connector含义&#xff0c;芯片引脚的含义。 KL30 &#xff0c;通常表示电瓶的正极。positive KL31&#xff0c;通常表示电瓶的负极。negative KL15, 通常汽车处于RUN模式 KL50&#xff0c;通常汽车处于crank模式 KLR&#xff0c;通常汽车处于的ACC模式 汽车钥…

浅谈汽车应用中的KL15与KL30

浅谈汽车应用中的KL15与KL30 身处汽车行业或者经常看汽车应用的原理图&#xff0c;就经常能看到KL30和KL15等网络标号&#xff0c;这是什么意思&#xff0c;来简单聊下。 KL15指点火信号 KL30指蓄电池供电电压 为啥叫KL呢 其实他是德语Klemme的缩写&#xff0c;指的是ECU的管…

KL15和汽车各个档位

KL是德语Klemme的缩写&#xff0c;意思是ECU的管脚、接线柱&#xff0c;和Pin意思相同&#xff0c;后面的数字代表不同的电源模式。 KL15表示发动机的点火信号和启动车辆的信号&#xff0c;驾驶循环以此为准 KL15R&#xff0c;其中R表示Radio&#xff0c;用于启动车辆的仪表盘…

为什么点火信号叫KL15,蓄电池电压叫KL30?

在刚进入汽车行业时&#xff0c;听到前辈讨论问题时偶尔蹦出来的KL15、KL30&#xff0c;那会内心一脸懵逼&#xff0c;这啥意思呢&#xff1f; 当时也没好意思打断大家的讨论&#xff0c;直接询问。 等他们讨论完后悄咪咪的问了一下坐我对面的同事。 才知道KL15是指点火信号…

在微信开发者工具导入整个weui的实例,查看weui的用法

方法 下载weui的源代码&#xff0c;https://github.com/Tencent/weui-wxss/ &#xff0c; clone or download > Download ZIP解压&#xff0c;找到dist文件夹&#xff0c;在./weui-wxss-master/dist/打开“微信开发者工具”&#xff0c;选择“小程序” > “导入项目” &…

WeUI实例(官方)

博主最近想用小程序画几个页面&#xff0c;于是想试试WeUI的样式。但是没找到WeUI的文档&#xff0c;只找到了在线的实例演示。还有的例子是在div上显示的&#xff0c;当时比较疑惑。后来发现&#xff0c;可能是公众号的页面。 实例演示的链接&#xff1a;传送门 其实这些实例…

WeUI—微信官方UI库

WeUI 为微信 Web 服务量身设计 概述 WeUI是一套同微信原生视觉体验一致的基础样式库&#xff0c;由微信官方设计团队为微信 Web 开发量身设计&#xff0c;可以令用户的使用感知更加统一。包含button、cell、dialog、 progress, toast、article、icon等各式元素。 使用 方法一&a…

HTML5 weui笔记

按钮 <a href"javascript:;" class"weui_btn weui_btn_primary">按钮-确定-可用</a> <a href"javascript:;" class"weui_btn weui_btn_disabled weui_btn_primary">按钮-确定-不可用</a> <a href"jav…

微信小程序引入原生组件——WeUI组件库,详细步骤

第一步&#xff1a;查看是否可使用npm命令&#xff0c;没有则安装&#xff1a; 我这里已经安装了&#xff0c;如果没有则安装node.js node官网下载地址&#xff1a;https://nodejs.org/en/ 注意这个windows 64位的&#xff1a; 其他系统看这里&#xff1a;点击dowloads 先点击L…