适宜阅读人群
需要面试的初级 Java 程序员
想要查漏补缺的人
想要不断完善扩充自己 Java 技术栈的人
具体面试题
JDK是Java Development Kit的缩写,是Java的开发工具包,主要面向开发人员。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。JDK是整个Java开发的核心,包括了Java运行环境,Java工具和Java基础类库。
JRE是Java Runtime Environment的缩写,是Java程序的运行环境,面向Java程序的使用者,而不是开发者。它包括Java虚拟机(jvm)、Java核心类库和支持文件。
对于==,比较的是值是否相等
如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址
对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object 类,比较的是是否是同一个对象
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
不一定相同。正常情况下,因为equals()方法比较的就是对象在内存中的值,如果值相同,那么Hashcode值也应该相同。但是如果不重写hashcode方法,就会出现不相等的情况。
凡是引用final关键字的地方皆不可修改!
(1)修饰类:表示该类不能被继承;
(2)修饰方法:表示方法不能被重写;
(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
Math.round(1.5)的返回值是2,Math.round(-1.5)的返回值是-1。四舍五入的原理是在参数上加0.5然后做向下取整。
String不是基本的数据类型,是final修饰的java类,java中的基本类型一共有8个,它们分别为:
1 字符类型:byte,char
2 基本整型:short,int,long
3 浮点型:float,double
4 布尔类型:boolean
String、StringBuffer、StringBuilder
String : final修饰,String类的方法都是返回new String。即对String对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象。
StringBuffer : 对字符串的操作的方法都加了synchronized,保证线程安全。
StringBuilder : 不保证线程安全,在方法体内需要进行字符串的修改操作,可以new StringBuilder对象,调用StringBuilder对象的append、replace、delete等方法修改字符串。
不一样,因为他们不是同一个对象。
String str=“i” 常量i会分分配到栈里面(常量池)
String str=new String(“i”) 分配到堆内存
第一种,通过String类的charAt()的方法来获取字符串中的每一个字符,然后将其拼接为一个新的字符串。
第二种,通过String的toCharArray()方法可以获得字符串中的每一个字符串并转换为字符数组,然后用一个空的字符串从后向前一个个的拼接成新的字符串。
第三种,通过StringBuiler的reverse()的方法,最快的方式。
1、求字符串长度
public int length()//返回该字符串的长度
2、求字符串某一位置字符
public char charAt(int index)
3.提取子串
用String类的substring方法可以提取字符串中的子串,该方法有两种常用参数:
1)public String substring(int beginIndex)
4、字符串比较
public int compareTo(String anotherString)
public boolean equals(Object anotherObject)
5.
字符串连接
public String concat(String str)
字符串中单个字符查找
1)public int indexOf(int ch/String str)
7、字符串中字符的大小写转换
public String toLowerCase()
public String toUpperCase()
字符串中字符的替换
public String replace
9.
String trim()//截去字符串两端的空格,但对于中间的空格不处理。
类型转换
如public static short parseInt(String s)
static String valueOf(char c)
11. 抽象类必须要有抽象方法吗?
抽象类可以没有抽象方法,但是如果你的一个类已经声明成了抽象类,即使这个类中没有抽象方法,它也不能再实例化,即不能直接构造一个该类的对象。
如果一个类中有了一个抽象方法,那么这个类必须声明为抽象类,否则编译通不过。
12. 普通类和抽象类有哪些区别?
抽象类必须用public、procted 修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。默认缺省为 public
抽象类无法创建对象
如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么必须定义为 abstract。
13. 抽象类能使用 final 修饰吗?
不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。
14. 接口和抽象类有什么区别?
抽象类只能继承一次,但是可以实现多个接口
接口和抽象类必须实现其中所有的方法,抽象类中如果有未实现的抽象方法,那么子类也需要定义为抽象类。抽象类中可以有非抽象的方法
接口中的变量必须用 public static final 修饰,并且需要给出初始值。所以实现类不能重新定义,也不能改变其值。
接口中的方法默认是 public abstract,也只能是这个类型。不能是 static,接口中的方法也不允许子类覆写,抽象类中允许有static 的方法
(1)按照数据的流向:
输入流、输出流
(2)按照流数据的格式:
字符流、字节流
(3)按照流数据的包装过程:
节点流(低级流)、处理流(高级流)
同步阻塞IO(BIO)
我们熟知的Socket编程就是BIO,一个socket连接一个处理线程(这个线程负责这个Socket连接的一系列数据传输操作)。阻塞的原因在于:操作系统允许的线程数量是有限的,多个socket申请与服务端建立连接时,服务端不能提供相应数量的处理线程,没有分配到处理线程的连接就会阻塞等待或被拒绝。
同步非阻塞IO(NIO)
New IO是对BIO的改进,基于Reactor模型。我们知道,一个socket连接只有在特点时候才会发生数据传输IO操作,大部分时间这个“数据通道”是空闲的,但还是占用着线程。NIO作出的改进就是“一个请求一个线程”,在连接到服务端的众多socket中,只有需要进行IO操作的才能获取服务端的处理线程进行IO。这样就不会因为线程不够用而限制了socket的接入。客户端的socket连接到服务端时,就会在事件分离器注册一个 IO请求事件 和 IO 事件处理器。在该连接发生IO请求时,IO事件处理器就会启动一个线程来处理这个IO请求,不断尝试获取系统的IO的使用权限,一旦成功(即:可以进行IO),则通知这个socket进行IO数据传输。
异步阻塞IO(AIO)
NIO是同步的IO,是因为程序需要IO操作时,必须获得了IO权限后亲自进行IO操作才能进行下一步操作。AIO是对NIO的改进(所以AIO又叫NIO.2),它是基于Proactor模型的。每个socket连接在事件分离器注册 IO完成事件 和 IO完成事件处理器。程序需要进行IO时,向分离器发出IO请求并把所用的Buffer区域告知分离器,分离器通知操作系统进行IO操作,操作系统自己不断尝试获取IO权限并进行IO操作(数据保存在Buffer区),操作完成后通知分离器;分离器检测到 IO完成事件,则激活 IO完成事件处理器,处理器会通知程序说“IO已完成”,程序知道后就直接从Buffer区进行数据的读写。
也就是说:AIO是发出IO请求后,由操作系统自己去获取IO权限并进行IO操作;NIO则是发出IO请求后,由线程不断尝试获取IO权限,获取到后通知应用程序自己进行IO操作。
Files.exists() 检测文件路径是否存在
Files.createFile()创建文件
Files.createDirectory()创建文件夹
Files.delete() 删除文件或者目录
Files.copy() 复制文件
Files.move() 移动文件
Files.size()查看文件个数
Files.read() 读取文件
Files.write()写入文件
数组,String,java.util下的集合容器(List、Set、Map)
java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等),大多数方法都是用来处理线性表的。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
List:存放有序,列表存储,元素可重复
Set:无序,元素不可重复
Map:无序,元素可重复
Hashtable:
1.无论是key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个Hashtable,效率低
2.初始size为11,扩容:newsize=oldsize2+1
Hashmap:
1.可以存储null键和null值,线程不安全
2.初始size为16,扩容:newsize =oldsize2,size一定为2的n次幂
TreeMap
而HashMap
大多情况下HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap.
HASHMAP是根据HASH算法储存数据的集合类,每一个存入其中的对象都有一个特定的哈希值!当新建一个HashMap对象,如果不给定它的大小,其默认为16,就相当与下面新建了编号为0到15的数组(链表数组)。以默认HashMap为例,put一个对象时,首先得到他的哈希值,在与十五相除得到余数,找到与余数相同编号的数组插入其中!
HASHSET就是没有value值的HASHMAP,你可以新建一个HASHSET,插入0到15,绝对以0到15的顺序打印。
List转数组:toArray()方法
数组转List:Arrays的asList(a)方法
(1)同步性:Vector是线程安全的,用synchronized实现线程安全,而ArrayList是线程不安全的,如果只有一个线程会访问到集合,那最好使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们再去考虑和编写线程安全的代码。
(2)数据容量增长:二者都有一个初始容量大小,采用线性连续存储空间,当存储的元素的个数超过了容量时,就需要增加二者的存储空间,Vector增长原来的一倍,ArrayList增加原来的0.5倍。
3 在CLR托管对中的存放方式
Array是始终是连续存放的,而ArrayList的存放不一定连续。
4 初始化大小
Array对象的初始化必须只定指定大小,且创建后的数组大小是固定的,
而ArrayList的大小可以动态指定,其大小可以在初始化时指定,也可以不指定,也就是说该对象的空间可以任意增加。
5 Array不能够随意添加和删除其中的项,而ArrayList可以在任意位置插入和删除项。
Queue 中 remove() 和 poll()都是用来从队列头部删除一个元素。
在队列元素为空的情况下,remove() 方法会抛出NoSuchElementException异常,poll() 方法只会返回 null 。
Vector 线程安全:
HashTable 线程安全:
StringBuffer 线程安全:
Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包括了可以返回迭代器实例的迭代方法。迭代器可以在迭代过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除。
Java中使用Iterator来遍历集合元素,Iterator遍历集合元素有以下几个特点:
1.** Iterator遍历集合元素的过程中不允许线程对集合元素进行修改,否则会抛出ConcurrentModificationEception的异常。**
2.Iterator遍历集合元素的过程中可以通过remove方法来移除集合中的元素。
3.Iterator必须依附某个Collection对象而存在,Iterator本身不具有装载数据对象的功能。
4.Iterator.remove方法删除的是上一次Iterator.next()方法返回的对象。
5.强调一下next()方法,该方法通过游标指向的形式返回Iterator下一个元素。
Iterator的常用方法:
1.boolean hasNext() ;判断迭代器中是否还有下一个元素,有则返回true
2.Object next(); 返回迭代器中下一个元素
3.void remove() ; 删除集合里上一个next方法调用的时候返回的对象元素
4.void forEachRemaining(Consumer action) ;使用Lambdda表达式的形式输出Iterator中所有的元素。注意该方法其实是间接调用next()方法进行遍历,所以再次是next()方法的时候Iterator中的对象已经被遍历完了。
我们可以采用Collections包下的unmodifiableMap方法,通过这个方法返回的map,是不可以修改的。他会报 java.lang.UnsupportedOperationException错。
同理:Collections包也提供了对list和set集合的方法。
Collections.unmodifiableList(List)
Collections.unmodifiableSet(Set)
…
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
1、进程是一段正在执行的程序,是资源分配的基本单元,而线程是CPU调度的基本单元。
2、进程间相互独立进程,进程之间不能共享资源,一个进程至少有一个线程,同一进程的各线程共享整个进程的资源(寄存器、堆栈、上下文)。
3、线程的创建和切换开销比进程小。
守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程,这是它的作用——而其他的线程只有一种,那就是用户线程。所以java里线程分2种,
1、守护线程,比如垃圾回收线程,就是最典型的守护线程。
2、用户线程,就是应用程序里的自定义线程。
实现Runable接口,实现Callable接口和实现Thread类。
两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任 务线程不能返回结果;
Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化, 不能继续上抛;
新建,就绪,运行,阻塞,死亡。
1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。
2.sleep()不会释放锁, wait()会释放锁,使得其他线程可以使用同步控制块或者方法。
3.sleep()可以在任何地方使用,wait()只能在同步代码块中使用
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只有一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
调用 start() 方法是用来启动线程的,轮到该线程执行时,会自动调用 run();直接调用 run() 方法,无法达到启动多线程的目的,相当于主线程线性执行 Thread 对象的 run() 方法。
一个线程对线的 start() 方法只能调用一次,多次调用会抛出 java.lang.IllegalThreadStateException 异常;run() 方法没有限制。
newSingleThreadExecutor创建一个单线程的线程池。
newFixedThreadPool 创建固定大小的线程池。
newCachedThreadPool 创建一个可缓存的线程池。
newScheduledThreadPool 创建一个大小无限的线程池。
线程池的5种状态:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED。
execute() 参数 Runnable ;submit() 参数 (Runnable) 或 (Runnable 和 结果 T) 或 (Callable)
execute() 没有返回值;而 submit() 有返回值
submit() 的返回值 Future 调用get方法时,可以捕获处理异常
JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
synchronized、volatile、LOCK,可以解决可见性问题
Happens-Before 规则可以解决有序性问题
所谓锁的升级、降级,就是 JVM 优化 synchronized 运行的机制,当 JVM 检测到不同的竞争状况时,会自动切换到适合的锁实现,这种切换就是锁的升级、降级。
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之
一不满足,就不会发生死锁。
ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。
同步代码块是通过 monitorenter 和 monitorexit 指令获取线程的执行权
同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制
volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化
1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
synchronized 竞争锁时会一直等待;ReentrantLock 可以尝试获取锁,并得到获取结果
synchronized 获取锁无法设置超时;ReentrantLock 可以设置获取锁的超时时间
synchronized 无法实现公平锁;ReentrantLock 可以满足公平锁,即先等待先获取到锁
synchronized 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll();ReentrantLock 控制等待和唤醒需要结合 Condition 的 await() 和 signal()、signalAll() 方法
synchronized 是 JVM 层面实现的;ReentrantLock 是 JDK 代码层面实现
synchronized 在加锁代码块执行完或者出现异常,自动释放锁;ReentrantLock 不会自动释放锁,需要在 finally{} 代码块显示释放
使用atomic 修饰属性,编译器会设置默认读写方法为原子读写,并使用互斥锁添加保护。
4. 反射
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
序列化就是把Java对象储存在某一地方(硬盘、网络),也就是将对象的内容进行流化。
当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。
在运行时,创建目标类,可以调用和扩展目标类的方法。
应用场景如:
Spring的AOP,加事务,加权限,加日志。
Java领域中,常用的动态代理实现方式有两种,一种是利用JDK反射机制生成代理,另外一种是使用CGLIB代理。
5. 对象拷贝
想对一个对象进行处理,又想保留原有的数据进行接下来的操作,就需要克隆了。
1). 实现Cloneable接口并重写Object类中的clone()方法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。63. 深拷贝和浅拷贝区别是什么?
浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝(例:assign())
深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝(例:JSON.parse()和JSON.stringify(),但是此方法无法复制函数类型)
Servlet 适合动态输出 Web 数据和业务逻辑处理,对于 html 页面内容的修改非常不方便;Jsp 是在 Html 代码中嵌入 Java 代码,适合页面的显示
内置对象不同,获取内置对象的方式不同
request对象 客户端请求,此请求包含来自GET/POST的请求参数,通过它才能了解到客户的需求,然后做出相应。
response对象 响应客户端的请求的有关信息。
session对象 它之客户端与服务起的一次会话,从客户端到服务器的一个WebApplication开始,直到客户端与服务器的链接断开为止。
out 对象 它是JspWriter类的实力,是向客户端输出内容常用的对象
page对象 它指当前JSP页面本身,有点类似this指针,它是java.lang.object类的一个实例
applicationd对象 它实现用户间的数据共享,可以改变全局变量,它从服务器启动开始直到服务器关闭。
exception对象 它是一个例外对象当一个页面的运行过程中发生了例外,就产生这个对象。
pageContext对象 它提供了对JSP页所有对象及名字空间的访问。
config对象 它是在一个Servlet初始化时,JSP引擎向它传递信息用的。
4个JSP内置对象的作用域分别为:application、session、request、page 。
如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。
如果把变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。
如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。
如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前jsp页面里。
session对象是在服务器内存中的,而基于窗口的cookie是在客户端内存中的。
cookie不是很安全,别人可以分析存放在本地的cookie,进行cookie欺骗;session会在一定时间内保存在服务器上,当访问增多,会占用服务器性能
cookie保存数据不能超过4k,很多浏览器都限制一个站点最多存放20个cookie
口头试:
session是一个存在服务器上的类似于一个散列表格的文件。里面存有我们需要的信息,在我们需要用的时候可以从里面取出来。类似于一个大号的map吧,里面的键存储的是用户的sessionid,用户向服务器发送请求的时候会带上这个sessionid。这时就可以从中取出对应的值了。
如果在浏览器中禁止使用Cookie时候也会不能使用Cookie和Session这样两个都是不能用的。
1.预处理PreparedStatement
2.使用正则表达式过滤传入的参数
3.字符串过滤
即跨站脚本攻击,是一种常见于web应用程序中的计算机安全漏洞.XSS通过在用户端注入恶意的可运行脚本,若服务器端对用户输入不进行处理,直接将用户输入输出到浏览器,然后浏览器将会执行用户注入的脚本。
1、获取用户输入,不用.innerHTML,用innerText。
2、对用户输入进行过滤,如 HTMLEncode 函数实现应该至少进行 & < > " ’ / 等符号转义成 & < > " ' /;
CSRF:Cross Site Request Forgery(跨站点请求伪造),攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的。
CSRF 漏洞进行检测的工具,如 CSRFTester、CSRF Request Builder…
验证 HTTP Referer 字段
添加并验证 token
添加自定义 http 请求头
敏感操作添加验证码
使用 post 请求
throw:
表示方法内抛出某种异常对象
如果异常对象是非 RuntimeException 则需要在方法申明时加上该异常的抛出 即需要加上 throws 语句 或者 在方法体内 try catch 处理该异常,否则编译报错
执行到 throw 语句则后面的语句块不再执行
throws:
方法的定义上使用 throws 表示这个方法可能抛出某种异常
需要由方法的调用者进行异常处理
final
final修饰类,表示该类不可以被继承
final修饰变量,表示该变量不可以被修改,只允许赋值一次
final修饰方法,表示该方法不可以被重写
finally
finally是java保证代码一定要被执行的一种机制。
比如try-finally或try-catch-finally,用来关闭JDBC连接资源,用来解锁等等
finalize
finalize是Object的一个方法,它的目的是保证对象在被垃圾收集前完成特定资源的回收。
不过finalize已经不推荐使用,JDK9已经标记为过时。
线程的创建方式有哪些?都有什么优劣?
线程创建的方式:3种
实现runnable接口、继承Thread、实现Callable接口
采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
你使用python做过什么?反扒机制怎么实现?
用python做过对excel的数据进行读取、分析和拆分,然后保存为txt文件,方便存入数据库。
一、HTTP请求头
每次向服务器发送HTTP请求时,都会传送一组属性和配置信息,那就是HTTP请求头。由于浏览器直接访问和爬虫代码发送的请求头不同,很有可能被反爬虫发现,导致封IP。
二、cookie设置
网站会通过cookie跟踪你的访问过程,如果发现有爬虫行为会立刻中断你的访问,比如特别快的填写表单,或者短时间内浏览大量页面。而正确地处理cookie,又可以避免很多采集问题,建议在采集网站过程中,检查一下这些网站生成的cookie,然后想想哪一个是爬虫需要处理的。
三、访问路径
一般爬虫程序访问的路径总是千篇一律,也很容易被反爬虫识别,尽量模拟用户访问,随机访问页面。
四、访问频率
大部分的封IP原因是因为访问频率过快,毕竟都想快速的完成爬虫任务,然而欲速则不达,封IP后效率反而下降。
基本的反爬虫策略就是这些,当然,有些更严格的反爬虫,不仅仅是这些,这就需要反爬虫工程师去慢慢的研究目标网站的反爬虫策略了,跟随着反爬虫策略的不断升级,爬虫策略也需要不断的升级,再加上高效优质的代理IP,爬虫工作才能高效的进行。
python里两个变量的值如何调换?和java对比有什么区别?
python可以直接赋值调换,但Java需要第三方变量才能调换
递归了解吗?递归的方法调用了解吗?
项目中的分页怎么做的
最近使用mybatis-plus的分页组件,处理下显示页数,然后前端用thymeleaf标签显示。
之前写一个工具类,来获得一些必要的参数,然后传到前端显示。
spring特性有哪些?
轻量
IOC控制反转
AOP面向切面
容器
框架
你的学习能力和抗压能力怎么样?我如何判断你具备这些能力?你的优点缺点是什么?你对新技术有什么看法?你经常会去关注新技术吗?
sql防止注入
对比下session和cookie
maven构建项目?
描述下你做的人像识别项目
string能继承吗?为什么?
Sting不能被继承 它是这样定义的: public final class String extends Object 里边有final关键字 所以不能被继承
数据库的分页怎么实现的
一对多怎么实现?
final、finally、finalize 有什么区别?
try-catch-finally 中哪个部分可以省略?
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
会
常见的异常类有哪些?
(1)NullPointerException 当应用程序试图访问空对象时,则抛出该异常。
(2)SQLException 提供关于数据库访问错误或其他错误信息的异常。
(3)IndexOutOfBoundsException指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
(4)NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
(5)FileNotFoundException当试图打开指定路径名表示的文件失败时,抛出此异常。
(6)IOException当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
(7)ClassCastException当试图将对象强制转换为不是实例的子类时,抛出该异常。
(8)ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常。
(9)IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
(10)ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
(11)NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常。
(12)NoSuchMethodException无法找到某一特定方法时,抛出该异常。
(13)SecurityException由安全管理器抛出的异常,指示存在安全侵犯。
(14)UnsupportedOperationException当不支持请求的操作时,抛出该异常。
(15)RuntimeExceptionRuntimeException 是那些可能在Java虚拟机正常运行期间抛出的异常的超类。
网络
http 响应码 301 和 302 代表的是什么?有什么区别?
301 redirect: 301 代表永久性转移(Permanently Moved)
302 redirect: 302 代表暂时性转移(Temporarily Moved )
301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。
forword只有一次请求;而redirect有两次请求
tcp 为什么要三次握手,两次不行吗?为什么?
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认
说一下 tcp 粘包是怎么产生的?
我们知道,TCP默认会使用Nagle算法。而Nagle算法主要做两件事:1)只有上一个分组得到确认,才会发送下一个分组;2)收集多个小分组,在一个确认到来时一起发送。
所以,正是Nagle算法造成了发送方有可能造成粘包现象。
OSI 的七层模型都有哪些?
OSI模型把网络通信的工作分为7层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
get 和 post 请求有哪些区别?
在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次
get请求参数是连接在url后面的,而post请求参数是存放在requestbody内的
get请求因为浏览器对url长度有限制(不同浏览器长度限制不一样)对传参数量有限制,而post请求因为参数存放在requestbody内所以参数数量没有限制(事实上get请求也能在requestbody内携带参数,只不过不符合规定,有的浏览器能够获取到数据,而有的不能)
因为get请求参数暴露在url上,所以安全方面post比get更加安全
get请求浏览器会主动cache,post并不会,除非主动设置
get请求参数会保存在浏览器历史记录内,post请求并不会
get请求只能进行url编码,而post请求可以支持多种编码方式
get请求产生1个tcp数据包,post请求产生2个tcp数据包
浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200 OK
说一下 JSONP 实现原理?
设计模式
说一下你熟悉的设计模式?
-工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
观察者模式:当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
责任链模式:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
89. 简单工厂和抽象工厂有什么区别?
Spring/Spring MVC
为什么要使用 spring?
轻量:非入侵性的、所依赖的东西少、资源占用少、部署简单,不同功能选择不同的 jar 组合
容器:工厂模式实现对 JavaBean 进行管理,通过控制反转(IOC)将应用程序的配置和依赖性与应用代码分开
松耦合:通过 xml 配置或注解即可完成 bean 的依赖注入
AOP:通过 xml 配置 或注解即可加入面向切面编程的能力,完成切面功能,如:日志,事务…的统一处理
方便集成:通过配置和简单的对象注入即可集成其他框架,如 Mybatis、Hibernate、Shiro…
丰富的功能:JDBC 层抽象、事务管理、MVC、Java Mail、任务调度、JMX、JMS、JNDI、EJB、动态语言、远程访问、Web Service…
解释一下什么是 aop?
在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。
解释一下什么是 ioc?
控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的”控制反转”就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。
spring 有哪些主要模块?
Spring有七大功能模块,分别是Spring Core,AOP,ORM,DAO,MVC,WEB,Context。
spring 常用的注入方式有哪些?
构造方法注入,setter注入,基于注解的注入。
spring 中的 bean 是线程安全的吗?
单例模式的就不是线程安全的,protype模式的就是线程安全的。
spring 支持几种 bean 的作用域?
五种
singleton:单例模式
prototype:原型模式
只有在 Web 应用中使用Spring时,request、session、global-session 作用域才有效
spring 自动装配 bean 有哪些方式?
default - 默认的方式和 “no” 方式一样
no - 不自动装配,需要使用 节点或参数
byName - 根据名称进行装配
byType - 根据类型进行装配
constructor - 根据构造函数进行装配
spring 事务实现方式有哪些?
(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务
说一下 spring 的事务隔离?
DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
未提交读(read uncommited) :脏读,不可重复读,虚读都有可能发生
已提交读 (read commited):避免脏读。但是不可重复读和虚读有可能发生
可重复读 (repeatable read) :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 (serializable) :避免以上所有读问题.
说一下 spring mvc 运行流程?
核心控制器捕获请求、查找Handler、执行Handler、选择ViewResolver(视图处理器),通过ViewResolver渲染视图并返回
spring mvc 有哪些组件?
1.DispatcherServlet 请求入口
2.HandlerMapping 请求派发,负责请求和控制器建立一一对应的关系
3.Controller 处理器
4.ModelAndView 封装模型信息和视图信息
5.ViewResolver 视图处理器,定位页面
@RequestMapping 的作用是什么?
用来标识 http 请求地址与 Controller 类的方法之间的映射。
@Autowired 的作用是什么?
它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
Spring Boot/Spring Cloud
什么是 spring boot?
SpringBoot是一个服务于框架的框架,服务范围是简化配置文件。
为什么要用 spring boot?
让文件配置变的相当简单、让应用部署变的简单(SpringBoot内置服务器,并装备启动类代码),可以快速开启一个Web容器进行开发。
spring boot 核心配置文件是什么?
application (.yml 或者 .properties)
spring boot 配置文件有哪几种类型?它们有什么区别?
.properties 和 .yml,它们的区别主要是书写格式不同。
spring boot 有哪些方式可以实现热部署?
1.在项目的pom文件中添加依赖
2.在项目中添加(bulid标签里的plugins标签下)
jpa 和 hibernate 有什么区别?
Hibernate是JPA规范的一个具体实现
hibernate有JPA没有的特性
hibernate 的效率更快
JPA 有更好的移植性,通用性
什么是 spring cloud?
根据Spring Cloud的官方网站,Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,领导选举,分布式会话,集群状态)。
spring cloud 断路器的作用是什么?
断路器有完全打开状态
一定时间内 达到一定的次数无法调用 并且多次检测没有恢复的迹象 断路器完全打开,那么下次请求就不会请求到该服务
半开
短时间内 有恢复迹象 断路器会将部分请求发给该服务 当能正常调用时 断路器关闭
关闭
当服务一直处于正常状态 能正常调用 断路器关闭
112. spring cloud 的核心组件有哪些?
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config
Hibernate
为什么要使用 hibernate?
Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它很大程度的简化了dao层编码工作
Hibernate使用java的反射机制,而不是字节码增强程序类实现透明性
Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系
*Hibernate本身性能并不是很好,存在很多优化手段 (一级缓存、二级缓存、查询缓存、抓取策略)
什么是 ORM 框架?
ORM(Object Relation Mapping)对象关系映射
即通过类与数据库表的映射关系,将对象持久化到数据库中,
常用的有: Hibernate(Nhibernate),iBATIS,mybatis,EclipseLink,JFinal
hibernate 中如何在控制台查看打印的 sql 语句?
只需要在配置文件里 hibernate.show_sql=true
hibernate 有几种查询方式?
hibernate 实体类可以被定义为 final 吗?
在 hibernate 中使用 Integer 和 int 做映射有什么区别?
hibernate 是如何工作的?
get()和 load()的区别?
说一下 hibernate 的缓存机制?
hibernate 对象有哪些状态?
在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
hibernate 实体类必须要有无参构造函数吗?为什么?
老贾(838739465) 17:55:04
数据挖掘,机器学习有学过吗?了解哪些算法?数据库的左连接右连接
关于多线程你了解多少?
有没有了解过代理?
你对面向对象是怎么理解的?
自我介绍?spring mvc的组件流程是怎么样的?前端框架接触过哪些?描述下二叉树,描述下快速排序的思想
多态是什么?
为什么从上家实习公司离职?
JQ里的选择器
加班的看法
有自己主动学习过一些新技术吗?是哪些?
入职后,需要一边工作一边学习新的技术,你怎么考虑?
你简历上的技术有哪些是自己学的?哪些是老师讲的?
有用过什么插件?
Java代理了解吗?
动态代理能做什么?
你熟悉的排序有哪些?
描述下你熟悉的排序
你写代码时遇到过哪些异常?
sql的左联接右连接
set的是有序还是无序?
创建线程的两种方式是什么?死锁怎么产生的?
mybatis原理,和springboot有整合过吗?怎么整合的?
了解过缓存吗?
NIO了解吗?
中文乱码是怎么回事?怎么解决?
了解哪些设计模式?熟练使用的是哪几种?你为什么使用这些设计模式?
看下你写的单例模式,如果在多线程的情况下还安全吗?
补码???
自己有搭建过hadoop?描述一下快速排序
springmvc的组件流程
底层组件了解多少?
分布式运行计算的原理