面试题-Java基础

JavaSE

JDK 和 JRE 有什么区别?

  1. JDK:java开发工具包,提供了java的开发环境和运行环境。
  2. JRE:java运行环境,为java的运行提供了所需环境。
    具体来说就是JDK其实包含了JRE,同时还提供了编译Java源码的编译器JAVAC,以及很多java程序调试和分析的工具。
    简单来说:如果你需要运行Java程序,只需安装JRE就可以了,但是如果你需要编写Java程序,那么需要安装JDK。

== 和 equals 的区别是什么?

对于基本类型和应用类型 == 的作用是不同的:
基本类型:比较的是值是否相同。
引用类型:比较的是引用是否相同。
equals方法默认就是==,但是很多类都重写了equals,例如String、Integer,都重写了自己的equals变成了数据内容值的比较。我们也是可以重写自己的equals方法的。
总结:==对于基本类型来说是值比较,对于引用类型来说比较的是引用。而equals默认情况下是引用比较,只是很多类都重写了equals方法,比如String、Integer等都把它变成了值的比较,所以一般情况下equals比较的是值是否相等。

两个对象的hashCode()相同,equals也一定为true,对吗?

不对,两个对象的hashCode()相同,而equals也不一定为true。
我们总结一下关于hashCode相关的点:

  1. 两个对象的hashCode()相同,而equals是不一定为true的。
  2. 只有两个对象的hashCode()相同,且equals为true,这两个对象才完全相同。
  3. 如果重写了equals,那么一定要重写hashCode()。保证equals为true的同时,hashCode()的值相同。

final在Java中有什么作用?

  1. final修饰的类叫最终类,该类不能被继承。
  2. final修饰的方法不能被重写。
  3. final修饰的变量叫常量,常量必须被初始化,初始化之后的值不能被修改。

Java中的Math.round(-1.5)等于多少?

等于-1,Math.round()四舍五入,大于0.5则向上取整。

String属于基础的数据类型吗?

String不属于基础类型,属于引用数据类型,即属于对象。
基础类型有8种:byte、short、int、long、float、double、 boolean、char

Java操作字符串都有哪些类?他们之间有什么区别?

String、StringBuffer、StringBuilder。
String和StringBuffer、StringBuilder的区别在于String声明的是不可变的对象,每次操作都会生成新的String对象,然后将指针指向新的String对象,而StringBuffer、StringBuilder可以再原有对象的基础上进行操作,所有在经常改变字符串内容的情况下最好不要使用String。
StringBuffer和StringBuilder最大的区别在于,StringBuffer是线程安全的,而StringBuilder是非线程安全的,但StringBuilder的性能要高于StringBuffer,所以在单线程环境下推荐使用StringBuilder,多线程环境下推荐使用StringBuffer。

String str="i" 与 String str = new String("i") 一样吗?

不一样,因为内存的分配方式不一样。String str = "i"的方式,Java虚拟机会将其分配到常量池中;而String str = new String("i")则会被分到堆内存中。

如何将字符串反转?

使用StringBuilder或者StringBuffer的reverse()方法。

String类的常用方法都有哪些?

  1. indexOf():返回指定字符串的索引。
  2. charAt():返回指定索引处的字符。
  3. replace():字符串替换。
  4. replace():替换全部字符串。
  5. trim():去除字符串两端的空格。
  6. split():分割字符串,返回一个分割后的字符串数组。
  7. getBytes():返回字符串的byte类型数组。
  8. length():返回字符串长度。
  9. toLowerCase():将字符串转成小写字母。
  10. toUpperCase():将字符转成大写字母。
  11. substring():截取字符串。
  12. equals():字符串比较。

抽象类必须要有抽象方法吗?

不需要,抽象类不一定非要有抽象方法。

普通类和抽象类有哪些区别?

普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化的。

抽象类可以使用final修饰吗?

不能,定义抽象类的目的就是让其他类继承的,如果定义为final该类就不能被继承,这样彼此就会产生矛盾,所以final不能修饰抽象类。

