一. java基础
1. JVM,用户自己写一个String类,会发生什么?
假设用户自己写了一个String类,就会加载不进内存。
原因:
基于JVM的双亲委派机制,类加载器收到了加载类的请求,会把这个请求委派给他的父类加载器。
而只有父类加载器自己无法完成加载请求时,子类才会自己加载。
这样用户自定义的String类的加载请求就会最终达到顶层的BootStrap ClassLoader启动类加载器,
启动类加载器加载的是系统中的String对象,而用户编写的java.lang.String不会被加载。
2.sleep()和wait()的区别
区别1:使用限制
使用 sleep 方法可以让让当前线程休眠,时间一到当前线程继续往下执行,在任何地方都能使用,但需要捕获 InterruptedException 异常。
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
而使用 wait 方法则必须放在 synchronized 块里面,同样需要捕获 InterruptedException 异常,并且需要获取对象的锁。
synchronized (lock){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
而且 wait 还需要额外的方法 notify/ notifyAll 进行唤醒,它们同样需要放在 synchronized 块里面,且获取对象的锁。
synchronized (lock) {
// 随机唤醒
lock.notify();
// 唤醒全部
lock.notifyAll();
}
当然也可以使用带时间的 wait(long millis) 方法,时间一到,无需其他线程唤醒,也会重新竞争获取对象的锁继续执行。
区别2:使用场景
sleep 一般用于当前线程休眠,或者轮循暂停操作,wait 则多用于多线程之间的通信。
区别3:所属类
sleep 是 Thread 类的静态本地方法,wait 则是 Object 类的本地方法。
java.lang.Thread#sleep
public static native void sleep(long millis) throws InterruptedException;
java.lang.Object#wait
public final native void wait(long timeout) throws InterruptedException;
为什么要这样设计呢?
因为 sleep 是让当前线程休眠,不涉及到对象类,也不需要获得对象的锁,所以是线程类的方法。wait 是让获得对象锁的线程实现等待,前提是要获得对象的锁,所以是类的方法。
区别4:释放锁
Object lock = new Object();
synchronized (lock) {
try {
lock.wait(3000L);
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
如上代码所示,wait 可以释放当前线程对 lock 对象锁的持有,而 sleep 则不会。
区别5:线程切换
sleep 会让出 CPU 执行时间且强制上下文切换,而 wait 则不一定,wait 后可能还是有机会重新竞争到锁继续执行的。
3.object类有哪些方法
Object类,属于java.lang包,位于类层次结构树的顶部。每个类都是Object类的直接或间接的后代。使用或编写的每个类都继承Object的实例方法。Object类总共13个方法。
3.1 clone方法
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里将参数改变,这是就需要在类中复写clone方法。
3.2 getClass方法
final方法,获得运行时类型。
3.3 toString方法
该方法用得比较多,一般子类都有覆盖。
3.4 finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
3.5 equals方法
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
3.6 hashCode方法
该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
如果不重写hashcode(),在HashSet中添加两个equals的对象,会将两个对象都加入进去。
3.7 wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
3.8 notify方法
该方法唤醒在该对象上等待的某个线程。
3.9 notifyAll方法
该方法唤醒在该对象上等待的所有线程。
Object的notify、notifyAll和wait方法都在同步程序中独立运行线程的活动中起着作用
3.10 finalize 方法
Java允许在类中定义一个名为finalize()的方法。它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
关于垃圾回收,有三点需要记住:
1、对象可能不被垃圾回收。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。
2、垃圾回收并不等于“析构”。
3、垃圾回收只与内存有关。使用垃圾回收的唯一原因是为了回收程序不再使用的内存。
finalize()的用途:
无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。
为什么不能显示直接调用finalize方法?
如前文所述,finalize方法在垃圾回收时一定会被执行,而如果在此之前显示执行的话,也就是说finalize会被执行两次以上,而在第一次资源已经被释放,那么在第二次释放资源时系统一定会报错,因此一般finalize方法的访问权限和父类保持一致,为protected。
4.讲一下equals()与hashcode(),什么时候重写,为什么重写,怎么重写?
如果你需要要在 HashMap 的“键”部分存放自定义的对象,一定要重写 equals 和 hashCode 方法。
总结下就是自定义对象作为key时要重写hashcode和equals方法,因为要比较两个对象,是先比较hashcode,再比较equals方法,从object继承的hashcode和equals方法都是比较的内存地址,由于自定义的两个对象,内存地址肯定不一致,但是我们可能创建的入参是一样的,所以我们希望它们是相等的。
hashCode()与equals()相关规定
1.如果两个对象相等,则hashcode必须相等。
2.如果两个对象相等,对其中的一个对象调用equals()必须返回true,也就是说a .equals(b),则 b.equals(a).
3.如果两个对象有相同的hashCode值,他们也不一定相等。但若两个对象相等,则hashcode值一定相等。
4.因此若equals()被覆盖过,则hashcode()也必须被覆盖。
5.hashCode()的默认行为实在对heap上的对象产生独特的值。如果没有override过hashCode(),则该class的两个对象怎么都不会被认为是相同的。
6.equals()的默认行为是执行==的比较。也就是说会去测试两个引用是否对上heap上同一个对象。如果equals()没有被覆盖过,两个对象永远都不会被视为相同的。因此不同的对象有不同的字节组合。
a.equals(b)必须与a.hashCode()==b.hashCode()等值。
但a.hashCode()==b.hashCode不一定要与a.equals()等值。
5.java多态,如何实现?动态绑定
多态,顾名思义,表示一个对象具有多种的状态,具体表现为父类的引用指向子类的实例。
多态的特点:
1.对象类型和引用类型之间具有继承(类)/实现(接口)的关系;
2.引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
3.多态不能调用“只在子类存在但在父类不存在”的方法;
4.如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。
https://blog.csdn.net/guanshengg/article/details/126380197?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-126380197-blog-52191321.pc_relevant_aa_2&spm=1001.2101.3001.4242.1&utm_relevant_index=3
6. java如何保证多线程安全
https://blog.csdn.net/qq_46546793/article/details/120195232?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-3-120195232-blog-90018414.pc_relevant_multi_platform_whitelistv4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-3-120195232-blog-90018414.pc_relevant_multi_platform_whitelistv4&utm_relevant_index=4
7.I/O多路复用讲一下,epoll优势在哪里,为什么,epoll水平与边缘触发
https://blog.csdn.net/qq_35423154/article/details/107709322
8. == 和equals的区别?
8.1 对象类型不同
1、equals():是超类Object中的方法。
2、==:是操作符。
8.2 比较的对象不同
1、equals():用来检测两个对象是否相等,即两个对象的内容是否相等。
2、==:用于比较引用和比较基本数据类型时具有不同的功能,具体如下:
(1)、基础数据类型:比较的是他们的值是否相等,比如两个int类型的变量,比较的是变量的值是否一样。
(2)、引用数据类型:比较的是引用的地址是否相同,比如说新建了两个User对象,比较的是两个User的地址是否一样。
8.3 运行速度不同
1、equals():没有运行速度快。
2、:运行速度比equals()快,因为只是比较引用。