JAVA基础类面试问题

Q1:HashMap在JDK8实现原理

Tips:主要是说put、get、resize的过程

 

HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。Entry就是数组中的元素,每个 Map.Entry 其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表。

 

当Map的调用put方法的时候:

先判断table是否为空或数组长度为0,如果是则resize扩容。

接下来对Key计算hash值,然后计算下标。直接插入。

如果发生计算出来的hash值相等,也就是俗称的碰撞,会以链表方式连接在后面。

如果链表长度超过8,就把链表转成TreeNode,如果低于6,就把TreeNode转回链表。

如果节点已存在就直接覆盖。

当最后一次调整之后size大于临界值,再次扩容2倍后重排。

这里要说一下因为HashMap可以存放null的键值对,所以在key是空的情况下会自动分配hash也就是索引位置为0.这就意味着没有做hash操作,避免了NPE。

 

当Map的调用get方法的时候:

会调用hash方法获取hash值也就是bucket位置,找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

 

resize操作

也就是元素超过16*0.75 (16是数组默认大小,0.75是负载因子)也就是12的时候,就扩大到32,然后重新计算元素的位置,所以这个地方特别损耗性能,一般都会预设大小来解决。

resize在并发情况下是有缺陷的,当多个线程都需要扩容的时候,在扩容时会数组中的元素会倒序排列,要重新移动到bucket位置的时候,HashMap并不会将元素放在链表尾部,而是放在头部,这样就死循环了。所以说多线程并发的情况下不适用HashMap,改用ConcurrentHashMap。

 

Q2:ConcurrentHashMap实现原理

在jdk1.7之前是

在它的内部使用了一个叫Segment 架构,实际就类似于一个HashTable结构。

在获取元素时进行两次hash,一次是定位到Segment ,第二次定位到bucket,这样做的好处就是修改的时候不会像HashTable一样锁住整个数组,这个叫分段锁技术吧好像...

jdk1.8优化

跟HashMap很像,跟1.7之前比

取消segments,对table用volatile 修饰,实现对每一行数据加锁。

修改时直接用内置synchronized加锁。

 

 

Q2:Java线程池实现原理,线程池构的几个主要参数

三种线程池类型

newFixedThreadPool

newSingleThreadExecutor

newCachedThreadPool

1、首先判断线程池中核心线程池(corePoolSize)是否已经满了,如果不是,则创建新的线程来执行任务。

2、判断工作队列(BlockingQueue)是否满了,如果没有满,将线程放入队列。

3.、判断线程池里的线程是否都在工作,如果不是,则创建一个工作线程来执行任务,如果线程池满了,则交给饱和策略来处理任务。

4、 如果创建一个新的工作线程将使当前运行的线程数量超过maximumPoolSize,则交给RejectedExecutionHandler来处理任务

 

主要参数

int corePoolSize (核心线程数)

int maximumPoolSize(线程池中允许的最大线程数)

long keepAliveTime (线程空闲时的存活时间)

TimeUnit unit (keepAliveTime 的单位)

BlockingQueue<Runnable> workQueue (用来保存等待被执行的任务的阻塞队列)

RejectedExecutionHandler handler(线程池的饱和策略)

详解:https://blog.csdn.net/programmer_at/article/details/79799267

饱和策略

当队列和线程池都满了,说明线程池处于饱和状态,那么必须对新提交的任务采用一种特殊的策略来进行处理。这个策略默认配置是AbortPolicy,表示无法处理新的任务而抛出异常。JAVA提供了4中策略:

 

1、AbortPolicy:直接抛出异常

2、CallerRunsPolicy:只用调用所在的线程运行任务

3、DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。

4、DiscardPolicy:不处理,丢弃掉。

 

Q3: wait,sleep区别

最大区别:

sleep()睡眠时,保持对象锁,仍然占有该锁;其他线程无法访问

而wait()睡眠时,释放对象锁。其他线程可以访问

Q4:synchronized和volatile各自什么使用场景,两者什么区别。

 

在多线程中做判断的时候就可以用volatile来修饰标志位,还有就是计数器,

 

不同:

volatile不会造成线程阻塞。synchronized可能会造成线程阻塞

