当前位置:网站首页 > Java基础 > 正文

面试会问java基础吗



java基础

1.一个java源文件中可以声明多个class类,但是只能有一个public类,而且其类名必须和源文件名称相同。

2.jdk = jre + java开发工具(javac,java,javadoc...);jre(java运行环境)= JVM + java核心类库。

3.break和continue默认跳出最近的一层循环。(return结束一个方法,并不是用来结束循环的)。

4.switch语句中default使用细节

  • default可以随意与case语句更换位置,不论在哪,都是最后被执行
  • default语句如果在所有case后面使用,则可以不用break语句
  • default语句如果在部分case之前,或在所有case之前,则建议在其语句中加如break语句。否则,执行完default语句后,会从上往下顺序执行case语句,知道遇到break语句,如果一直遇不到break语句,则执行完default下方所有的case语句。
  • default在同一switch语句中不可重复使用
  • 在case或default语句中定义的变量,只能被他们自己使用,不能被其他的case或default语句使用

5.String、StringBuffer与StringBuilder之间区别?(StringBuffer是线程安全的)

6.构造器得作用:【构造器不能被重写,可以被重载,因为构造器与类名相同

       1)创建对象  2)初始化对象得信息

7.java方法中参数传递机制的具体体现:

8.基本数据类型,包装类和String类型之间的数据转换?

9.代码块:

10.对属性可以赋值的先后顺序:

11.Error与Exception的区别?

          Exception: 可以预见到的异常情况,应该被捕获或者处理,在java中,分为检查异常(编译期)和不检查异常(运行期)。

          Error: 出现了错误系统不能正常运行或者恢复,一般情况不容易发生;

          共同点:都继承自Throwable,在java中只有Throwable的子类可以被Catch或者Throw;

12.成员变量、类变量(静态变量)、局部变量的区别?

  • 成员变量和局部变量的区别:

       成员变量:

          1、成员变量定义在类中,在整个类中都可以被访问。

          2、成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。

          3、成员变量有默认初始化值。

      局部变量:

          1、局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。

          2、局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。

          3、局部变量没有默认初始化值 

  • 成员变量和类变量的区别:

   1、两个变量的生命周期不同

      成员变量随着对象的创建而存在,随着对象的回收而释放。

      静态变量随着类的加载而存在,随着类的消失而消失。

   2、调用方式不同

      成员变量只能被对象调用。

      静态变量可以被对象调用,还可以被类名调用。

   4、数据存储位置不同

      成员变量存储在堆内存的对象中,所以也叫对象的特有数据。

      静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

13.==和equals的区别?

14.重写了equals方法为什么还要重写hashCode?

        重写了equals方法保证了两个对象相等,但是,hashCode不一定相等。java里规定,两个对象相等,其hashCode一定相等。为了避免在equals相等的条件下,出现hashCode值不相同的情况。所以我们在重写equals方法的同时要重写hashCode。像我们常用的hashSet都是根据hashCode值来判断是否相同的。

15.创建对象的几种方式?

  • 用new语句创建对象,这是最常用的创建对象的方式。
  • 运用反射手段,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
  • 调用对象的clone()方法。
  • 运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法.

16.linux最常用的命令?

linux最常用的20个命令_linux常用命令_JackPai的博客-CSDN博客

17.泛型

        指在类定义时不会设置类中的属性或方法参数的具体类型,而是在类使用时(创建对象)再进行类型的定义。会在编译期检查类型是否错误。

18.过滤器和拦截器区别

        过滤器和拦截器均体现了AOP的编程思想,都可以实现诸如日志记录、登录鉴权等功能。

1.区别:

  • 过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射
  • Filter依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用
  • 过滤器在请求进入容器后,在进入servlet之前进行预处理;拦截器在请求进入servlet后,在进入Controller之前进行预处理的
  • Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,拦截器可以获取IOC容器中的各个bean,而过滤器就不行

2.应用场景:

过滤器:

  • 过滤敏感词汇(防止sql注入)
  • 设置字符编码
  • URL级别的权限访问控制

拦截器:

  • 登录验证,判断用户是否登录。
  • 权限验证,判断用户是否有权限访问资源,如校验token
  • 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
  • 处理国际化、主题等。
  • 性能监控,监控请求处理时长等。
  • 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用

19.List去除重复数据的五种方式:

1.使用LinkedHashSet删除arraylist中的重复数据

  • 删除重复数据
  • 保持添加到其中的数据的顺序

2.使用java8新特性stream进行List去重

  • 使用steam的distinct()方法返回一个由不同数据组成的流

3.利用HashSet不能添加重复数据的特性,由于HashSet不能保证添加顺序,所以只能作为判断条件保证顺序

private static void removeDuplicate(List<String> list) {
    HashSet<String> set = new HashSet<String>(list.size());
    List<String> result = new ArrayList<String>(list.size());
    for (String str : list) {
        if (set.add(str)) {
            result.add(str);
        }
    }
    list.clear();
    list.addAll(result);
}

4.双重for循环去重

for (int i = 0; i < list.size(); i++) { 
    for (int j = 0; j < list.size(); j++) { 
        if(i!=j&&list.get(i)==list.get(j)) { 
            list.remove(list.get(j)); 
        }
    } 

5.利用List的contains方法循环遍历,重新排序,只添加一次数据,避免重复

private static void removeDuplicate(List<String> list) {
    List<String> result = new ArrayList<String>(list.size());
    for (String str : list) {
        if (!result.contains(str)) {
            result.add(str);
        }
    }
    list.clear();
    list.addAll(result);
}

内存及数组

内存的简化结构

        数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。(数组中堆的首地址值赋给栈,栈通过首地址值指向堆中的实体值)

1)栈是只能在某一端插入和删除的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。

2)在计算机科学中,堆是一种特殊的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。

​​

堆外内存

        堆外内存也叫直接内存,是机器的物理内存。使用native 函数库直接分配堆外内存,通过 DirectByteBuffer 对象作为这块内存的引用进行操作。通过设置 -XX:MaxDirectMemorySize=10M 控制堆外内存的大小,超过此内存则会报错。

优点:

  • 减少了垃圾回收的工作,因为堆外内存的释放不受虚拟机管理,真正的内存由操作系统释放
  • 省去了不必要的内存复制,实现zero copy

缺点:

  • 堆外内存难以控制,在发生内存泄漏的时候不易排查。谨慎使用。
  • 堆外内存相对来说,不适合存储很复杂的对象。一般则是放大块的内存。格式需要自己定义。

使用堆外内存场景:

  • 和nio有关的一些API需要使用堆外内存。操作系统内核直接把数据写到堆外内存里,不需要像普通API一样,操作系统内核缓存一份,程序读的时候再复制一份到程序空间,减少了复制的过程,提高了性能,Netty 就是这样做的。
  • 为业务专门调优的时候,比如一个连接批量申请1M给1000个小对象用,连接断开直接批量释放这1M内存,(如果对于GC那可是管理1000个对象的负担,GC不知道这1000个对象用完可以直接批量释放)。

数组排序

        排序算法分为内部算法和外部算法,比较重要的是冒泡排序,快速排序,堆排序和归并排序。数组的查找有线性查找和二分法查找。(二分法查找的前提是数组是有序的排列)

  • 选择排序:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零【时间复杂度:O(n^2)/空间复杂度:O(1)/稳定性:不稳定】
  • 快速排序:挖坑获取基准值,从右开始,小于基准值放坑位,再从左开始,大于基准值放坑位,然后循环【时间复杂度:O(n*logn)~O(n^2)之间】
  • 冒泡排序:从左到右,俩俩对比【时间复杂度:O(n^2)/空间复杂度:O(1)/稳定性:稳定】
  • 归并排序:先分解到个体,后合并进行排序【时间复杂度:O(n*logn)/空间复杂度:O(n)/稳定性:稳定】

