-
将 byte[] 转换为 String?
可以使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。
-
Java 中代表价格的数据类型?
如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义精度的 double 类型。
-
我们能将 int 强制转换为 byte 类型的变量吗?如果该值大于 byte 类型的范围,将会出现什么现象?
可以强制转换,但是 Java 中 int 是 32 位的,而 byte 是 8 位的,所以,如果强制转化是,int 类型的高 24 位将会被丢弃,byte 类型的范围是从 -128 到 128。
-
Java 中 ++ 操作符是线程安全的吗?
不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。
-
3*0.1 == 0.3 将会返回什么?true 还是 false?
false,因为有些浮点数不能完全精确的表示出来。
-
int 和 Integer 哪个会占用更多的内存?
Integer 对象会占用更多的内存。Integer 是一个对象,需要存储对象的元数据。但是 int 是一个原始类型的数据,所以占用的空间更少。
-
为什么 Java 中的 String 是不可变的(Immutable)?
Java 中的 String 不可变是因为 Java 的设计者认为字符串使用非常频繁,将字符串设置为不可变可以允许多个客户端之间共享相同的字符串。
-
final、finalize 和 finally 的不同之处?
final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。finalize 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证。finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。
-
ArrayList 与 LinkedList 的区别?
最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构书链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。
-
Java 中的 HashSet,内部是如何工作的?
HashSet 的内部采用 HashMap来实现。由于 Map 需要 key 和 value,所以所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个null key,意思就是 HashSet 中只允许存储一个 null 对象。
-
什么是线程?
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。
-
线程和进程有什么区别?
线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。
-
如何在Java中实现线程?
在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。
-
用Runnable还是Thread?
这个问题是上题的后续,大家都知道我们可以通过继承Thread类或者调用Runnable接口来实现线程,问题是,那个方法更好呢?什么情况下使用它?这个问题很容易回答,如果你知道Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好了。更多详细信息请点击这里。
-
Thread 类中的start() 和 run() 方法有什么区别?
这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
-
Java中堆和栈有什么不同?
为什么把这个问题归类在多线程和并发面试题里?因为栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用了,它要求线程从主存中读取变量的值。
-
什么是线程池? 为什么要使用它?
创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。
-
Java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
-
解释内存中的栈(stack)、堆(heap)和静态存储区的用法。
答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;而通过new关键字和构造器创建的对象放在堆空间;程序中的字面量(literal)如直接书写的100、“hello”和常量都是放在静态存储区中。栈空间操作最快但是也很小,通常大量的对象都是放在堆空间,整个内存包括硬盘上的虚拟内存都可以被当成堆空间来使用。
String str = new String(“hello”);
上面的语句中 str 放在栈上,用 new 创建出来的字符串对象放在堆上,而“hello”这个字面量放在静态存储区。
-
Java支持的基本数据类型有哪些?什么是自动拆装箱?
java支持的基本数据类型有以下9种:byte,shot,int,long,float,double,char,boolean,void.
自动拆装箱是java从jdk1.5引用,目的是将原始类型自动的装换为相对应的对象,也可以逆向进行,即拆箱。这也体现java中一切皆对象的宗旨。
所谓自动装箱就是将原始类型自动的转换为对应的对象,而拆箱就是将对象类型转换为基本类型。java中的自动拆装箱通常发生在变量赋值的过程中,如:
Integer object = 3; //自动装箱
int o = object; //拆箱
在java中,应该注意自动拆装箱,因为有时可能因为java自动装箱机制,而导致创建了许多对象,对于内存小的平台会造成压力。
-
接口和抽象类的区别是什么?
不同点在于:
接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
类可以实现很多个接口,但是只能继承一个抽象类
类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
抽象类可以在不提供接口方法实现的情况下实现接口。
Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。
Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private,protected 或者是 public 。
接口是绝对抽象的,不可以被实例化(java 8已支持在接口中实现默认的方法)。抽象类也不可以被实例化,但是,如果它包含 main 方法的话是可以被调用的。
-
Array和ArrayList有何区别?什么时候更适合用Array?
- Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
- Array是指定大小的,而ArrayList大小是固定的
-
哪些集合类提供对元素的随机访问?
ArrayList、HashMap、TreeMap和HashTable类提供对元素的随机访问。
-
HashSet的底层实现是什么?
通过看源码知道HashSet的实现是依赖于HashMap的,HashSet的值都是存储在HashMap中的。在HashSet的构造法中会初始化一个HashMap对象,HashSet不允许值重复,因此,HashSet的值是作为HashMap的key存储在HashMap中的,当存储的值已经存在时返回false。
-
LinkedHashMap的实现原理?
LinkedHashMap也是基于HashMap实现的,不同的是它定义了一个Entry header,这个header不是放在Table里,它是额外独立出来的。LinkedHashMap通过继承hashMap中的Entry,并添加两个属性Entry before,after,和header结合起来组成一个双向链表,来实现按插入顺序或访问顺序排序。LinkedHashMap定义了排序模式accessOrder,该属性为boolean型变量,对于访问顺序,为true;对于插入顺序,则为false。一般情况下,不必指定排序模式,其迭代顺序即为默认为插入顺序。
-
LinkedList和ArrayList的区别是什么?
ArrayList是基于数组实现,LinkedList是基于链表实现
ArrayList在查找时速度快,LinkedList在插入与删除时更具优势
-
什么是线程?进程和线程的关系是什么?
线程可定义为进程内的一个执行单位,或者定义为进程内的一个可调度实体。 在具有多线程机制的操作系统中,处理机调度的基本单位不是进程而是线程。一个进程可以有多个线程,而且至少有一个可执行线程。
打个比喻:进程好比工厂(计算机)里的车间,一个工厂里有多个车间(进程)在运转,每个车间里有多个工人(线程)在协同工作,这些工人就可以理解为线程。
线程和进程的关系:
线程是进程的一个组成部分.
进程的多个线程都在进程地址空间活动.
系统资源是分配给进程的,线程需要资源时,系统从进程的资源里分配给线程.
处理机调度的基本单位是线程.
-
Thread 类中的start() 和 run() 方法有什么区别?
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
-
什么是线程安全?
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为。
线程安全的核心是“正确性”,也就是说当多个线程访问某个类时,能够得到预期的结果,那么就是线程安全的。
-
final、static、static final修饰的字段赋值的区别:
static修饰的字段在类加载过程中的准备阶段被初始化为0或null等默认值,而后在初始化阶段(触发类构造器
final修饰的字段在运行时被初始化(可以直接赋值,也可以在实例构造器中赋值),一旦赋值便不可更改;
static final修饰的字段在Javac时生成ConstantValue属性,在类加载的准备阶段根据ConstantValue的值为该字段赋值,它没有默认值,必须显式地赋值,否则Javac时会报错。可以理解为在编译期即把结果放入了常量池中。
-
Java的四种引用的区别
- 强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM 也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象
- 软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
- 弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象
- 虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。
-
JAVA 中堆和栈的区别
- 基本数据类型比如变量和对象的引用都是在栈分配的
- 堆内存用来存放由new创建的对象和数组
- 类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中
- 实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的"物理位置”,实例变量的生命周期--当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存
- 局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放
-
进程和线程的区别
简而言之,一个程序至少有一个进程,一个进程至少有一个线程。
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。参考《现代操作系统》或者《操作系统的设计与实现》。
-
接口与抽象类的区别
- 默认的方法实现 抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现
- 实现 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。
子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现 - 构造器
抽象类可以有构造器 接口不能有构造器 - 与正常Java类的区别
除了你不能实例化抽象类之外,它和普通Java类没有任何区 接口是完全不同的类型 - 访问修饰符
抽象方法可以有public、protected和default这些修饰符 接口方法默认修饰符是public。你不可以使用其它修饰符。 - main方法
抽象方法可以有main方法并且我们可以运行它
接口没有main方法,因此我们不能运行它。 - 多继承
抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。 - 速度
它比接口速度要快
接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 - 添加新方法
如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。
如果你往接口中添加方法,那么你必须改变实现该接口的类。