接口和抽象类有什么区别?

  1. 默认方法实现:抽象类可以有默认的方法实现,而接口不能有默认的方法实现。
  2. 实现:抽象类的子类是使用extends来继承的,而接口的实现类是使用implements来实现接口的。
  3. 构造函数:抽象类可以有构造函数,但是接口不能有构造函数。
  4. main方法:抽象类可以有main方法,并且我们能运行它。但是接口不能有main()方法。
  5. 实现数量:一个类可以实现多个接口,但是只能继承一个抽象类。
  6. 访问修饰符:接口中的方法默认都使用public修饰,而抽象类中的方法可以使用任意访问修饰符。

Java中IO流分为几种?

  1. 按功能来分:输入流,输出流。
  2. 按类型来分:字节流,字符流。
    字节流和字符流的区别是:字节流按8位传输以字节为单位输入输出数据,而字符流按16位传输以字符为单位输入输出数据。

BIO、NIO、AIO有什么区别?

  1. BIO:Block IO同步阻塞式IO,就是我们平常使用的传统IO,它的特点是模式简单使用方便,但并发处理能力低。
  2. NIO:New IO同步非阻塞IO,是传统IO的升级,客户端和服务器通过Channel(通信)通讯,实现了多路复用。
  3. AIO:Asynchronus IO又是在NIO上的进一步升级,也叫NIO2,实现了异步非阻塞式IO,异步IO的操作基于事件和回调机制。

Flies的常用方法都有哪些哪些?

  1. Flies.exists():检测文件路径是否存在。
  2. Flies.createFile():创建文件。
  3. Flies.createDirectory():创建文件夹。
  4. Files.delete():删除一个文件或者目录。
  5. Files.copy():复制文件。
  6. File.move():移动文件。
  7. Files.size():查看文件个数。
  8. Files.read():读取文件。
  9. Files.write():写入文件。

Java容器

Java容器都有哪些?

Java容器分为Collection和Map两大类,其下又有很多类,如下所示:
Collection:

+ List
+ ArrayList
+ LinkedList
+ Vector
+ Stack
+ Set
+ HashSet
+ LinkedHashSet
+ TreeSet

Map:

+ HashMap
+ LinkedHashMap
+ TreeMap
+ ConcurrentHashMap
+ HashTable

Collection和Collection有什么区别?

Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如List、Set等等。
而Collections是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序方法:Collections.sort(list)。

List、Set、Map之间有什么区别?

我们先分别谈一谈List、Set和Map:

  1. List列表
    List的元素以线性方式存储,可以存放重复对象,List主要有以下两个实现类:

    • ArrayList:长度可变的数组,对元素随机访问的速度快,但向ArrayList中插入与删除元素的速度慢。JDK8ArrayList扩容的实现是通过grow()方法里使用语句newCapacity=oldCapacity+(oldCapacity>>1)(即1.5倍扩容)计算祘两,然后调用Arrays.copyof()方法进行对原数组进行复制。
    • LinkedList:采用链表数据结构,插入和删除速度快,但访问速度慢。
  2. Set集合
    Set中的对象不按特定(HashCode)的方式排序,并且没有重复对象,Set主要有以下两个实现类:

    • HashSetHashSet按照哈希算法来存取集合中的对象,存取速度比较快。当HashSet中的元素个数超过数组大小*loadFactor(默认值为0.75)时,就会进行近似两倍扩容(newCapacity=(oldCapacity<<1)+1)。
    • TreeSet:TreeSet实现了SortedSet接口,能够对集合中的对象进行排序。
  3. Map映射
    Map是一种把键对象和值对象映射的集合,它的每一个元素都包含一个键对象和值对象。Map主要有以下两个实现类:

    • HashMapHashMap基于散列表实现,其插入和查询的开销是固定的,可以通过构造器设置容量和负载因子来调整容器的性能。
    • LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得的顺序是其插入次序,或者是最近最少使用(LRU)的次序。
    • TreeMapTreeMap基于红黑树实现。查看时,它们会被排序。TreeMap是唯一的带有subMap()方法的map,subMap()可以返回一个子树。

    总结来说:

  4. List:继承接口为Collection,常见实现类为ArrayList、LinkedList,常用方法为add()、remove()、clear()等,元素可重复、有序。
  5. Set:继承接口为Collection,常见实现类HashSet、LinkedHashSet,常用方法add()、remove()、clear()等,元素不可重复。
  6. Map:常见实现类HashMap、HashTable,常见方法put()、get()、remove(),元素不可重复。

