介绍Java中的常/变量.各种数据类型以及类型转换和提升的用法

news2025/1/15 16:54:24

本文简单描述了什么是常量和变量,介绍了Java各种数据类型:基本数据类型(四类八种,大小和范围)和引用数据类型(种类),简单介绍了包装类字符串类型,以及不同数据类型之间的常量和变量,数据类型之间的转换和提升…

Java常/变量和数据类型

  • 一.什么是常量?
  • 二.什么是变量?
  • 三.数据类型有哪些?
  • 四.不同数据类型的常量和变量
    • 简单介绍一下包装类:
    • 1.整形家族变量
      • ①.字节型byte
      • ②.短整型short
      • ③.整形int
      • ④.长整形long
    • 2.浮点型家族
      • ①.单精度浮点型float
      • ②.双精度浮点型double
    • 3.字符型char
    • 4.布尔型boolean
    • 5.字符串类型String
  • 五.类型转换和提升
    • 1.自动类型转换(隐式)
    • 2.强制类型转换(显式)
    • 3.类型提升

一.什么是常量?

常量即程序运行期间,固定不变的量称为常量.比如一年有365天,一个星期有7天,这些都是不变的量

public class Demo{
public static void main(String[] args){
System.Out.println("hello world!");
System.Out.println(100);
System.Out.println(3.14);
System.Out.println('A');
System.Out.println(true);
System.Out.println(false);
}
}

以上输出的都是常量,是不可被更改的,也被称为字面常量

字面常量的分类:

  1. 字符串常量:由""括起来的,比如“12345”、“hello”、“你好”。
  2. 整形常量:程序中直接写的数字(注意没有小数点),比如:100、1000
  3. 浮点数常量:程序中直接写的小数,比如:3.14、0.49
  4. 字符常量:由 单引号 括起来的当个字符,比如:‘A’、‘1’
  5. 布尔常量:只有两种true和false
  6. 空常量:null

二.什么是变量?

在程序中,除了有始终不变的常量外,有些内容可能会经常改变,比如:人的年龄、身高、成绩分数、数学函数的计算结果等,
对于这些经常改变的内容,在Java程序中,称为变量。
而变量也可以看做就是一个空间,用来存放描述信息的常量.常量是固定不变的,但是空间里的常量可以被其他常量覆盖,从而产生了变化的效果,而这个空间就是一个固定容器用来描述不断变化的量

定义变量的格式:

数据类型 变量名 = 初始值;// 定义出来的一个变量必须得先存放一个初始值
变量名= 常量值 // 变量里的值可以通过赋值 更改 达到变化的效果

上面说的常量有很多种类型,这些不同类型的常量需要类型相对应的空间来存储,所以变量也有很多种,也就是各种不同类型的空间,这些不同类型也被称为数据类型,下面来认识一下Java中的数据类型吧

三.数据类型有哪些?

在Java中数据类型主要分为两类:基本数据类型和引用数据类型。
引用类型:

类,接口,数组 java中有字符串类型属于引用类型

而基本数据类型有四类八种

1. 四类:

整型、浮点型、字符型以及布尔型

2.八种

数据类型关键字内存占用 (单位:字节Mb)范 围
字节型byte1-128~127 (- 2^7~ 2^7-1)
短整型short2-32768 ~ 32767(- 2^15~ 2^15-1)
整形int4-2,147,483,648 ~2,147,483,647 (- 2^31~ 2^31-1)
长整形long8(- 2^63~ 2^63-1)
单精度浮点型float4有范围,因存储精度损失等原因 一般不关注
双精度浮点型double8有范围,因存储精度损失等原因 一般不关注
字符型char20~65,535 (\u0000 ~\uffff)
布尔型boolean没有明确规定true 或者 false

注意:

不论是在64位系统还是32位系统,int都占用4个字节,long都占8个字节
且整形和浮点型都是带有符号的 最高位表示正负位
整型默认为int型,浮点型默认为double

这些不同数据类型的数据在计算机中都是以二进制形式存储,而每八个二进制位代表一个字节
什么是字节?