代码块、方法、类、静态方法用synchronized

volatile修饰变量,共享变量。

 

Q5: Java内存模型

所有的变量在主内存,每条线程有自己的工作内存。

工作内存又保存了该线程用到的主内存副本,线程对变量的所有操作都必须在工作内存中进行,而不能直接写入主存。

不同的线程之间也无法直接访问对方的工作内存中的变量,线程间变量的传递需要自己的工作内存和主存之间进行数据同步进行。

工作内存和主存之间数据同步的过程就是java的内存模型JMM。它规定了如何做数据同步以及什么时候做数据同步。

 

Q6:重入锁,读写锁,实现原理

重入锁:
就如同在饭堂打饭,你在窗口排着队。
排到你的时候,突然路人A让你顺带着打个饭吧,
然后你就打了两份饭,这时候你还没离开窗口,
又有路人B让你打一份汤,于是你又额外打了一份汤。
 
即:可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,
内层递归函数仍然有获取该锁的代码,但不受影响。
ReentrantLock和Synchronized都是可重入锁.

 

读写锁:
然而餐次的人流量一大,老板发现经常排起很长的队伍,厨师却都闲着没事干。
老板拍脑子一想,这样不行啊,所以稍微改进了一下点餐方式。
所有人都可以扫二维码用H页进行点餐,只要这个菜不是正在做(写锁),那么就可以随便点。
 
即:假设你的程序中涉及到对一些共享资源的读和写操作,
且写操作没有读操作那么频繁。在没有写操作的时候,
两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。
但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。

 

Q7:设计模式:单例有哪几种实现方式

1.饿汉式(线程安全,调用效率高,但是不能延时加载):

public class ImageLoader{ 
     private static ImageLoader instance = new ImageLoader; 
     private ImageLoader(){} 
     public static ImageLoader getInstance(){  
          return instance;  
      } 
}

2.懒汉式(线程安全,调用效率不高,但是能延时加载):

public class SingletonDemo2 {
    //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
    private static SingletonDemo2 instance;
    //构造器私有化
    private SingletonDemo2(){}
    //方法同步,调用效率低
    public static synchronized SingletonDemo2 getInstance(){
        if(instance==null){
            instance=new SingletonDemo2();
        }
        return instance;
    }
}

3.静态内部类实现模式(线程安全,调用效率高,可以延时加载)

public class SingletonDemo3 {
    private static class SingletonClassInstance{
        private static final SingletonDemo3 instance=new SingletonDemo3();
    }
    private SingletonDemo3(){}
 
    public static SingletonDemo3 getInstance(){
        return SingletonClassInstance.instance;
    }
 
}

4.枚举类(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用)

public enum SingletonDemo4 {
    //枚举元素本身就是单例
    INSTANCE;
    //添加自己需要的操作
    public void singletonOperation(){     
    }
}

 

Q8:mysql四个隔离级别,各自使用场景,幻读是什么,间隙锁是什么

 

mysql默认的事务隔离级别为repeatable-read 可重复读,原因是主从复制。

项目中一般使用读已提交!!!

项目中不用串行化和读未提交。首先读未提交逻辑上说不过去,串行化每次操作都加锁强一致性事务性能不佳。

为了便于描述,下面将

  • 可重复读(Repeatable Read),简称为RR;
  • 读已提交(Read Commited),简称为RC;

缘由一:在RR隔离级别下,存在间隙锁,导致出现死锁的几率比RC大的多!

缘由二:在RR隔离级别下,条件列未命中索引会锁表!而在RC隔离级别下,只锁行。

缘由三:在RC隔离级别下,半一致性读(semi-consistent)特性增加了update操作的并发性!

在RC级别下,不可重复读问题需要解决么?

不用解决,这个问题是可以接受的!毕竟你数据都已经提交了,读出来本身就没有太大问题!Oracle的默认隔离级别就是RC,你们改过Oracle的默认隔离级别么?

在RC级别下,主从复制用什么binlog格式?