HashMap和HashTable有什么区别?

  1. 存储:HashMap允许key和value为null,而HashTable不允许。
  2. 线程安全:HashTable是线程安全的,而HashMap是非线程安全的。
  3. 推荐使用:在HashTable的类注释可以看到,Hashtable是保留类不建议使用的,推荐在单线程环境下使用HashMap,多线程环境则使用ConcurrentHashMap代替。

如何决定使用HashMap还是TreeMap?

对于在Map中插入、删除定位一个元素这类操作,HashMap是最好的选择,因为相对而言HashMap的插入会更好,但如果你要对一个key集合进行有序的遍历,那TreeMap是更好的选择。

说一下HashMap的实现原理?

HashMap基于Hash算法实现的,我们通过put(key,value)存储,get(key)来获取。当传入key时,HashMap会根据key,hashCode()计算出hash值,根据hash值将value保存在bucket李。当计算出的hash值相同时,我们称之为hash冲突,HashMap的做法是用链表和红黑树存储相同hash值的value。当Hash冲突的个数比较少时使用链表,否则使用红黑树。

说一下HashSet的实现原理?

HashSet是基于HashMap实现的,HashSet底层使用HashMap的key来保存所有元素,因此HashSet的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成的,HashSet不允许重复的值。

ArrayList和LinkedList的区别是什么?

  1. 数据结构实现:ArrayList是动态数组的数据结构实现,而LinkedList是双向链表的数据结构实现。
  2. 随机访问法效率:ArrayList比LinkedList在随机访问的时候效率要高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后以此查找。
  3. 增加和删除效率:在非首尾的增加和删除操作,LinkedList要比ArrayList效率要高,因为ArrayList增删操作要影响数组内的其他数据的下表。
    综合来说,在需要频繁读取集合中的元素时,更推荐使用ArrayList,而在插入和删除操作较多时,更推荐使用LinkedList。

如何实现数组和List之间的转换?

  1. 数组转List:使用Arrays.asList(array)进行转换。
  2. List转数组:使用List自带的toArray()方法。

ArrayList和Vector的区别是什么?

  1. 线程安全:Vector使用了Synchronized来实现线程同步,是线程安全的,而ArrayList是非线程安全的。
  2. 性能:ArrayList在性能方面更优于Vector。
  3. 扩容:ArrayList和Vector都会根据实际的需要动态的调整容量,只不过在Vector扩容每次会增加1倍,而ArrayList之后增加50%。

Array和ArrayList有和区别?

  1. Array可以存储基本数据类型和对象,而ArrayList只能存储对象。
  2. Array是指定固定大小的,而ArrayList大小是自动扩展的。
  3. Array内置方法没有ArrayList多,比如addAll、removeAll、iteration等方法只有ArrayList有。

在Queue中poll()和remove()有什么区别?

  1. 相同点:都是返回第一个元素,并在队列中删除返回的对象。
  2. 不同点:如果没有元素poll()会返回null,而remove()会直接抛出NoSuchElementException异常。

哪些集合类似线程安全的?

Vector、Hashtable、Stack都是线程安全。而像HashMap则是非线程安全的,不过在JDK1.5之后随着Java.util.concurrent并发包的出现,它们也有了自己的对应的线程安全类,比如HashMap对应的线程安全类就是ConcurrentHashMap。

