JDK、JRE、JVM 分别是什么关系?
JDK:Java开发工具包,包含编写Java程序所必须的编译运行等开发工具以及JRE.
开发工具:
- 用于编译Java程序的javac命令
- 用于启动JVM运行Java程序的Java命令
- 用于生成文档的javadoc命令
- 用于打包的jar命令
- …
JDK包含JRE,JVM
JRE
JRE 即为 Java 运行环境,提供了运行 Java 应用程序所必须的软件环境,包含有 Java 虚拟机(JVM)和丰富的系统类库。系统类库即为 Java 提前封装好的功能类,只需拿来直接使用即可,可以大大的提高开发效率。
JRE 包含 JVM
JVM
Java虚拟机,提供了字节码(.class)的运行环境支持
为什么 Java 被称作是“平台无关的编程语言”?
Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程.
- Java 源文件( .java )被编译成能被 Java 虚拟机执行的字节码文件( .class )。
- Java 被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。
JDK 各版本的新特性?
JDK5 ~ JDK10 , https://www.jianshu.com/p/37b52f1ebd4a 。
JDK11 , https://www.jianshu.com/p/81b65eded96c 。
Java 和 C++ 的区别?
- 都是面向对象的语言,都支持封装、继承和多态。
- Java 不提供指针来直接访问内存,程序内存更加安全。
- Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承。
- 【重要】Java 有自动内存管理机制,不需要程序员手动释放无用内存。
什么是字节码?采用字节码的最大好处是什么?
什么是字节码?
这个问题,面试官可以衍生提问,Java 是编译执行的语言,还是解释执行的语言。
Java 中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。
编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在 Java 中,这种供虚拟机理解的代码叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。
每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java 源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。这也就是解释了 Java 的编译与解释并存的特点。
Java 源代码
=> 编译器 => JVM 可执行的 Java 字节码(即虚拟指令)
=> JVM => JVM 中解释器 => 机器可执行的二进制机器码 => 程序运行
采用字节码的好处?
Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。
解释型语言:解释型语言,是在运行的时候将程序翻译成机器语言。解释型语言的程序不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的时候解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。——百度百科
例如:Python、PHP 。
Java 中的几种基本数据类型是什么?各自占用多少字节?
Java 支持的数据类型包括基本数据类型和引用类型。
基本数据类型如下:
- 整数值型:byte、short、int、long
- 字符型:char
- 浮点类型:float、double
- 布尔型:boolean
- 整数型:默认 int 型,小数默认是 double 型。Float 和 Long 类型的必须加后缀。比如:float f = 100f 。
引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。
引用类型包括类、接口、数组等。
特别注意,String 是引用类型不是基本类型。
什么是值传递和引用传递?
值传递,是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。
引用传递,一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。
一般认为,Java 内的传递都是值传递*,Java 中实例对象的传递是引用传递。
char 型变量中能不能存贮一个中文汉字?为什么?
在 Java 语言中,char 类型占 2 个字节,而且 Java 默认采用 Unicode 编码,一个 Unicode 码是 16 位,所以一个 Unicode 码占两个字节,Java 中无论汉字还是英文字母,都是用 Unicode 编码来表示的。所以,在 Java 中,char 类型变量可以存储一个中文汉字。
String、StringBuffer、StringBuilder 的区别?
Java 平台提供了两种类型的字符串:String 和 StringBuffer/StringBuilder,它们可以储存和操作字符串。
String ,是只读字符串,也就意味着 String 引用的字符串内容是不能被改变的。
每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
StringBuffer/StringBuilder
StringBuffer/StringBuilder类,表示的字符串对象可以直接进行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被 synchronized(同步) 修饰,因此它的效率也比 StringBuffer 要高。
StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。
相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
参考链接:https://www.journaldev.com/538/string-vs-stringbuffer-vs-stringbuilder
对于三者使用的总结?
操作少量的数据 = String.
单线程操作字符串缓冲区下操作大量数据 = StringBuilder.
多线程操作字符串缓冲区下操作大量数据 = StringBuffer
实际场景下,我们基本不太会出现,多线程操作同一个 StringBuffer对象.
String s = new String(“xyz”) 会创建几个对象?
-
首先,在 String 池内找,找到 “xyz” 字符串,不创建 “xyz” 对应的 String 对象,否则创建一个对象。
-
然后,遇到 new 关键字,在内存上创建 String 对象,并将其返回给 s ,又一个对象。
所以,总共是 1 个或者 2 个对象。
String 为什么是不可变的?
简单的来说,String 类中使用 final 关键字字符数组保存字符串。代码如下:
/** The value is used for character storage. */
private final char value[];
所以 String 对象是不可变的。
而 StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串 char[] value ,但是没有用 final 关键字修饰。代码如下:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
所以这两种对象都是可变的。
StringTokenizer 是什么?
StringTokenizer ,是一个用来分割字符串的工具类。
public class Demo {
public static void main(String[] args) {
String musicPath = "H:\\\\DongYinVideoMedia\\\\SmallProgramDownLoadMusic\\\\";
StringTokenizer zo = new StringTokenizer(musicPath, "\\\\");
String[] pathArr = new String[zo.countTokens()];
for (int i = 0; i <= pathArr.length; i++) {
if (zo.hasMoreTokens()){
pathArr[i] = zo.nextToken();
}else{
break;
}
}
for (String a : pathArr
) {
System.out.println(a);
}
}
}
输出如下:
H:
DongYinVideoMedia
SmallProgramDownLoadMusic
什么是自动拆装箱?
自动装箱和拆箱,就是基本类型和引用类型之间的转换。
为什么要转换?
如果你在 Java5 下进行过编程的话,你一定不会陌生这一点,你不能直接地向集合( Collection )中放入原始类型值,因为集合只接收对象。
-
通常这种情况下你的做法是,将这些原始类型的值转换成对象,然后将这些转换的对象放入集合中。使用 Integer、Double、Boolean 等这些类,我们可以将原始类型值转换成对应的对象,但是从某些程度可能使得代码不是那么简洁精炼。
-
为了让代码简练,Java5 引入了具有在原始类型和对象类型自动转换的装箱和拆箱机制。
-
但是自动装箱和拆箱并非完美,在使用时需要有一些注意事项,如果没有搞明白自动装箱和拆箱,可能会引起难以察觉的 Bug 。
int 和 Integer 有什么区别?
- int 是基本数据类型。
- Integer 是其包装类,注意是一个类。
当然,要注意下 Integer 的缓存策略,可以看看 JavaInteger的缓存策略 文章。