重载与重写

1.重载与重写的区别:(https://www.cnblogs.com/ConstXiong/p/11862766.html)

访问权限修饰符

1.访问权限修饰符:(对于class的权限修饰只能用public和缺省)

关键字的使用

1.this的作用:(this理解为当前对象或者当前正在创建的对象)

2.super关键字:(理解为父类的,可以用来调用属性,方法,构造器)

1)调用属性和方法

 

2)调用构造器

3.static关键字的使用?

​​

4.final关键字的使用:

5.final,finally,finalize的区别?

https://www.cnblogs.com/ktao/p/8586966.html

6.abstract关键字的使用:(1.abstract不能用来修饰属性,构造器等...2.abstract不能用来修饰final修饰的类和方法,因为final修饰的类不能被继承,final修饰的方法不能被重写。也不面试会问java基础吗能用来修饰私有方法和静态方法,因为私有方法不能被重写,静态方法不算被重写)

7.接口的使用:(jdk8后,接口中定义的静态方法只能通过接口去调用,通过实现类的对象,可以调用接口中的普通方法,如果实现类重写的接口中的方法,则调用重写后的方法)

8.抽象类与接口的异同点是什么?

抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。所以,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。

区别:

  • 抽象类的修饰符是abstract ,接口的修饰符是interface 。另外对于实现的子类来说,有extends 和 implements  之分。
  • 接口中的方法必须是抽象方法,而抽象类中的方法可以不是抽象方法。(jdk8中可以定义静态方法和默认方法)
  • 接口可以多继承,抽象类不行
  • 接口定义方法,不能实现,而抽象类可以实现部分方法。

相同点:

  • 都不能实例化,都位于继承树的顶端,用于被其他类实现和实现
  • 都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必须重写这些抽象方法

mvc设计模式

java的三大特性

1.说说java的三大特性?

  1. 封装:隐藏具体的实现细节,对外暴露简单的使用方法,常见的实现方式就是:getter、setter。提高了安全性,可重用性,将比变化分离,便于使用;
  2. 继承:继承是类与类的一种关系,子类拥有父类的所有属性和方法(除了private修饰的属性不能拥有)从而实现了实现代码的复用;
  3. 多态:多态是具有表现多种形态的能力的特征,必须有继承关系;父类引用调用方法时,根据引用指向的对象决定调用父类定义的方法还是子类定义的方法,这体现了多态。调用方法时通过传递给它们的不同个数和类型的参数来决定具体使用哪个方法,这也体现了多态。

2.多态中为什么要使用向下转型?

https://www.cnblogs.com/insist-bin/p/11123064.html

常用设计模式

单例设计模式

1.单例设计模式分懒汉式和饿汉式,所谓例的单例设计模式就是采取一定的方法保证在整个系统中,对某个类只能存在一个实例对象。

1)其优点分别是:

2)区分懒汉式和饿汉式:

3.上代码:

工厂模式

1.工厂模式分为简单工厂模式,工厂方法模式,抽象工厂模式三种:

建造者模式

它将一个复杂的对象的构建过程和表示分离开来,使得同样的构建过程可以创建不同的表示;建造者模式主要由4部分组成:抽象建造者、具体建造者、指挥者和产品。其中,抽象建造者和具体建造者用于定义和实现产品的创建过程,指挥者协调建造者来构建产品,而产品则是最终构建出的对象。

策略模式

定义了一系列算法,将每个算法封装起来,并且使它们可以互换,让算法独立于使用它的客户端而变化;策略模式主要由三部分组成:策略接口、具体策略类和上下文类。策略接口定义了算法的统一接口,具体策略类实现了策略接口中定义的算法,而上下文类持有一个策略接口的引用,负责调用具体策略类中的算法。

观察者模式