迭代器Iterator是什么?

Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration,迭代器允许调用者在迭代器过程中移除元素。

Iterator怎么使用?有什么特点?

List list = new ArrrayList<>():
Iterator it = list.iterator();
while(it.hashNext()){
    String obj = it.next();
    System.out.println(obj);
}

Iterator的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出ConcurrentModificationException异常。

Iterator和ListIterator有什么区别?

  1. Iterator可以遍历Set和List集合,而ListIterator只能遍历List。
  2. Iterator只能单向遍历,而ListIterator可以双向遍历(向前/后遍历).
  3. ListIterator从Iterator接口继承,然后添加一些了额外的功能,比如添加一个元素、替换一个元素、获取前面或者后面元素的索引位置。

怎么确保一个集合不能被修改

可以使用Collections.unmodifiableCollection(Collection c)方法来创建一个只读集合,这样改变集合的任何操作都会抛出Java.lang.UnsupportedOperationException异常。

Java多线程并发

并行和并发有什么区别?

  1. 并行:多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上看那些任务时同时执行。
  2. 并发:多个处理器或多核处理器同时处理多个任务。

    并发:两个人用一台咖啡机
    并行:两个队列和两台咖啡机。

线程和进程的区别?

一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。

守护线程是什么?

守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在Java中垃圾回收线程就是特殊的守护线程。

创建线程有哪几种方式?

三种:

  1. 继承Thread重写run()方法,调用start()方法启动线程。
  2. 实现Runnable接口,重写run()方法,调用start()方法启动线程。
  3. 实现Callable接口。

说一下runnable和callable有什么区别?

  1. runnable没有返回值,callable有返回值
  2. runnable无法捕捉异常, callable可以捕捉到异常。

线程有哪些状态?

  1. NEW 尚未启动,新创建
  2. RUNNABLE 进入运行状态或者即将运行的状态
  3. BLOCKED 阻塞状态(被同步锁或者IO锁阻塞)
  4. WITING 永久等待状态
  5. TIMED_WAITING 等待指定的时间重新被唤醒的状态。
  6. TERMINATED 执行完成

sleep() 和 wait() 有什么区别?

  1. 类的不同:sleep()来自Thread,wait()来自Object类.
  2. 释放锁:sleep()不会释放锁,wait()释放锁。
  3. 用法不同:sleep()时间到会自动恢复,wait()可以使用notify()/notifyAll()直接唤醒。

notify()和notifyAll()有什么区别?

  1. notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。
  2. notifyAll()调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。

线程的run()的start()方法有什么区别?

  1. run()方法体内保存的是线程需要执行的代码内容,而start()是用于启动线程的。
  2. 单单的调用run()方法,只是在调用了一个普通的方法,并不会开启一个新的线程,进行异步代码的执行。
  3. 而如果调用的是start()方法,则会真正调用开启一个线程。

创建线程池有哪几种方式?

线程池创建有七种方式,我们一般使用最后一种。

  1. newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。
  2. newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后回收,若线程数不够,则新建线程。
  3. newSingleThreadExecutor:创建单个线程池数的线程池,它可以保证先进先出的执行顺序。
  4. newScheduledThreadPool:创建一个可以执行延迟任务的线程池。
  5. newSingleThreadScheduledExecutor:创建一个车单线程的可以延迟任务的线程池。
  6. newWorkStealingPool:创建一个车抢占式执行的线程池(任务执行顺序不确定)
  7. ThreadPoolExecutor:手动创建线程池的方式,它创建时最多可以设置7个参数。

    • corePoolSize:核心线程数
      核心线程会一直存活,及时没有任务需要执行。当线程数大于corePoolSize时,且任务队列已满时,线程池会创建新线程来处理任务。
    • maxPoolSize:最大线程数
      当线程数大于maxPoolSize时,且任务队列已满时,线程池会拒绝处理任务并且抛出异常。
    • queueCapacity:任务队列容量(阻塞队列)
      当线程数达到了核心线程数时,会把线程放到任务队列中。
    • keepAliveTime:线程空闲时间
      当线程空闲时间达到keepAliveTime时,线程就会退出,直到线程数量达到corePoolSize。
    • allowCreThreadTimeOut:允许核心线程超出
      当allowCoreThreadTimeOut=true时,线程达到keepAliveTime时,核心线程池可以等于0
    • rejectedExecutionHandler:任务拒绝处理器
      ......

