本章重点:
一维数组的静态初始化,动态初始化,数组的长度,调用数组元素,遍历
二维同上
冒泡排序,快速排序
Arrays工具类
数组的概念:
数组,是多个相同类型数据按一定顺序排序的集合,并使用一个名字命名,通过编号的方式对这些数据进行统一管理
数组中的概念:数组名,下标,元素,数组的长度
数组的特定:
数组本身是引用数据类型,而数组中元素可以是任何数据类型,包括基本数据类型(byte\int\short\long\float\double\char\boolean)和引用数据类型(类,数组,接口,枚举,注解,记录)
创建数组对象会在内存中开辟一整块连续的空间,占据空间的大小,取决于数组的长度和数组中元素的类型。
数组中的元素在内存中是依次紧密排列的,有序的
数组,一旦完成初始化,其长度就是确定的,数组的长度一旦确定,就不能再修改
数组名中引用的是这块连续空间的首地址
数组的分类:
按照元素的类型:基于数据类型元素的数组,引用数据类型元素的数组
按照数组的维数:一维数组,二维数组
一维数组的使用(重点):
数组的声明和初始化
调用数组的指定元素
数组的属性:length,表示数组的长度
数组的遍历
数组元素的默认初始值
一维数组的内存解析
前四个基本点:
public class OneArrayTest {
public static void main(String[] args){
//1.数组的声明与初始化
//声明
double[] arr;
//静态初始化
arr = new double[]{23,34,45,6456,657};
//或者
int[] arr2 = {12,23,43,5};//类型推断
//动态初始化
String[] foods;
foods = new String[4];
//其他方式
int[] arr1 = new int[4];
//注意静态和动态不能一起用,即不能两个括号里的数字一起写
//比如:int[] arr3 = new int[4]{1,2,3,4};这种就会报错
//2.数组的调用
//通过角标的方式,输出
System.out.println(arr2[1]);
System.out.println(arr2[3]);
//赋值
foods[0] = "拌海蜇";
foods[3] = "冬瓜";
//3.数组的长度:用来描述数组容器中容量的大小
//使用length属性表示
System.out.println(arr2.length);//输出数组的长度
System.out.println(foods.length);//输出数组的长度
//4.如何遍历数组
//遍历数组
for(int i = 0;i<arr2.length;i++){
System.out.println(arr2[i]);
}
}
}
数组元素的默认初始化值的情况:
注意:以数组的动态初始化方式为例说明:
1.整型数组元素的默认初始化值:0
2.浮点型数组元素的默认初始化值:0.0
3.字符型数组元素的默认初始化值:0
4.boolean型数组元素的默认初始值:flase
5.引用数据类型数组元素的默认初始化值:null
举例:
public class OneArrayTest_02 {
public static void main(String[] args){
//5.数组元素的默认初始化值
// 1.整型数组元素的默认初始化值:0
int[] arr = new int[3];
System.out.println(arr[0]);//输出的初始值是0
short[] arr2 = new short[4];
System.out.println(arr2[0]);//输出的初始值是0
for(int i = 0; i < arr2.length; i++){
System.out.println(arr2[i]);//遍历输出的值全都是0
}
// 2.浮点型数组元素的默认初始化值:0.0
double[] arr3 = new double[3];
System.out.println(arr3[0]);//输出的初始值是0.0
// 3.字符型数组元素的默认初始化值:0
char[] arr4 = new char[3];
System.out.println(arr4[2]);
// 4.boolean型数组元素的默认初始值:false
boolean[] arr5 = new boolean[3];
System.out.println(arr5[0]);//输出的初始值是false
// 5.引用数据类型数组元素的默认初始化值:null
String[] arr6 = new String[4];
System.out.println(arr6[0]);//输出的初始值是null
}
}
一维数组的内存解析:
jvm架构图:

各部分的主要作用:

举例;
public class OneArrayTest_03 {
public static void main(String[] args){
//6.一维数组的内存分析
//Java中的内存结构是如何划分的(主要关心jvm的运行时的内存环境)
//将内存区域划分为5各部分:笔记上有
//与目前数组有关的内存结构:虚拟机栈:用于存储方法中声明的变量
// 堆:用于存放数组的实体(数字中的所有的元素)
//举例:具体一维数组的代码的内存解析
int[] a1 = new int[]{1,2,3};
int[] a2 = a1;
a2[1] = 10;
System.out.println(a1[1]);//打印出来的是10,要注意到给的是地址,没有new,就没有新开辟一个空间
//把a1的地址值直接给了a2,所以改a2会影响到a1的值
System.out.println(a1);//可以看到a1和a2的地址是一样的
System.out.println(a2);
}
}
练习:

import java.util.Scanner;
//提示:先读入学生人数,根据人数创建int数组,存放学生成绩
public class OneArrayTest_04 {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入学生人数:");
int num =sc.nextInt();
int[] arr = new int[num];
for(int i = 0;i < num;i++){
System.out.println("请输入学生成绩:" );
int score = sc.nextInt();
arr[i] = score;
}
int max = arr[0];
for(int i = 0;i < num;i++) {
if (arr[i] > max) {
max = arr[i];
}
}
for(int i = 0;i < num;i++){
if(max - arr[i] <= 10){
System.out.println(arr[i]+ ", 该学生成绩等级为A");
} else if (max - arr[i] <= 20) {
System.out.println(arr[i] + ", 该生成绩为B");
} else if (max - arr[i] <= 30) {
System.out.println(arr[i] + ", 该生成绩为C");
}else {
System.out.println(arr[i] + ", 该生成绩为D");
}
}
//不要忘记回收
sc.close();
}
}
多维数组的使用:
Java语言提供了支持多维数组的语法
二维数组的使用(难点):
数组的声明和初始化
调用数组的指定元素
数组的属性:length,表示数组的长度
数组的遍历
数组元素的默认初始值
二维数组的内存解析
前四个基本点:
public class TwoArrayTest_01 {
public static void main(String[] args){
//1.二维数组的声明与初始化
//声明和静态初始化
int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};
//动态初始化方式1:
int[][] arr1 = new int[3][4];
//动态初始化方式2:这个和C语言不一样,感觉要比C语言灵活一些
double[][] arr2 = new double[3][];
//2.数组元素的调用
int[][] arr3 = new int[][]{{1,2,3},{4,5},{6,7,8,9}};
//针对数组arr3来说,外层元素:{1,2,3},{4,5},{6,7,8,9}.内层元素:1,2,3,4,5,6,7,8,9
//调用内层元素
System.out.println(arr[0][0]);//1
System.out.println(arr[2][1]);//把7打印出来
//调用外层元素
System.out.println(arr[0]);//打印的是第0个外层元素的地址值:[I@4eec7777
String[][] arr4 = new String[3][4];
double[][] arr5 = new double[2][];
//测试arr4 arr5
arr4[0][1] = "Tom";
System.out.println(arr4[0][1]);//Tom
System.out.println(arr4[0]);//[Ljava.lang.String;@3b07d329
arr5[0] = new double[4];//把第一个外层元素赋了4个内层元素给它
arr5[0][1] = 1.0;//给arr5[0][1]赋值
System.out.println(arr5[0][1]);
//3.数组的长度
//针对arr3来测试一下
//int[][] arr3 = new int[][]{{1,2,3},{4,5},{6,7,8,9}};
System.out.println(arr3.length);//本质上没有二维数组,都是一维数组,只是人为的看成二维。输出的是外层数组,结果是3
System.out.println(arr3[0].length);//3
System.out.println(arr3[1].length);//2
System.out.println(arr3[2].length);//4
//4.遍历二维数组
//针对arr3来测试一下
//int[][] arr3 = new int[][]{{1,2,3},{4,5},{6,7,8,9}};
for(int i = 0;i < arr3.length;i++){
for (int j = 0;j < arr3[i].length;j++){
System.out.print(arr3[i][j] + " ");
}
System.out.println("\n");
}
}
}
二维数组元素的默认初始值:
知识点:
public class TwoArrayTest_02 {
public static void main(String[] args){
//二维数组元素的默认初始化值
//以方式一命名进行:
int[][] arr = new int[3][2];
//外层元素的默认值
System.out.println(arr[0]);//[I@4eec7777
System.out.println(arr[1]);//[I@3b07d329
//内层元素默认值
System.out.println(arr[0][0]);//0
boolean[][] arr2 = new boolean[3][4];
//外层元素默认值
System.out.println(arr2[0]);//[Z@41629346
System.out.println(arr2[1]);//[Z@404b9385
//内层元素默认初始值
System.out.println(arr2[0][0]);//false
String[][] arr3 = new String[3][4];
//外层默认初始值
System.out.println(arr3[0]);//[Ljava.lang.String;@6d311334
System.out.println(arr3[1]);//[Ljava.lang.String;@682a0b20
//内层默认初始值
System.out.println(arr3[0][0]);//null
System.out.println(arr3[1][0]);//null
//**********************************************
//以动态初始化方式2命名进行
int[][] arr4 = new int[3][];
//外层元素默认值
System.out.println(arr4[0]);//null。没给数组赋值,又因为数组是引用数据类型,所以外层的数默认初始值都是null值,因为arr4[0]
//内层元素默认值
System.out.println(arr4[0][0]);//报错,找不到
String[][] arr5 = new String[3][];
//外层
System.out.println(arr5[0]);//null.理由和上面一样
//内层
System.out.println(arr5[0][0]);//报错
}
}
动态初始化方式1:(int[][] arr = new int[3][2];)
外层数组:默认存储地址值
内层数组:默认与一维数组元素的不同类型的默认值规定相同:
1.整型数组元素的默认初始化值:0
2.浮点型数组元素的默认初始化值:0.0
3.字符型数组元素的默认初始化值:0
4.boolean型数组元素的默认初始值:flase
5.引用数据类型数组元素的默认初始化值:null
动态初始化方式2:int[][] arr4 = new int[3][];
外层元素:null
内层元素:报错
二维数组的内存解析:


练习:
求和:
public class TwoArrayExer_01 {
public static void main(String[] args){
int[][] arr = new int[][]{{3,5,8},{12,9},{7,0,6,4}};
int total = 0;
for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
total += arr[i][j];
}
}
System.out.println("总和是:" + total);
}
}
数组中常见的算法操作(重点):
1.特征值赋值,数组赋值和复制:
【数组的常见算法1】:
1.数值型数组的特征值统计
这里的特征值涉及到:平均值,最大值,最小值,总和等
举例1:
// 1.数值型数组的特征值统计
// 这里的特征值涉及到:平均值,最大值,最小值,总和等
//案例1:定义一个int型的数组,包含十个元素,分别赋随机整数值,求出所有元素的最大值,最小值,总和,平均值
//要求:所有随机数都是两位整数:[10,99]
//求[a,b)范围随机数的公式:(int)(Math.random() * (b- a + 1)) + a
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = ((int) (Math.random() * 90)) + 10;
System.out.print(arr[i] + "\t");
}
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];//找出最大值
}
}
int min = arr[0];
for (int i = 0; i < arr.length; i++) {
if (min > arr[i]) {
min = arr[i];//找出最小值
}
}
double sum = 0, average;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];//求和
}
average = sum / arr.length;
System.out.println(max);
System.out.println(min);
System.out.println(sum);
System.out.println(average);
举例2:
//案例2:评委打分
//题目:十位选手的分数是:
//求选手最后得分,去掉最高分,去掉最低分求平均值
int[] arr1 = new int[]{5, 4, 6, 8, 9, 0, 1, 2, 7, 3};
int max1 = arr1[0];
int min1 = arr1[0];
for (int i = 0; i < arr.length; i++) {
if (max1 < arr1[i]) {
max1 = arr1[i];
}
}
for (int j = 0; j < arr.length; j++) {
if (min1 > arr1[j]) {
min1 = arr1[j];
}
}
int total = 0;
for (int k = 0; k < arr.length; k++) {
total += arr1[k];
}
int average1 = (total - max1 - min1) / 8;
System.out.println(average1);
2.数组元素的赋值
// 2.数组元素的赋值
// 使用二维数组创建杨辉三角
//2.1创建二维数组
int[][] yangHui = new int[10][];
//2.2使用循环体,初始化外层数组元素
for(int i = 0; i < yangHui.length; i++) {
yangHui[i] = new int[i + 1];
//3.给数组元素赋值
yangHui[i][0] = 1;
yangHui[i][i] = 1;
for(int j = 1;j < i ;j++){
yangHui[i][j] = yangHui[i - 1][j] + yangHui[i - 1][j - 1];
}
}
//创建数组的框架
for(int i = 0; i < yangHui.length; i++) {
for (int j = 0; j <yangHui[i].length ; j++) {
System.out.print(yangHui[i][j] + "\t");
}
System.out.println("\n");
}
3.数组的复制
// 3.数组的复制
//创建一个名为ArrayExer04的类,在main()方法中声明array1和array2两个变量,它们是int型数组
int[] array1,array2;
//初始化array1的变量值
array1 = new int[]{2,3,5,7,11,13,17,19};
//显示array1的内容。
for(int i = 0; i < array1.length; i++) {
System.out.print(array1[i] + "\t");
}
System.out.println("\n");
//赋值array2变量等于array1,修改array2中的索引元素,使其值等于索引值
array2 = array1;
for(int i = 0; i < array1.length; i++) {
if(i % 2 == 0){
array2[i] = i;
}
}
//打印array1
for(int i = 0;i < array1.length; i++) {
System.out.print(array1[i] + "\t");
//可以看到array1和array2的值是相同的,它们的地址指向的是同一个地址
}
要真复制的话要这么做:
//要真复制的话要这么做
array2 = new int[array1.length];//新造一块空间给array2
for(int i = 0; i < array1.length; i++) {
array2[i] = array1[i];
}
4.数组的反转
// 4.数组的反转
//定义一个数组,实现元素的反转储存
int[] arr2 = new int[]{34,54,3,2,65,7,34,5,76,34,67};
for(int i = 0; i < arr2.length/2; i++) {
// //不管奇数还是偶数,判断的范围都是length / 2
int temp = arr2[i];
arr2[i] = arr2[arr2.length - i - 1];
arr2[arr2.length - i - 1] = temp;
}
for(int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + "\t");
}
}
}
【数组的常见算法2】:
1.数组的扩容与缩容
扩容:
//现有数组int[] arr = new int[]{1,2,3,4,5};
//先将数组长度扩容1倍,并将10,20,30三个数据添加到arr数组中
//要扩容,只能new一个新数组然后将原来的数组值复制过去
//扩容一倍容量
int[] arr = new int[]{1,2,3,4,5};
int[] newArr = new int[arr.length * 2];//或者左移一位,也是乘2的意思
//将原有数组的复制过去
for(int i = 0;i < arr.length;i++){
newArr[i] = arr[i];
}
//再新增数值
newArr[arr.length] = 10;
newArr[arr.length + 1] = 20;
newArr[arr.length + 2] = 30;
//最后让arr等于这个新做的数组
arr = newArr;
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
缩容:
方式1:
//现有数组:int[] arr = {1,2,3,4,5,6,7},先需删除数组中索引为4的元素
//方式1,不新建数组,从要删除的数据开始,让后一个数据覆盖前一个数据,再修改最后一个数据的值,设为默认值
int[] arr1 = {1,2,3,4,5,6,7};
int deleteIndex = 4;
for(int i = deleteIndex;i < arr1.length - 1;i++){
arr1[i] = arr1[i + 1];
}
//修改最后元素
arr1[arr1.length - 1] = 0;
//遍历输出
for(int i = 0;i < arr1.length;i++){
System.out.print(arr1[i] + "\t");
}
方式2:新建一个数组
新建一个数组,新的数组的长度比原有数组的长度少1
int[] newArray = new int[arr1.length-1];
//分成两部分来赋值,直接跳过要删掉的数据
for(int i = 0;i < deleteIndex;i++){
newArray[i] = arr1[i];
}
for(int i = deleteIndex ;i < arr1.length - 1; i++ ){
newArray[i] = arr1[i+1];
}
arr = newArray;
//输出:
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
2.数组元素的查找
顺序查找:
优点:算法简单
缺点:效率低
// 顺序查找:
//案例1:线性查找
//定义数组:
int[] arr1 = new int[]{34,54,3,2,65,7,34,5,76,34,67};
//查找元素5是否在上述数组中出现过,如果出现,输出对应的索引值
int i = 0;
int target = 5;
for(;i < arr1.length;i++){
if(target == arr1[i]){
System.out.println("找到了" + target + ",对应的位置为:" + i);
}
}
if(target == arr1.length){
System.out.println("抱歉,没找到");
}
二分法查找:
优点:效率高
缺点:算法比顺序查找难一点。前提:数组必须有序

