java面试题--java基础二

1. 两个对象的hashCode相同,则equals也一定为true,对吗?

不对,答案见下面的代码:

@Override
public int hashCode() {
    return 1;
}
两个对象equals为true,则hashCode也一定相同,对吗?

这块肯定是有争议的。面试的时候这样答:如果按照官方设计要求来打代码的话,hashcode一定相等。但是如果不按官方照设计要求、不重写hashcode方法,就会出现不相等的情况。

2. java线程池用过没有?

Executors提供了四种方法来创建线程池。

  1. newFixedThreadPool() :创建固定大小的线程池。
  2. newCachedThreadPool(): 创建无限大小的线程池,线程池中线程数量不固定,可根据需求自动更改。
  3. newSingleThreadPool() : 创建单个线程池,线程池中只有一个线程。
  4. 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();
}
线程池作用
  1. 限制线程个数,避免线程过多导致系统运行缓慢或崩溃。
  2. 不需要频繁的创建和销毁,节约资源、响应更快。

3. Math.round(-2.5)等于多少?

不要认为它是四舍五入!不要认为它是四舍五入!不要认为它是四舍五入!

口诀:+0.5后向下取整。所以结果是-2。

留个题,Math.round(-2.6)结果和Math.round(2.6)结果

4. 面向对象六大原则

  1. 单一职责原则——SRP

让每个类只专心处理自己的方法。

  1. 开闭原则——OCP

软件中的对象(类,模块,函数等)应该对于扩展是开放的,但是对于修改是关闭的。

  1. 里式替换原则——LSP

子类可以去扩展父类,但是不能改变父类原有的功能。

  1. 依赖倒置原则——DIP

应该通过调用接口或抽象类(比较高层),而不是调用实现类(细节)。

  1. 接口隔离原则——ISP

把接口分成满足依赖关系的最小接口,实现类中不能有不需要的方法。

  1. 迪米特原则——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)

  1. char
  2. byte
  3. short
  4. int
  5. Character
  6. Byte
  7. Short
  8. Integer
  9. String
  10. enum

更好的记忆方法:

基本类型中,没有boolean浮点类型+长类型long.相应的包装类型也没有。

外加Stringenum

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. 初始化

  1. 分配完内存后要对对象的头(Object Header)进行初始化,这新信息包括:该对象对应类的元数据、该对象的GC代、对象的哈希码。
  2. 抽象数据类型默认初始化为null,基本数据类型为0,布尔为false。。。

5. 调用对象的初始化方法

也就是执行构造方法。

posted on 2020-09-17 20:37  liqiangbk  阅读(154)  评论(0编辑  收藏  举报

导航