线程池都有哪些状态?

  1. running:接受新任务并处理队列中的任务。
  2. shutdown:虽然不接受新任务,但是处理队列中的任务。
  3. stop:不接受新的任务提交,不在处理等待队列中的任务,中断正在执行任务的线程。
  4. tidying:所以的任务都销毁了,workCount为0,线程池的状态在转换为tidying状态时,会执行钩子方法terminated()。
  5. terminated:运行已经完成了

线程池中sumbit()和execute()方法有什么区别?

  1. 两者的接受参数不一样:execute()方法只能接受Runnable类型的参数,而submit()方法可以接收Callable、Runnable两种类型的参数。
  2. 返回值不同:submit()提交任务后可以有返回值,而execute()提交任务后是不会有返回值的。
  3. 异常不同:submit()可以捕获到异常,但是execute()是没法捕获异常的。

在Java程序中怎么保证多线程的运行安全?

  1. 使用安全类:比如Java.util.concurrent类的
  2. 使用自动锁:synchronized关键字给代码块、方法、类加锁
  3. 使用手动锁:lock关键字

多线程中synchronzied锁升级的原理是什么?

  1. 在锁对象的对象头里面有一个threadid的字段,在第一次访问的时候threadid为空,jvm会让其持有偏向锁,并将threadid设置为该线程的id。
  2. 下次有线程来获取锁资源的时候,会先判断该线程的id与锁对象的对象头threadid字段是否一致。如果一致则直接获取到锁资源,如果不一致,则升级为轻量级锁(自旋锁)。
  3. 轻量级锁通过不断的循环CAS来尝试获取锁资源,直到循环到一定次数后,还拿不到锁资源,则升级为重量级锁。
    锁升级是为了减少锁带来的性能消耗,在Java6之后优化synchronized的实现方式,使用了偏向锁升级为轻量级再升级到重量级锁的方式,从而减低了锁带来的性能消耗。

什么是死锁?

两个或者一组线程同时被阻塞,都互相拥有对方的锁,但同时都互相尝试获取对方手中的锁资源,却又都不释放。两个或多个线程都被无限的阻塞下去,程序不能正常的执行或结束,这被称为死锁。

死锁形成的条件?

  1. 互斥条件:一个资源每次只能被一个进使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程以获取的资源,在未使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
    只有这四个条件,才会形成死锁。

如果避免死锁的产生?

只有四个死锁条件同时成立,才会发生死锁的情况,我们只需要破坏其中的一条就可以避免死锁。

  1. 尽量使用tryLock(long timout, TimeUnit unit)的方法,设置超时时间,超时可以退出防止出现死锁。
  2. 尽量使用java.util.concurrent下的并发类来代替自己手写锁。
  3. 尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
  4. 尽量减少同步的代码块。

ThreadLocal是什么?有哪些使用场景?

ThreadLocal为每个使用该变量的线程提供了独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程说对应的副本。
ThraedLocal的经典使用场景是数据库链接和session管理等。

说一下synchronized底层实现原理?

sychronized是由一对monitorenter/monitorexit指令实现的,字节码执行到monitorenter时,count+1,字节码执行到monitorexit指令时,count-1。当count=0是,判断为当前锁资源没有被占有,count不为1则表示当前锁资源已经被占有了。因为需要进行用户态到内核态的切换,所有同步操作是一个无差别的重量级操作,性能很低。但在Java6之后,改为锁升级机制,提供了三种不同的monitor实现。也就是常常说的:偏向锁、轻量级锁、重量级锁,大大改进了其性能。

