面试题整理—Java初级面试题

Java中有哪几种方式来创建线程执行任务

在Java中本质上只有一种创建线程的方式—–实现Runnable接口

(1)实现Runnable接口

(2)继承Thread

(3)实现Callable接口(可以获取任务结果,使用FutureTask)

(4)使用线程池来创建线程

线程池有哪几种状态,每种状态表示什么?

(1)Running状态:表示线程池正常运行,既能接收任务也会处理队列任务

(2)Shutdown状态:表示线程池处于正在关闭状态,不会接收新任务,但会把队列中的任务处理完,使用shutdow()方法

(3)Stop状态:表示线程池处于正在停止状态,既不会接收任务,也不会处理队列中的任务,使用shutdownow()方法

(4)Tidying:线程池没用线程运行后的状态,并会调用terminated()空方法,给与扩展

(5)Terminated状态:terminated()方法调用后会变成该状态

JDK、JRE、JVM之间的区别

JDK,Java标准开发包,提供编译、运行Java所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用Java类库

JRE,Java运行环境,用于运行Java字节码文件

JVM,Java虚拟机,是JRE的一部分,负责运行字节码文件

Java代码使用JDK中的编译器javac编译为字节码,再在JVM中运行。

JDK包含了JRE,JRE包含了JVM

hashCode()与equals()之间的关系

在Java中,每个对象都可以调用自己的hashCode()方法来得到自己的哈希值,相当于对象的指纹信息。

当两个对象哈希值相同时,不一定是同一个对象。

在比较两个对象是否相等时,会先比较两个对象的hashCode(),如果哈希值相同,再调用equals()方法比较,如果相同则是两个相等的对象。

String、StringBuffer、StringBuilder的区别

(1)String是不可变的,如果尝试修改,会生成一个新的字符串对象,而StringBuffer和StringBuilder是可变的。

(2)StringBuffer是线程安全的,StringBuilder是线程不安全的,所以在单线程环境下StringBuilder效率会更高。

泛型中extends和super的区别

1.<? extends T>表示包括T在内的任何T的子类

2.<? super T>表示包括T在内的任何T的父类

如List<E extends Number> 可以用于限制泛型的类型

==和equals方法的区别

==如果是基本数据类型,比较的是值,如果是引用类型,比较的是引用地址

equals:具体看各个类重写equals方法之后的比较逻辑。

如String类,不能使用==比较两个字符串的值,而需要使用equals

重载和重写的区别

重载:发生在同一个类中,方法名相同,参数类型、个数、顺序不同,方法返回值和访问修饰符可以不同,但重载和返回值无关,即只有返回值不一样不叫重载

重写:发生在子类中,方法名、参数列表相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类不能重写该方法。

List和Set的区别

List:有序的,按对象进入顺序保存对象,可重复,运行多个null元素,可以使用iterator取出所有元素,再逐一遍历,也可以使用get方法获取下标元素

Set:无序的,不可重复,最多允许一个null元素,取元素时使用iterator接口取得所有元素,再逐一遍历

ArrayList和LinkedList的区别

两者底层数据结构不同,ArrayList底层基于数组实现,LinkedList底层基于链表实现

由于底层不同,适用场景也不同,ArrayList适合随机查找,LinkedList适合删除和添加较多的场景

两者都实现了List接口,但LinkedList还实现了Deque接口,所以可以当作队列使用

Jdk1.7到Jdk1.8 HashMap的变化

  1. 1.7中底层为数组+链表,1.8中为数组+链表+红黑树,目的是提高插入和查询整体效率
  2. 1.7链表插入是头插法,1.8为尾插法,因为1.8中插入key和value需要判断列表元素个数,需要遍历链表,所以直接使用尾插法。
  3. 1.7中哈希算法比较复杂,存在各种右移与异或运算,1.8进行了简化

深拷贝与浅拷贝

深拷贝和浅拷贝指对象的拷贝,一个对象存在两种类型的属性,一种是基本数据类型,一种是实例对象的引用。

浅拷贝指只会拷贝基本数据类型的值,以及实例对象的引用地址,并不会复制引用对象的值,即拷贝出来的对象,内部实例对象指向同一个对象。

深拷贝不仅会拷贝基本数据类型,也会针对实例对象的引用地址所指向的对象进行复制,即深拷贝出来的对象,内部实例对象指向不是同一个对象。

HashMap的扩容机制

HashMap的默认容量为16,默认的负载因子为0.75,当HashMap中元素个数超过容量乘以负载因子的个数时,就创建一个大小为前一次两倍的新数组,再将原来数组中的数据复制到新数组中。当数组长度到达64且链表长度大于8时,链表转为红黑树

想要线程安全的HashMap怎么办?

(1)使用ConcurrentHashMap

(2)使用HashTable

(3)Collections.synchronizedHashMap()方法

ConcurrentHashMap原如何保证的线程安全?

JDK1.7:使用分段锁,将一个Map分为了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁

JDK1.8:采用CAS+Synchronized保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参与扩容;删除方法用了synchronized修饰,保证并发下移除元素安全

HashTable与HashMap的区别

(1)HashTable的每个方法都用synchronized修饰,因此是线程安全的,但同时读写效率很低

(2)HashTable的Key不允许为null

(3)HashTable只对key进行一次hash,HashMap进行了两次Hash

(4)HashTable底层使用的数组加链表

如何保证ArrayList的线程安全?

(1)使用collentions.synchronizedList()方法为ArrayList加锁

(2)使用Vector,Vector底层与Arraylist相同,但是每个方法都由synchronized修饰,速度很慢

(3)使用juc下的CopyOnWriterArrayList,该类实现了读操作不加锁,写操作时为list创建一个副本,期间其它线程读取的都是原本list,写操作都在副本中进行,写入完成后,再将指针指向副本。

面向对象和面向过程的区别

面向对象有封装、继承、多态性的特性,所以相比面向过程易维护、易复用、易扩展,但是因为类调用时要实例化,所以开销大性能比面向过程低

多态的作用

多态的实现要有继承、重写,父类引用指向子类对象。它的好处是可以消除类型之间的耦合关系,增加类的可扩充性和灵活性。

什么是反射

反射是通过获取类的class对象,然后动态的获取到这个类的内部结构,动态的去操作类的属性和方法。
应用场景有:要操作权限不够的类属性和方法时、实现自定义注解时、动态加载第三方jar包时、按需加载类,节省编译和初始化时间;
获取class对象的方法有:class.forName(类路径),类.class(),对象的getClass()

Java创建对象得五种方式?

(1)new关键字   (2)Class.newInstance  (3)Constructor.newInstance

(4)Clone方法   (5)反序列化