也叫发布-订阅模式,它定义了对象之间一对多的依赖关系,使得当一个对象状态改变时,所有依赖它的对象都能收到通知并自动更新。观察者模式中,有两种类型的对象:观察者和被观察者。观察者将自己注册到被观察者,以便在被观察者的状态改变时接收通知。被观察者会维护一组观察者,并在自身状态改变时通知它们。被观察者通过调用观察者的统一接口来通知它们状态的变化。

多线程

创建多线程的方法

继承于Thread类,需要注意的是start()方法有俩个作用,一个是启动当前线程,一个是调用当前线程的run()方法,不能通过调用run()方法启动线程。其次,再启动一个线程不能让已经start()的线程去执行,需要重新创建一个线程对象。

实现Runnable接口

实现Callable接口

  1. 创建一个实现了Callable接口的类
  2. 实现类去实现Callable中的call()方法
  3. 创建实现类的对象
  4. 将此实现类的对象传递到futureTask构造器中,创建futureTask的对象
  5. 将futureTask对象传递到Thread类的构造器中,并创建Thread类的对象
  6. 通过Thread类的对象调用start()方法

使用线程池

线程池接执行步骤

  • 如果发现线程池中有空闲线程,则直接执行该任务;
  • 如果没有空闲线程,且当前运行的线程数少于corePoolSize,则创建新的线程执行该任务;
  • 如果没有空闲线程,且当前的线程数等于corePoolSize,同时阻塞队列未满,则将任务入队列,而不添加新的线程;
  • 如果没有空闲线程,且阻塞队列已满,同时池中的线程数小于maximumPoolSize ,则创建新的线程执行任务;
  • 如果没有空闲线程,且阻塞队列已满,同时池中的线程数等于maximumPoolSize,则根据构造函数中的 handler 指定的策略来拒绝新的任务。

线程池拒绝策略

  • AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
  • CallerRunsPolicy:如果任务被拒绝,由调用线程(提交任务的线程)处理该任务。
  • DiscardPolicy:丢弃任务,但是不抛出异常。
  • DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

如何判断线程池是否全部完成

  • isTerminated() 判断,在执行 shutdown() 关闭线程池后,循环判断是否所有任务已经完成。
  • ThreadPoolExecutor 的 getCompletedTaskCount() 方法,判断完成任务数和全部任务数是否相等。
  • CountDownLatch 计数器,使用闭锁计数来判断是否全部完成。【常用的方法有 countDown 和 await ,CountDownLatch 在初始化时,需要给定一个整数作为计数器。当调用 countDown 方法时,计数器会被减1;当调用 await 方法时,如果计数器大于0时,线程会被阻塞,一直到计数器被 countDown 方法减到0时,线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用 await 方法都会直接返回】

线程的生命周期

解决线程安全

同步代码块,同步方法,lock锁。

1.死锁的产生原因及解决办法?

https://www.cnblogs.com/JimmyFanHome/p/9914562.html

2.synchronized与Lock的区别?

相同点:二者皆时为了解决线程安全问题

不同点:

  • synchronized在执行完相应的同步代码后,会自动的释放同步监视器。而lock需要手动的启动同步(lock),同时结束也需要手动的实现(unlock);
  • lock只有代码块锁,而synchronized还有方法锁;
  • 使用lcok锁,JVM可以花费较少的时间去调度线程,性能更好。并且具有更好的扩展性;

3.volatile和synchronized的区别?

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

4.深挖ThreadLocal?(Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离)

ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocalMap是ThreadLocal类的一个静态内部类,它是实现数据隔离的关键。它是由key-value组成的一个entry数组,它的key就是ThreadLocal对象,value就是对应的线程变量副本。每个线程中都有一个独立的ThreadLocalMap副本,它所存储的值,只能被当前线程读取和修改。ThreadLocal类通过操作每一个线程特有的ThreadLocalMap副本,从而实现了变量访问在不同线程中的隔离。因为每个线程的变量都是自己特有的,完全不会有并发错误。同时因为entry继承了一个弱引用,继承之后只是对key进行了弱引用,value仍然是一个强引用。而弱引用是为了帮助我们更好的GC,下次就会出现key为null的entry,所以我们就没办法通过key去找到这个value,这个value又是强引用的,如果线程一直存在,那么就会造成内存泄露,而在调用ThreadLocal的get,set,remove方法时,都会对这个key为null的entry进行清除,把entry的value致为null,如果我们没有调用这些方法,则在使用完ThreadLocal后,手动的调用一下他的remove方法就可以了。