字节是计算机中表示空间大小的一个基本单位. 计算机使用二进制表示数据. 我们认为 8 个二进制位(bit) 为一个字节(Byte).
我们平时的计算机为 8GB 内存, 意思是 8G 个字节. 其中 1KB = 1024 Byte, 1MB = 1024 KB, 1GB =
1024 MB. 所以 8GB 相当于 80 多亿个字节

四.不同数据类型的常量和变量

上面简单介绍到了常量和变量 以及每个数据类型,下面介绍的是不同数据类型的常量和变量的声明定义

简单介绍一下包装类:

Java本身是一个面向对象的语言,而基本数据类型并不满足面向对象的特点,为了解决这一不足,设计了包装类,也就是对应的八个基本数据类型的八个个类类型,这些类类型里有很多设计好的静态成员方法或成员变量等,当我们想实现某种功能时,可以通过包装类类型 . 然后对应的成员方法或成员变量
如: Integer.valueOf() 是调用一个int对应的包装类Integer 里面的valueOf方法 可以实现将某个特定数据类型转换为整数. 具体详细以后介绍

1.整形家族变量

整形家族变量可细分为 字节型变量 短整型变量 整形变量 长整形变量
而整形常量默认就是int也就是整形类型

①.字节型byte

byte b = 10;
System.Out.println(b);
// byte型变量所能表示的范围:
System.Out.println(Byte.MIN_VALUE); //字节类型对应的包装类类型
System.Out.println(Byte.MAX_VALUE);

注意事项:

  1. byte在任何系统下都占1个字节
  2. byte的范围是:-128 ~ 127
  3. 字节的包装类型为Byte

②.短整型short

short a = 10;
System.Out.println(a);
// short型变量所能表示的范围:
System.Out.println(Short.MIN_VALUE);
System.Out.println(Short.MAX_VALUE);

注意事项:

  1. short在任何系统下都占2个字节
  2. short的表示范围为:-32768 ~ 32767
  3. 使用时注意不要超过范围(一般使用比较少)
  4. short的包装类型为Short

③.整形int

// 方式一:在定义时给出初始值
int a = 10;
System.Out.println(a);
// 方式二:在定义时没有给初始值,但使用前必须设置初值
int b;
b = 10;
System.Out.println(b);
// 使用方式二定义后,在使用前如果没有赋值,则编译期间会报错
int c;
System.Out.println(c);
c = 100;
// int型变量所能表示的范围:
System.Out.println(Integer.MIN_VALUE);
System.Out.println(Integer.MAX_VALUE);
// 注意:在定义int性变量时,所赋值不能超过int的范围
int d = 12345678901234; // 编译时报错,初值超过了int的范围

注意事项:

  1. int不论在何种系统下都是4个字节
  2. 推荐使用方式一定义,如果没有合适的初始值,可以设置为0
  3. 在给变量设置初始值时,值不能超过int的表示范围,否则会导致溢出
  4. 变量在使用之前必须要赋初值,否则编译报错
  5. int的包装类型为 Integer

④.长整形long

int a = 10;
long b = 10; // long定义的长整型变量
long c = 10L; // 为了区分int和long类型,一般建议:long类型变量的初始值之后加L或者l
long d = 10l; // 一般更加以加大写L,因为小写l与1不好区分
// long型变量所能表示的范围:这个数据范围远超过 int 的表示范围. 足够绝大部分的工程场景使用.
System.Out.println(Long.MIN_VALUE);
System.Out.println(Long.MAX_VALUE);

注意事项:

  1. 长整型变量的初始值后加L或者l,推荐加L
  2. 长整型不论在那个系统下都占8个字节
  3. 长整型的表示范围为: - 2^63 ~ 2^63-1
  4. long的包装类型为Long
  5. 整形常量默认是int类型,如果其大小超过int会报错 要表示一个长整形一定要在后面加上L

2.浮点型家族

①.单精度浮点型float

float num = 1.0f; // 写作 1.0F 也可以
System.out.println(num);

注意事项:

1.浮点型常量默认是double类型
2.要表示float类型变量要在后面加上f或者F
3.单精度浮点型大小为4个字节
4.float 类型在 Java 中占四个字节, 同样遵守 IEEE 754 标准. 由于表示的数据精度范围较小, 一般在工程上用到浮点数都优先考虑 double, 不太推荐使用 float.
5. float的包装类型为Float。