OK,在该隔离级别下,用的binlog为row格式,是基于行的复制!Innodb的创始人也是建议binlog使用该格式!

 

  • 脏读:指一个线程中的事务读取到了另外一个线程中未提交的数据。
  • 不可重复读(虚读):指一个线程中的事务读取到了另外一个线程中提交的update的数据。
  • 幻读:指一个线程中的事务读取到了另外一个线程中提交的insert的数据。

 

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁,比如更新前100名抢到机位的考生设置优先选择权。这时候update的时候会加锁,防止幻读,

 

 

Q9 :mysql死锁的解释,如何避免

死锁分三种情况:

1.两个用户抢占资源,导致互相等待。

这种一般是程序的bug或者是业务逻辑上的错误造成的,解决办法就是多表操作时,尽量按照相同的顺序处理,尽量避免同时锁定两个资源,必须同时操作两张表时,应该保证任何时候都按照相同的顺序来锁表。

 

2、两个用户同时修改一条记录的时候。比如重复提交

一般是通过加版本号来比较。

 

3、执行了一条不满足条件的update语句,会造成全表扫描,行级锁上升到表级锁。数据量大或者是没有对应的索引,会一直阻塞,越来越慢最后死锁。

SQL语句中尽量不要使用太过于复杂的多表操作,加索引之类的

 

总体上来说,产生内存溢出与锁表都是由于代码写的不好造成的,因此提高代码的质量是最根本的解决办法。有的人认为先把功能实现,有BUG时再在测试阶段进 行修正,这种想法是错误的。正如一件产品的质量是在生产制造的过程中决定的,而不是质量检测时决定的,软件的质量在设计与编码阶段就已经决定了,测试只是 对软件质量的一个验证,因为测试不可能找出软件中所有的BUG。

 

Q10:数据库行锁,表锁,页锁

页级:引擎 BDB。

表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行

行级:引擎 INNODB , 单独的一行记录加锁

表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写操作。如果你是写锁,则其它进程则读也不允许

行级,,仅对指定的记录进行加锁,这样其它进程还是可以对同一个表中的其它记录进行操作。

页级,表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。

 

Q11:数据库结构B+树大致了解,说清楚索引的过程

B+Tree 是索引数据结构。

mysql的两种引擎都是使用了B+Tree索引数据结构。但是底层索引存储不同。

InnoDB聚集索引,数据文件和索引是绑定在一起的,必须要有主键(如果没有指定会自己找或者产生一个主键),通过主键索引效率很高,但是非主键索引需要查询两次,先查询到主键,然后通过主键查到数据,所以这也就是主键不要太大会导致其他索引都会变大。

MyISAM是非聚集索引,索引和数据文件是在一起的,索引保存的是数据文件的指针,查找过程中,如果指定的key存在,取到data,根据data和数据指针去查找相应的数据记录。

 

Q12: 悲观锁,乐观锁,CAS

悲观锁是一种独占锁,synchronized就是一种悲观锁,会导致其他需要锁的线程全部挂起,等它释放后才能继续进行。

乐观锁就是不加锁,只有在提交的时候判断是否有冲突,有冲突就失败,不断的自旋重试,直到成功为止。所以乐观锁会有自旋过多和ABA问题。

 

乐观锁得机制就是CAS,它的执行步骤是将指定位置的值和新值比较,如果相等则修改成新值,如果不相等就放弃修改。

ABA问题:

在并发下,有其他线程修改了值并且最终此值和原值相同,CAS是会忽略修改的历史。

比如:CAS目前值是1,修改成2,在修改前1被修改成3又修改成1,这是再执行CAS就会通过,程序是无法知道修改历史,如果只是数据自增这样的逻辑不用在乎ABA问题,但是如果业务逻辑需要关心是否被修改过就需要解决ABA问题,可以通过java的AtomicStampedReference解决。

自旋过多:

如果并发比较厉害,修改失败的几率就很大,自旋就会很多,会影响效率。

所以总体来说CAS适用于那些不太会发生冲突或者冲突不多的业务场景,如果并发概率还是很大就只能用悲观锁。

 

Q13: sso单点登录系统

项目中有做过sso,主要是兽医考试的管理后台,后续是根据农业部要求接入农业部综合管理服务平台,实现单点登录。

