java面试题--java基础二
1. 两个对象的hashCode相同,则equals也一定为true,对吗?
不对,答案见下面的代码:
@Override
public int hashCode() {
return 1;
}
两个对象equals为true,则hashCode也一定相同,对吗?
这块肯定是有争议的。面试的时候这样答:如果按照官方设计要求来打代码的话,hashcode一定相等。但是如果不按官方照设计要求、不重写hashcode方法,就会出现不相等的情况。
2. java线程池用过没有?
Executors提供了四种方法来创建线程池。
- newFixedThreadPool() :创建固定大小的线程池。
- newCachedThreadPool(): 创建无限大小的线程池,线程池中线程数量不固定,可根据需求自动更改。
- newSingleThreadPool() : 创建单个线程池,线程池中只有一个线程。
- newScheduledThreadPool() 创建固定大小的线程池,可以延迟或定时的执行任务。
手写一个:
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.execute(() -> {
for (int i = 0; i< 20;i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
});
threadPool.shutdown();
}
线程池作用
- 限制线程个数,避免线程过多导致系统运行缓慢或崩溃。
- 不需要频繁的创建和销毁,节约资源、响应更快。
3. Math.round(-2.5)等于多少?
不要认为它是四舍五入!不要认为它是四舍五入!不要认为它是四舍五入!
口诀:+0.5后向下取整。所以结果是-2。
留个题,Math.round(-2.6)结果和Math.round(2.6)结果
4. 面向对象六大原则
- 单一职责原则——SRP
让每个类只专心处理自己的方法。
- 开闭原则——OCP
软件中的对象(类,模块,函数等)应该对于扩展是开放的,但是对于修改是关闭的。
- 里式替换原则——LSP
子类可以去扩展父类,但是不能改变父类原有的功能。
- 依赖倒置原则——DIP
应该通过调用接口或抽象类(比较高层),而不是调用实现类(细节)。
- 接口隔离原则——ISP
把接口分成满足依赖关系的最小接口,实现类中不能有不需要的方法。
- 迪米特原则——LOD
高内聚,低耦合。
5. static和final区别
关键词 | 修饰物 | 影响 | ||
---|---|---|---|---|
final | 变量 | 分配到常量池中,程序不可改变其值 | ||
final | 方法 | 子类中将不能被重写 | ||
final | 类 | 不能被继承 | ||
static | 变量 | 分配在内存堆上,引用都会指向这一个地址而不会重新分配内存 | ||
static | 方法块 | 虚拟机优先加载 | ||
static | 类 | 可以直接通过类来调用而不需要new |
6. String s = "hello"和String s = new String("hello");区别
String s = new String("hello");
可能创建两个对象也可能创建一个对象。如果常量池中有hello
字符串常量的话,则仅仅在堆中创建一个对象。如果常量池中没有hello
对象,则堆上和常量池都需要创建。
String s = "hello"
这样创建的对象,JVM会直接检查字符串常量池是否已有"hello"字符串对象,如没有,就分配一个内存存放"hello",如有了,则直接将字符串常量池中的地址返回给栈。(没有new,没有堆的操作)
7. 引用类型是占用几个字节?
hotspot在64位平台上,占8个字节,在32位平台上占4个字节。
8. (1<3)?"a":"b")+3+4
和(1<3)?"a":"b")+(3+4)
区别
System.out.println(((1<3)?"a":"b")+3+4);
System.out.println(((1<3)?"a":"b")+(3+4));
控制台:
a34
a7
8.1 什么情况下,加号会变成字符串连接符
当加号前面是一个字符串的时候,后面即使是数字,通过加号连接也是字符串的拼接
9. java中的switch选择结构可以使用数据类型的数据(JDK1.8)
- char
- byte
- short
- int
- Character
- Byte
- Short
- Integer
- String
- enum
更好的记忆方法:
基本类型中,没有boolean
和浮点类型
+长类型long
.相应的包装类型也没有。
外加String
和enum
。
10. 4&5``4^5``4&10>>1
各等于多少
// 0100 & 0101 = 0100 = 4
System.out.println(4&5);
// 0100 ^ 0101 = 0001 = 1
System.out.println(4^5);
System.out.println(10>>1);
// 有疑问参考下面的运算符优先级
System.out.println(4&10>>1);
4
1
5
4
4|5
等于多少呢
答案:5
运算符优先级
运算符 | 结合性 | ||
---|---|---|---|
[ ] . ( ) (方法调用) |
从左向右 | ||
! ~ ++ -- + (一元运算) -(一元运算) |
从右向左 | ||
* / % |
从左向右 | ||
+ - |
从左向右 | ||
<< >> >>> |
从左向右 | ||
< <= > >= instanceof |
从左向右 | ||
== != |
从左向右 | ||
& |
从左向右 | ||
^ |
从左向右 | ||
` | ` | 从左向右 | |
&& |
从左向右 | ||
` | ` | 从左向右 | |
?: |
从右向左 | ||
= |
从右向左 |
11. 某些java类为什么要实现Serializable接口
为了网络进行传输或者持久化
什么是序列化
将对象的状态信息转换为可以存储或传输的形式的过程
除了实现Serializable接口还有什么序列化方式
- Json序列化
- FastJson序列化
- ProtoBuff序列化
...
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html#t5)
12. JVM中对象的创建过程
1. 拿到内存创建指令
当虚拟机遇到内存创建的指令的时候(new 类名),来到了方法区,找 根据new的参数在常量池中定位一个类的符号引用。
2. 检查符号引用
检查该符号引用有没有被加载、解析和初始化过,如果没有则执行类加载过程,否则直接准备为新的对象分配内存
3. 分配内存
虚拟机为对象分配内存(堆)分配内存分为指针碰撞和空闲列表两种方式;分配内存还要要保证并发安全,有两种方式。
3.1. 指针碰撞
所有的存储空间分为两部分,一部分是空闲,一部分是占用,需要分配空间的时候,只需要计算指针移动的长度即可。
3.2. 空闲列表
虚拟机维护了一个空闲列表,需要分配空间的时候去查该空闲列表进行分配并对空闲列表做更新。
可以看出,内存分配方式是由java堆是否规整决定的,java堆的规整是由垃圾回收机制来决定的
3.2.5 安全性问题的思考
假如分配内存策略是指针碰撞,如果在高并发情况下,多个对象需要分配内存,如果不做处理,肯定会出现线程安全问题,导致一些对象分配不到空间等。
下面是解决方案:
3.3 线程同步策略
也就是每个线程都进行同步,防止出现线程安全。
3.4. 本地线程分配缓冲
也称TLAB(Thread Local Allocation Buffer),在堆中为每一个线程分配一小块独立的内存,这样以来就不存并发问题了,Java 层面与之对应的是 ThreadLocal 类的实现
4. 初始化
- 分配完内存后要对对象的头(Object Header)进行初始化,这新信息包括:该对象对应类的元数据、该对象的GC代、对象的哈希码。
- 抽象数据类型默认初始化为null,基本数据类型为0,布尔为false。。。
5. 调用对象的初始化方法
也就是执行构造方法。