②.双精度浮点型double

double d = 3.14;   //3.14 浮点型常量 默认为double类型
System.Out.println(d);

注意事项

  1. double在任何系统下都占8个字节
  2. 浮点数与整数在内存中的存储方式不同,不能单纯使用 的形式来计算
  3. double的包装类型为Double

关于浮点数精度损失:

浮点数在计算机内存储最后会转换为二进制数会存在精度损失,存储是遵守IEEE754标准,想仔细了解可以单击右方看看我这篇博客->浮点数在内存中存储

3.字符型char

java中表达字符型变量 要用char类型声明,而表达char类型的常量需要写在两个单引号内 如:‘1’ 即是字符常量1 不写单引号则是数字1

char c1 = 'A'; // 大写字母
char c2 = '1'; // 数字字符
System.out.println(c1);
System.out.println(c2);
// 注意:java中的字符可以存放整形
char c3 = '帅';
System.out.println(c3);

注意事项:

  1. Java 中使用 单引号 + 单个字母 的形式表示字符字面值.
  2. 计算机中的字符本质上是一个整数. 在 C 语言中使用 ASCII 表示字符, 而 Java 中使用 Unicode 表示字符. 因此 一个字符占用两个字节, 表示的字符种类更多, 包括中文
  3. char的包装类型为Character

执行 javac 的时候可能出现以下错误:

Test.java:3: 错误: 未结束的字符文字
char ch = ‘鍛?’;
^

此时我们在执行 javac 时加上 -encoding UTF-8 选项即可

javac -encoding UTF-8 Test.java(文件名.后缀名)

感兴趣也可以看看这篇文章了解 ->java char类型

4.布尔型boolean

布尔类型是Java中用来表示真或者假,它只有两种取值,true表示真 false表示假

boolean b = true;
System.out.println(b);
b = false;
System.out.println(b);

注意事项:

  1. boolean 类型的变量只有两种取值, true 表示真, false 表示假.
  2. Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法.
  3. Java虚拟机规范中,并没有明确规定boolean占几个字节,也没有专门用来处理boolean的字节码指令,在Oracle公司的虚拟机实现中,boolean占1个字节。
  4. boolean的包装类型为Boolean
    5.boolean类型的常量不能与其他类型进行交互运算如:true+1

5.字符串类型String

字符串类型是Java中的一个引用类型,并不属于基本数据类型,但是时常需要使用到,先简单介绍一些基本的用法

public static void main(String[] args) {
String s1 = "hello";
String s2 = " world";
System.out.println(s1);
System.out.println(s2);
System.out.println(s1+s2); // s1+s2表示:将s1和s2进行拼接
}

注意事项:

1.字符串类型常量需要在"“双引号内,声明字符串变量要用String
2.字符串可以进行拼接即字符串+任何基本数据类型的数据可以拼接成一个新字符串,
3. 1+1+“abc"结果会变为"2abc"而"abc”+1+1会变为"abc11”,加法运算遵循从左往右,第一个是两个整形相加后再拼接,第二个是先拼接一个整数再拼接第二个整数1

在有些情况下,需要将字符串和整形数字之间进行转换:
1. int 转成 String

int num = 10;
// 方法1
String str1 = num + "";//通过拼接一个空字符串将整形变为字符串
// 方法2
String str2 = String.valueOf(num);  //valueOf将整形转换为字符串的一个方法

2. String 转成 int

String str = "100";
int num = Integer.parseInt(str);//parseInt 是Integer包装类里的一个将数字字符串转换为整形的方法
int num = Integer.valueOf(str); //Integer包装类里的valueOf方法也能使字符串转换为整形

五.类型转换和提升

类型提升有点类似于不同数据类型的转换,当两个数据之间类型不同时,若直接进行比较或赋值运算时会自动先将两个不同类型的数据均转化为其中的某种类型再进行操作,因此发生了类型提升。导致一些意外性让人茫然的错误。

Java 作为一个强类型编程语言, 当不同类型之间的变量相互赋值的时候, 会有教严格的校验

