Java基础面试题第一弹
1. 面向对象的特征有哪些方面
- 抽象:抽象是将一类对象的共同特征抽离出来构造成类的过程。包括数据抽象和行为抽象两个部分,抽象只关注对象的属性和行为,并不关注行为的具体细节。【如狗都会叫,但是不同品种的狗的叫声有差异】
- 继承:继承是从已有类,得到继承信息并创建新类的过程。提供继承信息的类被称为父类【超类、基类】,得到继承信息的类被称为子类【派生类】。继承让变化中的系统有了一定的延续性。
- 封装:封装是把数据和操作数据的方法绑定在一起,对数据的访问只能通过已定义的接口。
- 多态:多态指的是允许不同子类型的对象对同一信息作出不同的响应。换言之就是,相同的对象引用调用相同的方法会执行不同的处理。分为
编译时的多态性
和运行时的多态性
。
- 编译时的多态性:方法重载【overload】实现的是编译时的多态性,也称为前绑定。
- 运行时的多态性:方法重写【overwrite】实现的是运行时的多态性,也称为后绑定。实现运行时多态需要两步:其一,方法重写;其二,由父类引用子类对象,并调用方法。该方法会根据不同的子类实现而执行不同的代码。
2. 访问修饰符 public,private,protected,以及不写时的区别
修饰符 当前类 相同包下 子类 其他包下 public 可访问 可访问 可访问 可访问 protected 可访问 可访问 可访问 不可访问
default 可访问 可访问 不可访问
不可访问
private 可访问 不可访问
不可访问
不可访问
- 类的成员不写访问修饰符时默认为default。
- 外部类的修饰符只能是public或默认,类的成员【包括内部类】的修饰符可以是以上四种。
3. String是最基本的数据类型吗?
答:不是;Java中基本数据类型有8种:byte、short、char、int、float、double、long、boolean。Java除了基本数据类型外,剩下的都是引用类型。Java5以后引入的枚举类型也算是一种特殊的引用类型。
4. float f = 3.4; 是否正确
答:不正确。3.4 是双精度数,将双精度赋值给浮点型,属于下转型【窄化】,会造成精度损失,因此需要强制类型转换:float f = (float)3.4; 或者 float f = 3.4F;
5. short s1 = 1; s1 = s1 + 1;是否有错?
答:有错,无法正确编译;由于 1 是int类型,因此s1+1运算结果也是int类型,需要强制类型转换才能赋值给short类型。如:
short s1 = 1; s1 = (short) (s1 + 1);
6. short s1 = 1; s1 += 1;是否有错?
答:可以正确编译;s1+=1; 相当于s1 = (short) (s1 + 1); 其中隐含了强制类型转换。
7. Java是否有goto?
答:goto是Java的保留字,在目前Java版本中没有使用。goto 和 const 是目前无法使用的关键字,有些地方称之为保留字。
8. int 和 Integer 的区别
- Integer是int的包装类型,int是Java的一个基本数据类型。
- Integer的默认值为null,int的默认值为0。在实际编程的实体类中,一般使用Integer类型而不使用int类型。因为当Integer类型没有赋值时,为null,有特殊含义;当int类型没有赋值时,为默认值0。
【如,某个系统用户的年龄为Integer类型,当该用户没有填写年龄,则该值为null,若为int类型,则默认为0,无法表明该用户是否填写了年龄】
- 为了能够将基本数据类型当成对象操作,Java为每一个基本数据类型引入了对应的包装类型,而int的包装类型就是Integer。
- 整型之间的比较:
/** * @author: zipeng Li * 2021/5/25 15:15 */ class Test { public static void main(String[] args) { Integer a = new Integer(3); Integer b = 3; // 将 3 自动装箱为Integer类型 int c = 3; System.out.println(a == b); // 结果为 false,这里比较的是两个引用类型的内存地址 System.out.println(b == c); // 结果为 true,这里 b自动拆箱成int类型,比较的是值。 Integer d = 100; Integer e = 100; System.out.println(d == e); // 结果为 true,因为 -128 - 127 之间的整数缓存在java常量池中 Integer f = 150; Integer g = 150; // 结果为 false,因为 150 不在java常量池中,每次都会新建一个Integer对象 System.out.println(f == g); } }
9. & 与 && 的区别
- & 运算符有两种用法:按位与 和 逻辑与。
- && 运算符是短路与运算。
- 逻辑与 和 短路与 的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是 true,整个表达式的值才是 true。若 && 左边的表达式为 false,则右边的表达式会被直接短路掉,不会进行运算。
- 例子:
username != null && username.equals("")
二者之间的顺序不能交换,更不能使用 & 运算符,因为第一个条件不成立,则根本不能进行字符串的equals比较,否则会抛出NullPointerException异常。- | 和 || 运算符的差别也是差不多。
10. 解释内存中栈、堆和方法区的用法
- 通常定义的基本数据类的变量、对象的引用、函数调用的现场保存都使用JVM的栈空间;
- 通过关键字 new 和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域;
- 现在的垃圾收集器都使用分代收集算法,所以堆空间还可以细分为新生代、老生代;具体还可以细分为Eden、Survivor【From Survivor 和 To Survivor】、Tenured;
- 堆和方法区都是线程共享的内存区域,用于存储已被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;
- 程序中的字面量【如直接书写的100、“hello”】和常量都是放在常量池中,常量池是方法区的一部分;
- 栈空间操作起来最快但是比较小,对象通常放在堆空间内;栈和堆空间可以通过JVM的启动参数来进行调整
- 栈空间用完会引发StackOverflowError异常;堆和常量池空间不足会引发OutOfMemoryError异常。
String str = new String("hello");
// 1. 变量 str 放在栈上,用 new 创建出来的字符串对象放在堆上,而“hello”这个字面量放在方法区。
// 2. 补充1:较新版本的Java【从 Java 6 的某个更新开始】中,由于JIT编译器的发展和“逃逸分析”技术的逐渐成熟,栈上分配、标量替换等优化技术使得对象一定分配在堆上变得不是那么绝对了。
// 3. 补充2:运行时常量池 相当于 Class文件常量池 具有动态性,Java语言并不要求常量一定只有编译期间才能产生,运行期间也可以将新的常量放入池中,String类的 intern() 方法就是这样。
// 4. String.intern() 方法,若字符串在常量池可以找到,则返回常量池地址;否则,把该字符串保存到常量池,返回原来字符串对象地址
/**
* @author: zipeng Li
* 2021/5/25 15:15
*/
class Test {
public static void main(String[] args) {
String s1 = new StringBuilder("go").append("od").toString();
System.out.println(s1.intern() == s1); // true 因为常量池一开始没有 "good";
String s2 = new StringBuilder("ja").append("va").toString();
System.out.println(s2.intern() == s2); // false 因为常量池一开始就有 "java"
}
}