synchronized和volatile的区别是什么?

  1. volatile只能修饰变量,而synchronized可以修饰类、方法、代码块。
  2. volatile仅能实现变量的可见性、禁止指令的重排序;而synchroized可以保证资源的可见性和原子性。
  3. volatile是不会造成线程的阻塞的,而synchronized是可能造成线程的阻塞的。

sychronized和lock有什么区别?

  1. synchronized可以给类、方法、代码块加锁;而lock只能给代码块加锁。
  2. synchronized不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会导致死锁;而Lock需要自己加锁和释放锁,如果使用不当没有unlock()去释放锁,就可能会导致死锁。
  3. lock可以知道是否成功获取锁,而synchronized是无法知道的。

synchronized和ReentrantLock

  1. ReentrantLock显示地获得、释放锁,synchronized隐式的获得、释放锁。
  2. ReentrantLock是API级别的,synchronized是JVM级别的。
  3. ReentrantLock可以实现公平锁。
  4. ReentranLock可响应中断,可轮回,synchronized是不可以响应中断的。

说一下atomic的原理?

atomic主要是利用CAS、volatile、native方法来保证原子操作,从而避免synchronized的高开销,执行效率大为提升。

反射

什么是反射?

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够掉拽死它的任意一个方法和属性。这种动态获取信息以及动态调用对象的方法功能称为Java语言的反射机制。

什么是Java序列化?什么情况下需要序列化?

Java序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。
以下情况需要使用Java序列化:

  1. 想把内存中的对象状态保存到一个文件中或者数据库中的时候。
  2. 想用套接字在网络上传送对象的时候。
  3. 想通过RMI(远程方法调用)传输对象的时候。

动态代理是什么?有哪些应用?

动态代理就是运行时动态生成代理类。
动态代理的应用有spring aop、hibernate数据查询、测试框架的后端mock、rpc、java注解对象获取等。

怎么实现动态代理?

JDK原生的动态代理和CGLIB动态代理。
JDK原生动态代理是基于接口实现的,而CGLIB是基于继承当前类的子类实现的。

对象拷贝

为什么要使用克隆?

对象的拷贝需要使用克隆,如果想对一个对象进行处理,又想保留原有的数据进行接下来的操作,就需要使用克隆了,Java语言中克隆针对的是类的实例。

如何实现克隆对象?

有两种方式:

  1. 实现Cloneable接口并重写Object类中的clone()方法。
  2. 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

深拷贝和浅拷贝区别是什么?

深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

servlet相关

session和cookie的区别?

  1. 存储位置不同:session 存储在服务器端;cookie 存储在浏览器端。
  2. 安全性不同:cookie 安全性一般,在浏览器存储,可以被伪造和修改。
  3. 容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。
  4. 存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器
    中。

说一下 session 的工作原理?

session 的工作原理是客户端登录完成之后,服务器会创建对应的 session,session 创建完之后,会把session 的 id 发客户端,客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着sessionid,服务器拿到 sessionid 之后,在内存找到与之对应的 session 这样就可以正常工作了。

如果客户端禁止 cookie 能实现 session 还能用吗?

可以用,session 只是依赖 cookie 存储 sessionid,如果 cookie 被禁用了,可以使用 url 中添加sessionid 的方式保证 session 能正常使用。

如何避免sql注入?

  1. 使用预处理 PreparedStatement。
  2. 使用正则表达式过滤掉字符中的特殊字符

什么是 XSS 攻击,如何避免?

XSS 攻击:即跨站脚本攻击,它是 Web 程序中常见的漏洞。原理是攻击者往 Web 页面里插入恶意的脚本代码(css 代码、Javascript 代码等),当用户浏览该页面时,嵌入其中的脚本代码会被执行,从而达到恶意攻击用户的目的,如盗取用户 cookie、破坏页面结构、重定向到其他网站等。
预防 XSS 的核心是必须对输入的数据做过滤处理。
真实项目中,我们会使用一个Filter对指定的特殊数据进行过滤。