5.线程的基本控制方法:

interrupt()和stop()的区别?

  • 对于stop()方法,直接终止线程,释放线程所获的资源,但是在释放过程中会造成对象状态不一致,从而使程序进入未知的境地。
  • 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回。这里需要注意的是,如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行。

wait()与sleep()的区别?

集合

List

ArrayList添加的源码分析:

LinkedList添加的源码分析:

        LinkedList底层通过双向链表实现,双向链表的每个节点用内部类Node表示。LinkedList通过first和last引用分别指向链表的第一个和最后一个元素。

Vector添加的源码分析:

Set

hashset底层的源码分析

        HashSet底层其实是一个HashMap

Map

HashMap添加的源码分析:

HashMap和Hashtable的区别?

  1. 两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全;
  2. HashMap可以使用null作为key,而Hashtable则不允许null作为key;
  3. HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1;
  4. 两者计算hash的方法不同【Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模】【HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸】

CurrentHashMap的实现原理?

        CurrentHashMap的实现原理_currenthashmap原理_自由圣骑士的博客-CSDN博客

链表结构

        一种物理存储结构上非连续存储结构,由一系列节点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域;在一个链表中我们称链表的第一个节点为头节点用于存储链表的基地址,称链表的最后一个节点为尾节点,其next指针指向空地址

【 单链表、循环列表、双向链表、循环双向链表】

对象序列化机制与反序列化   

        序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。 为什么要把Java对象序列化呢?因为序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。 有序列化,就有反序列化,即把一个二进制内容(也就是byte[]数组)变回Java对象。有了反序列化,保存到文件中的byte[]数组又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。

反射机制

        在程序运行状态中,对于任意一个类或对象,都能够获取到这个类的所有属性和方法(包括私有属性和方法),这种动态获取信息以及动态调用对象方法的功能就称为反射机制。简单来讲,通过反射,类对我们是完全透明的,想要获取任何东西都可以。

  • 提供的功能:
  1. 在运行时能够判断任意一个对象所属的类
  2. 可以在程序运行过程中,操作这些对象;
  3. 可以解耦,提高程序的可扩展性。
  • 哪里用到反射机制

        jdbc中有一行代码:Class.forName('com.MySQL.jdbc.Driver.class').newInstance();那个时候只知道生成驱动对象实例,后来才知道,这就是反射.

  • 获取class实例的三种常见方式(同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个。)

  • 框架中的反射机制优点

        对于框架来说,已经对基础的代码进行了封装并提供相应的API。在框架的基础上进行软件开发,可以简化编码。但如果我们使用传统的new形式来实例化,那么当类更改时我们就要修改Java代码,这是很繁琐的。修改Java代码以后我们还要进行重新编译、测试、发布等一系列的操作。而如果我们仅仅只是修改配置文件,而不需要修改Java代码就简单的多。此外使用反射还能达到解耦的效果,如果我们使用的是new这种形式进行对象的实例化。此时如果在项目的某一个小模块中我们的一个实例类丢失了,那么在编译期间就会报错,会导致整个项目无法启动。而对于反射创建对象Class.forName(“全类名”)这种形式,我们在编译期需要的仅仅只是一个字符串(全类名),在编译期不会报错,这样其他的模块就可以正常的运行,而不会因为一个模块的问题导致整个项目崩溃。

maven

