常用类
创始人
2025-05-30 01:15:47
0

常用类

      • 常用类
        • 一、内部类
          • 1.1 基本概念
          • 1.2 成员内部类【了解】
          • 1.3 静态内部类【重点】
          • 1.4 局部内部类【了解】
          • 1.5 匿名内部类【重点】
        • 二、Object类
          • 2.1 getClass()
          • 2.2 hashCode()
          • 2.3 equals方法
          • 2.4 toString()方法
          • 2.5 finalize()方法
          • 2.6 Java中的垃圾回收机制
        • 三、包装类
          • 3.1 基本使用
          • 3.2 整数缓冲区(常量池)
        • 四、String类
        • 五、可变字符串
        • 六、BigDecimal
        • 七、日期时间
          • 7.1 Date
          • 7.2 Calendar
          • 7.3 SimpleDateFormat
          • 7.4 System

常用类

一、内部类

1.1 基本概念

在类的内部定义的类,叫做内部类。

分为:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类
public class Outter {// 在类的内部定义的类class Inner{}
}

在类的内部定义类,一般还是封装思想的体现,可以将该类定义为私有类。

在一个类中,可以定义四种情况的变量,对应四种内部类,使用方式也相似

public class Outter {String s1; // 成员变量(实例变量)、属性static String s2; // 静态属性,类属性public void m1() {String s3 = new String("aaa"); // 局部变量System.out.println(new String("hello")); // 匿名变量}
}
1.2 成员内部类【了解】

成员内部类是直接在类的内部定义的普通类。

注意:

  • 不能定义静态属性
  • 不能定义静态方法
  • 在内部类的方法中,如果要调用外部类的属性,可以直接使用,但是如果内部类有同名属性或局部变量,可以使用外部类的名称.this.属性名。
  • 在外部类的静态方法中,不能直接创建成员内部类的对象

由于成员内部类的功能有缺陷(不能定义静态属性,不能定义静态方法),一般很少使用。