举例:
public class TwoArrayExer_04 {
public static void main(String[] args){
int[] arr2 = new int[]{2,4,5,8,12,15,19,26,37,49,51,66,89,100};
//查找元素5是否在上述数组中出现过,如果出现,输出对应索引值
int target1 = 15;
int head = 0;//默认的首索引
int end = arr2.length - 1;//默认尾索引
boolean isFlag = false;
while(head <= end){
int mid = (head + end)/2;
if(target1 == arr2[mid]){
System.out.println("找到了,目标的索引数字是" + mid);
isFlag = true;
break;
}else if(target1 > arr2[mid]){
head = mid + 1;
}else{//target1 < arr2[mid]
end = mid -1;
}
}
if(isFlag == false){
System.out.println("抱歉,没找到");
}
}
}
3.数组排序(搭配查找使用,算法的效率就很高)
算法概述:
定义:排序:假设含有n个记录的序列为{r1,r2,r3……rn}其相应的关键字(属性)序列为{K1,K2,K3,……,Kn},将这些记录重新排序为{Ri1,Ri2,Ri3…………Rin},使得相应的关键字值满足条件k1<k2<k3<k4……<kn,这样的一种操作被称为排序
通常来说:排序的目的是为了快速查找
衡量排序算法的优劣:
时间复杂度:分析关键字(属性)的比较次数和记录的移动次数


