本文收录于《面试小抄》系列,Github 地址 (可下载 pdf):https://github.com/cosen1024/…
国内 Gitee(可下载 pdf):https://gitee.com/cosen1024/J…
这是一个很干的面试题合集,次要波及 Java 根底、Java 并发、JVM、MySQL、Redis、Spring、MyBatis、Kafka、操作系统、计算机网络等知识点。
Java 根底内容较多,我将分成两篇。这是本期的 Java 根底面试题目录,看看你会哪些?
话不多说,开始发车了~
1. Java 语言有哪些特点?
- 面向对象(封装,继承,多态);
- 平台无关性,平台无关性的具体表现在于,Java 是“一次编写,到处运行(Write Once,Run any Where)”的语言,因而采纳 Java 语言编写的程序具备很好的可移植性,而保障这一点的正是 Java 的虚拟机机制。在引入虚拟机之后,Java 语言在不同的平台上运行不须要从新编译。
- 可靠性、安全性;
- 反对多线程。C++ 语言没有内置的多线程机制,因而必须调用操作系统的多线程性能来进行多线程程序设计,而 Java 语言却提供了多线程反对;
- 反对网络编程并且很不便。Java 语言诞生自身就是为简化网络编程设计的,因而 Java 语言不仅反对网络编程而且很不便;
- 编译与解释并存;
2. Java 和 C ++ 有什么关系,它们有什么区别?
- 都是面向对象的语言,都反对封装、继承和多态;
- C++ 反对指针,而 Java 没有指针的概念;
- C++ 反对多继承,而 Java 不反对多重继承,但容许一个类实现多个接口;
- Java 主动进行无用内存回收操作,不再须要程序员进行手动删除,而 C++ 中必须由程序开释内存资源,这就减少了程序员的累赘。
- Java 不反对操作符重载,操作符重载则被认为是 C++ 的突出特色;
- Java 是齐全面向对象的语言,并且还勾销了 C/C++ 中的构造和联结,使编译程序更加简洁;
- C 和 C++ 不反对字符串变量,在 C 和 C++ 程序中应用“Null”终止符代表字符串的完结。在 Java 中字符串是用类对象(String 和 StringBuffer)来实现的;
- goto 语句是 C 和 C++ 的“遗物”,Java 不提供 goto 语句,尽管 Java 指定 goto 作为关键字,但不反对它的应用,这使程序更简洁易读;
3. JVM、JRE 和 JDK 的关系是什么?
JDK 是(Java Development Kit)的缩写,它是功能齐全的 Java SDK。它领有 JRE 所领有的所有,还有编译器(javac)和工具(如 javadoc 和 jdb)。它可能创立和编译程序。
JRE 是 Java Runtime Environment 缩写,它是运行已编译 Java 程序所需的所有内容的汇合,包含 Java 虚拟机(JVM),Java 类库,java 命令和其余的一些根底构件。然而,它不能用于创立新程序。
JDK 蕴含 JRE,JRE 蕴含 JVM。
4. 什么是字节码? 采纳字节码的益处是什么?
这个问题,面试官能够扩大发问,Java 是编译执行的语言,还是解释执行的语言?
Java 之所以能够“一次编译,到处运行”,一是因为 JVM 针对各种操作系统、平台都进行了定制,二是因为无论在什么平台,都能够编译生成固定格局的字节码(.class 文件)供 JVM 应用。因而,也能够看出字节码对于 Java 生态的重要性。
之所以被称之为字节码,是因为字节码文件由十六进制值组成,而 JVM 以两个十六进制值为一组,即以字节为单位进行读取。在 Java 中个别是用 javac 命令编译源代码为字节码文件,一个.java 文件从编译到运行的示例如图所示。
Java 语言通过字节码的形式,在肯定水平上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比拟高效,而且,因为字节码并不专对一种特定的机器,因而,Java 程序毋庸从新编译便可在多种不同的计算机上运行。
5. Oracle JDK 和 OpenJDK 的区别是什么?
可能在看这个问题之前很多人和我一样并没有接触和应用过 OpenJDK。上面通过我通过我收集到一些材料对你解答这个被很多人漠视的问题。
- Oracle JDK 版本将每三年公布一次,而 OpenJDK 版本每三个月公布一次;
- OpenJDK 是一个参考模型并且是齐全开源的,而 Oracle JDK 是 OpenJDK 的一个实现,并不是齐全开源的;
- Oracle JDK 比 OpenJDK 更稳固。OpenJDK 和 Oracle JDK 的代码简直雷同,但 Oracle JDK 有更多的类和一些谬误修复。因而,如果您想开发企业 / 商业软件,倡议抉择 Oracle JDK,因为它通过了彻底的测试和稳固。某些状况下,有些人提到在应用 OpenJDK 可能会遇到了许多应用程序解体的问题,然而,只需切换到 Oracle JDK 就能够解决问题;
- 在响应性和 JVM 性能方面,Oracle JDK 与 OpenJDK 相比提供了更好的性能;
- Oracle JDK 不会为行将公布的版本提供长期反对,用户每次都必须通过更新到最新版本取得反对来获取最新版本;
- Oracle JDK 依据二进制代码许可协定取得许可,而 OpenJDK 依据 GPLv2 许可取得许可。
6. Java 有哪些数据类型?
Java 语言的数据类型分为两种:根本数据类型和援用数据类型。
根本数据类型包含 boolean(布尔型)、float(单精度浮点型)、char(字符型)、byte(字节型)、short(短整型)、int(整型)、long(长整型)和 double(双精度浮点型)共 8 种,如下图所示。
image-
援用数据类型建设在根本数据类型的根底上,包含数组、类和接口。援用数据类型是由用户自定义,用来限度其余数据的类型。另外,Java 语言中不反对 C++ 中的指针类型、构造类型、联结类型和枚举类型。
7. switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
Java5 以前 switch(expr)中,expr 只能是 byte、short、char、int。
从 Java 5 开始,Java 中引入了枚举类型,expr 也能够是 enum 类型。
从 Java 7 开始,expr 还能够是字符串 (String),然而长整型(long) 在目前所有的版本中都是不能够的。
8. 拜访修饰符 public、private、protected、以及不写(默认)时的区别?
Java 中,能够应用拜访控制符来爱护对类、变量、办法和构造方法的拜访。Java 反对 4 种不同的拜访权限。
- default (即默认,什么也不写): 在同一包内可见,不应用任何修饰符。应用对象:类、接口、变量、办法。
- private : 在同一类内可见。应用对象:变量、办法。留神:不能润饰类(外部类)
- public : 对所有类可见。应用对象:类、接口、变量、办法
- protected : 对同一包内的类和所有子类可见。应用对象:变量、办法。留神:不能润饰类(外部类)。
9. break ,continue ,return 的区别及作用?
- break 跳出总上一层循环,不再执行循环 ( 完结以后的循环体)
- continue 跳出本次循环,继续执行下次循环 ( 完结正在执行的循环 进入下一个循环条件)
- return 程序返回,不再执行上面的代码 ( 完结以后的办法 间接返回)
10. final、finally、finalize 的区别?
final 用于润饰变量、办法和类。
- final 变量:被润饰的变量不可变,不可变分为
援用不可变
和对象不可变
,final 指的是援用不可变
,final 润饰的变量必须初始化,通常称被润饰的变量为常量
。 - final 办法:被润饰的办法不容许任何子类重写,子类能够应用该办法。
- final 类:被润饰的类不能被继承,所有办法不能被重写。
finally 作为异样解决的一部分,它只能在 try/catch
语句中,并且附带一个语句块示意这段语句最终肯定被执行(无论是否抛出异样),常常被用在须要开释资源的状况下,System.exit (0)
能够阻断 finally 执行。
finalize 是在 java.lang.Object
里定义的办法,也就是说每一个对象都有这么个办法,这个办法在 gc
启动,该对象被回收的时候被调用。
一个对象的 finalize 办法只会被调用一次,finalize 被调用不肯定会立刻回收该对象,所以有可能调用 finalize 后,该对象又不须要被回收了,而后到了真正要被回收的时候,因为后面调用过一次,所以不会再次调用 finalize 了,进而产生问题,因而不举荐应用 finalize 办法。
11. 为什么要用 static 关键字?
通常来说,用 new 创立类的对象时,数据存储空间才被调配,办法才供外界调用。但有时咱们只想为特定域调配繁多存储空间,不思考要创立多少对象或者说基本就不创立任何对象,再就是咱们想在没有创建对象的状况下也想调用办法。在这两种状况下,static 关键字,满足了咱们的需要。
12.”static”关键字是什么意思?Java 中是否能够笼罩 (override) 一个 private 或者是 static 的办法?
“static”关键字表明一个成员变量或者是成员办法能够在没有所属的类的实例变量的状况下被拜访。
Java 中 static 办法不能被笼罩,因为办法笼罩是基于运行时动静绑定的,而 static 办法是编译时动态绑定的。static 办法跟类的任何实例都不相干,所以概念上不实用。
13. 是否能够在 static 环境中拜访非 static 变量?
static 变量在 Java 中是属于类的,它在所有的实例中的值是一样的。当类被 Java 虚拟机载入的时候,会对 static 变量进行初始化。如果你的代码尝试不必实例来拜访非 static 的变量,编译器会报错,因为这些变量还没有被创立进去,还没有跟任何实例关联上。
14. static 静态方法能不能引用非动态资源?
不能,new 的时候才会产生的货色,对于初始化后就存在的动态资源来说,基本不意识它。
15. static 静态方法外面能不能引用动态资源?
能够,因为都是类初始化的时候加载的,大家互相都意识。
16. 非静态方法外面能不能引用动态资源?
能够,非静态方法就是实例办法,那是 new 之后才产生的,那么属于类的内容它都意识。
17. java 动态变量、代码块、和静态方法的执行程序是什么?
基本上代码块分为三种:Static 动态代码块、结构代码块、一般代码块
代码块执行程序 动态代码块——> 结构代码块 ——> 构造函数——> 一般代码块
继承中代码块执行程序:父类动态块——> 子类动态块——> 父类代码块——> 父类结构器——> 子类代码块——> 子类结构器
想要深刻理解,能够参考这篇文章:https://juejin.cn/post/684490…
18. 面向对象和面向过程的区别?
面向过程:
- 长处:性能比面向对象高,因为类调用时须要实例化,开销比拟大,比拟耗费资源; 比方单片机、嵌入式开发、Linux/Unix 等个别采纳面向过程开发,性能是最重要的因素。
- 毛病:没有面向对象易保护、易复用、易扩大。
面向对象:
- 长处:易保护、易复用、易扩大,因为面向对象有封装、继承、多态性的个性,能够设计出低耦合的零碎,使零碎更加灵便、更加易于保护。
- 毛病:性能比面向过程低。
19. 讲讲面向对象三大个性
- 封装。封装最好了解了。封装是面向对象的特色之一,是对象和类概念的次要个性。封装,也就是把客观事物封装成形象的类,并且类能够把本人的数据和办法只让可信的类或者对象操作,对不可信的进行信息暗藏。
- 继承。继承是指这样一种能力:它能够应用现有类的所有性能,并在无需从新编写原来的类的状况下对这些性能进行扩大。通过继承创立的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。
- 多态性。它是指在父类中定义的属性和办法被子类继承之后,能够具备不同的数据类型或体现出不同的行为,这使得同一个属性或办法在父类及其各个子类中具备不同的含意。
20. Java 语言是如何实现多态的?
实质上多态分两种:
1、编译时多态(又称动态多态)
2、运行时多态(又称动静多态)
重载(overload)就是编译时多态的一个例子,编译时多态在编译时就曾经确定,运行的时候调用的是确定的办法。
咱们通常所说的多态指的都是运行时多态,也就是编译时不确定到底调用哪个具体方法,始终提早到运行时能力确定。这也是为什么有时候多态办法又被称为提早办法的起因。
Java 实现多态有 3 个必要条件:继承、重写和向上转型。只有满足这 3 个条件,开发人员才可能在同一个继承构造中应用对立的逻辑实现代码解决不同的对象,从而执行不同的行为。
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些办法进行从新定义,在调用这些办法时就会调用子类的办法。
- 向上转型:在多态中须要将子类的援用赋给父类对象,只有这样该援用才既能能够调用父类的办法,又能调用子类的办法。
Java 多态的实现原理可看这篇文章:https://my.oschina.net/u/4432…
21. 重载(Overload)和重写(Override)的区别是什么?
办法的重载和重写都是实现多态的形式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
- 重写产生在子类与父类之间, 重写办法返回值和形参都不能扭转,与办法返回值和拜访修饰符无关,即重载的办法不能依据返回类型进行辨别。即外壳不变,外围重写!
- 重载(overloading) 是在一个类外面,办法名字雷同,而参数不同。返回类型能够雷同也能够不同。每个重载的办法(或者构造函数)都必须有一个举世无双的参数类型列表。最罕用的中央就是结构器的重载。
22. 重载的办法是否依据返回值类型进行辨别?
不能依据返回值类型来辨别重载的办法。因为调用时不指定类型信息,编译器不晓得你要调用哪个函数。
float max(int a, int b);
int max(int a, int b);
当调用 max(1,2);
时无奈确定调用的是哪个,单从这一点上来说,仅返回值类型不同的重载是不应该容许的。
23. 结构器(constructor)是否可被重写(override)?
结构器不能被继承,因而不能被重写,但能够被重载。每一个类必须有本人的构造函数,负责结构本人这部分的结构。子类不会笼罩父类的构造函数,相同必须一开始调用父类的构造函数。
24. 抽象类和接口的区别是什么?
语法层面上的区别:
- 抽象类能够提供成员办法的实现细节,而接口中只能存在 public abstract 办法;
- 抽象类中的成员变量能够是各种类型的,而接口中的成员变量只能是 public static final 类型的;
- 接口中不能含有动态代码块以及静态方法,而抽象类能够有动态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却能够实现多个接口。
设计层面上的区别:
- 抽象类是对一种事物的形象,即对类形象,而接口是对行为的形象。抽象类是对整个类整体进行形象,包含属性、行为,然而接口却是对类部分(行为)进行形象。
- 设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。
想要深刻理解,能够参考这篇文章:https://www.cnblogs.com/dolph…
25. 抽象类能应用 final 润饰吗?
不能,定义抽象类就是让其余类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能润饰抽象类
26. java 创建对象有哪几种形式?
java 中提供了以下四种创建对象的形式:
- new 创立新对象
- 通过反射机制
- 采纳 clone 机制
- 通过序列化机制
前两者都须要显式地调用构造方法。对于 clone 机制, 须要留神浅拷贝和深拷贝的区别,对于序列化机制须要明确其实现原理,在 java 中序列化能够通过实现 Externalizable 或者 Serializable 来实现。
27. 什么是不可变对象? 益处是什么?
不可变对象指对象一旦被创立, 状态就不能再扭转, 任何批改都会创立一个新的对象, 如 String、Integer 及其它包装类. 不可变对象最大的益处是线程平安.
28. 是否创立一个蕴含可变对象的不可变对象?
当然能够, 比方 final Person[] persons = new Persion[]{}
. persons
是不可变对象的援用, 但其数组中的 Person 实例却是可变的. 这种状况下须要特地审慎, 不要共享可变对象的援用. 这种状况下, 如果数据须要变动时, 就返回原对象的一个拷贝.
29. 值传递和援用传递的区别的什么?为什么说 Java 中只有值传递?
值传递:指的是在办法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相干了。
援用传递:指的是在办法调用时,传递的参数是按援用进行传递,其实传递的是援用的地址,也就是变量所对应的内存空间的地址。传递的是值的援用,也就是说传递前和传递后都指向同一个援用(也就是同一个内存空间)。
根本类型作为参数被传递时必定是值传递;援用类型作为参数被传递时也是值传递,只不过“值”为对应的援用。
想要深刻理解,能够参考这篇文章:http://www.itwanger.com/java/…
30. == 和 equals 区别是什么?
==
罕用于雷同的根本数据类型之间的比拟,也可用于雷同类型的对象之间的比拟;
- 如果
==
比拟的是根本数据类型,那么比拟的是两个根本数据类型的值是否相等; - 如果
==
是比拟的两个对象,那么比拟的是两个对象的援用,也就是判断两个对象是否指向了同一块内存区域;
equals 办法次要用于两个对象之间,检测一个对象是否等于另一个对象
看一看 Object 类中 equals 办法的源码:
public boolean equals(Object obj) {return (this == obj);
}
它的作用也是 判断两个对象是否相等,般有两种应用状况:
- 状况 1,类没有笼罩 equals()办法。则通过 equals()比拟该类的两个对象时,等价于通过“==”比拟这两个对象。
- 状况 2,类笼罩了 equals()办法。个别,咱们都笼罩 equals()办法来两个对象的内容相等;若它们的内容相等,则返回 true(即,认为这两个对象相等)。
java 语言标准要求 equals 办法具备以下个性:
- 自反性。对于任意不为 null 的援用值 x,x.equals(x)肯定是 true。
- 对称性)。对于任意不为 null 的援用值 x 和 y,当且仅当 x.equals(y)是 true 时,y.equals(x)也是 true。
- 传递性。对于任意不为 null 的援用值 x、y 和 z,如果 x.equals(y)是 true,同时 y.equals(z)是 true,那么 x.equals(z)肯定是 true。
- 一致性。对于任意不为 null 的援用值 x 和 y,如果用于 equals 比拟的对象信息没有被批改的话,屡次调用时 x.equals(y)要么统一地返回 true 要么统一地返回 false。
- 对于任意不为 null 的援用值 x,x.equals(null)返回 false。
31. 介绍下 hashCode()?
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引地位。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都蕴含有 hashCode()函数。
散列表存储的是键值对(key-value),它的特点是:能依据“键”疾速的检索出对应的“值”。这其中就利用到了散列码!(能够疾速找到所须要的对象)
32. 为什么要有 hashCode?
以“HashSet 如何查看反复”为例子来阐明为什么要有 hashCode:
当你把对象退出 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象退出的地位,同时也会与其余曾经退出的对象的 hashcode 值作比拟,如果没有相符的 hashcode,HashSet 会假如对象没有反复呈现。
然而如果发现有雷同 hashcode 值的对象,这时会调用 equals()办法来查看 hashcode 相等的对象是否真的雷同。如果两者雷同,HashSet 就不会让其退出操作胜利。如果不同的话,就会从新散列到其余地位。这样咱们就大大减少了 equals 的次数,相应就大大提高了执行速度。
33. hashCode(),equals()两种办法是什么关系?
Java 对于 eqauls()
办法和 hashCode()
办法是这样规定的:
- 同一对象上屡次调用 hashCode() 办法,总是返回雷同的整型值。
- 如果 a.equals(b),则肯定有 a.hashCode() 肯定等于 b.hashCode()。
- 如果 !a.equals(b),则 a.hashCode() 不肯定等于 b.hashCode()。此时如果 a.hashCode() 总是不等于 b.hashCode(),会进步 hashtables 的性能。
- a.hashCode()==b.hashCode() 则 a.equals(b) 可真可假
- a.hashCode()!= b.hashCode() 则 a.equals(b) 为假。
下面论断简记:
- 如果两个对象 equals,Java 运行时环境会认为他们的 hashCode 肯定相等。
- 如果两个对象不 equals,他们的 hashCode 有可能相等。
- 如果两个对象 hashCode 相等,他们不肯定 equals。
- 如果两个对象 hashCode 不相等,他们肯定不 equals
补充:对于 equals() 和 hashCode() 的重要标准
- 标准 1:若重写 equals() 办法,有必要重写 hashcode()办法,确保通过 equals()办法判断后果为 true 的两个对象具备相等的 hashcode() 办法返回值。说得简略点就是:“如果两个对象雷同,那么他们的 hashCode 应该相等”。不过请留神:这个只是标准,如果非要写一个类让 equals() 办法返回 true 而 hashCode() 办法返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了 Java 标准,程序也就埋下了 BUG。
- 标准 2:如果 equals() 办法返回 false,即两个对象“不雷同”,并不要求对这两个对象调用 hashCode() 办法失去两个不雷同的数。说的简略点就是:“如果两个对象不雷同,他们的 hashCode 可能雷同”。
34. 为什么重写 equals 办法必须重写 hashcode 办法 ?
断的时候先依据 hashcode 进行的判断,雷同的状况下再依据 equals()办法进行判断。如果只重写了 equals 办法,而不重写 hashcode 的办法,会造成 hashcode 的值不同,而 equals()办法判断进去的后果为 true。
在 Java 中的一些容器中,不容许有两个完全相同的对象,插入的时候,如果判断雷同则会进行笼罩。这时候如果只重写了 equals()的办法,而不重写 hashcode 的办法,Object 中 hashcode 是依据对象的存储地址转换而造成的一个哈希值。这时候就有可能因为没有重写 hashcode 办法,造成雷同的对象散列到不同的地位而造成对象的不能笼罩的问题。
35. String,StringBuffer, StringBuilder 的区别是什么?
1. 可变与不可变。String 类中应用字符数组保留字符串,因为有“final”修饰符,所以 string 对象是不可变的。对于曾经存在的 String 对象的批改都是从新创立一个新的对象, 而后把新的值保留进去.
private final char value[];
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是应用字符数组保留字符串,这两种对象都是可变的。
char[] value;
2. 是否线程平安。
String 中的对象是不可变的,也就能够了解为常量,显然线程平安。
StringBuilder 是非线程平安的。
StringBuffer 对办法加了同步锁或者对调用的办法加了同步锁,所以是线程平安的。
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
3. 如果你只是在单线程中应用字符串缓冲区,那么 StringBuilder 的效率会更高些。值得注意的是 StringBuilder 是在 JDK1.5 版本中减少的。以前版本的 JDK 不能应用该类。
36. String 为什么要设计成不可变的?
1. 便于实现字符串池(String pool)
在 Java 中,因为会大量的应用 String 常量,如果每一次申明一个 String 都创立一个 String 对象,那将会造成极大的空间资源的节约。Java 提出了 String pool 的概念,在堆中开拓一块存储空间 String pool,当初始化一个 String 变量时,如果该字符串曾经存在了,就不会去创立一个新的字符串变量,而是会返回曾经存在了的字符串的援用。
String a = "Hello world!";
String b = "Hello world!";
如果字符串是可变的,某一个字符串变量扭转了其值,那么其指向的变量的值也会扭转,String pool 将不可能实现!
2. 使多线程平安
在并发场景下,多个线程同时读一个资源,是平安的,不会引发竞争,但对资源进行写操作时是不平安的,不可变对象不能被写,所以保障了多线程的平安。
3. 防止平安问题
在网络连接和数据库连贯中字符串经常作为参数,例如,网络连接地址 URL,文件门路 path,反射机制所须要的 String 参数。其不可变性能够保障连贯的安全性。如果字符串是可变的,黑客就有可能扭转字符串指向对象的值,那么会引起很重大的平安问题。
4. 放慢字符串处理速度
因为 String 是不可变的,保障了 hashcode 的唯一性,于是在创建对象时其 hashcode 就能够释怀的缓存了,不须要从新计算。这也就是 Map 喜爱将 String 作为 Key 的起因,处理速度要快过其它的键对象。所以 HashMap 中的键往往都应用 String。
总体来说,String 不可变的起因要包含 设计思考,效率优化,以及安全性这三大方面。
这里也举荐一个我收集的计算机书籍仓库,仓库目前有上百本经典 cs 电子书,看经典的书籍会更悟得深~
点此链接即可中转书单,计算机必看经典书籍(含 pdf 下载)
Github 也有相应仓库,https://github.com/cosen1024/…
欢送 star。