目录
1 JDK和JRE有什么区别?
1.1、JRE
1.2、JDK
2、==和equals的区别是什么?
3、比较
4、装箱,拆箱
4.1、什么是装箱?什么是拆箱?
4.2、装箱和拆箱的执行过程?
4.3、常见问题
5、hashCode()相同,equals()也一定为true吗?
6、final在java中的作用
7、final finally finalize()区别
7.1、final
7.2、finally
7.3、finalize()
8、finally语句块一定执行吗?
9、final与static的区别
10 、return与finally对返回值的影响
1 JDK和JRE有什么区别?
1.1、JRE
Java Runtime Environment( java 运行时环境)。即java程序的运行时环境,包含了 java 虚拟机,java基础类库。
1.2、JDK
Java Development Kit( java 开发工具包)。即java语言编写的程序所需的开发工具包。
备注:JDK 包含了 JRE,同时还包括 java 源码的编译器 javac、监控工具 jconsole、分析工具 jvisualvm等。
2、==和equals的区别是什么?
==是关系运算符,equals() 是方法,结果都返回布尔值
1)Object 的比较 ==和equals() 比较的都是地址,作用相同,== 不能比较没有父子关系的两个对象
2)基本类型比较 只有==比较值是否相等
3、比较
1)值不同
使用 == 和 equals() 比较都返回 false
2)值相同== 比较
基本类型 - 基本类型、基本类型 - 包装对象返回 true
包装对象 - 包装对象 或不同对象返回 falseInteger 缓存中取的包装对象比较返回 true(原因是 JVM 缓存部分基本类型常用的包装类对象,如 Integer -128 ~ 127 是被缓存的)
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;System.out.println(i1==i2); //打印true
System.out.println(i3==i4); //打印false
3)值相同equals 方法
equals JDK 中的类一般已经重写了 equals(),比较的是内容
自定义类如果没有重写 equals(),将调用父类(默认 Object 类)的 equals() 方法,Object的 equals() 比较使用了 this == obj,可以按照需求逻辑,重写对象的 equals() 方法(重写 equals 方法,一般须重写 hashCode 方法)
4、装箱,拆箱
4.1、什么是装箱?什么是拆箱?
装箱:基本类型转变为包装器类型的过程。
拆箱:包装器类型转变为基本类型的过程。
//JDK1.5之前是不支持自动装箱和自动拆箱的,定义Integer对象,必须 Integer i = new Integer(8);
//JDK1.5开始,提供了自动装箱的功能,定义Integer对象可以这样
Integer i = 8; // 装箱
int n = i; //自动拆箱
4.2、装箱和拆箱的执行过程?
1)装箱是通过调用包装器类的 valueOf 方法实现的
2)拆箱是通过调用包装器类的 xxxValue 方法实现的,xxx代表对应的基本数据类型。
如int装箱的时候自动调用Integer的valueOf(int)方法;Integer拆箱的时候自动调用Integer的intValue方法。
4.3、常见问题
1) 整型的包装类 valueOf 方法返回对象时,在常用的取值范围内,会返回缓存对象。
2) 浮点型的包装类 valueOf 方法返回新的对象。
3)布尔型的包装类 valueOf 方法 Boolean类的静态常量 TRUE | FALSE, == 和 equals 相等,跟Integer 类似4)包含算术运算会触发自动拆箱
存在大量自动装箱的过程,如果装箱返回的包装对象不是从缓存中获取,会创建很多新的对象,比较消耗内存。
5、hashCode()相同,equals()也一定为true吗?
首先,答案肯定是不一定。同时反过来 equals() 为true,hashCode() 也不一定相同。
类的 hashCode() 方法和 equals() 方法都可以重写,返回的值完全在于自己定义。
hashCode() 返回该对象的哈希码值;equals() 返回两个对象是否相等。
关于 hashCode() 和 equals() 是方法是有一些 常规协定:
1) 两个对象用 equals() 比较返回true,那么两个对象的hashCode()方法必须返回相同的结果。
2) 两个对象用 equals() 比较返回false,不要求hashCode()方法也一定返回不同的值,但是最好返回不同值,以提搞哈希表性能。
3) 重写 equals() 方法,必须重写 hashCode() 方法,以保证 equals() 方法相等时两个对象 hashcode() 返回相同的值。
6、final在java中的作用
final 语义是不可改变的。
1) 被 final 修饰的类,不能够被继承。
2) 被 final 修饰的成员变量必须要初始化,赋初值后不能再重新赋值(可以调用对象方法修改属性值)。对基本类型来说是其值不可变;对引用变量来说其引用不可变,即不能再指向其他的对象。
3) 被 final 修饰的方法代表不能重写。
7、final finally finalize()区别
7.1、final
表示最终的、不可改变的,final用于修饰类、方法和变量。
final 变量必须在声明时给定初值,只能读取,不可修改。
final 方法也同样只能使用,不能重写,但能够重载。
final 修饰的对象,对象的引用地址不能变,但对象的属性值可以改变
7.2、finally
finally异常处理的一部分,它只能用在 try/catch 语句中,表示希望 finally 语句块中的代码最后一定被执行(存在一些情况导致 finally 语句块不会被执行,如 jvm 结束)
7.3、finalize()
finalize是在 java.lang.Object 里定义的,Object 的 finalize() 方法什么都不做,对象被回收时 finalize() 方法会被调用。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要清理工作,在垃圾收集器删除对象之前被调用的。一般情况下,此方法由JVM调用。特殊情况下,可重写 finalize() 方法,当对象被回收的时候释放一些资源,须调用 super.finalize() 。
8、finally语句块一定执行吗?
不一定。存在很多特殊情况导致 finally 语句块不执行。如:
直接返回未执行到 finally 语句块
public static String test() {
String str = null;
int i = 0;
if (i == 0) {
return str;//直接返回未执行到finally语句块
}
try {
System.out.println("try...");
return str;
} finally {
System.out.println("finally...");
}
}
抛出异常未执行到 finally 语句块
public static String test2() {
String str = null;
int i = 0;
i = i / 0;
//抛出异常未执行到finally语句块
try {
System.out.println("try...");
return str;
} finally {
System.out.println("finally...");
}
}
系统退出未执行到 finally 语句块
public static String test3() {
String str = null;
try {
System.out.println("try...");
System.exit(0);//系统退出未执行到finally语句块
return str;
} finally {
System.out.println("finally...");
}
}
9、final与static的区别
9.1、区别
都可以修饰类、方法、成员变量。
static 可以修饰类的代码块,final 不可以。
static 不可以修饰方法内的局部变量,final 可以。
9.2、static
static 修饰表示静态或全局,被修饰的属性和方法属于类,可以用类名.静态属性 / 方法名 访问
static 修饰的代码块表示静态代码块,当 Java 虚拟机(JVM)加载类时,就会执行该代码块,只会被执行一次
static 修饰的属性,也就是类变量,是在类加载时被创建并进行初始化,只会被创建一次
static 修饰的变量可以重新赋值
static 方法中不能用 this 和 super 关键字
static 方法必须被实现,而不能是抽象的abstract
static 方法只能被 static 方法覆盖
9.3、final
final 修饰表示常量、一旦创建不可改变
final 标记的成员变量必须在声明的同时赋值,或在该类的构造方法中赋值,不可以重新赋值
final 方法不能被子类重写
final 类不能被继承,没有子类,final 类中的方法默认是 final 的
final 不能用于修饰构造方法
private 类型的方法默认是final类型的
final 和 static 修饰成员变量加载过程例子
import java.util.Random;
public class TestStaticFinal {
public static void main(String[] args) {
StaticFinal sf1 = new StaticFinal();
StaticFinal sf2 = new StaticFinal();
System.out.println(sf1.fValue == sf2.fValue);//打印false
System.out.println(sf1.sValue == sf2.sValue);//打印true
}
}
class StaticFinal {
final int fValue = new Random().nextInt();
static int sValue = new Random().nextInt();
}
10 、return与finally对返回值的影响
finally 没有 return,finally 对 return 变量的重新赋值修改无效
public static void main(String[] args) {
System.out.println(getString());
}
public static String getString() {
String str = "A";
try {
str = "B";
return str;
} finally {
System.out.println("finally change return string to C");
str = "C";
}
}
finally change return string to C B
2)try 和 finally 都包含return,return 值会以 finally 语句块 return 值为准
如下面的例子
public static void main(String[] args) {
System.out.println(getString());
}
public static String getString() {
String str = "A";
try {
str = "B";
return str;
} finally {
System.out.println("finally change return string to C");
str = "C";
return str;
}
}
finally change return string to C
11、String的replace和replaceAll的区别?
replace() 和 replaceAll()都是常用的替换字符串的方法
两者都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串。如果只想替换第一次出现的,可以使用 replaceFirst()
replaceFirst(), replaceAll()都是“优先”基于规则表达式的替换。优先判断被替换的参数 regex 是不是一个正则表达式。如果是正则,执行正则替换;如果是字符串,执行字符串替换,此时和 replace() 效果就是一样的了
执行了替换操作后,返回一个新的对象,源字符串的内容是没有发生改变的
测试代码:
String str = “Hello Java. Java is a language.”;
System.out.println(str.replace(“Java.”, “c++”));//打印 Hello c++ Java is a language.
System.out.println(str.replaceAll(“Java.”, “c++”));//打印 Hello c++ c++is a language.
打印结果:
Hello c++ Java is a language.
Hello c++ c++is a language.
12、 Math.round(-1.5) 等于多少?
round() :返回四舍五入,负 .5 小数返回较大整数,如 -1.5 返回 -1。
ceil() :返回小数所在两整数间的较大值,如 -1.5 返回 -1。
floor() :返回小数所在两整数间的较小值,如 -1.5 返回 -2。
System.out.println(“Math.round(1.4)=” + Math.round(1.4));
System.out.println(“Math.round(-1.4)=” + Math.round(-1.4));
System.out.println(“Math.round(1.5)=” + Math.round(1.5));
System.out.println(“Math.round(-1.5)=” + Math.round(-1.5));
System.out.println(“Math.round(1.6)=” + Math.round(1.6));
System.out.println(“Math.round(-1.6)=” + Math.round(-1.6));
System.out.println();
System.out.println(“Math.ceil(1.4)=” + Math.ceil(1.4));
System.out.println(“Math.ceil(-1.4)=” + Math.ceil(-1.4));
System.out.println(“Math.ceil(1.5)=” + Math.ceil(1.5));
System.out.println(“Math.ceil(-1.5)=” + Math.ceil(-1.5));
System.out.println(“Math.ceil(1.6)=” + Math.ceil(1.6));
System.out.println(“Math.ceil(-1.6)=” + Math.ceil(-1.6));
System.out.println();
System.out.println(“Math.floor(1.4)=” + Math.floor(1.4));
System.out.println(“Math.floor(-1.4)=” + Math.floor(-1.4));
System.out.println(“Math.floor(1.5)=” + Math.floor(1.5));
System.out.println(“Math.floor(-1.5)=” + Math.floor(-1.5));
System.out.println(“Math.floor(1.6)=” + Math.floor(1.6));
System.out.println(“Math.floor(-1.6)=” + Math.floor(-1.6));
打印结果:
Math.round(1.4)=1
Math.round(-1.4)=-1
Math.round(1.5)=2
Math.round(-1.5)=-1
Math.round(1.6)=2
Math.round(-1.6)=-2
Math.ceil(1.4)=2.0
Math.ceil(-1.4)=-1.0
Math.ceil(1.5)=2.0
Math.ceil(-1.5)=-1.0
Math.ceil(1.6)=2.0
Math.ceil(-1.6)=-1.0
Math.floor(1.4)=1.0
Math.floor(-1.4)=-2.0
Math.floor(1.5)=1.0
Math.floor(-1.5)=-2.0
Math.floor(1.6)=1.0
Math.floor(-1.6)=-2.0
13、String属于基础的数据类型吗?
不属于。
Java 中 8 种基础的数据类型:byte、short、char、int、long、float、double、boolean
但是 String 类型却是最常用到的引用类型。
14、java中操作字符串都有哪些类?它们之间有什么区别?
Java 中,常用的对字符串操作的类有 String、StringBuffer、StringBuilder
1)String : final 修饰,String 类的方法都是返回 new String。即对 String 对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象。
2)StringBuffer : 对字符串的操作的方法都加了synchronized,保证线程安全。
3)StringBuilder : 不保证线程安全,在方法体内需要进行字符串的修改操作,可以 new StringBuilder 对象,调用 StringBuilder 对象的 append()、replace()、delete() 等方法修改字符串。
15、如何将字符串反转?
使用 StringBuilder 或 StringBuffer 的 reverse 方法,本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。(JDK1.8)
package constxiong.interview;
public class TestReverseString {
public static void main(String[] args) {
String str = "ABCDE";
System.out.println(reverseString(str));
System.out.println(reverseStringByStringBuilderApi(str));
System.out.println(reverseStringByRecursion(str));
}
/**
* 自己实现
* @param str
* @return
*/
public static String reverseString(String str) {
if (str != null && str.length() > 0) {
int len = str.length();
char[] chars = new char[len];
for (int i = len - 1; i >= 0; i--) {
chars[len - 1 - i] = str.charAt(i);
}
return new String(chars);
}
return str;
}
/**
* 使用 StringBuilder
* @param str
* @return
*/
public static String reverseStringByStringBuilderApi(String str) {
if (str != null && str.length() > 0) {
return new StringBuilder(str).reverse().toString();
}
return str;
}
/**
* 递归
* @param str
* @return
*/
public static String reverseStringByRecursion(String str) {
if (str == null || str.length() <= 1) {
return str;
}
return reverseStringByRecursion(str.substring(1)) + str.charAt(0);
}
}
16、String类的常用方法有哪些?
equals:字符串是否相同
equalsIgnoreCase:忽略大小写后字符串是否相同
compareTo:根据字符串中每个字符的Unicode编码进行比较
compareToIgnoreCase:根据字符串中每个字符的Unicode编码进行忽略大小写比较
indexOf:目标字符或字符串在源字符串中位置下标
lastIndexOf:目标字符或字符串在源字符串中最后一次出现的位置下标
valueOf:其他类型转字符串
charAt:获取指定下标位置的字符
codePointAt:指定下标的字符的Unicode编码
concat:追加字符串到当前字符串
isEmpty:字符串长度是否为0
contains:是否包含目标字符串
startsWith:是否以目标字符串开头
endsWith:是否以目标字符串结束
format:格式化字符串
getBytes:获取字符串的字节数组
getChars:获取字符串的指定长度字符数组
toCharArray:获取字符串的字符数组
join:以某字符串,连接某字符串数组
length:字符串字符数
matches:字符串是否匹配正则表达式
replace:字符串替换
replaceAll:带正则字符串替换
replaceFirst:替换第一个出现的目标字符串
split:以某正则表达式分割字符串
substring:截取字符串
toLowerCase:字符串转小写
toUpperCase:字符串转大写
trim:去字符串首尾空格
17、 普通类和抽象类有哪些区别?
抽象类不能被实例化
抽象类可以有抽象方法,抽象方法只需申明,无需实现
含有抽象方法的类必须申明为抽象类
抽象类的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类
抽象方法不能被声明为静态
抽象方法不能用 private 修饰
抽象方法不能用 final 修饰
抽象类可以没有抽象方法,如
public abstract class TestAbstractClass {
public static void notAbstractMethod() {
System.out.println("I am not a abstract method.");
}
}
18、抽象类能使用final修饰吗?
不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。
19、接口和抽象类有什么区别?
抽象类可以有构造方法;接口中不能有构造方法。
抽象类中可以有普通成员变量;接口中没有普通成员变量。
抽象类中可以包含非抽象普通方法;接口中的所有方法必须都是抽象的。
抽象类中的抽象方法的访问权限可以是 public、protected 和 default;接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。
抽象类中可以包含静态方法;JDK1.8 前接口中不能包含静态方法,JDK1.8 及以后可以包含已实现的静态方法。
public interface TestInterfaceStaticMethod {
static String getA() {
return "a";
}
}
抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量可以是任意访问权限;接口中变量默认且只能是 public static final 类型。
一个类可以实现多个接口,用逗号隔开,但只能继承一个抽象类。
接口不可以实现接口,但可以继承接口,并且可以继承多个接口,用逗号隔开。
20 Java访问修饰符有哪些?权限的区别?
Java 语言中有四种权限访问控制符,能够控制类中成员变量和方法的可见性。
public被 public 修饰的成员变量和方法可以在任何类中都能被访问到。被 public 修饰的类,在一个 java 源文件中只能有一个类被声明为 public ,而且一旦有一个类为 public ,那这个 java 源文件的文件名就必须要和这个被 public 所修饰的类的类名相同,否则编译不能通过。
protected被 protected 修饰的成员会被位于同一 package 中的所有类访问到,也能被该类的所有子类继承下来。
friendly默认,缺省的。在成员的前面不写访问修饰符的时候,默认就是友好的。
同一package中的所有类都能访问。被 friendly 所修饰的成员只能被该类所在同一个 package 中的子类所继承下来。
private私有的。只能在当前类中被访问到。