maven是一款服务于java平台的自动化构建工具。

  1. maven可以将一个项目拆分成多个工程;
  2. 借助maven可以将jar包仅仅存在与仓库中,有需要的工程直接引用这个文件接口,而不需要把jar包全部复制过来;
  3. 借助maven可以更规范的下载jar包,因为所有知名的框架或第三方的jar包已经按照统一的规范存放于maven的中央仓库;
  4. maven可以自动将被依赖的jar包导入进来;

网络通讯

TCP/IP协议三次握手和四次挥手

        https://www.cnblogs.com/lishiyuan/p/10296987.html

Cookie 和 Session 的区别

        HTTP是一种无状态协议,不会记录用户信息。服务器怎么判断发来HTTP请求的是哪个用户?于是,两种用于保持HTTP状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session。

  • Cookie:cookie 机制采用的是在客户端保持状态的方案,Cookie 是服务器生成的,但是发送给客户端,并且由客户端来保存。Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie,当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
  • Session:Session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 Session 保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是 Session。客户端浏览器再次访问时,只需要从该 Session 中查找该客户的状态就可以了。虽然 Session 保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为 Session 需要使用Cookie 作为识别标志。HTTP协议是无状态的,Session 不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为 JSESSIONID 的 Cookie,它的值为该 Session 的 id(即放在HTTP响应报文头部信息里的Set-Cookie)。Session依据该 Cookie 来识别是否为同一用户。

区别:

  1. Cookie 数据存放在客户的浏览器上,Session 数据放在服务器上;
  2. Cookie 不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用 Session ;
  3. Session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE;
  4. 单个Cookie 在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K;

TCP与UDP的区别

1.区别?

2.应用场景:

  • 对某些实时性要求比较高的情况使用UDP,比如游戏,媒体通信,实时直播
  • 其它大部分情况下,HTTP都是用TCP,因为要求传输的内容可靠,不出现丢失的情况

HTTP协议

        Http协议是对客户端和服务器端之间数据间实现可靠性的传输文字、图片、音频、视频等超文本数据的规范,简称为“超文本传输协议”,Http协议属于应用层。

1.TCP属于传输层,HTTP属于应用层,IP在网络层

2.http和https的区别:

  • HTTPS是基于SSL安全连接的HTTP协议,通过SSL提供的数据加密、身份验证和消息完整性验证等安全机制。为Web访问提供了安全性保证,广泛应用于网上银行、电子商务等领域。
  • 端口不一样,http是80,https443;
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议;

3.常见状态码

状态码 描述200:请求被正常处理301:永久性重定向302:临时重定向400:请求报文语法有误,服务器无法识别404:服务器无法找到对应资源500:服务器内部错误

SSL(Secure Socket Layer,安全套接字层)

        SSL用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。

1.对称加密与非对称加密

  • 对称密钥加密是指加密和解密使用同一个密钥,存在问题是密钥发送问题,即如何安全地将密钥发给对方,但有计算速度快的长处,通常使用于对大量信息进行加密;
  • 而非对称加密是指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。 不需要发送用来解密的私钥,所以可以保证安全性;但是只能实现单向加密,客户端没有解密能力,性能相对而言较差;

2.SSL协议实现的安全机制包含:

  • 传输数据的机密性:利用对称密钥算法对传输的数据进行加密。
  • 身份验证机制:基于证书利用数字签名方法对server和client进行身份验证,当中client的身份验证是可选的。
  • 消息完整性验证:消息传输过程中使用MAC算法来检验消息的完整性。

传输数据的机密性

        SSL采用在通信两方之间建立加密通道的方法保证传输数据的机密性,为了获得较优的性能,对话的内容用”对称加密”,而对于”对称加密”带来的密钥传输问题,则由”非对称加密”来解决,由于客户端没有”非对称加密”的解密能力,所以密钥由客户端来产生并用公钥加密传输给服务端,这样就(在思路上)解决了密钥传输的安全问题和对话数据解密的性能问题。注:利用PKI保证公钥的真实性,PKI通过数字证书来公布用户的公钥,并提供了验证公钥真实性的机制。数字证书(简称证书)是一个包括用户的公钥及其身份信息的文件,证明了用户与公钥的关联。