int a = 10;
long b = 100L;
b = a; // 可以通过编译
a = b; // 编译失败

在Java中,当参与运算数据类型不一致时,就会进行类型转换。Java中类型转换主要分为两类:
自动类型转换(隐式) 和 强制类型转换(显式)。

1.自动类型转换(隐式)

自动类型转换即:代码不需要经过任何处理,在代码编译时,编译器会自动进行处理。特点:数据范围小的转为数 据范围大的时会自动进行。

System.Out.println(1024); // 整型默认情况下是int
System.Out.println(3.14); // 浮点型默认情况下是double
int a = 100;
long b = 10L;
b = a; // a和b都是整形,a的范围小,b的范围大,当将a赋值给b时,编译器会自动将a提升为long类型,然后赋值
a = b; // 编译报错,long的范围比int范围大,可能会有数据丢失,不安全
float e=3.14//编译报错 3.14是默认为double 此时直接赋值给float类型的变量可能存在数据丢失必须在后面加上F类型转换
float f = 3.14F;
double d = 5.12;
d = f; // 编译器会将f转换为double,然后进行赋值
f = d; // double表示数据范围大,直接将float交给double会有数据丢失,不安全
byte b1 = 100; // 编译通过,100没有超过byte的范围,编译器隐式将100转换为byte
byte b2 = 257; // 编译失败,257超过了byte的数据范围,有数据丢失

在这里插入图片描述

2.强制类型转换(显式)

强制类型转换:当进行操作时,代码需要经过一定的格式处理,不能自动完成。特点:数据范围大的到数据范围小的。需要借助强制类型转换操作符 (类型)数据

在上面看到许多编译报错,是由范围大的数据放到范围小的变量中,如果要实现赋值,需要借助强转类型操作符也就是强制类型转换

int a = 10;
long b = 100L;
b = a; // int-->long,数据范围由小到大,隐式转换
a = (int)b; // long-->int, 数据范围由大到小,需要强转,否则编译失败
float f = 3.14F;
double d = 5.12;
d = f; // float-->double,数据范围由小到大,隐式转换
f = (float)d; // double-->float, 数据范围由大到小,需要强转,否则编译失败
a = d; // 报错,类型不兼容
a = (int)d; // int没有double表示的数据范围大,需要强转,小数点之后全部丢弃
byte b1 = 100; // 100默认为int,没有超过byte范围,隐式转换
byte b2 = (byte)257; // 257默认为int,超过byte范围,需要显示转换,否则报错
boolean flag = true;
a = flag; // 编译失败:类型不兼容
flag = a; // 编译失败:类型不兼容

在这里插入图片描述

注意事项:

  1. 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型
  2. 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失
    如:byte b2=(byte)257;因为257是整形范围大 而转化为byte后范围变小发生截断 在byte类型后表达是的数字1
  3. 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查
    byte b1=100;对字面常量进行赋值 java会对数字范围检查 100虽然是int类型但是在byte范围内则会自动转换为byte直接赋值 不会报错 但如果超过了范围java也会编译失败,除非进行强转发生截断
    如果 int a=100; byte b1=a则会报错,因为a是一个整形类型变量不是字面常量,编译器无法自动对范围检查即便其内的数据范围满足byte范围也必须进行强转
  4. 强制类型转换不一定能成功,不相干的类型不能互相转换
    int a =(int)true 会报错

3.类型提升

当两个不同数据类型的数据进行交互运算时,范围全小于int类型时会自动提升到int类型范围
当其中一个数据类型大于等于int类型且大于另一个数据类型时,另一个数据类型会提升到和该数据类型一样的范围进行运算

1. int与long之间:int会被提升为long

int a = 10;
long b = 20;
int c = a + b; // 编译出错: a + b==》int + long--> long + long 赋值给int时会丢失数据必须强转
long d = a + b; // 编译成功:a + b==>int + long--->long + long 赋值给long

2. byte与byte的运算

byte a = 10;
byte b = 20;
byte c = a + b;  //编译失败 a+b会类型提升为int类型 此时赋给c会报错 必须进行强转
System.out.println(c);
// 编译报错
Test.java:5: 错误: 不兼容的类型:int转换到byte可能会有损失
byte c = a + b;
^

