前几天,在茫茫的互联网海洋中寻寻觅觅,我收藏了800道Java基础经典面试题,有小伙伴私聊我要答案。因此感受没有答案的面试题是没有灵魂的,因而今天先整理基础篇的前80道答案出来~html
全部的Java面试题已经上传github,答案也上传了一部分~java
公众号:捡田螺的小男孩程序员
equalsgithub
两个对象equals相等,则它们的hashcode必须相等,若是两个对象的hashCode()相同,则equals()不必定为true。面试
hashCode 的常规协定:sql
这个答案来自互联网哈,我的以为是最好理解的~编程
- BIO:线程发起 IO 请求,无论内核是否准备好 IO 操做,从发起请求起,线程一直阻塞,直到操做完成。
- NIO:线程发起 IO 请求,当即返回;内核在作好 IO 操做的准备以后,经过调用注册的回调函数通知线程作 IO 操做,线程开始阻塞,直到操做完成。
- AIO:线程发起 IO 请求,当即返回;内存作好 IO 操做的准备以后,作 IO 操做,直到操做完成或者失败,经过调用注册的回调函数通知线程作 IO 操做完成或者失败。
BIO 是一个链接一个线程。,NIO 是一个请求一个线程。,AIO 是一个有效请求一个线程。设计模式
- BIO:同步并阻塞,服务器实现模式为一个链接一个线程,即客户端有链接请求时服务器端就须要启动一个线程进行处理,若是这个链接不作任何事情会形成没必要要的线程开销,固然能够经过线程池机制改善。
- NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的链接请求都会注册到多路复用器上,多路复用器轮询到链接有I/O请求时才启动一个线程进行处理。
- AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的 IO 请求都是由 OS 先完成了再通知服务器应用去启动线程进行处理。
String:数组
StringBuffer:
StringBuilder:
基本类型 | 位数 | 字节 |
---|---|---|
int | 32 | 4 |
short | 16 | 2 |
long | 64 | 8 |
byte | 8 | 1 |
char | 16 | 2 |
float | 32 | 4 |
double | 64 | 8 |
boolean | ? | ? |
对于boolean,官方文档未明肯定义,它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1位,可是实际中会考虑计算机高效存储因素
感兴趣的小伙伴,能够去看官网
在牛客网看到这道题的答案,以为写的最好~
连接:www.nowcoder.com/questionTer… 来源:牛客网
- Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,因此,如想实现排序,就须要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。
- Comparator位于包java.util下,而Comparable位于包 java.lang下。
- Comparable 是一个对象自己就已经支持自比较所须要实现的接口(如 String、Integer 本身就能够完成比较大小操做,已经实现了Comparable接口) 自定义的类要在加入list容器中后可以排序,能够实现Comparable接口,在用Collections类的sort方法排序时,若是不指定Comparator,那么就以天然顺序排序, 这里的天然顺序就是实现Comparable接口设定的排序方式。
- 而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能知足你的要求时,你能够写一个比较器来完成两个对象之间大小的比较。
- 能够说一个是自已完成比较,一个是外部程序实现比较的差异而已。 用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。 好比:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不须要去修改 Integer 类(实际上你也不能这么作)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就好了。
首先,String是一个final修饰的类,final修饰的类不能够被继承。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
复制代码
String类为何不能被继承呢?
有两个缘由:
举个例子吧,假设有个Fruit父类,一个taste味道方法,两个子类Apple和Pear,以下:
abstract class Fruit {
abstract String taste() ;
}
class Apple extends Fruit {
@Override
String taste() {
return "酸酸的";
}
}
class Pear extends Fruit {
@Override
String taste() {
return "甜甜的";
}
}
public class Test {
public static void main(String[] args) {
Fruit f = new Apple();
System.out.println(f.taste());
}
}
复制代码
程序运行,当调用对象Fruit f的方法taste时,JVM查找Fruit对象类的方法表以肯定taste方法的直接引用地址,到底来自Apple仍是Pear,肯定后才真正调用对应子类的taste方法,
这个面试题,能够看我这篇文章哈~
这里考察3个知识点吧:
看个Integer的缓存的例子,加深一下印象哈:
Integer a = 10;
Integer b = 10;
Integer c = 129;
Integer d = 129;
System.out.println(a == b);
System.out.println(c == d);
输出结果:
true
false
复制代码
这道面试题,看我这篇文章哈:谈谈Java反射:从入门到实践,再到原理
Java获取反射的三种方法:
面向对象的三大特征:
直接看个例子吧:
public class Parent {
{
System.out.println("父类非静态代码块");
}
static {
System.out.println("父类静态块");
}
public Parent() {
System.out.println("父类构造器");
}
}
public class Son extends Parent {
public Son() {
System.out.println("子类构造器");
}
static {
System.out.println("子类静态代码块");
}
{
System.out.println("子类非静态代码块");
}
}
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
复制代码
运行结果:
父类静态块
子类静态代码块
父类非静态代码块
父类构造器
子类非静态代码块
子类构造器
复制代码
因此,类实例化顺序为: 父类静态代码块/静态域->子类静态代码块/静态域 -> 父类非静态代码块 -> 父类构造器 -> 子类非静态代码块 -> 子类构造器
Java建立对象有5种方式
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "捡田螺的小男孩";
String strIso = new String(str.getBytes("GB2312"), "ISO-8859-1");
System.out.println(strIso);
}
}
复制代码
这道面试题,能够看我这篇文章哈:Java程序员必备:异常的十个关键知识点
从前从前,有位老人,他的名字叫Throwable,他生了两个儿子,大儿子叫Error,二儿子叫Exception。
Error
表示编译时或者系统错误,如虚拟机相关的错误,OutOfMemoryError等,error是没法处理的。
Exception
代码异常,Java程序员关心的基类型一般是Exception。它能被程序自己能够处理,这也是它跟Error的区别。
它能够分为RuntimeException(运行时异常)和CheckedException(可检查的异常)。
常见的RuntimeException异常:
- NullPointerException 空指针异常
- ArithmeticException 出现异常的运算条件时,抛出此异常
- IndexOutOfBoundsException 数组索引越界异常
- ClassNotFoundException 找不到类异常
- IllegalArgumentException(非法参数异常)
复制代码
常见的 Checked Exception 异常:
- IOException (操做输入流和输出流时可能出现的异常)
- ClassCastException(类型转换异常类)
复制代码
这道面试题,能够看我这篇文章哈:Java程序员必备基础:内部类解析
String str ="whx";
String newStr =new String ("whx");
复制代码
String str ="whx"
先在常量池中查找有没有"whx" 这个对象,若是有,就让str指向那个"whx".若是没有,在常量池中新建一个“whx”对象,并让str指向在常量池中新建的对象"whx"。
String newStr =new String ("whx");
是在堆中创建的对象"whx" ,在栈中建立堆中"whx" 对象的内存地址。
如图所示:
网上这篇文章讲的挺好的: String和New String()的区别
Class.forName和ClassLoader均可以对类进行加载。它们区别在哪里呢? ClassLoader负责加载 Java 类的字节代码到 Java 虚拟机中。Class.forName实际上是调用了ClassLoader,以下:
Class<?> forName(String name, boolean initialize, ClassLoader loader)
方法实现同样的功能,它的源码以下:
因此,Class.forName和ClassLoader的区别,就是在类加载的时候,class.forName有参数控制是否对类进行初始化。
网上这篇文章写得不错,描述Java动态代理的几种实现方式,分别说出相应的优缺点
Error: 表示编译时或者系统错误,如虚拟机相关的错误,OutOfMemoryError等,error是没法处理的。
Exception: 代码异常,Java程序员关心的基类型一般是Exception。它能被程序自己能够处理,这也是它跟Error的区别。
它能够分为RuntimeException(运行时异常)和CheckedException(可检查的异常)。 常见的RuntimeException异常:
- NullPointerException 空指针异常
- ArithmeticException 出现异常的运算条件时,抛出此异常
- IndexOutOfBoundsException 数组索引越界异常
- ClassNotFoundException 找不到类异常
- IllegalArgumentException(非法参数异常)
复制代码
常见的 Checked Exception 异常:
- IOException (操做输入流和输出流时可能出现的异常)
- ClassCastException(类型转换异常类)
复制代码
有兴趣能够看我以前写得这篇文章: Java程序员必备:异常的十个关键知识点
浅拷贝
复制了对象的引用地址,两个对象指向同一个内存地址,因此修改其中任意的值,另外一个值都会随之变化。
深拷贝
将对象及值复制过来,两个对象修改其中任意的值另外一个值不会改变
有关于注解,建议你们看一下java编程思想的注解篇章哈~
设计模式分为三大类:
最好平时积累一下,单例模式(7种实现方式),工厂模式,模板方法设计模式,策略模式,装饰者模式、代理模式这几种怎么写吧~
我的以为,能够看看Hollis大神相关设计模式的文章哈,写得特别好!设计模式(二)——单例模式
static变量在Java中是属于类的,它在全部的实例中的值是同样的。当类被Java虚拟机载入的时候,会对static变量进行初始化。由于静态的成员属于类,随着类的加载而加载到静态方法区内存,当类加载时,此时不必定有实例建立,没有实例,就不能够访问非静态的成员。类的加载先于实例的建立,所以静态环境中,不能够访问非静态!
不支持多继承,缘由:
2 << 3
复制代码
构造器是不能被继承的,由于每一个类的类名都不相同,而构造器名称与类名相同,因此谈不上继承。 又因为构造器不能被继承,因此相应的就不能被重写了。
在Java中,char类型占2个字节,并且Java默认采用Unicode编码,一个Unicode码是16位,因此一个Unicode码占两个字节,Java中不管汉子仍是英文字母都是用Unicode编码来表示的。因此,在Java中,char类型变量能够存储一个中文汉字。
char ch = '啦';
System.out.println("char:" + ch);
复制代码
- hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中肯定对象的存储地址的;
- 若是两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode必定要相同;
- 若是对象的equals方法被重写,那么对象的hashCode也尽可能重写,而且产生hashCode使用的对象,必定要和equals方法中使用的一致,不然就会违反上面提到的第2点;
- 两个对象的hashCode相同,并不必定表示两个对象就相同,也就是不必定适用于equals(java.lang.Object) 方法,只可以说明这两个对象在散列存储结构中.
这篇文章讲得挺详细的:Java中hashCode的做用
关于这个问题,《Effective Java》给咱们作的解答:
for-each可以让代码更加清晰,而且减小了出错的机会。 下面的惯用代码适用于集合与数组类型:
for (Element e : elements) { doSomething(e); } 复制代码
使用for-each循环与常规的for循环相比,并不存在性能损失,即便对数组进行迭代也是如此。实际上,在有些场合下它还能带来微小的性能提高,由于它只计算一次数组索引的上限。
7种:
能够看这篇文章:单例模式的七种写法
- NullPointerException 空指针异常
- ArithmeticException 出现异常的运算条件时,抛出此异常
- IndexOutOfBoundsException 数组索引越界异常
- ClassNotFoundException 找不到类异常
- IllegalArgumentException(非法参数异常)
复制代码
有可能哈~
hashCode 的常规协定:
JDK 中的 java.lang.Math 类:
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。
不能够。由于JDK处于安全性的考虑,基于双亲委派模型,优先加载JDK的String类,若是java.lang.String已经加载,便不会再次被加载。
- 在咱们的业务系统中判断对象时有时候须要的不是一种严格意义上的相等,而是一种业务上的对象相等。在这种状况下,原生的equals方法就不能知足咱们的需求了,因此这个时候咱们须要重写equals方法,来知足咱们的业务系统上的需求。
- 那么为何在重写equals方法的时候须要重写hashCode方法呢? 若是只重写了equals方法而没有重写hashCode方法的话,则会违反约定的第二条:相等的对象必须具备相等的散列码.因此hashCode和equals方法都须要重写
能够看网上这篇文章哈:java为何要重写hashCode和equals方法
Java 泛型(generics)是 JDK 5 中引入的一个新特性,其本质是参数化类型,解决不肯定具体对象类型的问题。
复制代码
这个面试题,能够看我这篇文章哈~Java程序员必备基础:泛型解析
能够看我这篇文章哈~ Java程序员必备:序列化全方位解析
匿名内部类就是没有名字的内部类,平常开发中使用的比较多。
public class Outer {
private void test(final int i) {
new Service() {
public void method() {
for (int j = 0; j < i; j++) {
System.out.println("匿名内部类" );
}
}
}.method();
}
}
//匿名内部类必须继承或实现一个已有的接口
interface Service{
void method();
}
复制代码
匿名内部类还有如下特色:
能够看我这篇文章哈~Java程序员必备基础:内部类解析
没有。由于 String 被设计成不可变(immutable)类,因此它的全部对象都是不可变对象。
1个而已啦。
Java 编译器对字符串常量直接相加的表达式进行优化,不等到运行期去进行加法运算,在编译时就去掉了加号,直接将其编译成一个这些常量相连的结果。因此 "a"+"b"+"c"+"d" 至关于直接定义一个 "abcd" 的字符串。
try-catch-finally-return 执行描述:
看一个例子
public static void main(String[] args) throws IOException {
System.out.println("result:" + test());
}
private static int test() {
int temp = 1;
try {
System.out.println("start execute try,temp is:"+temp);
return ++temp;
} catch (Exception e) {
System.out.println("start execute catch temp is: "+temp);
return ++temp;
} finally {
System.out.println("start execute finally,temp is:" + temp);
++temp;
}
}
复制代码
运行结果:
start execute try,temp is:1
start execute finally,temp is:2
result:2
复制代码
分析:
++temp
表达式,temp变为2,这个值被保存起来。++temp
表达式.try-with-resources,是Java7提供的一个新功能,它用于自动资源管理。
在try-with-resources
出现以前
try{
//open resources like File, Database connection, Sockets etc
} catch (FileNotFoundException e) {
// Exception handling like FileNotFoundException, IOException etc
}finally{
// close resources
}
复制代码
Java7,try-with-resources
出现以后,使用资源实现
try(// open resources here){
// use resources
} catch (FileNotFoundException e) {
// exception handling
}
// resources are closed as soon as try-catch block is executed.
复制代码
Java7使用资源demo
public class Java7TryResourceTest {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader(
"C:/jaywei.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
使用了try-with-resources
的好处
不能够。
一个或两个
- 第一次调用 new String("jay"); 时,会在堆内存中建立一个字符串对象,同时在字符串常量池中建立一个对象 "jay"
- 第二次调用 new String("jay"); 时,只会在堆内存中建立一个字符串对象,指向以前在字符串常量池中建立的 "jay"
能够看老王这篇文章,很清晰~ 别再问我 new 字符串建立了几个对象了!我来证实给你看!
this:
super:
能够,咱们能够作强制转换,可是在Java中,int是32位,byte是8位,若是强制作转化,int类型的高24位将会被丢弃。
public class Test {
public static void main(String[] args) {
int a =129;
byte b = (byte) a;
System.out.println(b);
int c =10;
byte d = (byte) c;
System.out.println(d);
}
}
输出:
-127
10
复制代码
不正确,精度不许确,应该用强制类型转换
均可以的
参考这篇文章~ 同步和异步的区别
java中使用BigDecimal来表示价格是比较好的。
能够看这篇文章,写得很是好 老大说:谁要再用double定义商品金额,就本身收拾东西走
int数据类型占4个字节 32位,跟JVM位数不要紧的