身份验证机制

        SSL利用数字签名来验证通信对端的身份。非对称密钥算法能够用来实现数字签名。因为通过私钥加密后的数据仅仅能利用相应的公钥进行解密,因此依据解密是否成功,就能够推断发送者的身份。如同发送者对数据进行了“签名”。比如。Alice使用自己的私钥对一段固定的信息加密后发给Bob,Bob利用Alice的公钥解密,假设解密结果与固定信息同样。那么就能够确认信息的发送者为Alice,这个过程就称为数字签名。SSLclient必须验证SSLserver的身份,SSLserver是否验证SSLclient的身份。则由SSLserver决定。

消息完整性验证

        为了避免网络中传输的数据被非法篡改,SSL利用基于MD5或SHA的MAC算法来保证消息的完整性。发送者在密钥的参与下,利用MAC算法计算出消息的MAC值。并将其加在消息之后发送给接收者。接收者利用相同的密钥和MAC算法计算出消息的MAC值。并与接收到的MAC值比较。假设二者相同。则报文没有改变;否则,报文在传输过程中被改动,接收者将丢弃该报文。

接口调用安全性

  • 使用MD5对参数进行加密,再通过解密获取到数据(对称加密算法)
  • 接口采用dto实现参数转化,同时对参数进行校验
  • 基于网关实现黑明单与白名单拦截
  • 使用https协议通过ssl保证接口安全(非对称加密算法)
  • 使用token,通过用户登录在服务端生成token返回给客户端保存,当再次访问时携带token,再服务端进行token有效性校验(ip+uid+时间戳)

跨域

1.什么是跨域?

        跨域就是当在页面上发送ajax请求时,由于浏览器同源策略的限制,要求当前页面和服务端必须同源,也就是协议、域名和端口号必须一致,如果协议、域名和端口号中有其中有一个不一致,则浏览器视为跨域,进行拦截。

2.解决方案

jsonp

        jsonp的原理就是利用了script标签不受浏览器同源策略的限制,然后和后端一起配合来解决跨域问题。jsonp的优点就是兼容性好,可以解决主流浏览器的跨域问题,缺点是仅支持GET请求,不安全,可能遭受xss(跨站脚本攻击)攻击。

CORS方式

        cors是跨域资源共享,是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它 origin(域,协议和端口),使得浏览器允许这些 origin 访问加载自己的资源。服务端设置了Access-Control-Allow-Origin就开启了CORS,所以这种方式只要后端实现了CORS,就解决跨域问题,前端不需要配置。

Websocket方式

        WebSocket本身不存在跨域问题,所以我们可以利用webSocket来进行非同源之间的通信

Nginx反向代理

        nginx通过反向代理解决跨域是利用了服务器请求服务器不受浏览器同源策略的限制实现的。客户端请求nginx服务器,在nginx.conf配置文件中配置server监听客户端的请求,然后把location匹配的路径代理到真实的服务器,服务器处理请求后返回数据,nginx再把数据给客户端返回

在这里插入图片描述

邮件发送

1.邮件收发原理

版权声明


相关文章:

  • 什么是java基础数据类型2024-10-23 17:26:06
  • java基础语法词汇2024-10-23 17:26:06
  • java基础教程第203讲2024-10-23 17:26:06
  • 零基础学java就业2024-10-23 17:26:06
  • java字符串基础题2024-10-23 17:26:06
  • java基础简单的项目2024-10-23 17:26:06
  • java期末考试考基础2024-10-23 17:26:06
  • 动力节点java学院零基础2024-10-23 17:26:06
  • java零基础取值2024-10-23 17:26:06
  • 毕向东java基础35天视频2024-10-23 17:26:06