在这里插入图片描述

byte 和 byte 都是相同类型, 但是出现编译报错. 原因是, 虽然 a 和 b 都是 byte, 但是计算 a + b 会先将 a
和 b 都提升成 int, 再进行计算, 得到的结果也是 int, 这是赋给 c, 就会出现上述错误.
由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short
这种低于 4 个字节的类型, 会先提升成 int, 再参与计算

正确的写法:

byte a = 10;
byte b = 20;
byte c = (byte)(a + b);
System.out.println(c)

注意:

当使用+=这类的操作符出现数据类型不同时不需要强转,编译器会自动完成

【类型提升小结:】

  1. 不同类型的数据混合运算, 范围小的会提升成范围大的.
  2. 对于 short, byte 这种比 4 个字节小的类型, 会先提升成 4 个字节的 int , 再运算.

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/166251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[审核]因为审核人员不了解苹果登录被拒

1.审核被拒信息 Guideline 2.1 - Information Needed We’re looking forward to completing the review of your app, but we need more information to continue. Next Steps Please provide detailed answers to the following questions in your reply to this message i…

寒假集训一期总结(一)–––思维训练

目录 思维训练 走方格 解题思路 参考代码 最短曼哈顿距离 ​编辑 解题思路 参考代码 酒厂选址 解题思路 参考代码 雪地足迹Tracks in the Snow 解题思路 参考代码 一个星期没有更博客了…这一个星期,去学校信竞集训的我收获颇丰,下面就是我的还加集训总结 思…

【小白向】让电脑成为热点WIFI

让电脑成为热点WIFI 本文针对下述情况,有一台电脑,一部手机,但是电脑通过网线连接。此时电脑可以上网,手机没有流量, 仅能通过WIFI上网,但此时没有WIFI。 其实你的电脑可能自己本身就能作为热点发布WIFI&…

绕任一向量旋转矩阵计算思考与实现

欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击。 问题提出 如图所示,在空间中有一向量A,问点O绕A方向逆时针旋转角度α的矩阵如何表示。 问题分析 问题化规 直接去构造一个矩阵是比较困难的。…

自从我学会了Jenkins的自动构建,我再也没有每次都打包上传到服务器然后发布Java服务了

上次我们讲了使用Jenkins部署maven项目 工作两年半,终于学会了Jenkins部署Maven项目 这次我们来讲一下每次提交代码的时候Jenkins自动构建 我们使用的代码仓库是gitee 文章目录🏃第一步,我们在Jenkins中安装gitee插件🏃第二步&am…

Go语言并发编程及依赖管理

目录🧡并发编程GoroutineCSP(Communicating Sequential Processes)🧡依赖管理依赖演变依赖管理三要素💟这里是CS大白话专场,让枯燥的学习变得有趣! 💟没有对象不要怕,我们new一个出来&#xff0…

Linux (open、write、read、close、lseek、chmod、sync)操作文件的函数详解

目录 一、文件操作方式 二、Linux底层文件操作 1. open 2. write 3. read 4. close 5. lseek 6. chmod 7. sync、syncfs、fsync、fdatasync 三、 Linux 系统调用 四、总结 linux中,一切皆文件(网络设备除外) 硬件设备也“是”文件&a…

力扣刷题记录——507.完美数、509. 斐波那契数、520. 检测大写字母

本专栏主要记录力扣的刷题记录,备战蓝桥杯,供复盘和优化算法使用,也希望给大家带来帮助,博主是算法小白,希望各位大佬不要见笑,今天要分享的是——《507.完美数、509. 斐波那契数、520. 检测大写字母》。 目…

InfluxDB + Grafana计算成功率

