JVM、JRE及JDK的关系 **
JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。
Java Runtime Environment(JRE)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。
JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。
简单来说就是JDK是Java的开发工具,JRE是Java程序运行所需的环境,JVM是Java虚拟机.它们之间的关系是JDK包含JRE和JVM,JRE包含JVM.
JAVA语言特点 **
- Java是一种面向对象的语言
- Java通过Java虚拟机实现了平台无关性,一次编译,到处运行
- 支持多线程
- 支持网络编程
- 具有较高的安全性和可靠性
JAVA和C++的区别 **
面试时记住前四个就行了
- Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
- Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
- Java 支持自动垃圾回收,而 C++ 需要手动回收。
- Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
- Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操
作符重载,而 C++ 可以。 - Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
Java的基本数据类型 **
注意
String
不是基本数据类型
类型 | 关键字 | 包装器类型 | 占用内存(字节)(重要) | 取值范围 | 默认值 |
---|---|---|---|---|---|
字节型 | byte | Byte | 1 | -128(-2^7) ~ 127(2^7-1) | 0 |
短整型 | short | Short | 2 | -2^15 ~ 2^15-1 | 0 |
整型 | int | Integer | 4 | -2^31 ~ 2^31-1 | 0 |
长整型 | long | Long | 8 | -2^63 ~ 2^63-1 | 0L |
单精度浮点型 | float | Float | 4 | 3.4e-45 ~ 1.4e38 | 0.0F |
双精度浮点型 | double | Double | 8 | 4.9e-324 ~ 1.8e308 | 0.0D |
字符型 | char | Character | 2 | '\u0000' | |
布尔型 | boolean | Boolean | 1 | true/flase | flase |
隐式(自动)类型转换和显示(强制)类型转换 **
- 隐式(自动)类型转换:从存储范围小的类型到存储范围大的类型。
byte
→short(char)
→int
→long
→float
→double
- 显示(强制)类型转换:从存储范围大的类型到存储范围小的类型。
double
→float
→long
→int
→short(char)
→byte
。该类类型转换很可能存在精度的损失。
看一个经典的代码
short s = 1; s = s + 1;
这是会报错的,因为1是int
型,s+1
会自动转换为int
型,将int
型直接赋值给short
型会报错。
做一下修改即可避免报错
short s = 1; s = (short)(s + 1);
或这样写,因为s += 1
会自动进行强制类型转换
short s = 1; s += 1;
自动装箱与拆箱 **
- 装箱:将基本类型用包装器类型包装起来
-
拆箱:将包装器类型转换为基本类型
这个地方有很多易混淆的地方,但在面试中问到的频率一般,笔试的选择题中经常出现,还有一个
String
创建对象和这个比较像,很容易混淆,在下文可以看到 -
下面这段代码的输出结果是什么?
public class Main { public static void main(String[] args) { Integer a = 100; Integer b = 100; Integer c = 128; Integer d = 128; System.out.println(a==b); System.out.println(c==d); } }
true false
很多人看到这个结果会很疑惑,为什么会是一个
true
一个flase
.其实从源码中可以很容易找到原因.首先找到Integer
方法中的valueOf
方法public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
可以看到当不满足
if
语句中的条件,就会重新创建一个对象返回,那结果必然不相等。继续打开IntegerCache
可以看到private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
代码挺长,大概说的就是在通过
valueOf
方法创建Integer
对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache
中已经存在的对象的引用;否则创建一个新的Integer
对象。所以上面代码中a
与b
相等,c
与d
不相等。 -
在看下面的代码会输出什么
public class Main { public static void main(String[] args) { Double a = 1.0; Double b = 1.0; Double c = 2.0; Double d = 2.0; System.out.println(a==b); System.out.println(c==d); } }
flase flase
采用同样的方法,可以看到
Double
的valueOf
方法,每次返回都是重新new
一个新的对象,所以上面代码中的结果都不想等。public static Double valueOf(double d) { return new Double(d); }
-
最后再看这段代码的输出结果
public class Main { public static void main(String[] args) { Boolean a = false; Boolean b = false; Boolean c = true; Boolean d = true; System.out.println(a==b); System.out.println(c==d); } }
true true
老方法继续看
valueOf
方法public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
再看看
TRUE
和FALSE
是个什么东西,是两个静态成员属性。public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false);
说下结论 :Integer
、Short
、Byte
、Character
、Long
这几个类的valueOf
方法的实现是类似的。Double
、Float
的valueOf
方法的实现是类似的。然后是Boolean
的valueOf
方法是单独一组的。
-
Integer i = new Integer(xxx)
和Integer i =xxx
的区别这两者的区别主要是第一种会触发自动装箱,第二者不会
最后看看下面这段程序的输出结果
public class Main { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Long g = 3L; int int1 = 12; int int2 = 12; Integer integer1 = new Integer(12); Integer integer2 = new Integer(12); Integer integer3 = new Integer(1); System.out.println("c==(a+b) ->"+ (c==(a+b))); System.out.println("g==(a+b) ->" + (g==(a+b))); System.out.println( "c.equals(a+b) ->" + (c.equals(a+b))); System.out.println( "g.equals(a+b) ->" + (g.equals(a+b))); System.out.println("int1 == int2 -> " + (int1 == int2)); System.out.println("int1 == integer1 -> " + (int1 == integer1)); System.out.println("integer1 == integer2 -> " + (integer1 == integer2)); System.out.println("integer3 == a1 -> " + (integer3 == a)); } }
c==(a+b) ->true g==(a+b) ->true c.equals(a+b) ->true g.equals(a+b) ->false int1 == int2 -> true int1 == integer1 -> true integer1 == integer2 -> false integer3 == a1 -> false
下面简单解释这些结果。
1.当 "=="运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。所以
c==a+b
,g==a+b
为true
。2.而对于
equals
方法会先触发自动拆箱过程,再触发自动装箱过程。也就是说a+b,会先各自调用intValue
方法,得到了加法运算后的数值之后,便调用Integer.valueOf
方法,再进行equals
比较。所以c.equals(a+b)
为true
。而对于g.equals(a+b)
,a+b
会先拆箱进行相加运算,在装箱进行equals
比较,但是装箱后为Integer
,g
为Long
,所以g.equals(a+b)
为false
。3.
int1 == int2
为true
无需解释,int1 == integer1
,在进行比较时,integer1
会先进行一个拆箱操作变成int
型在进行比较,所以int1 == integer1
为true
。4.
integer1 == integer2
->false
。integer1
和integer2
都是通过new
关键字创建的,可以看成两个对象,所以integer1 == integer2
为false
。integer3 == a1
->false
,integer3
是一个对象类型,而a1
是一个常量它们存放内存的位置不一样,所以integer3 == a1
为false
,具体原因可学习下java的内存模型。
String(不是基本数据类型)
String的不可变性 ***
在 Java 8 中,String
内部使用 char
数组存储数据。并且被声明为final
,因此它不可被继承。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; }
为什么<