什么是 CSRF 攻击,如何避免?

CSRF:Cross-Site Request Forgery(中文:跨站请求伪造),可以理解为攻击者盗用了你的身份,以你的名义发送恶意请求,比如:以你名义发送邮件、发消息、购买商品,虚拟货币转账等
避免:

  1. 验证请求来源地址
  2. 关键操作添加验证码;
  3. 在请求地址添加 token 并验证。

throw 和 throws 的区别?

  1. throw:是真实抛出一个异常
  2. throws:是声明可能会抛出一个异常。

final、finally、finalize 有什么区别?

  • final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,则表示此方法和此变量不能在被改变,只能使用
  • finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。
  • finalize:是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。

try-catch-finally 中哪个部分可以省略?

try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。

try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。

常见的异常类有哪些?

  1. NullPointerException 空指针异常
  2. ClassNotFoundException 指定类不存在
  3. NumberFormatException 字符串转换为数字异常
  4. IndexOutOfBoundsException 数组下标越界异常
  5. ClassCastException 数据类型转换异常
  6. FileNotFoundException 文件未找到异常
  7. NoSuchMethodException 方法不存在异常
  8. IOException IO 异常
  9. SocketException Socket 异常

http 响应码 301 和 302 代表的是什么?有什么区别?

  1. 301:永久重定向。
  2. 302:暂时重定向。
    它们的区别是,301 对搜索引擎优化(SEO)更加有利;302 有被提示为网络拦截的风险。

forward 和 redirect 的区别?

  1. forward 是转发,而redirect是重定向
  2. 地址栏 url 显示:foward url 不会发生改变,redirect url 会发生改变;
  3. 数据共享:forward 可以共享 request 里的数据,redirect 不能共享;
  4. 效率:forward 比 redirect 效率高。

简述 tcp 和 udp 的区别?

tcp 和 udp 是 OSI 模型中的运输层中的协议。tcp 提供可靠的通信传输,而 udp 则常被用于让广播和细节控制交给应用的通信传输。

  1. tcp 面向连接,udp 面向非连接即发送数据前不需要建立链接;
  2. tcp 提供可靠的服务(数据传输),udp 无法保证;
  3. tcp 面向字节流,udp 面向报文;
  4. tcp 数据传输慢,udp 数据传输快;

tcp 为什么要三次握手,两次不行吗?为什么?

如果采用两次握手,那么只要服务器发出确认数据包就会建立连接,但由于客户端此时并未响应服务器端的请求,那此时服务器端就会一直在等待客户端,这样服务器端就白白浪费了一定的资源。若采用三次握手,服务器端没有收到来自客户端的再此确认,则就会知道客户端并没有要求建立请求,就不会浪费服务器的资源。

说一下 tcp 粘包是怎么产生的?

tcp 粘包可能发生在发送端或者接收端,分别来看两端各种产生粘包的原因:

  1. 发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包;
  2. 接收方粘包:接收方不及时接收缓冲区的包,造成多个包接收。

OSI 的七层模型都有哪些?

  1. 物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
  2. 数据链路层:负责建立和管理节点间的链路。
  3. 网络层:通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。
  4. 传输层:向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。
  5. 会话层:向两个实体的表示层提供建立和使用连接的方法。
  6. 表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等
  7. 应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作。

get 和 post 请求有哪些区别?

  1. get 请求会被浏览器主动缓存,而 post 不会。
  2. get 传递参数有大小限制,而 post 没有。
  3. post 参数传输更安全,get 的参数会明文限制在 url 上,post 不会。

如何实现跨域?

  1. 服务器端运行跨域 设置 CORS 等于 *;
  2. 在单个接口使用注解 @CrossOrigin 运行跨域;
  3. 使用 jsonp 跨域;

说一下 JSONP 实现原理?

jsonp:JSON with Padding,它是利用 script 标签的 src 连接可以访问不同源的特性,加载远程返回的“JS 函数”来执行的

你可能感兴趣的:(java面试)