文章目录方式一 借助Grafana的Transfrom方式二 Influx子查询Transfrom介绍建议针对每类Metric,使用一个Metric,增加success的tag区分成功还是失败。 方式一 借助Grafana的Transfrom 第一步:新建2个Query Query Total: SELECT sum("coun…

安科瑞电气火灾监控系统在春晓161#地块人防工程的设计与应用

安科瑞 华楠摘要:本文简述了电气火灾监控系统的组成原理,分析了电气火灾监控系统在应用中的设计依据和相关规范。通过安科瑞剩余电流式电气火灾监控系统在春晓161#地块人防工程电气火灾监控系统项目的实例介绍,阐述了电气火灾监控系统功能的实…

c语言实现扫雷(详细讲解)

本篇介绍,讲解如何使用c语言实现扫雷小游戏. 金句分享: ✨✨✨爱你所爱,行你所行✨✨✨ 目录前言:一、游戏设计思路介绍:效果展示二、游戏的分步讲解2.1、主函数测试区(test.c)基本构成2.2、游戏中函数实现区(game.c) (重点)2.21、雷盘的创建与初始化函…

centos8 Ambari-2.7.6.3+HDP-3.3.1离线安装详细教程(附安装包)

自2021年1月31日开始,所有Cloudera软件都需要有效的订阅,且订阅费昂贵。此外,CDH6和HDP3将是CDH和HDP的最后企业版本,原有企业版用户无法继续获取新的功能和性能提升。至2022年3月份,CDH/HDP全部停止服务(EoS),用户没办法获取售后支持。由于生产环境系统升级到centos8,…

linux 中 PCIE 中断映射机制

PCIE 中断映射机制 1、 PCIE 中有三种中断方式, MSI,MSI-X 和INTx PCIe总线继承了PCI总线的所有中断特性(包括INTx和MSI/MSI-X),以兼容早期的一些PCI应用层软件。 PCI总线最早采用的中断机制是INTx,这是…

基于Flink+kafka实时告警

引出问题 项目使用告警系统的逻辑是将实时数据保存到本地数据库再使用定时任务做判断,然后产生告警数据。这种方式存在告警的延时实在是太高了。数据从产生到保存,从保存到判断都会存在时间差,按照保存数据定时5分钟一次,定时任务…

智慧水务能效管理平台在污水处理厂电气节能中的应用

摘要:污水处理属于高能耗行业,会消耗大量的电能、燃料和药剂等,高能耗不仅会提升污水处理成本,还会加剧能源危机。所以,本文首先探究了污水处理厂耗能的原因,分析了污水处理与节能降耗的关系,然…

MyBatis-Plus数据安全保护(加密解密)

项目创建POM依赖 <dependency><!--MyBatis-Plus 企业级模块--><groupId>com.baomidou</groupId><artifactId>mybatis-mate-starter</artifactId><version>1.2.8</version> </dependency> <!-- https://mvnrepository…

git commit 命令详解

文章目录前言1. git commit 介绍2. git commit 使用3. git commit -m4. git commit -am5. git commit --amend6. commit 多行提交信息7. commit 背后到底发生了什么前言 CSDN 只用来做博客主站文章的转载 博客主站&#xff1a;https://www.itqaq.com 下面地址路径可能会发生变…

Java---中间件---Redis的常见命令和客户端使用

Redis的常见命令和客户端使用1.初识Redis1.1.认识NoSQL1.1.1.结构化与非结构化1.1.2.关联和非关联1.1.3.查询方式1.1.4.事务1.1.5.总结1.2.认识Redis1.3.安装Redis1.3.1.依赖库1.3.2.上传安装包并解压1.3.3.启动1.3.4.默认启动1.3.5.指定配置启动1.3.6.开机自启1.4.Redis桌面客…

VulnHub2018_DeRPnStiNK靶机总结

VulnHub2018_DeRPnStiNK靶机渗透总结 靶机下载地址: https://download.vulnhub.com/derpnstink/VulnHub2018_DeRPnStiNK.ova https://www.dropbox.com/s/8jqor3tuc3jhe1w/VulnHub2018_DeRPnStiNK.ova?dl0 打开靶机,使用nmap扫描出靶机的ip和开放的所有端口 可以看到,靶机开放…

从零开始学习Linux

Linux Linux内核版本&#xff1a;Linux内核运维开发小组&#xff0c;源码在不开源 Linux发行版本&#xff1a;由各大互联网/软件公司定制&#xff0c;开源 一个内核版本是有多种多样的发行版本 Ubuntu&#xff1a;以强大的桌面应用为主&#xff0c;吸收不少Windows用户&…