参考博文:Java基础常见面试题总结(上) | JavaGuide
目录
参考博文:Java基础常见面试题总结(上) | JavaGuide
continue、break 和 return 的区别是什么?
Java语言的特点
- 简单易学
- 面向对象
- 与平台无关
- 支持多线程
- 可靠性高
- 安全性
- 编译与解释并存
JVM JRE JDK
JVM就是Java虚拟机,每个不同的系统(Windows,Linux,macOS)都有自己的不同实现。JVM的目的是实现在不同的系统下,使用相同的字节码,他们都会给出相同的结果。
JRE是Java运行时的环境,但是它不提供创建Java程序
JDK负责编程Java程序。
为什么说Java语言“解释与编译并存”
- 解释型:解释型语言是通过解释器,将代码一句一句地解释为机器代码后执行,者类语言的特点是执行效率低,开发效率高。
- 编译型:编译型语言是将代码一次性整体翻译为机器能识别的语言。这类语言的特点是执行效率高,但是开发效率低
为什么Java“解释和编译并存”
因为Java需要先编译后执行,运行一个程序首先要将程序编译为一个。.class文件,然后由解释器解释这个.class文件
Java与c++之间的区别
- Java不支持指针直接访问内存
- Java内置垃圾回收机制
- java只支持单继承,但是接口可以多继承。C++支持多继承
- Java只支持方法重载,C++支持方法重载和操作符重载
基本语法
注释
Java有三种注释
- 单行注释:对某一行的代码进行注释
- 文档注释:通常用于编写Java开发
- 多行注释:对某一段代码进行解释
注释其实就是一个说明作用,比如你今天写的代码,过几天,你可能就忘记这些代码的作用了,所以注释可以帮助我们回忆代码的说明,同时也帮助团队的其他人快速理清代码之间的逻辑关系
标识符和关键字
标识符就是为程序,类,方法,变量取名字。
关键字就是Java就是特殊的标志符,这些标识符被赋予了特殊的含义,不可以被随意使用
常见关键字(来自于百度百科)
关键字 | 含义 |
abstract | 表明类或者成员方法具有抽象属性 |
assert | 断言,用来进行程序调试 |
boolean | 基本数据类型之一,声明布尔类型的关键字 |
break | 提前跳出一个块 |
byte | 基本数据类型之一,字节类型 |
case | 用在switch语句之中,表示其中的一个分支 |
catch | 用在异常处理中,用来捕捉异常 |
char | 基本数据类型之一,字符类型 |
class | 声明一个类 |
const | 保留关键字,没有具体含义 |
continue | 回到一个块的开始处 |
default | 默认,例如,用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现 |
do | 用在do-while循环结构中 |
double | 基本数据类型之一,双精度浮点数类型 |
else | 用在条件语句中,表明当条件不成立时的分支 |
enum | 枚举 |
extends | 表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口 |
final | 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量 |
finally | 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块 |
float | 基本数据类型之一,单精度浮点数类型 |
for | 一种循环结构的引导词 |
goto | 保留关键字,没有具体含义 |
if | 条件语句的引导词 |
implements | 表明一个类实现了给定的接口 |
import | 表明要访问指定的类或包 |
instanceof | 用来测试一个对象是否是指定类型的实例对象 |
int | 基本数据类型之一,整数类型 |
interface | 接口 |
long | 基本数据类型之一,长整数类型 |
native | 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的 |
new | 用来创建新实例对象 |
package | 包 |
private | 一种访问控制方式:私用模式 |
protected | 一种访问控制方式:保护模式 |
public | 一种访问控制方式:共用模式 |
return | 从成员方法中返回数据 |
short | 基本数据类型之一,短整数类型 |
static | 表明具有静态属性 |
strictfp | 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范 |
super | 表明当前对象的父类型的引用或者父类型的构造方法 |
switch | 分支语句结构的引导词 |
synchronized | 表明一段代码需要同步执行 |
this | 指向当前实例对象的引用 |
throw | 抛出一个异常 |
throws | 声明在当前定义的成员方法中所有需要抛出的异常 |
transient | 声明不用序列化的成员域 |
try | 尝试一个可能抛出异常的程序块 |
void | 声明当前成员方法没有返回值 |
volatile | 表明两个或者多个变量必须同步地发生变化 |
while | 用在循环结构中 |
continue、break 和 return 的区别是什么?
- continue:用于跳出某一次循环,然后继续执行下一个循环
- break:用于退出整个循坏
- return:用于退出方法
变量
局部变量和成员变量的区别
- 语法形式 :从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
- 存储方式 :从变量在内存中的存储方式来看,如果成员变量是使用 static 修饰的,那么这个成员变量是属于类的,如果没有使用 static 修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。
- 生存时间 :从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
- 默认值 :从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。
静态变量的作用
无论类创建了多少个实例,所有实例都共享一个静态变量。
字符型常量和字符串常量
- 字符型常量是由一个单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符。
- 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。
- 字符常量只占 2 个字节; 字符串常量占若干个字节。
方法
静态方法为什么不能调用非静态方法
结合JVM来看
- 静态方法属于类,在类被创建的时候就会被分配内存,非静态方法属于类的实例对象,只有在对象实例化之后才可以被分配内存
- 在非静态方法不存在的时候,静态方法就已经存在了。所以,静态方法不能去调用一个不存在的方法。
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员
什么是可变参数
可变参数是指,可以在方法中传入不定长度的参数
public void method(String... args) { //...... }
可变参数只可以当作传入的最后一个参数
public void method(int x,String... args) {
//......
}
当可变参数遇到方法重载时会发生什么
优先匹配固定参数的方法
基本类型和包装类的区别
- 基本数据类型不赋初值时不为空,包装类不赋初值时为null
- 基本类型变量(不被static修饰) 存放在虚拟机的栈中,包装类类似与一个对象,存放在堆中
- 包装类型可用于泛型,而基本类型不可以。
- 相比于包装类,基本类型占用空间很小
注意:基本数据类型成员变量如果没有被static修饰的话,就是存放在堆中
包装类型的缓存机制
缓存机制可以提高性能
Integer缓存源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static {
// high value may be configured by property
int h = 127;
}
}
Character 缓存源码:
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
private static class CharacterCache {
private CharacterCache(){}
static final Character cache[] = new Character[127 + 1];
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
Boolean 缓存源码:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。
浮点数float和double包装类并没有缓存机制
所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
自动装箱和拆箱
- 装箱:将基本类型用他们对应的基本类型包装起来
- 拆箱:将包装类型转换为基本类型
可以看出来装箱就是对应的valueOf()方法,拆箱就是对应xxxValue()方法
频繁的拆箱和装箱会影响性能
为什么浮点数进行运算时会发生精度丢失
计算机的存储是二进制的,并且是有限的,在存储一个无线循环小数的时候,会被截断,会发生小数精度损失的情况。
如何解决浮点数丢失的情况
BigDecimal 可以实现对浮点数的运算,不会造成精度丢失
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
超过long的整形数据如何表示
BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。但是相对来说BIgInterger运算效率相对较低