根据技术对接文档。实现单点登录主要是做两个操作,一是用户同步,从对方业务系统获取到用户信息后入库,同时在原先系统增加中间表于原先系统用户做关联,

二是开发单点登录接口,根据规定的好的参数和数字签名,去做业务跳转,根据用户中间表,做一次登录操作。

 

个人觉得sso单点登录的核心是保持用户认证和用户信任。达到免登陆的效果。

 

Q14: Elasticsearch

参考面试小结之Elasticsearch篇

 

框架类

Q15: 了解什么是服务治理,服务注册和发现的过程和原理

服务治理

当我们服务之间通讯的时候,前期一般都会暴露一个httpclient去请求,没有第三方管理,然后路径写死,我们一旦更换了路径,所有相关调用都会改变,维护的成本很高,这时候就需要将这些服务统一管理起来,后来就有了相关的组件比如zookeeper和springcloud中的Eureka,服务治理一般也会有引入相关的一些组件,比如springCloud的服务发现,负载均衡,统一配置,熔断器等。

服务注册

会有一个注册中心,当服务启动后,会根据相关配置,会把当前自己服务的一些信息,比如服务器通讯地址等以别名的方式注册到注册中心中,供调用。

服务发现

以别名的方式去注册中心上获取实际的通讯地址,然后实现调用。

 

原理和过程:拿springCloud说

当Eureka client 启动时,会将自身的一些信息发送到Eureka Server 中,然后调用当前服务器节点中的其他服务信息,保存在Eureka Client 中,当服务之前进行调用时,在Eureka Client获取服务信息比如地址端口映射,然后根据信息直接调用服务。

当某个服务仅需要调用其他服务,自身不在提供服务时,在EurekaClient启动后会拉取EurekaServer的其他服务信息,需要调用时在Client 的本地缓存中获取信息,调用服务。

Client和server之间通过发送心跳来监听是否可用,默认是30秒,超过90秒会被踢出注册中心,同时每隔30秒也会监听是否有更新。

 

Q16: 了解微服务系统有哪些主要点

服务注册和发现,负载均衡,API网关,统一配置管理,熔断限流降级防止雪崩,还有就是监控。

缓存,数据库横向扩展,

参考:https://www.jianshu.com/p/b92c2d5d5295

 

Q17: RabbitMQ 参考RabbitMQ面试题

 

Q18:如何提高RabbitMQ的消息可靠性

1、设置mandatory为true

2、设置publisher confirm机制保证消息发送

3、设置交换器。队列,消息都持久化防止消息丢失

4、设置消费端对于的antoAck为false并消费完成后手动确认。

5、还有就是TTL,死信队列,延迟队列,优先级队列等

 

Q19:一个分布式系统有哪些设计要点

三高。

高可用:容灾备份,可以扩展服务器数量,数据库做主备。过载保护,防止雪崩,服务拆分,比如微服务。

高性能:多地部署,异步调用,队列处理,缓存,对文件等一些数据进行压缩,批量处理

高并发:增加并发处理,负载均衡,集群

其他的比如 监控,

 

Q20:分布式系统之间如何保证数据完整性

1、业务逻辑保证幂等性,如果无法保证可以增加版本号或者加一个去重表。

2、有些业务不适合异步,就采用同步事务的方式。

 

Q21:分布式事务一般几种实现方式

分阶段提交

事务补偿

MQ

 

Q22: Paxos,BASE,CAP,区别

 

Q23: Spring依赖注入的实现,AOP实现

IoC(控制反转),将类的创建和依赖关系写在配置文件里,由配置文件注入,实现了松耦合

AOP 将安全,事务等于程序逻辑相对独立的功能抽取出来,利用spring的配置文件将这些功能插进去,实现了按照方面编程,提高了复用性

 

IOC实现

目前使用最广泛的 @Autowired:自动装配

spring.xml文件中声明bean

setter注入

 

AOP实现

Spring中AOP的有两种实现方式:

一种是采用声明的方式来实现(基于XML),一种是采用注解的方式来实现(基于AspectJ)。

采用声明的方式实现(在XML文件中配置),大致步骤为:配置文件中配置pointcut, 在java中用编写实际的aspect 类, 针对对切入点进行相关的业务处理。