空间复杂度:分析排序算法中需要多少辅助内存

稳定性:若两个记录A和B的关键字(属性)值相等,但排序后A,B的先后次序保持不变,则称这种排序算法是稳定的
排序算法概述:
排序算法分类:内部排序和外部排序
内部排序:整个排序过程不需要借助于外部存储器(如磁盘),所有排序操作都在内存中完成
外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘),外部排序最常见的是多路归并排序,可以认为外部排序是由多次内部排序组成。
十大内部排序算法:

冒泡排序:
排序步骤:
1.比较相邻的元素,如果第一个比第二个大(升序),就交换他们两个
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这步做完后,最后的元素会是最大的数
3.针对所有元素重复以上步骤,除了最后一个
4.持续每次对越来越少的元素重复上面的步骤,知道没有任何一对数字需要比较为止。
举例:
public class TwoArrayTest_03 {
public static void main(String[] args){
//案例1:使用冒泡排序,实现整型数组元素的排序操作
int[] arr = new int[]{18,45,7,63,29,5,92,37,11,56};
//使用冒泡排序
for(int j = 0;j < arr.length- 1;j++){
for(int i = 0;i < arr.length - 1 - j;i++){
if(arr[i] > arr[i+1]){
int temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
//输出
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
}
}
快速排序(最快的,开发中默认使用的方式):
快速排序的时间复杂度是O(nlog(n))
排序步骤:
1.从数列中挑出一个元素,称为“基准”
2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准值后面(和基准值相同的可以放在任一边)。在这个分区结束后,该基准就处于数列的中间位置,这个称为分区操作
3.递归地把小于基准值元素的子数列和大于基准值元素的子数列排序
4.递归的最底部的情形,是数列的大小是零或一,也就是永远都已经被排序好了,虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代中,他至少会把一个元素摆到它最后的位置去
代码要使用递归这个类,还没学类,先不敲代码,把步骤搞清楚
Array工具类的使用:
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法,比如:

常用的功能测试:
import java.util.Arrays;
public class TwoArrayTest_01 {
public static void main(String[] args) {
//array类的使用
//1.boolean equals(int[] a,int[] b) 比较两个数组的元素是否依次相等
int[] arr1 = new int[]{1,2,3,4,5};
int[] arr2 = new int[]{1,2,3,4,5};
System.out.println(arr1 == arr2);//这里判断的是地址是否一样,结果是false
boolean isEquals = Arrays.equals(arr1,arr2);//运用这个类判断的就是元素是否依次相等
System.out.println(isEquals);//结果是true
//2.String toString(int[] a):输出数组元素信息,就相当于是使用循环输出数组
System.out.println(arr1);//[I@4eec7777
System.out.println(Arrays.toString(arr1));//[1, 2, 3, 4, 5]
//3.void fill(int[] a,int val):将指定值填充到数组之中
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));//[10, 10, 10, 10, 10]
//4.void sort(int[] a):使用快速排序算法实现的排序
int[] arr3 = new int[]{1,2,5,3,4};
Arrays.sort(arr3);//使用快速排序对数组排序
System.out.println(Arrays.toString(arr3));//[1, 2, 3, 4, 5]
//5.int binarySearch(int[] a,int key):二分查找
//使用前提是数组必须是有序的
Arrays.sort(arr3);
int index = Arrays.binarySearch(arr3,4);
System.out.println(index);//3,如果返回的是负数,就说明没找到
}
}
1.数组的使用中常见的异常:
数组角标越界的异常:ArrayIndexOutBoundsException
空指针的异常:NullPointerException
public class TwoArrayTest_02 {
public static void main(String[] args) {
//1.数组角标越界的异常:
int[] arr = new int[10];
System.out.println(arr[10]);//越界
System.out.println(arr[-1]);//越界
//2.空指针异常:
//情况1:
int[] arr2 = new int[10];
System.out.println(arr2[0]);//输出默认初始值,0
arr2 = null;//如果给数组的地址赋值null
System.out.println(arr2[0]);//那么此时就报错,空指针异常
//情况2:
int[][] arr3 = new int[10][];
System.out.println(arr3[0][1]);//报错,空指针异常,没给元素赋值,,此时元素位置上的是null值,找不到这个元素
//情况3:
String[] arr4 = new String[10];
System.out.println(arr4[0].toString());//未给数组赋值,此时数组中是null值,调null值的方法就会报错
}
}
2.如果异常出现会怎么样?如何处理?
2.1一旦程序执行出现了异常,程序就会终止执行
2.2针对异常出现提供的信息,修改对应代码,避免异常再次出现
企业真题
数组有没有length()这个方法?String有没有length()这个方法:
数组没有length()方法,但有length这个属性
String有length方法
有数组int[] arr,用Java代码将数组元素顺序颠倒
笔记里数组的反转那个例子
为什么数组要从0开始编号,而不是1
数组的索引,表示了数组元素距离首地址元素的偏移量,因为第一个元素的地址与首地址相同,所以偏移量为0,所以从0开始
数组有什么排序的方法,手写
冒泡
快排
常见排序算法,说下快排过程,时间复杂度

过程:
1.从数列中挑出一个元素,称为“基准”
2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准值后面(和基准值相同的可以放在任一边)。在这个分区结束后,该基准就处于数列的中间位置,这个称为分区操作
3.递归地把小于基准值元素的子数列和大于基准值元素的子数列排序
4.递归的最底部的情形,是数列的大小是零或一,也就是永远都已经被排序好了,虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代中,他至少会把一个元素摆到它最后的位置去
329

被折叠的 条评论
为什么被折叠?



