目录
9.Forward(转发) 和 Redirect(重定向)的区别?
12.notify(), notifyAll()和wait()
16.ThreadLocal和HashMap解决哈希冲突的方法
1.重载与重写的区别
重载发生在同一个类当中,可以声明多个同名方法,通过参数列表(参数类型,参数个数以及参数的顺序)进行区分。重写发生在具有继承关系的父子类中,子类可以重写父类非私有的方法实现特有的功能,要求重写的方法与父类方法方法名,参数列表保持一致,返回值和抛出异常的范围不能大于父类,访问权限不能小于父类
两同两小一大原则:
方法名相同,参数相同
子类返回类型小于等于父类; 抛出异常范围小于等于父类;
子类访问权限大于等于分类访问权限
2.equals和==的区别
对于 == 来说,如果比较的是基本数据类型,则直接比较等号两边的值是否相等;如果比较的是引用对象,比较等号两边对象的地址是否相同;
对于equals来说,如果没有对equals进行重写,那么和 == 等价,对于引用对象来说仍比较的是对象的地址;
3.代码块分类,定义位置,特点
java中代码块分为 局部代码块,构造代码块,静态代码块和同步代码块
1.局部代码块:定义在方法中,就是方法体,用于限定变量的生命周期,方便尽早释放局部变量,提高内存利用率
public void test() {
int num = 10;
}
2.构造代码块:定义在类中方法外,每次构造方法执行时,都会执行该代码块中的方法,并且在构造方法之前执行;每一次创建对象前执行一次
可以将多个构造函数中的公共部分抽取出来,减少代码量的书写,提高代码的复用性
{
// 构造方法的公共部分
System.out.println("我是构造代码块")
}
3.静态代码块:定义在类中方法外,通过static进行修饰,随着类加载而加载,并且执行一次;用于类加载的时候做一些初始化操作
static {
System.out.println("我是静态代码块")
}
执行顺序: 静态代码块 》 构造代码块 》 局部代码块
4.同步代码块:用于线程同步问题,使用synchronized(object)进行修饰,参数为一个公共对象,只有获取访问权的时候才可以执行方法体中的代码,实现多线程同步;尾货得访问权的线程进入阻塞状态
4.ArrayList和LinkedList的区别
ArrayList和LinkedList都实现了List接口。ArrayList底层使用数组实现,在尾部插入以及查询的效率较高;LinkedList使用双向链表实现,插入和删除的效率较高,查询效率低。
5.final有什么作用
final修饰的类不能被继承,被修饰的方法不能被重写, 但可以重载;final修饰的局部变量属性值不能被更改;被修饰的引用类型变量其引用不能被修改,但是可以修改对象的属性值;final修饰成员变量一般与static一起使用,修饰常量。
5.1 为什么局部内部类和匿名内部类只能访问局部final变量
匿名内部类:
// 为什么局部内部类和匿名内部类只能访问局部final变量
public class Test01 {
public static void main(String[] args) {
test(1);
}
public static void test(int b) {
int a = 10;
new Thread() {
@Override
public void run() {
b += 10; // 编译错误
System.out.println(b);
System.out.println(a);
}
}.start();
}
}
局部内部类:
public class Test02 {
public static void main(String[] args) {
new Test02().outPrint(1);
}
private int age = 12;
public void outPrint(int x) {
class InClass {
public void InPrint() {
x += 10; // 编译错误
System.out.println(x);
System.out.println(age);
}
}
new InClass().InPrint();
}
}
在编写程序后发现,内部类中可以访问输出成员变量和外部类中的局部变量;但是不能再内部类中对其进行修改,因此为了避免这种情况,直接妥协需要final修饰,明确不能修改这些变量
原因:
在进行编译后,外部类以及内部类都会生成.class文件;内部类和外部类属于同一级别,因此尽管外部类结束也不会导致内部类的销毁;这就导致了当外部类结束的时候(局部变量销毁)内部类却使用着外部类的局部变量,所以为了解决这个问题将外部类的局部变量复制一份到内部类中。
然而内部类消费局部变量的时候,应该保证副本和外部类内容地址相同,但很明显不能达到,所以直接要求不准内部类修改局部变量,使用final修饰
6.String和StringBuffer,StringBuilder的区别
String和StringBuffer操作的对象都是字符串,对于String来说字符串值是不可变的,在进行字符串拼接的操作时产生新的字符串,新产生的字符串会被放入字符串常量池,效率低;
StringBuffer使用new()方法实例化对象,它的字符串值是可变的,可以使用append添加新的字符。StringBuffer底层使用数组实现,使用append()方法操作的就是这个字符数组,所以每次添加不会产生新的字符串。
StringBuffer是线程安全的,StringBuilder是非线程安全的。StringBuffer的方法都是Synchronized修饰的
性能:StringBuilder > StringBuffer > String
优先使用StringBuilder,因为他的性能最优;但是在多线程环境共享变量的情况下需要使用StringBuffer
7.类和对象的区别
类:是一个抽象的概念,是具有某些公共特性的实体的集合
对象:是类的实例化,每个对象具有独立的属性。java中类的实例使用new创建
8.java中如何实现序列化,有什么意义?
序列化是一种用来处理对象流的机制。使用对象流(ObjecctInputStream和ObjectOutputStream)可以将数据在网络上进行传输。使用对象流的类需要实现Serializable接口,该接口是标识性接口,没有方法需要实现,标志一个类需要被序列化。实现序列化接口的类,JVM会给这个类添加一个属性:static final long serialVersion(序列化版本号),进行标识。对于一个添加了Serializable的类,最好手动添加一个serialVersion,不让系统自动生成;避免发生.class发生变化时导致反序列化错误。
9.Forward(转发) 和 Redirect(重定向)的区别?
转发和重定向都是用于请求跳转操作。
转发属于服务端行为,请求到达服务器,由服务器内部完成请求处理和转发操作,然后将相应资源返回给客户端。整个过程中发送一次请求(request)一次响应(response), request和response对象由服务器进行转发,被没有发生改变,其中的attribute没有发生改变,可以携带请求的数据。
重定向是一个客户端行为,用户请求到达服务器之后,服务器返回响应,HTTP状态码置为302,并将转发的页面保存在响应头中的Location属性中,告诉客户端应该向这个地址发出请求,然后客户端再次发出请求。在整个过程中客户端发送了最少两次请求,因为请求是不同的,因此request和response对象在重定向前后是不同的,两个对象中的attribute在重定向前后也都是不同的。
二者的直接体现:转发url不发生改变;重定向url发生改变
10.ArrayList底层扩容机制
ArrayList底层使用数组实现,实现List接口
初始化的时候数组长度为10,如果传递参数,数组大小就是传递的参数值
当数组容量不足,发生扩容,扩容到原来的1.5倍
11.Cookie原理
Cookie是一种会话跟踪技术;与http的无状态请求不同,cookie的目的是为了追踪多条请求之间的数据传递。cookie是由服务器生成,保存在客户端的一种载体。
用户提交第一次请求后,由服务器生成cookie并将其封装在响应头中,以响应的形式发送给客户端。客户端接收这个响应后,将cookie保存在客户端。当客户端再次发送同类请求(资源路径相同的请求),在请求中会携带保存在客户端的cookie发送到服务端,由服务端对会话进行跟踪
12.notify(), notifyAll()和wait()
这三个方法仅在 synchronized 方法中才能被调用。
wait()方法告知被调用的线程释放锁并进入等待状态,直到其他线程进入相同的监视器并调用 notify( ) 方法。
notify( ) 方法通知同一对象上某一个调用 wait( )线程。(随机)
notifyAll() 方法通知调用 wait() 的所有线程,竞争胜利的线程将先运行。
牛客上的一道题:
哪种情况会导致线程中断或停止运行?
1. InterruptedException异常被捕获:
java一般通过interrupt方法中断线程,这个方法的原理就是抛出异常
2.线程调用wait()方法
线程使用wait方法,会强行打断当前操作,进入阻塞状态,释放当前锁,等待notify或notifyAll方法才能进入就绪状态
13.内部类相关
对于局部内部类,只有在方法的局部变量被标记为final或局部变量是effctively final的时候,内部类才可以使用
成员内部类位于外部类内部,可以直接调用外部类的所有方法(静态或者非静态)
14.java中的ceil()和floor()
ceil()是向上取整, floor()是向下取整。
方法说明中:如果参数是NaN, 无穷, 正0, 负0那么结果与参数相同;即如果参数是-0.0,结果也是-0.0
15.访问修饰符
protected:可以被该类本身,与他在同一包中的其他类、在其他包中的该类的子类访问
16.ThreadLocal和HashMap解决哈希冲突的方法
java8中,ThreadLocal使用开放地址法;HashMap使用拉链法
ThreadLocal采用哈希表的方式为每个线程提供一个变量的副本,保证各个线程之间的数据安全。每个线程的数据不会被其他线程访问;
ThreadLocal的主要作用就是数据的独立;并不继承Thread类也不实现Runable接口
使用ThreadLocal维护变量的时候,ThreadLocal为每个该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的副本,而不影响其他线程中的副本
注:牛客刷题时候根据评论总结的评论,有重复
17. sleep(), wait(), join(), yield()的区别
1. 锁池
所有竞争同步锁的线程会进入锁池;如当前共享对象被一个线程已经获取到锁,其他线程会进入锁池进行等待直到共享对象的锁被释放。释放后,锁池中的线程会竞争,获取到锁的线程进入就绪状态
2. 等待池
当使用wait()方法后,线程会进入等待池,释放当前的锁,直到notify或者notifyAll方法唤醒再次进入争夺锁;进入等待池的线程不会竞争锁,notify后从等待池中随机唤醒一个线程放入锁池;
sleep是Thread中的静态方法,wait是Object中的方法
sleep不会释放当前的锁,会携带锁共同进入休眠状态;wait处于synchronize环境,释放锁后进入等待池,唤醒后进入锁池重新争夺;
sleep只需要时间到了就会重新进入就绪态,但是wait的线程必须等待notify唤醒
sleep一般用于线程休眠或者轮询,wait一般用于进程之间通信
sleep会让CPU强制切换上下文,但是wait后的线程可能马上被唤醒再次得到cpu
yield将当前线程进入就绪状态;可以再次抢夺时间片,获取cpu的使用权。
join在当前线程中插入其他线程的运行,只有其他线程完成后,当前线程才可以继续运行
18.Java会存在内存泄漏吗?请简单描述
内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。理论上来说,Java是有GC垃圾回收机制的,也就是说,不再被使用的对象,会被GC自动回收掉,自动从内存中清除。
但是,即使这样,Java也还是存在着内存泄漏的情况,java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。
19. 怎么理解配置文件能减耦合(个人理解)
比如 ${jdbc.driver}, 这样的字段只是一种标识,具体的实现细节,即配置信息写到了配置文件中的value值,在程序运行中动态的绑定数据; 这个想法可以匹配面向对象思想。
例子:程序里边儿有一个类,这个类属于啥呢?属于目标类,使用委托类作代理,他就相当于那个代理商,需要啥,就去那个代理商那儿获取,如果那个代理商那儿没有的情况下,我们是不是应该告诉这个代理商,你这个东西没有,然后你这个东西没有,你去给我进一个货之类的,也就是咱们在这个代理文件里进行,就是写这个配置文件呀。
东西 -》 ${jdbc.driver} 具体要啥:配置文件vlaue
一句话:我要驱动(抽象的),mysql驱动(具体的)
总结
主要记录下java中的一些知识点,没有顺序的记录