采用注解来做aop, 主要是将写在spring 配置文件中的连接点写到注解里面。

 

Q24:Spring事务的原理,以及嵌套事务怎么处理

spring并没有直接管理事务,它提供了事务管理器来管理事务。

事务的一个概念是事务的传播行为,当事务被调用,必须指定该事务如何传播,可以在现有的事务中执行,或者开启一个新事物。

spring有7中事务传播行为

  •   PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  •   PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
  •   PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
  •   PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
  •   PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  •   PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
  •   PROPAGATION_NESTED--如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

Spring配置声明式事务:

* 配置DataSource

* 配置事务管理器

* 事务的传播特性

* 那些类那些方法使用事务

嵌套事务处理:把调用的方法放在另一个service中,配置事务隔离级别 requires_new

 

 

JVM

参考JVM面试题

bug shooting,检验实际线上问题处理

Q25: 如果出现cpu 100%是如何处理 --说清楚使用的一些linux命令。

top -c 命令查看进程情况

把占用最高的进程PID记下来 27269

top -Hp 27269 查看最耗cpu的线程

kill -9 27269 杀掉进程

 

Q26: 出现oom 内存溢出如何处理 --说清楚使用的一些linux命令。

1、通过命令查看对应的进程号 比如:jps 或者 ps -ef | grep servicemix

2、输入命令查看gc情况 命令:jstat -gcutil 进程号 刷新的毫秒数 展示的记录数

比如:jstat -gcutil 14050 1000 10 (查看进程号14050,每隔1秒获取下,展示10条记录)

3、查看具体占用情况:

(1)命令: jmap -histo 进程号 | more (默认展示到控制台)

(2)命令: jmap -histo 14050 | more > exceptionlog.txt (输出到当前目录的exceptionlog.txt文件)

比如:jmap -histo 14050 | more 查看具体的classname,是否有开发人员的类,也可以输出到具体文件分析

 

Q27: 了解处理问题时使用了哪些工具,

比如jProfiler,btrace等

 

架构设计类问题

Q28.如何设计一个秒杀系统,具体的思路,秒杀系统在处理高并发时候有哪些处理点

秒杀系统的难点或者说注意点有三个:高并发,超库存,性能

1、高并发可以做限流,熔断,可以使用springCloud 的hystrix。在核心的控制器层通过hystrix进行交易并发限流,当交易流量超出了我们设定的最大流量时,返回静态失败页面。

2、超库存。可以将库存数放到redis里,因为redis是单线程,线程安全就不用考虑了,在交易时实时扣减库存数和异步发送到消息队列中,有消息队列去处理数据库中的库存数量。

Q29.接口幂等性的几种处理方式,在实际项目中是如何处理的

新增、基于主键的更新、基于条件的更新、业务方面的逻辑删除都不具备幂等性。

http常用的方法中除了get也都不是幂等的。

 

处理幂等可以用全局唯一索引id,去重表,版本号,状态位判断。,

 

项目中订单微服务用了去重表,状态位,

根据第三方非税接口(每省对应一个非税基础表,存放一些非税相关信息,比如是否唯一订单,订单规则,提交地址等)

 

考生在第一次创建支付请求时,会根据报名的省份,判断是否唯一订单。

 

唯一订单:状态位

状态位有生成订单,支付中,支付成功。每次请求都会走一遍业务逻辑判断状态位。保证每个考生只有一笔订单支付成功!

 

不是唯一订单:去重表

每次创建支付请求都会生成一笔新的订单,会把订单插入订单表和考生ID做关联,这样会有重复缴费,等报名结束后会根据重复订单像第三方非税平台发起退费请求。

 

还有就是用悲观锁来实现。

 

Q30.设计一个分布式日志系统,用什么工具比较合适,

比如ELK

 

Q31.MySQL分库分表,规则,考虑,如何实现,维度问题、新老库表扩容问题

https://cloud.tencent.com/developer/article/1404798

mysql是做了集群

1、HAProxy作为负载均衡器

2、部署了2个mycat节点作为数据库中间件

3、部署了2个PXC集群节点,作为2个Mycat分片,每个PXC集群中有2个节点,作为数据的同步存储

