以下问题都是在百度找的常见的面试题目。解答是根据自己的知识和百度搜索资料写的。
一、Java 基础
1.JDK 和 JRE 有什么区别?
JDK包括JRE、java基础工具(java、javac、jdb等)和java基础类库。JRE是运行环境包括JVM、Java核心类库。
2.== 和 equals 的区别是什么?
1、==是操作符,equals是方法。 2、equals用来比较两个对象内容是否相等,而==用来比较两个对象指针是否相等。经典举例就是字符串问题。以下就是字符串对比的源码: public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }如果指针指的是同一个对象就直接返回true,如果对象不一样而且anObject是String的实例取得两个对象的字符数组一个一个对比。 == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况(前面第1部分已详细介绍过): 情况1,类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。 情况2,类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
hashCode()在Obejct中的实现是: 1、随机值 2、1(用于敏感度测试) 3、看不懂 4、取内存地址 具体要看JVM的设计。 hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。在散列表中, 1、如果两个对象相等,那么它们的hashCode()值一定要相同; 2、如果两个对象hashCode()相等,它们并不一定相等。注意:这是在散列表中的情况。在非散列表中一定如此!
1 public int hashCode() { 2 int h = hash; 3 if (h == 0 && value.length > 0) { 4 char val[] = value; 5 for (int i = 0; i < value.length; i++) { 6 h = 31 * h + val[i]; 7 } 8 hash = h; 9 }10 return h;11 }
String类的hashCode是这么实现的:长度为0就返回0(或者是之前的哈希值?),
总而言之,就是一切取决于hashCode和equals怎么重写的,如果hashCode和equals都没有重写,就按上面的来。
4.final 在 java 中有什么作用?
1、final成员变量表示常量,如果final指针,那么指针地址不可以改变,但是指针指向的对象可以改变2、final类不能继承3、final方法不能重写,但是可以继承3、final不能修饰构造函数注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。byte b1=1;byte b2=3;byte b3=b1+b2;以上最后一行直接报错,因为byte相加会直接转换成int,int赋值给byte会发生截断,会报错。final byte b1=1;final byte b2=3;byte b3=b1+b2;以上可以通过编译,因为一切都是确定的,所以编译期间就确定了变量值且不改变。final byte b1=6;final byte b2=125;byte b3=b1+b2;以上最后一行直接报错,因为byte相加会溢出,编译截断报错。
5.java 中的 Math.round(-1.5) 等于多少?
Math.round()的原理是对传入的参数+0.5之后,再向下取整得到的数就是返回的结果,返回值为long型。这里的向下取整是说取比它小的第一个整数或者和它相等的整数。-1.5+0.5=-1向下取整为-1,。向下取整:Math.floor();向上取整:Math.ceil();
6.String 属于基础的数据类型吗?
很明显不是,很简单判断方法,大写开头是类,小写开头是基本数据类型。String是final修饰的java类,java中的基本类型一共有8个,它们分别为:1、字符类型:byte,char2、基本整型:short,int,long3、浮点型:float,double4、布尔类型:boolean
7.java 中操作字符串都有哪些类?它们之间有什么区别?
String、StringBuffer和StringBuilder1、首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String String最慢的原因: String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例: String str="abc"; System.out.println(str); str=str+"de"; System.out.println(str);如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。另外,有时候我们会这样对字符串进行赋值: String str="abc"+"de"; StringBuilder stringBuilder=new StringBuilder().append("abc").append("de"); System.out.println(str); System.out.println(stringBuilder.toString());这样输出结果也是“abcde”和“abcde”,但是String的速度却比StringBuilder的反应速度要快很多,这是因为第1行中的操作和 String str="abcde"; 是完全一样的,所以会很快,而如果写成下面这种形式 String str1="abc"; String str2="de"; String str=str1+str2;那么JVM就会像上面说的那样,不断的创建、回收对象来进行这个操作了。速度就会很慢。2. 再来说线程安全在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。3. 总结一下String:适用于少量的字符串操作的情况StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
8.String str="i"与 String str=new String("i")一样吗?
1.当使用String str="abc",这种方式时,先去内存的Heap中找是否存在"abc"这个字符串,若存在,则将地址引用。若不存在则创建。2.当使用String str=new String("abc");时,不管事先是否存在"abc",每次都会创建其新的对象。测试一下:String s1="abc";String s2="abc";String s3=new String("abc");String s4=new String("abc");System.out.println(s1 == s2);System.out.println(s2 == s3);System.out.println(s1 == s3);System.out.println(s4 == s3);打印的结果为:truefalsefalsefalse这就很明显了。
9.如何将字符串反转?
两种好理解简单的方法:1、直接用StringBuffer自带的方法public static String reverse1(String s) { return new StringBuffer(s).reverse().toString(); }2、 把字符串转换成字符数组首位对调位置public static String reverse5(String orig) { char[] s = orig.toCharArray(); int n = s.length - 1; int halfLength = n / 2; for (int i = 0; i <= halfLength; i++) { char temp = s[i]; s[i] = s[n - i]; s[n - i] = temp; } return new String(s); }
10.String 类的常用方法都有那些?
char charAt(int index);//返回指定索引处的 char 值。int compareTo(String anotherString) ;//按字典顺序比较两个字符串。String concat(String str) ;将指定字符串连接到此字符串的结尾。boolean contains(CharSequence s);当且仅当此字符串包含指定的 char 值序列时,返回 true。boolean endsWith(String suffix) ;//测试此字符串是否以指定的后缀结束。boolean equals(Object anObject) ;//将此字符串与指定的对象比较。byte[] getBytes();//使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。int indexOf(int ch);//返回指定字符在此字符串中第一次出现处的索引。int lastIndexOf(int ch) ;//返回指定字符在此字符串中最后一次出现处的索引。int length();//返回此字符串的长度。 String[] split(String regex);//根据给定正则表达式的匹配拆分此字符串。boolean startsWith(String prefix);//测试此字符串是否以指定的前缀开始。char[] toCharArray();//将此字符串转换为一个新的字符数组。String toUpperCase();//使用默认语言环境的规则将此 String 中的所有字符都转换为大写。String trim();//返回字符串的副本,忽略前导空白和尾部空白。String toLowerCase(Locale locale);//使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
11.抽象类必须要有抽象方法吗?
抽象类可以不包含抽象方法,包含抽象方法的类一定是抽象类。
12.普通类和抽象类有哪些区别?
1、抽象类不能被实例化。2、抽象类可以有构造函数,被继承时子类必须继承父类一个构造方法,抽象方法不能被声明为静态。3、抽象方法只需申明,而无需实现,抽象类中可以允许普通方法有主体4、含有抽象方法的类必须申明为抽象类5、抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类。
13.抽象类能使用 final 修饰吗?
java类一旦被声明为abstract(抽象类),必须要继承或者匿名(其实匿名也是种继承)才能使用。而final则是让该类无法被继承,所以final是必然不能和abstract同时声明的但是private呢?一个类被声明为private的时候,它当然是内部类,内部类是可以被它的外部类访问到的,所以,可以继承,private和abstract不冲突。
14.接口和抽象类有什么区别?
抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。
参数 | 抽象类 | 接口 |
默认的方法实现 | 它可以有默认的方法实现 | 接口完全是抽象的。它根本不存在方法的实现 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的抽象方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
与正常Java类的区别 | 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。你不可以使用其它修饰符。 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 接口没有main方法,因此我们不能运行它。 |
多继承 | 抽象方法可以继承一个类和实现多个接口 | 接口只可以继承一个或多个其它接口 |
速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | 如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
15.java 中 IO 流分为几种?
Java中的流,可以从不同的角度进行分类。按照数据流的方向不同可以分为:输入流和输出流。按照处理数据单位不同可以分为:字节流和字符流。按照实现功能不同可以分为:节点流和处理流。输出流:
输入流:
因此输入和输出都是从程序的角度来说的。字节流:一次读入或读出是8位二进制。字符流:一次读入或读出是16位二进制。字节流和字符流的原理是相同的,只不过处理的单位不同而已。后缀是Stream是字节流,而后缀是Reader,Writer是字符流。节点流:直接与数据源相连,读入或读出。
直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。处理流:与节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。
Jdk提供的流继承了四大类:InputStream(字节输入流),OutputStream(字节输出流),Reader(字符输入流),Writer(字符输出流)。以下是java中io中常用的流。
字节输入流:
字节输出流:
字符输入流:
字符输出流:
对文件进行操作:FileInputStream(字节输入流),FileOutputStream(字节输出流),FileReader(字符输入流),FileWriter(字符输出流)对管道进行操作:PipedInputStream(字节输入流),PipedOutStream(字节输出流),PipedReader(字符输入流),PipedWriter(字符输出流)PipedInputStream的一个实例要和PipedOutputStream的一个实例共同使用,共同完成管道的读取写入操作。主要用于线程操作。字节/字符数组:ByteArrayInputStream,ByteArrayOutputStream,CharArrayReader,CharArrayWriter是在内存中开辟了一个字节或字符数组。Buffered缓冲流::BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter,是带缓冲区的处理流,缓冲区的作用的主要目的是:避免每次和硬盘打交道,提高数据访问的效率。转化流:InputStreamReader/OutputStreamWriter,把字节转化成字符。数据流:DataInputStream,DataOutputStream。因为平时若是我们输出一个8个字节的long类型或4个字节的float类型,那怎么办呢?可以一个字节一个字节输出,也可以把转换成字符串输出,但是这样转换费时间,若是直接输出该多好啊,因此这个数据流就解决了我们输出数据类型的困难。数据流可以直接输出float类型或long类型,提高了数据读写的效率。打印流:printStream,printWriter,一般是打印到控制台,可以进行控制打印的地方。对象流:ObjectInputStream,ObjectOutputStream,把封装的对象直接输出,而不是一个个在转换成字符串再输出。序列化流:SequenceInputStream。对象序列化:把对象直接转换成二进制,写入介质中。使用对象流需要实现Serializable接口,否则会报错。而若用transient关键字修饰成员变量,不写入该成员变量,若是引用类型的成员变量为null,值类型的成员变量为0.
后面的过几天再写,刚开学就很忙了。。。。
16.BIO、NIO、AIO 有什么区别?
17.Files的常用方法都有哪些?
二、容器
18.java 容器都有哪些?
19.Collection 和 Collections 有什么区别?
20.List、Set、Map 之间的区别是什么?
21.HashMap 和 Hashtable 有什么区别?
22.如何决定使用 HashMap 还是 TreeMap?
23.说一下 HashMap 的实现原理?
24.说一下 HashSet 的实现原理?
25.ArrayList 和 LinkedList 的区别是什么?
26.如何实现数组和 List 之间的转换?
27.ArrayList 和 Vector 的区别是什么?
28.Array 和 ArrayList 有何区别?
29.在 Queue 中 poll()和 remove()有什么区别?
30.哪些集合类是线程安全的?
31.迭代器 Iterator 是什么?
32.Iterator 怎么使用?有什么特点?
33.Iterator 和 ListIterator 有什么区别?
34.怎么确保一个集合不能被修改?
三、多线程
35.并行和并发有什么区别?
36.线程和进程的区别?
37.守护线程是什么?
38.创建线程有哪几种方式?
39.说一下 runnable 和 callable 有什么区别?
40.线程有哪些状态?
41.sleep() 和 wait() 有什么区别?
42.notify()和 notifyAll()有什么区别?
43.线程的 run()和 start()有什么区别?
44.创建线程池有哪几种方式?
45.线程池都有哪些状态?
46.线程池中 submit()和 execute()方法有什么区别?
47.在 java 程序中怎么保证多线程的运行安全?
48.多线程锁的升级原理是什么?
49.什么是死锁?
50.怎么防止死锁?
51.ThreadLocal 是什么?有哪些使用场景?
52.说一下 synchronized 底层实现原理?
53.synchronized 和 volatile 的区别是什么?
54.synchronized 和 Lock 有什么区别?
55.synchronized 和 ReentrantLock 区别是什么?
56.说一下 atomic 的原理?
四、反射
57.什么是反射?
58.什么是 java 序列化?什么情况下需要序列化?
59.动态代理是什么?有哪些应用?
60.怎么实现动态代理?
五、对象拷贝
61.为什么要使用克隆?
62.如何实现对象克隆?
63.深拷贝和浅拷贝区别是什么?