对象4:new String(“b”)
对象5:常量池中的"b"
深入剖析:StringBuilder中的toString():
对象6:new String(“ab”)
强调一下,toString()的调用,在字符串常量池中,没有生成"ab"
附加题:
String s1 = new String(“1”) + new String(“1”);//s1变量记录的地址为:new String
s1.intern();//在字符串常量池中生成"11"。如何理解:jdk6:创建了一个新的对象"11",也就有新的地址;jdk7:此时常量池中并没有创建"11",而是创建了一个指向堆空间中new String(“11”)的地址;
String s2 = “11”;
System.out.println(s1 == s2);//jdk6:false;jdk7:true
添加到StringBuilder中,然后调用reverse()。
equals、length、contains、replace、split、hashcode、indexof、substring、trim、toUpperCase、toLowerCase、isEmpty等等。
-
抽象类不能被实例化;
-
抽象类可以有抽象方法,只需申明,无须实现;
-
有抽象方法的类一定是抽象类;
-
抽象类的子类必须实现抽象类中的所有抽象方法,否则子类仍然是抽象类;
-
抽象方法不能声明为静态、不能被static、final修饰。
1、接口
-
接口使用interface修饰;
-
接口不能实例化;
-
类可以实现多个接口;
-
①java8之前,接口中的方法都是抽象方法,省略了public abstract。②java8之后;接口中可以定义静态方法,静态方法必须有方法体,普通方法没有方法体,需要被实现;
2、抽象类
-
抽象类使用abstract修饰;
-
抽象类不能被实例化;
-
抽象类只能单继承;
-
抽象类中可以包含抽象方法和非抽象方法,非抽象方法需要有方法体;
-
如果一个类继承了抽象类,①如果实现了所有的抽象方法,子类可以不是抽象类;②如果没有实现所有的抽象方法,子类仍然是抽象类。
1、按流划分,可以分为输入流和输出流;
2、按单位划分,可以分为字节流和字符流;
字节流:inputStream、outputStream;
字符流:reader、writer;
1、同步阻塞BIO
一个连接一个线程。
JDK1.4之前,建立网络连接的时候采用BIO模式,先在启动服务端socket,然后启动客户端socket,对服务端通信,客户端发送请求后,先判断服务端是否有线程响应,如果没有则会一直等待或者遭到拒绝请求,如果有的话会等待请求结束后才继续执行。
2、同步非阻塞NIO
NIO主要是想解决BIO的大并发问题,BIO是每一个请求分配一个线程,当请求过多时,每个线程占用一定的内存空间,服务器瘫痪了。
JDK1.4开始支持NIO,适用于连接数目多且连接比较短的架构,比如聊天服务器,并发局限于应用中。
一个请求一个线程。
3、异步非阻塞AIO
一个有效请求一个线程。
JDK1.7开始支持AIO,适用于连接数目多且连接比较长的结构,比如相册服务器,充分调用OS参与并发操作。
-
exist
-
createFile
-
createDirectory
-
write
-
read
-
copy
-
size
-
delete
-
move
所谓反射,是java在运行时进行自我观察的能力,通过class、constructor、field、method四个方法获取一个类的各个组成部分。
在Java运行时环境中,对任意一个类,可以知道类有哪些属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于反射机制。
序列化就是一种用来处理对象流的机制。将对象的内容流化,将流化后的对象传输于网络之间。
序列化是通过实现serializable接口,该接口没有需要实现的方法,implement Serializable只是为了标注该对象是可被序列化的,使用一个输出流(FileOutputStream)来构造一个ObjectOutputStream对象,接着使用ObjectOutputStream对象的writeObejct(Object object)方法就可以将参数的obj对象到磁盘,需要恢复的时候使用输入流。
序列化是将对象转换为容易传输的格式的过程。
例如,可以序列化一个对象,然后通过HTTP通过Internet在客户端和服务器之间传输该对象。在另一端,反序列化将从流中心构造成对象。
一般程序在运行时,产生对象,这些对象随着程序的停止而消失,但我们想将某些对象保存下来,这时,我们就可以通过序列化将对象保存在磁盘,需要使用的时候通过反序列化获取到。
对象序列化的最主要目的就是传递和保存对象,保存对象的完整性和可传递性。
譬如通过网络传输或者把一个对象保存成本地一个文件的时候,需要使用序列化。
十九、为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?
1、什么要使用克隆?
想对一个对象进行复制,又想保留原有的对象进行接下来的操作,这个时候就需要克隆了。
2、如何实现对象克隆?
-
实现Cloneable接口,重写clone方法;
-
实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。
-
BeanUtils,apache和Spring都提供了bean工具,只是这都是浅克隆。
3、深拷贝和浅拷贝区别是什么?
-
浅拷贝:仅仅克隆基本类型变量,不克隆引用类型变量;
-
深克隆:既克隆基本类型变量,又克隆引用类型变量;
4、代码实例
二十、throw 和 throws 的区别?
1、throw
-
作用在方法内,表示抛出具体异常,由方法体内的语句处理;
-
一定抛出了异常;
2、throws
-
作用在方法的声明上,表示抛出异常,由调用者来进行异常处理;
-
可能出现异常,不一定会发生异常;
二十一、final、finally、finalize 有什么区别?
final可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
finally用于抛异常,finally代码块内语句无论是否发生异常,都会在执行finally,常用于一些流的关闭。
finalize方法用于垃圾回收。
一般情况下不需要我们实现finalize,当对象被回收的时候需要释放一些资源,比如socket链接,在对象初始化时创建,整个生命周期内有效,那么需要实现finalize方法,关闭这个链接。
但是当调用finalize方法后,并不意味着gc会立即回收该对象,所以有可能真正调用的时候,对象又不需要回收了,然后到了真正要回收的时候,因为之前调用过一次,这次又不会调用了,产生问题。所以,不推荐使用finalize方法。
二十二、try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
-
NullPointerException:空指针异常;
-
SQLException:数据库相关的异常;
-
IndexOutOfBoundsException:数组下角标越界异常;
-
FileNotFoundException:打开文件失败时抛出;
-
IOException:当发生某种IO异常时抛出;
-
ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出此异常;
-
NoSuchMethodException:无法找到某一方法时,抛出;
-
ArrayStoreException:试图将错误类型的对象存储到一个对象数组时抛出的异常;
-
NumberFormatException:当试图将字符串转换成数字时,失败了,抛出;
-
IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
-
ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
Java中Object有一个方法:
public native int hashcode();
1、hashcode()方法的作用
hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。
当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值,实际上hashmap中会有一个table保存已经存进去的对象的hashcode值,如果table中没有改hashcode值,则直接存入,如果有,就调用equals方法与新元素进行比较,相同就不存了,不同就存入。
2、equals和hashcode的关系
如果equals为true,hashcode一定相等;
如果equals为false,hashcode不一定不相等;
如果hashcode值相等,equals不一定相等;
如果hashcode值不等,equals一定不等;
3、重写equals方法时,一定要重写hashcode方法
4、百度百科
hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0 1 2 3 4 5 6 7
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除 8求余数直接找到存放的位置了。
2.但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。
也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊。
二十五、java 中操作字符串都有哪些类?它们之间有什么区别?
1、String
String是不可变对象,每次对String类型的改变时都会生成一个新的对象。
2、StringBuilder
线程不安全,效率高,多用于单线程。
3、StringBuffer
线程安全,由于加锁的原因,效率不如StringBuilder,多用于多线程。
不频繁的字符串操作使用String,操作频繁的情况不建议使用String。
StringBuilder > StringBuffer > String。
1、强引用
Java中默认声明的就是强引用,比如:
Object obj = new Object();
obj = null;
只要强引用存在,垃圾回收器将永远不会回收被引用的对象。如果想被回收,可以将对象置为null;
2、软引用(SoftReference)
在内存足够的时候,软引用不会被回收,只有在内存不足时,系统才会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会跑出内存溢出异常。
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
3、弱引用(WeakReference)
进行垃圾回收时,弱引用就会被回收。
4、虚引用(PhantomReference)
5、引用队列(ReferenceQueue)
引用队列可以与软引用、弱引用、虚引用一起配合使用。
当垃圾回收器准备回收一个对象时,如果发现它还有引用,就会在回收对象之前,把这个引用加入到引用队列中。
程序可以通过判断引用队列中是否加入了引用,来判断被引用的对象是否将要被垃圾回收,这样可以在对象被回收之前采取一些必要的措施。
二十七、在 Java 中,为什么不允许从静态方法中访问非静态变量?
-
静态变量属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;
-
非静态变量属于类的对象,只有在类的对象产生时,才会分配内存,通过类的实例去访问;
-
静态方法也属于类本身,但是此时没有类的实例,内存中没有非静态变量,所以无法调用。
二十八、说说Java Bean的命名规范
-
JavaBean 类必须是一个公共类,并将其访问属性设置为 public
-
JavaBean 类必须有一个空的构造函数:类中必须有一个不带参数的公用构造器,此构造器也应该通过调用各个特性的设置方法来设置特性的缺省值。
-
一个javaBean类不应有公共实例变量,类变量都为private
-
持有值应该通过一组存取方法(getXxx 和 setXxx)来访问:对于每个特性,应该有一个带匹配公用 getter 和 setter 方法的专用实例变量。
属性为布尔类型,可以使用 isXxx() 方法代替 getXxx() 方法。
通常属性名是要和 包名、类名、方法名、字段名、常量名作出区别的:
首先:必须用英文,不要用汉语拼音
1、包(package)
用于将完成不同功能的类分门别类,放在不同的目录(包)下,包的命名规则:将公司域名反转作为包名。比如www.sohu.com 对于包名:每个字母都需要小写。比如:com.sohu.test;该包下的Test类的全名是:com.sohu.Test.Java 。
如果定义类的时候没有使用package,那么java就认为我们所定义的类位于默认包里面(default package)。
2、类
首字母大写,如果一个类由多个单词构成,那么每个单词的首字母都大写,而且中间不使用任何的连接符。尽量使用英文。如ConnectionFactory
3、方法
首单词全部小写,如果一个方法由多个单词构成,那么从第二个单词开始首字母大写,不使用连接符。addPerson
4、字段
与方法相同。如ageOfPerson
5、常量
所有单词的字母都是大写,如果有多个单词,那么使用下划线链接即可。
如:public static final int AGE_OF_PERSON = 20; //通常加上static
public class User {
private String busName;
private String pCount;
private Boolean isRunning;
//正确的命名方式,驼峰式的
public String getBusName() {
return busName;
}
public void setBusName(String busName) {
this.busName = busName;
}
//这是什么?
public String getpCount() {
return pCount;
}
public void setpCount(String pCount) {
this.pCount = pCount;
}
//这个也是不允许的
public Boolean getIsRunning() {
return isRunning;
}
public void setIsRunning(Boolean isRunning) {
this.isRunning = isRunning;
}
}
面试题总结
其它面试题(springboot、mybatis、并发、java中高级面试总结等)
;
private String pCount;
private Boolean isRunning;
//正确的命名方式,驼峰式的
public String getBusName() {
return busName;
}
public void setBusName(String busName) {
this.busName = busName;
}
//这是什么?
public String getpCount() {
return pCount;
}
public void setpCount(String pCount) {
this.pCount = pCount;
}
//这个也是不允许的
public Boolean getIsRunning() {
return isRunning;
}
public void setIsRunning(Boolean isRunning) {
this.isRunning = isRunning;
}
}
# 面试题总结
**[面试文件获取方式:戳这里免费下载(助你面试无忧)](https://gitee.com/vip204888/java-p7)**
**其它面试题(springboot、mybatis、并发、java中高级面试总结等)**
[外链图片转存中...(img-idCClk94-1628597725840)]
[外链图片转存中...(img-AxaYSij8-1628597725844)]
![](https://img-blog.csdnimg.cn/img_convert/d09ae5323a84f40a877829a51f460943.png)