4、部署了1个主从复制集群

5、数据库做了3从3主,主备同步

 

规则

垂直切分和水平切分。

按照不同业务分成不同的库,

字段多,数据量大的表可以将字段分开存到不同的表,然后表与表之间做关联,

还可以根据范围来存到不同的表里,比如0-10万一张表,10-20万一张表。

还可以按照地理区域来切分。华北,华东。。

还可以按照时间,比如6月份之前之后,做冷热数据分离。

 

考虑

分库分表就有分布式事务问题了。

可以做阶段提交,也可以使用队列来处理。

 

维度问题

假如用户购买了商品,需要将交易记录保存取来,如果按照用户的纬度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的 购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,可以很方便的查找到此商品的购买情况,但要查找 到买人的交易记录比较麻烦。

1、避免跨库事务

避免操作db01库的表同时修改db02库的表,操作复杂,效率有影响。

2、尽量把同一组业务数据放在同一个DB服务器

说避免数据库中的数据依赖另一数据库中的数据,万一其他库数据库挂了,现在这个数据库也有不能正常使用了。

3、一主多备

实际应用中,读大于写,mysql做读写分离,读都在master上,增加slave数量,但是数量越多,同步效率也越低,当slave数量达到一定量的时候必须考虑分库了。

 

新老表扩容

mycat可以实现

 

Q32: SQL如何优化

优化分两个方面: 设计优化和sql优化

设计:字段不要太多,使用合理的数据类型,尽量使用定长,建立合理的索引

SQL:

 

 

 

其他问题

Q33:版本迭代管理

svn git

Q34:设计模式--单例

特点:唯一实例,自己创建自己的唯一实例,必须给其他对象提供这一实例

作用:保证java程序中,一个Class只有一个实例存在。

形式:饿汉、懒汉,常量式,同步懒汉,双重检查锁DCL,静态内部类,枚举单例,

https://www.cnblogs.com/joy99/p/9859764.html

 

Q35: 用过哪些设计模式?

代理(Proxy)模式

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

观察者(Observer)模式

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖它的对象都会得到通知并自动更新。

外观(Facade)模式

外观模式针对复杂的子系统提供了单一的接口,不需要暴露一些列的类和API给用户,你仅仅公开一个简单统一的API。

装饰器(Decorator)模式

装饰器模式在不修改原来代码的情况下动态的给对象增加新的行为和职责,它通过一个对象包装被装饰对象的方法来修改类的行为,这种方法可以做为子类化的一种替代方法。

适配器(Adapter)模式

适配器可以让一些接口不兼容的类一起工作。它包装一个对象然后暴漏一个标准的交互接口。

备忘录(Memento)模式

备忘录模式快照对象的内部状态并将其保存到外部。换句话说,它将状态保存到某处,过会你可以不破坏封装的情况下恢复对象的状态,也就是说原来对象中的私有数据仍然是私有的。

 

Q36:加密解密,对称加密,非对称加密 举几个例子

(对称加密)AES、DES (非对称加密)RSA、DSA

非对称加密就比较特殊了。非对称加密存在着公钥和私钥,公钥是用来加密内容的,私钥是用来解密内容的。支付宝接口使用此方式。

对称加密,就是加解密用同一个秘钥。

Q37:https的工作原理

HTTPS中,对称加密与非对称加密都有用到的!

比如打开一个网站时,这时候网站会把对称加密钥匙发到浏览器,然后可以传输一些加密信息给网站。为了保障这个秘钥的安全,这里就用到了非对称加密。网站先把公钥发给浏览器,然后用自己的私钥加密对称加密的钥匙,再传输到浏览器,浏览器收到后,用公钥就可以解开消息了。

这里有个问题就是如果浏览器收到的公钥不是正在浏览的网站发来的呢?如果是黑客发来的这就有问题了。。

为了解决这个问题数字证书就出现了。。

数字证书由CA和其他机关颁发的公开秘钥证书,然后发送给浏览器时就知道这是谁发来的。

数字证书首先要网站把自己的公钥登录到CA

CA再用自己的公钥对网站的公钥进行签名,并颁发证书。

这样我们浏览网站就知道谁发来的公钥了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值