public class Outter {String name; // 成员变量(实例变量)、属性// 成员内部类class Inner{String name;// 不能定义静态属性
//		public static String s;public void m1() {System.out.println(Outter.this.name);System.out.println(name);}// 不能定义静态方法
//		public static void m2() {}}public void m3() {Inner inner = new Inner();}public static void m2() {
//		Inner inner = new Inner(); // 在外部类的静态方法中,不能直接创建成员内部类的对象}
}public class Demo1 {public static void main(String[] args) {Outter outter = new Outter();outter.name = "aaa";
//		System.out.println(outter.name);Outter.Inner inner = outter.new Inner();inner.name = "bbb";inner.m1();// 必须先创建外部类的对象才能创建内部类的对象Outter.Inner inner1 = new Outter().new Inner();}
}
1.3 静态内部类【重点】

静态内部类是在类的内部定义的静态类。使用方式与普通类一样,一般在项目中使用静态内部类来体现封装的特征。

public class Outter1 {public static String name;public static class Inner1{public String a; // 可以定义属性public static String name; // 可以定义静态属性public void m1() { // 可以定义普通方法}public static void m2() {// 可以定义静态方法}}public void m1() {new Inner1(); // 可以在普通方法中创建对象}public static void m2() {new Inner1();// 可以在静态方法中创建对象}
}public class Demo2 {public static void main(String[] args) {Outter1.Inner1 inner = new Outter1.Inner1();inner.a = "aaa";}
}
1.4 局部内部类【了解】

在类的方法中定义的类称为局部内部类。

  • 不能定义静态成员和静态方法
  • 不能在类前面添加private、public等关键字
  • 必须在方法中定义后立即使用,否则出了作用域范围会无效
public class Outter2 {public void m1() {class Inner{// 不能定义静态成员和静态方法private String name = "aaa";public void m2() {System.out.println(name);}}Inner in = new Inner();in.m2();}
}
1.5 匿名内部类【重点】

当需要将一个抽象类或者接口创建对象时,会要求继承该抽象类或者实现接口才可以创建对象。如果需要直接对该抽象类或接口创建对象,并且只使用一次,可以使用匿名内部类的方式。

public interface MyInterface {void m1();
}public abstract class MyClass {
//	public abstract void m1();
}public class Person {public void use(MyInterface m) {m.m1();}
}public class Demo1 {public static void main(String[] args) {// 创建一个接口对象的同时实现,匿名内部类MyInterface m = new MyInterface() {@Overridepublic void m1() {System.out.println("m1");}};m.m1();// 使用抽象类创建匿名内部类
//		MyClass m1 = new MyClass() {
//			@Override
//			public void m1() {
//				System.out.println("m1===");
//			}
//		};
//		
//		m1.m1();// 如果接口或抽象类没有抽象方法,匿名内部类相对奇怪MyClass m1 = new MyClass() {};// 如果方法要传入一个接口或抽象类的对象,可以使用匿名内部类Person p = new Person();p.use(new MyInterface() {@Overridepublic void m1() {System.out.println("m1");}});// jdk1.8中的lambda表达式
//		p.use(() -> System.out.println("m1"));}
}

二、Object类

Object类是所有类的父类,无论是否直接继承。

2.1 getClass()

得到对象的实际类型,一般用来比较两个对象是否同一个类的对象。

也可以通过类名.class来得到类型。

public class Demo1 {public static void main(String[] args) {Animal a = new Dog();Dog d = new Dog();if(a instanceof Dog) {System.out.println("a对象是Dog类的对象");}// 判断对象是否某个类型if(a.getClass() == Dog.class) {System.out.println("a对象是Dog类的对象");}// 判断是否同一个类型的对象if(a.getClass() == d.getClass()) {System.out.println("a对象和d对象是同一类型");}// 得到类名System.out.println(a.getClass().getName());// 得到短类名System.out.println(a.getClass().getSimpleName());}
}
2.2 hashCode()

返回对象的十进制的hash码值,使用哈希算法根据对象的地址或者字符串或数字计算出来的int型的值。

自定义类的对象hashCode默认返回对象的地址。

一般情况下需要重写hashCode方法,以便更好的利用hash算法。

注意:hashCode并不唯一,必须保证相同的对象具备相同的hashCode,尽量保证不同对象有不同的hashCode。

public class Student {private String id;private String name;private int age;@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((id == null) ? 0 : id.hashCode());return result;}
}
2.3 equals方法

用来比较两个对象是否相同。

默认是比较地址,在项目中如果需要比较两个对象是否相同,应该重写equals方法。

public class Student {private String id;private String name;private int age;@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((id == null) ? 0 : id.hashCode());return result;}@Overridepublic boolean equals(Object obj) {// 如果地址相同if (this == obj)return true;// 如果比较对象为空if (obj == null)return false;// 如果不是同一个类型if (getClass() != obj.getClass())return false;Student other = (Student) obj;// 如果id属性为空if (id == null) {if (other.id != null)return false;// 如果id属性不相同} else if (!id.equals(other.id))return false;return true;}
}

注意:equals方法和hashCode方法应该一起重写。

2.4 toString()方法

当将对象作为字符串使用或输出时,会自动调用toString方法,而该方法默认输出hashCode值(地址),没有意义,应该重写toString以便输出对象信息。

public class Student {private String id;private String name;private int age;@Overridepublic String toString() {return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";}
}
public class Demo3 {public static void main(String[] args) {Student s1 = new Student("1001", "你开心", 18);System.out.println(s1);String s = s1 + "====";System.out.println(s);}
}
2.5 finalize()方法

当对象被判定为垃圾对象时,由JVM自动调用,将该对象标识为垃圾,并进入回收队列。

垃圾对象:没有有效引用的指向的对象,即为垃圾对象。

垃圾回收:释放内存空间。

自动回收:JVM会定时进行垃圾回收,如果内存空间占满,会强制进行垃圾回收。

手动回收:使用System.gc()方法,通知JVM进行垃圾回收。

2.6 Java中的垃圾回收机制

在JVM中,内存分为以下区域:程序计数器、栈、方法区、堆。

在项目中,使用new关键字创建的内容一般都在堆中,堆的大小理论来说可以与内存大小挂钩。在项目中程序计数器、栈、方法区一般不需要管理,只有堆空间需要进行内存管理,所以垃圾回收就是指堆空间的内存管理。

image

堆的分代

  • Java的堆是JVM中最大的一块内存区域,主要保存Java中各种类的实例。为了更好的管理堆中各个对象的内存,包括分配内存和回收内存。
  • JVM将堆分成了几块区域:
    • 新生代(Young) 新生代占堆的1/3空间
      • 新生代又分为: Eden、 Survivor1、 Survivor2
      • 新生代中的Eden\Survivor1\Survivor2空间占比为 8:1:1
    • 老年代(Old) 老年代占堆的2/3空间

垃圾回收涉及到的算法:标记、复制、整理、计数、分代

三、包装类

3.1 基本使用

是指基本数据类型所对应的引用数据类型。

int对应Integer、char对应Character,其他基本数据类型都是首字母大写变包装类,例如:Float、Byte

所有的包装类都是final的,不能被继承。

public class Demo1 {// 基本数据类型对应包装类public static void main(String[] args) {int n = 5;// 将基本数据类型转换成包装类Integer in = new Integer(n);// 1、使用newInteger in1 = n; // 2、直接赋值,jdk1.5的新特性,自动装箱Integer in2 = Integer.valueOf(n); // 3、使用valueOfdouble d = 2.0;Double d1 = new Double(d);// 1、使用newDouble d2 = d; // 2、直接赋值,jdk1.5的新特性,自动装箱Double d3 = Double.valueOf(d); // 3、使用valueOf// 将包装类转换成基本数据类型int n1 = in; // 直接赋值,jdk1.5的新特性,自动拆箱int n2 = in.intValue(); // 使用intValue// 基本数据类型的默认值是前面数组中使用过的默认值,例如:int默认值为0// 但是包装类由于都是Object类的子类,所以默认值为nullInteger in3 = null;// 包装类和基本数据类型在大多数时候都可以互换使用Integer in4 = 1;int n3 = new Integer(3);// 将字符串转换成数字int n4 = Integer.parseInt("23");double d4 = Double.parseDouble("25.5");// 转换失败会出现异常java.lang.NumberFormatExceptionint n5 = Integer.parseInt("23a");}
}
3.2 整数缓冲区(常量池)
  • 在加载类的时候,会在方法区创建256个Integer对象,范围是-128~127之间。如果使用valueOf或者直接赋值int会在该缓冲区中拿到对象直接使用,超出范围才会new一个新的Integer。
public static Integer valueOf(int i) {// 如果范围是-128~127之间if (i >= IntegerCache.low && i <= IntegerCache.high)// 返回常量池中(数组)的对象return IntegerCache.cache[i + (-IntegerCache.low)];// 否则返回一个new的对象return new Integer(i);
}

优点:

  • 效率高,使用速度快,不用new
  • 不用创建过多的重复对象,节约空间

四、String类

Java中使用的字符串值都是此类的对象。

创建方式有两种:

public static void main(String[] args) {// 创建方式有两种String s1 = "hello";String s2 = new String("hello");
}

原理:

  • 是一个final类,不能被继承。
  • 存储字符串的方式是采用字符数组。
  • 该数组是final的,表示不能改变该数组的地址。
  • String的值是不可变的
  • String也是使用常量池的,如果直接赋值,是在常量池中创建对象,如果使用new,是在堆中创建对象。
// 部分源码
public final class String // final类implements java.io.Serializable, Comparable, CharSequence {// final的字符数组private final char value[];
}
public class Demo3 {public static void main(String[] args) {// 创建方式有两种String s1 = "hello";String s2 = new String("hello");String s3 = "hello";String s4 = new String("hello");System.out.println(s3==s4); // false}
}

常见的字符串类中的方法:

public class Demo4 {public static void main(String[] args) {String s = "hello, world! hello, world";// 根据下标获取字符char ch = s.charAt(0);System.out.println(ch);// 判定一个字符串是否包含另一个字符串boolean b = s.contains("llo");System.out.println(b);// 将字符串转换成字符数组char[] array = s.toCharArray();System.out.println(Arrays.toString(array));// 查找一个字符串在另一个字符串中首次出现的位置,得到相应的下标,如果不存在返回-1int index = s.indexOf("world");System.out.println(index);// 查找一个字符串在另一个字符串中出现的位置,从最后开始查找,得到相应的下标,如果不存在返回-1int index1 = s.lastIndexOf("world");System.out.println(index1);// 返回字符串的长度int length = s.length();System.out.println(length);// 去掉字符串前后的空格String s1 = "        hello, world    ";s1 = s1.trim(); // 字符串的值是不可变的,所有改变字符串的结果的方法一定有返回值,应该接收返回值System.out.println(s1);// 将小写字母转成大写s = s.toUpperCase();System.out.println(s);// 将大写字母转成小写s = s.toLowerCase();System.out.println(s);// 判定一个字符串是否以另一个字符串结尾boolean b1 = s.endsWith("rld");System.out.println(b1);// 判定一个字符串是否以另一个字符串开头boolean b2 = s.startsWith("rld");System.out.println(b2);// 将一个字符串中的包含的字符串全部替换成其他字符串s = s.replace("hello", "a");System.out.println(s);// 从指定位置开始截取部分字符串,截取后面所有的System.out.println(s.substring(4));// 从指定位置开始截取部分字符串,截取到另一个位置,从4到8System.out.println(s.substring(4, 8));// 将字符串根据指定的内容进行切割,成一个数组String[] strings = s.split("!");System.out.println(Arrays.toString(strings));// 将两个字符串进行拼接String s2 = "hello";String s3 = "world";s2 = s2.concat(s3);System.out.println(s2);}
}

在使用字符串时,可能会发生编译器优化,例如下面的变量s3和s4:

public class Demo5 {public static void main(String[] args) {String a = "a";String b = "b";String ab = "ab";String s1 = a + b; // 使用StringBuilder创建出来的结果,相当于new一个对象System.out.println(s1 == ab); // falseString s2 = a + "b"; // 使用StringBuilder创建出来的结果,相当于new一个对象System.out.println(s2 == ab); // false// 两个常量,结果绝对不会发生其他的变化,就是ab,所以编译器会进行优化,直接将代码优化为String s3 = "ab";String s3 = "a" + "b"; System.out.println(s3 == ab); // true// 两个常量,结果绝对不会发生其他的变化,就是ab,所以编译器会进行优化,直接将代码优化为String s4 = "ab";final String a1 = "a";String s4 = a1 + "b";System.out.println(s4 == ab); // trueString s5 = a.concat(b); // 拼接字符串,结果是new的System.out.println(s5 == ab); // falseString s6 = ab.concat(""); // 当拼接的内容为null或者长度为0时,直接返回原字符串System.out.println(s6 == ab); // trueString s7 = s2.intern(); // 直接得到常量池中的地址,相当于String s7 = "ab";System.out.println(s7 == ab); // true}
}

五、可变字符串

当需要频繁改变字符串时,应该使用可变字符串。

StringBuffer:JDK1.0提供,安全性高,性能较低。

StringBuilder:JDK1.5提供,性能较高,不安全。

基本用法:

public class Demo6 {public static void main(String[] args) {StringBuffer sb = new StringBuffer();// 往最后追加内容sb.append("hello");sb.append("world");// 修改sb.replace(3, 5, "aaaaaaa");// 插入内容sb.insert(1, "bbb");// 删除内容sb.delete(1, 4);System.out.println(sb);}
}

原理:

  • 使用无参构造时,默认创建的字符数组大小为16个char
  • 可以在创建时指定大小。
  • 如果指定字符串,会设置大小为字符串的长度加上16
  • 当空间不够时,需要扩容,扩容的大小是原本的大小的2倍+2
// 部分源码
// 默认大小为16
public StringBuffer() {super(16);
}// 指定大小
public StringBuffer(int capacity) {super(capacity);
}// 如果指定字符串,会设置大小为字符串的长度加上16
public StringBuffer(String str) {super(str.length() + 16);append(str);
}void expandCapacity(int minimumCapacity) {// 当空间不够时,需要扩容,扩容的大小是原本的大小的2倍+2int newCapacity = value.length * 2 + 2;if (newCapacity - minimumCapacity < 0)newCapacity = minimumCapacity;if (newCapacity < 0) {if (minimumCapacity < 0) // overflowthrow new OutOfMemoryError();newCapacity = Integer.MAX_VALUE;}value = Arrays.copyOf(value, newCapacity);
}

六、BigDecimal

注意:使用BigDecimal计算使用应该使用字符串作为保存数字的参数。

作用:

  • 小数的精确计算
  • 超出long范围的整数计算
public class Demo7 {public static void main(String[] args) {// 加法BigDecimal b3 = new BigDecimal("3435");BigDecimal b4 = new BigDecimal("656757");System.out.println(b3.add(b4));// 减法BigDecimal b1 = new BigDecimal("1.0");BigDecimal b2 = new BigDecimal("0.9");System.out.println(b1.subtract(b2));// 乘法BigDecimal b5 = new BigDecimal("3456567457567856756756");BigDecimal b6 = new BigDecimal("4353453453453453453453");System.out.println(b5.multiply(b6));// 除法BigDecimal b7 = new BigDecimal("5");BigDecimal b8 = new BigDecimal("2");// 除法如果可以除尽,那么可以只用一个参数System.out.println(b7.divide(b8));BigDecimal b9 = new BigDecimal("5");BigDecimal b10 = new BigDecimal("3");// 除法如果不能除尽,那么需要指定保留的小数位,以及保留小数的方式,例如:四舍五入System.out.println(b9.divide(b10, 5000, RoundingMode.HALF_UP));}
}

七、日期时间

7.1 Date

指当前时间。精确到毫秒。

注意:

  • 使用java.util.Date
  • 不要拼写成Data
public class Demo1 {public static void main(String[] args) {// 得到当前时间Date now = new Date();System.out.println(now);// 得到时间的毫秒数,距离1970-1-1 00:00:00.000 GMTlong time = now.getTime();System.out.println(time);// 将一个时间毫秒数转成Date类的对象long n = 1647828409608L;Date d = new Date(n);System.out.println(d);// 大部分方法已经被废弃,推荐使用Calendar日历类
//		Date d1 = new Date("2022-03-15");}
}
7.2 Calendar
public class Demo2 {public static void main(String[] args) {// 日历类// 得到日历类对象,不能使用new,只有一个对象Calendar c = Calendar.getInstance();System.out.println(c);// time=1647829077175,areFieldsSet=true,areAllFieldsSet=true,lenient=true,// zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,// dstSavings=0,useDaylight=false,transitions=19,lastRule=null],// firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,// MONTH=2,WEEK_OF_YEAR=13,WEEK_OF_MONTH=4,DAY_OF_MONTH=21,// DAY_OF_YEAR=80,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=3,AM_PM=0,// HOUR=10,HOUR_OF_DAY=10,MINUTE=17,SECOND=57,MILLISECOND=175,ZONE_OFFSET=28800000,DST_OFFSET=0// 得到年份System.out.println(c.get(Calendar.YEAR));// 得到今天是一年的第多少天System.out.println(c.get(Calendar.DAY_OF_YEAR));// 设置日历的日期时间2015-5-30c.set(Calendar.YEAR, 2015);c.set(Calendar.MONTH, 4);c.set(Calendar.DAY_OF_MONTH, 30);// 一次设置多个(6月)c.set(2016, 5, 25);// 一次设置所有c.set(2020, 10, 20, 18, 36, 59);// 将日历转换成DateDate d = c.getTime();System.out.println(d);// 将Date转换成日历Date now = new Date();c.setTime(now);// 返回毫秒long timeInMillis = c.getTimeInMillis();System.out.println(timeInMillis);// 设置毫秒c.setTimeInMillis(timeInMillis);//用来计算c.add(Calendar.DAY_OF_MONTH, 180); // 180天后System.out.println(c.getTime());// 180小时前c.add(Calendar.HOUR_OF_DAY, -180);System.out.println(c.getTime());}
}
7.3 SimpleDateFormat

简单日期格式化:将字符串转换成Date或者将Date转换成字符串。

public class Demo3 {public static void main(String[] args) {Date now = new Date();System.out.println(now);// 定义一个日期的格式// yyyy年,yy两位数计年,MM月,dd日,HH24小时制,hh12小时制,mm分,ss秒,SSS毫秒,a上下午(AM\PM)SimpleDateFormat sdf = new SimpleDateFormat("公元yyyy年MM月dd日hh:mm:ss.SSS a");// 将当前时间以上面的格式显示String string = sdf.format(now);System.out.println(string);// 将一个指定格式的字符串时间转换成日期Date// yyyy-MM-ddSimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");String str = "2015-09-30";try {Date date = sdf1.parse(str);System.out.println(date);// 必须进行异常处理} catch (ParseException e) {// 错误信息Unparseable datee.printStackTrace();}}
}
7.4 System

系统类。

public class Demo4 {public static void main(String[] args) {// 数组复制
//		System.arraycopy(src, srcPos, dest, destPos, length);// 得到系统毫秒数时间System.out.println(System.currentTimeMillis());// 建议System在有空时尽快进行垃圾回收System.gc();// 退出系统,一般用于客户端开发System.exit(0);}
}

相关内容

热门资讯

小白开发微信小程序20--we... 1、什么是SwaggerSwagger 项目已于 2015 年捐赠给 OpenAPI 计划ÿ...
台州最新学区划分,最新或202... 台州公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍台州小...
衢州最新学区划分,最新或202... 柯城区最新或2023(历届)学区划分衢江区最新或2023(历届)学区划分
舟山最新学区划分,最新或202... 临城新区】1、南海实验小学片区:新城沈白线以南、千岛路以西区域,以及长峙社区居民子女。2、舟山第二小...
④电子产品拆解分析-太阳能自动... ④电子产品拆解分析-太阳能自动感应灯一、功能介绍二、电路分析以及器件作用1、太阳能控制电路分析2、优...
丽水最新学区划分,最新或202... 根据“就近入学,统筹安排”为原则,公办小学学区划分也已出炉。  市实验学校:丽阳门居委、高井弄居委。...
海南最新学区划分,最新或202... 1.市直属学校招生范围划分小 学招 生 范 围海口市滨海第九小学滨海大道北侧(至海边),港进路和港集...
从ChatGPT到AGI还有多... 1.引子 21年开始在公司负责一个全链路语音的项目,支持公司的Iot设备,...
海口最新学区划分,最新或202... 海口公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍海口小...
青海最新学区划分,最新或202... 为方便家长和学生们了解自己孩子所就读的小学或是自己孩子的户口究竟在不在想要入读的中学的学区范围内,小...
西宁最新学区划分,最新或202... 西宁公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍西宁小...
三亚最新学区划分,最新或202... 三亚公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍三亚小...
贵州最新学区划分,最新或202... 为方便家长和学生们了解自己孩子所就读的小学或是自己孩子的户口究竟在不在想要入读的中学的学区范围内,小...
21- 神经网络模型_超参数搜... 知识要点 fetch_california_housing:加利福尼亚的房价数据&#...
一文了解GPU并行计算CUDA 了解GPU并行计算CUDA一、CUDA和GPU简介二、GPU工作原理与结构2.1、基础GPU架构2....
贵阳最新学区划分,最新或202... 贵阳公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍贵阳小...
遵义最新学区划分,最新或202... 遵义公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍遵义小...
安顺最新学区划分,最新或202... 安顺公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍安顺小...
六盘水最新学区划分,最新或20... 百年教育网小编为您整理了关于六盘水市幼升小学区划分详情的相关信息,希望对您有帮助,想了解更多请继续关...
遍历二叉树线索二叉树 遍历二叉树 遍历定义 顺着某一条搜索路径寻访二叉树中的每一个结点,使得每个节点均被依次...