• 关于

    非对称多处理是什么

    的搜索结果

问题

tomcat实现https过程的加密算法能修改么?

落地花开啦 2019-12-01 19:26:41 959 浏览量 回答数 0

回答

HTTPS基本原理 一、http为什么不安全。 http协议没有任何的加密以及身份验证的机制,非常容易遭遇窃听、劫持、篡改,因此会造成个人隐私泄露,恶意的流量劫持等严重的安全问题。 国外很多网站都支持了全站https,国内方面目前百度已经在年初完成了搜索的全站https,其他大型的网站也在跟进中,百度最先完成全站https的最大原因就是百度作为国内最大的流量入口,劫持也必然是首当其冲的,造成的有形的和无形的损失也就越大。关于流量劫持问题,我在另一篇文章中也有提到,基本上是互联网企业的共同难题,https也是目前公认的比较好的解决方法。但是https也会带来很多性能以及访问速度上的牺牲,很多互联网公司在做大的时候都会遇到这个问题:https成本高,速度又慢,规模小的时候在涉及到登录和交易用上就够了,做大以后遇到信息泄露和劫持,想整体换,代价又很高。 2、https如何保证安全 要解决上面的问题,就要引入加密以及身份验证的机制。 这时我们引入了非对称加密的概念,我们知道非对称加密如果是公钥加密的数据私钥才能解密,所以我只要把公钥发给你,你就可以用这个公钥来加密未来我们进行数据交换的秘钥,发给我时,即使中间的人截取了信息,也无法解密,因为私钥在我这里,只有我才能解密,我拿到你的信息后用私钥解密后拿到加密数据用的对称秘钥,通过这个对称密钥来进行后续的数据加密。除此之外,非对称加密可以很好的管理秘钥,保证每次数据加密的对称密钥都是不相同的。 但是这样似乎还不够,如果中间人在收到我的给你公钥后并没有发给你,而是自己伪造了一个公钥发给你,这是你把对称密钥用这个公钥加密发回经过中间人,他可以用私钥解密并拿到对称密钥,此时他在把此对称密钥用我的公钥加密发回给我,这样中间人就拿到了对称密钥,可以解密传输的数据了。为了解决此问题,我们引入了数字证书的概念。我首先生成公私钥,将公钥提供给相关机构(CA),CA将公钥放入数字证书并将数字证书颁布给我,此时我就不是简单的把公钥给你,而是给你一个数字证书,数字证书中加入了一些数字签名的机制,保证了数字证书一定是我给你的。 所以综合以上三点: 非对称加密算法(公钥和私钥)交换秘钥 + 数字证书验证身份(验证公钥是否是伪造的) + 利用秘钥对称加密算法加密数据 = 安全 3、https协议简介 为什么是协议简介呢。因为https涉及的东西实在太多了,尤其是一些加密算法,非常的复杂,对于这些算法面的东西就不去深入研究了,这部分仅仅是梳理一下一些关于https最基本的原理,为后面分解https的连接建立以及https优化等内容打下理论基础。 3.1 对称加密算法 对称加密是指加密和解密使用相同密钥的加密算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信至关重要。 对称加密又分为两种模式:流加密和分组加密。 流加密是将消息作为位流对待,并且使用数学函数分别作用在每一个位上,使用流加密时,每加密一次,相同的明文位会转换成不同的密文位。流加密使用了密钥流生成器,它生成的位流与明文位进行异或,从而生成密文。现在常用的就是RC4,不过RC4已经不再安全,微软也建议网络尽量不要使用RC4流加密。 分组加密是将消息划分为若干位分组,这些分组随后会通过数学函数进行处理,每次一个分组。假设需要加密发生给对端的消息,并且使用的是64位的分组密码,此时如果消息长度为640位,就会被划分成10个64位的分组,每个分组都用一系列数学公式公式进行处理,最后得到10个加密文本分组。然后,将这条密文消息发送给对端。对端必须拥有相同的分组密码,以相反的顺序对10个密文分组使用前面的算法解密,最终得到明文的消息。比较常用的分组加密算法有DES、3DES、AES。其中DES是比较老的加密算法,现在已经被证明不安全。而3DES是一个过渡的加密算法,相当于在DES基础上进行三重运算来提高安全性,但其本质上还是和DES算法一致。而AES是DES算法的替代算法,是现在最安全的对称加密算法之一。分组加密算法除了算法本身外还存在很多种不同的运算方式,比如ECB、CBC、CFB、OFB、CTR等,这些不同的模式可能只针对特定功能的环境中有效,所以要了解各种不同的模式以及每种模式的用途。这个部分后面的文章中会详细讲。 对称加密算法的优、缺点: 优点:算法公开、计算量小、加密速度快、加密效率高。 缺点:(1)交易双方都使用同样钥匙,安全性得不到保证; (2)每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。 (3)能提供机密性,但是不能提供验证和不可否认性。 3.2 非对称加密算法 在非对称密钥交换算法出现以前,对称加密一个很大的问题就是不知道如何安全生成和保管密钥。非对称密钥交换过程主要就是为了解决这个问题,使得对称密钥的生成和使用更加安全。 密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。 常见的密钥交换算法有RSA,ECDHE,DH,DHE等算法。涉及到比较复杂的数学问题,下面就简单介绍下最经典的RSA算法。RSA:算法实现简单,诞生于1977年,历史悠久,经过了长时间的破解测试,安全性高。缺点就是需要比较大的素数也就是质数(目前常用的是2048位)来保证安全强度,很消耗CPU运算资源。RSA是目前唯一一个既能用于密钥交换又能用于证书签名的算法。我觉得RSA可以算是最经典的非对称加密算法了,虽然算法本身都是数学的东西,但是作为最经典的算法,我自己也花了点时间对算法进行了研究,后面会详细介绍。 非对称加密相比对称加密更加安全,但也存在两个明显缺点: 1,CPU计算资源消耗非常大。一次完全TLS握手,密钥交换时的非对称解密计算量占整个握手过程的90%以上。而对称加密的计算量只相当于非对称加密的0.1%,如果应用层数据也使用非对称加解密,性能开销太大,无法承受。 2,非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是2048位,意味着待加密内容不能超过256个字节。 所以公钥加密(极端消耗CPU资源)目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。 3.3 身份认证 https协议中身份认证的部分是由数字证书来完成的,证书由公钥、证书主体、数字签名等内容组成,在客户端发起SSL请求后,服务端会将数字证书发给客户端,客户端会对证书进行验证(验证查看这张证书是否是伪造的。也就是公钥是否是伪造的),并获取用于秘钥交换的非对称密钥(获取公钥)。 数字证书有两个作用: 1,身份授权。确保浏览器访问的网站是经过CA验证的可信任的网站。 2,分发公钥。每个数字证书都包含了注册者生成的公钥(验证确保是合法的,非伪造的公钥)。在SSL握手时会通过certificate消息传输给客户端。 申请一个受信任的数字证书通常有如下流程: 1,终端实体(可以是一个终端硬件或者网站)生成公私钥和证书请求。 2,RA(证书注册及审核机构)检查实体的合法性。如果个人或者小网站,这一步不是必须的。 3,CA(证书签发机构)签发证书,发送给申请者。 4,证书更新到repository(负责数字证书及CRL内容存储和分发),终端后续从repository更新证书,查询证书状态等。 数字证书验证: 申请者拿到CA的证书并部署在网站服务器端,那浏览器发起握手接收到证书后,如何确认这个证书就是CA签发的呢。怎样避免第三方伪造这个证书。答案就是数字签名(digital signature)。数字签名是证书的防伪标签,目前使用最广泛的SHA-RSA(SHA用于哈希算法,RSA用于非对称加密算法)数字签名的制作和验证过程如下: 1,数字签名的签发。首先是使用哈希函数对待签名内容进行安全哈希,生成消息摘要,然后使用CA自己的私钥对消息摘要进行加密。 2,数字签名的校验。使用CA的公钥解密签名,然后使用相同的签名函数对待签名证书内容进行签名并和服务端数字签名里的签名内容进行比较,如果相同就认为校验成功。 需要注意的是: 1)数字签名签发和校验使用的密钥对是CA自己的公私密钥,跟证书申请者提交的公钥没有关系。 2)数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。 3)现在大的CA都会有证书链,证书链的好处一是安全,保持根CA的私钥离线使用。第二个好处是方便部署和撤销,即如果证书出现问题,只需要撤销相应级别的证书,根证书依然安全。 4)根CA证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的密钥对完成签名和验证的。 5)怎样获取根CA和多级CA的密钥对。它们是否可信。当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的公钥都默认装到了浏览器或者操作系统环境里。 3.4 数据完整性验证 数据传输过程中的完整性使用MAC算法来保证。为了避免网络中传输的数据被非法篡改,SSL利用基于MD5或SHA的MAC算法来保证消息的完整性。 MAC算法是在密钥参与下的数据摘要算法,能将密钥和任意长度的数据转换为固定长度的数据。发送者在密钥的参与下,利用MAC算法计算出消息的MAC值,并将其加在消息之后发送给接收者。接收者利用同样的密钥和MAC算法计算出消息的MAC值,并与接收到的MAC值比较。如果二者相同,则报文没有改变;否则,报文在传输过程中被修改,接收者将丢弃该报文。 由于MD5在实际应用中存在冲突的可能性比较大,所以尽量别采用MD5来验证内容一致性。SHA也不能使用SHA0和SHA1,中国山东大学的王小云教授在2005年就宣布破解了 SHA-1完整版算法。微软和google都已经宣布16年及17年之后不再支持sha1签名证书。MAC算法涉及到很多复杂的数学问题,这里就不多讲细节了。 专题二--【实际抓包分析】 抓包结果: fiddler: wireshark: 可以看到,百度和我们公司一样,也采用以下策略: (1)对于高版本浏览器,如果支持 https,且加解密算法在TLS1.0 以上的,都将所有 http请求重定向到 https请求 (2)对于https请求,则不变。 【以下只解读https请求】 1、TCP三次握手 可以看到,我们访问的是 http://www.baidu.com/ , 在初次建立 三次握手的时候, 用户是去 连接 8080端口的(因为公司办公网做了代理,因此,我们实际和代理机做的三次握手,公司代理机再帮我们去连接百度服务器的80端口) 2、CONNECT 建立 由于公司办公网访问非腾讯域名,会做代理,因此,在进行https访问的时候,我们的电脑需要和公司代理机做 " CONNECT " 连接(关于 " CONNECT " 连接, 可以理解为虽然后续的https请求都是公司代理机和百度服务器进行公私钥连接和对称秘钥通信,但是,有了 " CONNECT " 连接之后,可以认为我们也在直接和百度服务器进行公私钥连接和对称秘钥通信。 ) fiddler抓包结果: CONNECT之后, 后面所有的通信过程,可以看做是我们的机器和百度服务器在直接通信 3、 client hello 整个 Secure Socket Layer只包含了: TLS1.2 Record Layer内容 (1)随机数 在客户端问候中,有四个字节以Unix时间格式记录了客户端的协调世界时间(UTC)。协调世界时间是从1970年1月1日开始到当前时刻所经历的秒数。在这个例子中,0x2516b84b就是协调世界时间。在他后面有28字节的随机数( random_C ),在后面的过程中我们会用到这个随机数。 (2)SID(Session ID) 如果出于某种原因,对话中断,就需要重新握手。为了避免重新握手而造成的访问效率低下,这时候引入了session ID的概念, session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。 因为我们抓包的时候,是几个小时内第一次访问 https://www.baodu.com 首页,因此,这里并没有 Session ID. (稍会儿我们会看到隔了半分钟,第二次抓包就有这个Session ID) session ID是目前所有浏览器都支持的方法,但是它的缺点在于session ID往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。 (3) 密文族(Cipher Suites): RFC2246中建议了很多中组合,一般写法是"密钥交换算法-对称加密算法-哈希算法,以“TLS_RSA_WITH_AES_256_CBC_SHA”为例: (a) TLS为协议,RSA为密钥交换的算法; (b) AES_256_CBC是对称加密算法(其中256是密钥长度,CBC是分组方式); (c) SHA是哈希的算法。 浏览器支持的加密算法一般会比较多,而服务端会根据自身的业务情况选择比较适合的加密组合发给客户端。(比如综合安全性以及速度、性能等因素) (4) Server_name扩展:( 一般浏览器也支持 SNI(Server Name Indication)) 当我们去访问一个站点时,一定是先通过DNS解析出站点对应的ip地址,通过ip地址来访问站点,由于很多时候一个ip地址是给很多的站点公用,因此如果没有server_name这个字段,server是无法给与客户端相应的数字证书的,Server_name扩展则允许服务器对浏览器的请求授予相对应的证书。 还有一个很好的功能: SNI(Server Name Indication)。这个的功能比较好,为了解决一个服务器使用多个域名和证书的SSL/TLS扩展。一句话简述它的工作原理就是,在连接到服务器建立SSL连接之前先发送要访问站点的域名(Hostname),这样服务器根据这个域名返回一个合适的CA证书。目前,大多数操作系统和浏览器都已经很好地支持SNI扩展,OpenSSL 0.9.8已经内置这一功能,据说新版的nginx也支持SNI。) 4、 服务器回复(包括 Server Hello, Certificate, Certificate Status) 服务器在收到client hello后,会回复三个数据包,下面分别看一下: 1)Server Hello 1、我们得到了服务器的以Unix时间格式记录的UTC和28字节的随机数 (random_S)。 2、Seesion ID,服务端对于session ID一般会有三种选择 (稍会儿我们会看到隔了半分钟,第二次抓包就有这个Session ID) : 1)恢复的session ID:我们之前在client hello里面已经提到,如果client hello里面的session ID在服务端有缓存,服务端会尝试恢复这个session; 2)新的session ID:这里又分两种情况,第一种是client hello里面的session ID是空值,此时服务端会给客户端一个新的session ID,第二种是client hello里面的session ID此服务器并没有找到对应的缓存,此时也会回一个新的session ID给客户端; 3)NULL:服务端不希望此session被恢复,因此session ID为空。 3、我们记得在client hello里面,客户端给出了21种加密族,而在我们所提供的21个加密族中,服务端挑选了“TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”。 (a) TLS为协议,RSA为密钥交换的算法; (b) AES_256_CBC是对称加密算法(其中256是密钥长度,CBC是分组方式); (c) SHA是哈希的算法。 这就意味着服务端会使用ECDHE-RSA算法进行密钥交换,通过AES_128_GCM对称加密算法来加密数据,利用SHA256哈希算法来确保数据完整性。这是百度综合了安全、性能、访问速度等多方面后选取的加密组合。 2)Certificate 在前面的https原理研究中,我们知道为了安全的将公钥发给客户端,服务端会把公钥放入数字证书中并发给客户端(数字证书可以自签发,但是一般为了保证安全会有一个专门的CA机构签发),所以这个报文就是数字证书,4097 bytes就是证书的长度。 我们打开这个证书,可以看到证书的具体信息,这个具体信息通过抓包报文的方式不是太直观,可以在浏览器上直接看。 (点击 chrome 浏览器 左上方的 绿色 锁型按钮) 3)Server Hello Done 我们抓的包是将 Server Hello Done 和 server key exchage 合并的包: 4)客户端验证证书真伪性 客户端验证证书的合法性,如果验证通过才会进行后续通信,否则根据错误情况不同做出提示和操作,合法性验证包括如下: 证书链的可信性trusted certificate path,方法如前文所述; 证书是否吊销revocation,有两类方式离线CRL与在线OCSP,不同的客户端行为会不同; 有效期expiry date,证书是否在有效时间范围; 域名domain,核查证书域名是否与当前的访问域名匹配,匹配规则后续分析; 5)秘钥交换 这个过程非常复杂,大概总结一下: (1)首先,其利用非对称加密实现身份认证和密钥协商,利用非对称加密,协商好加解密数据的 对称秘钥(外加CA认证,防止中间人窃取 对称秘钥) (2)然后,对称加密算法采用协商的密钥对数据加密,客户端和服务器利用 对称秘钥 进行通信; (3)最后,基于散列函数验证信息的完整性,确保通信数据不会被中间人恶意篡改。 此时客户端已经获取全部的计算协商密钥需要的信息:两个明文随机数random_C和random_S与自己计算产生的Pre-master(由客户端和服务器的 pubkey生成的一串随机数),计算得到协商对称密钥; enc_key=Fuc(random_C, random_S, Pre-Master) 6)生成 session ticket 如果出于某种原因,对话中断,就需要重新握手。为了避免重新握手而造成的访问效率低下,这时候引入了session ID的概念, session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。 因为我们抓包的时候,是几个小时内第一次访问 https://www.baodu.com 首页,因此,这里并没有 Session ID. (稍会儿我们会看到隔了半分钟,第二次抓包就有这个Session ID) session ID是目前所有浏览器都支持的方法,但是它的缺点在于session ID往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。 后续建立新的https会话,就可以利用 session ID 或者 session Tickets , 对称秘钥可以再次使用,从而免去了 https 公私钥交换、CA认证等等过程,极大地缩短 https 会话连接时间。 7) 利用对称秘钥传输数据 【半分钟后,再次访问百度】: 有这些大的不同: 由于服务器和浏览器缓存了 Session ID 和 Session Tickets,不需要再进行 公钥证书传递,CA认证,生成 对称秘钥等过程,直接利用半分钟前的 对称秘钥 加解密数据进行会话。 1)Client Hello 2)Server Hello

玄学酱 2019-12-02 01:27:08 0 浏览量 回答数 0

回答

首先,先回答什么是加密; “数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的密钥之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。” 其次,区块链中的加密算法有很多,比如常见的对称加密、非对称加密、哈希等。最近比较火的还有对于交易/内容的隐私保护,如环签名、零知识证明、同态加密、安全多方计算、Intel SGX等。 最后,在区块链中的作用就是保护数据不被非法窃取,保护用户的隐私不被泄露等。

游客xbsj4nm3gkm44 2020-03-30 09:49:56 0 浏览量 回答数 0

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

回答

已经用 重写MappingJackson2HttpMessageConverter 的read方法处理啦,谢谢各位######非对称加密,如 RSA 加密,浏览器用服务器端的公钥进行加密,服务器端用自己的私钥进行解密。###### 引用来自“公孙二狗”的评论 非对称加密,如 RSA 加密,浏览器用服务器端的公钥进行加密,服务器端用自己的私钥进行解密。 不好意思,我描述的有问题,我的意思是说,当加密的请求过来后,如何把对象里面的字段值进行解密! 例如houseRequest对象里面 有 字段addr=1231,假如请求过来的是 addr = [加密字符串],把addr 加密的字符串 解密城1231;######写个拦截器做这件事###### 引用来自“公孙二狗”的评论 非对称加密,如 RSA 加密,浏览器用服务器端的公钥进行加密,服务器端用自己的私钥进行解密。 引用来自“sanshao”的评论 不好意思,我描述的有问题,我的意思是说,当加密的请求过来后,如何把对象里面的字段值进行解密! 例如houseRequest对象里面 有 字段addr=1231,假如请求过来的是 addr = [加密字符串],把addr 加密的字符串 解密城1231; 考虑啦这个方式,但是这个方式不太适合,我现在有多个controller类,这个方法里面是:HouseRequest houseRequest对象,另一个controller中定义的是 SiteSearchRequest 等等很多类,如果用过滤器获取的值为:Object对象,要对所有的XXXRequest对象进行 instanceof 判断一遍,然后才能强制转换成该类,参数解密,再进行下一步操作,因为每一个XX Request类的参数都不一样,感觉这样写太麻烦啦!所以想看看有什么更好的办法吗?######写拦截器比较好###### 引用来自“漆黑的烈焰使”的评论 写拦截器比较好 我想的是重写 Spring中的MappingJackson2HttpMessageConverter ,但是当前没有思路,不知道是否研究过这样的方式?######我们之前是用过滤器,把加密属性解密后传到对应的方法里,跟你这个类似###### 引用来自“尚浩宇”的评论 我们之前是用过滤器,把加密属性解密后传到对应的方法里,跟你这个类似 其实过滤器我后面事实看看,本来打算用切面的,但是切面获取传入的对象用的方式是:Object[] getArgs() 用joinpoint.getArgs() 获取的时候,他是根据controller中定义的参数来确定具体哪一个才是你想要的;比如:我们上面的方式获取的就是 args request对象 args response对象 args才是 自定义的对象,如果调换位置,获取的第几个参数数也相应的有变化,不够灵活所以才更改为这个办法!######好吧,适合自己的才是好的

kun坤 2020-05-29 12:16:07 0 浏览量 回答数 0

回答

先说一些基础的东东吧,加密和解密是为了信息在传递过程中被他人知晓,对明文所做的混淆,看你举的这个场景,我感觉你对加密这一套的理解还有些欠缺。再多在网上学习一下吧。不过大体上也可以回答你的两个问题。 Q:比如一个系统我要加密用户密码,是不是我整个系统只需要一对公匙私匙?还是每个密码要一对 A: 不管是对称加密算法如AES的密钥(一个)还是非对称加密算法RSA的密钥(一对), 当然只需要一个(一对),要多个也没有意义,因为一个(一对)已经安全了哈。 Q: 然后数据库是保持加密得到的byte二进制数组吗还是保存什么,时应该前台页面用公匙把密码加密吗? A: 当然是保存密文,反正看起来是乱码,当然你理解成BYTE数组也行。因为你选的是RSA一对密钥,所以你任选一个来加密,另一个解密就行了。 ######非常感谢######保存密码请用单向散列函数,不要用任何可逆算法,即使被爆库也拿不到明文。RSA主要的作用是防止消息被篡改,具体应用可以百度,存密码侧重的是防止明文暴露。######这个场景只是举例,主要是后面那几个问题啊。求大神指点指点######你的应用场景用散列就行,没必要可逆。 ######这个场景只是举例,主要是后面那几个问题啊。求大神指点######系统用户的加密是用的是MD5加密,然后存入数据库,用户登录的时候就将用户输入的密码MD5加密然后和数据库的数据比对,如果相同就登录成功######像 散列(HASH)这种映射算法,仅仅是为了不明文保存数据而已,是不可逆的,不能从密文(映射值)中还原出明文。所以它也不应该归为加密算法一类。 ######密码用 md5 处理是绝对错误的,应该用 bcrypt 或者 scrypt ######绝对。即使加 salt 的 md5 也是极度不可靠的。 建议使用 bcrypt,用得很广。scrypt 更强,但相关的密码学分析还不多。######这么绝对么。。 你说那两种我都没接触过。

kun坤 2020-06-03 11:21:02 0 浏览量 回答数 0

回答

介绍了Amazon S3 使用的认证: http://dodomail.iteye.com/blog/1744389 ######这个很简单啊,把所有参数都做一次加密就是,秘钥你来生成授权给你的下游就是了,后台再做记录ip的的功能,这样谁请求你的API了就都知道了,自己实现也很快的######tokening,或者id这些加密,获取后再解密,密钥自己生成。就是加个验证的key值就可以吧,每次提交数据验证key的正确性###### 做一个认证服务,提供一个认证的webapi,用户先访问它获取token,然后拿着token去访问所有的webapi。每次接收到请求就拿着token找认证服务寻求验证。验证通过则papapa,不然就404。 你要说的是这种么?还是对访问做验证限制? ######回复 @devilsitan : 也是啊,那你再看看刚刚问的第二个问题######@liujiduo tomcat只是个web服务器。。不明白为什么和它要有关呢。。webapi又不是在tomcat上跑的。######回复 @devilsitan : 还有就是这种给webapi加token认证的方式,应该是我事先给某些指定的APP(比如我的iOS客户端或安卓客户端)发放私钥,然后它们根据私钥获取token。那如果我的网站前端通过ajax访问这些api是不是也需要通过token认证呢?如果是的话那不就会暴露出私钥了吗?先谢谢啦^_^######回复 @devilsitan : 那另一种 基于HTTP Digest认证的方式也是只用代码实现,不需要修改tomcat的配置吗?######@liujiduo 那这种和服务器就没多大关系了啥。。只要你有webapi服务在就行,什么访问都是通过HTTP来请求的。接口也很简单一个认证,一个验证。认证服务内部看你怎么设计,要么是简单的用户-权限,要么是用户-角色-权限,要么是带约束的用户-角色-权限,还有更加灵活的二者皆有,采取优先拒绝。###### 引用来自“devilsitan”的评论 做一个认证服务,提供一个认证的webapi,用户先访问它获取token,然后拿着token去访问所有的webapi。每次接收到请求就拿着token找认证服务寻求验证。验证通过则papapa,不然就404。 你要说的是这种么?还是对访问做验证限制? 肯定是要带Token的,访问还是用户名密码,认证通过cookie里存的就是用户名和token,token是有有效期的,过了有效期你就需要重新分配一个token。这个暴露问题,我也不知道肿么办,不过人家要存心搞你,这些还有用么。你看Digest还不是私钥放在cookie里,虽然用算法加密一次和服务器比对,人家只需要截下你的包,把加密后的验证字符拿去验证就是了。我没看出什么区别######回复 @liujiduo : 可以参考上面的那位给的亚马逊s3的rest api认证。也可以看下openstack的keystone的验证模式。都是一个令牌,就看你怎么用和。简单的就是我前面说的那样,复杂的更安全的就是他们那样。######明白了,谢谢!###### 顶 ######ajax的时候检测客户端用户权限不可以吗?###### Http Digest认证也就是防止重放攻击,如果是局域网项目感觉对认证的要求不用太高,主要还是网络安全和访问的监控和预警,要是互联网的觉得还是非对称签名比较安全,存粹算法决定。###### 引用来自“HandMU”的评论ajax的时候检测客户端用户权限不可以吗? 用户权限是跟用户绑定的,而客户端访问接口可能没有用户的概念,这样就不合适了啊######回复 @HandMU : 你没明白他意思,webapi,可能是非本系统用户######可参考open auth######回复 @liujiduo : 都会有基于用户权限检测的。你钻到死角了。######回复 @HandMU : 是啊,难道对于webapi的安全认证就没有一个好的办法么?不知道淘宝这些网站是怎么做的######ajax理论上还是post、get,依然带上所有你能使用的用户信息。###### 引用来自“刘敬伟”的评论 Http Digest认证也就是防止重放攻击,如果是局域网项目感觉对认证的要求不用太高,主要还是网络安全和访问的监控和预警,要是互联网的觉得还是非对称签名比较安全,存粹算法决定。 不是局域网项目,我是想让某些数据敏感的接口只能被已授权的客户端访问,而不是让别人只要知道了url就能恶意请求和操纵我的接口,我查了Http Basic和Http Digest的认证流程,但就是不清楚怎么应用到项目中来。######我觉得你的思路有点混乱,没搞清楚到底认证什么,怎么认证,认证力度如何。这些都要根据你的网络环境、服务器系统、还有你处理的数据类型有关系。如果不想用第三方安全策略,我建议采用非对称的安全算法,针对用户信息最签名和验证。在这个基础上对你接口接收的用户请求进行监控,如果有必要的话你接收的数据要进行过滤,就像支付宝也不是实时到账,中间肯定有一个审核数据的再次分发的缓冲处理机制。

kun坤 2020-06-02 15:55:28 0 浏览量 回答数 0

回答

" 介绍了Amazon S3 使用的认证: http://dodomail.iteye.com/blog/1744389 ######这个很简单啊,把所有参数都做一次加密就是,秘钥你来生成授权给你的下游就是了,后台再做记录ip的的功能,这样谁请求你的API了就都知道了,自己实现也很快的######tokening,或者id这些加密,获取后再解密,密钥自己生成。就是加个验证的key值就可以吧,每次提交数据验证key的正确性###### 做一个认证服务,提供一个认证的webapi,用户先访问它获取token,然后拿着token去访问所有的webapi。每次接收到请求就拿着token找认证服务寻求验证。验证通过则papapa,不然就404。 你要说的是这种么?还是对访问做验证限制? ######回复 @devilsitan : 也是啊,那你再看看刚刚问的第二个问题###### @liujiduo tomcat只是个web服务器。。不明白为什么和它要有关呢。。webapi又不是在tomcat上跑的。######回复 @devilsitan : 还有就是这种给webapi加token认证的方式,应该是我事先给某些指定的APP(比如我的iOS客户端或安卓客户端)发放私钥,然后它们根据私钥获取token。那如果我的网站前端通过ajax访问这些api是不是也需要通过token认证呢?如果是的话那不就会暴露出私钥了吗?先谢谢啦^_^######回复 @devilsitan : 那另一种 基于HTTP Digest认证的方式也是只用代码实现,不需要修改tomcat的配置吗?###### @liujiduo 那这种和服务器就没多大关系了啥。。只要你有webapi服务在就行,什么访问都是通过HTTP来请求的。接口也很简单一个认证,一个验证。认证服务内部看你怎么设计,要么是简单的用户-权限,要么是用户-角色-权限,要么是带约束的用户-角色-权限,还有更加灵活的二者皆有,采取优先拒绝。###### 引用来自“devilsitan”的评论 做一个认证服务,提供一个认证的webapi,用户先访问它获取token,然后拿着token去访问所有的webapi。每次接收到请求就拿着token找认证服务寻求验证。验证通过则papapa,不然就404。 你要说的是这种么?还是对访问做验证限制? 肯定是要带Token的,访问还是用户名密码,认证通过cookie里存的就是用户名和token,token是有有效期的,过了有效期你就需要重新分配一个token。这个暴露问题,我也不知道肿么办,不过人家要存心搞你,这些还有用么。你看Digest还不是私钥放在cookie里,虽然用算法加密一次和服务器比对,人家只需要截下你的包,把加密后的验证字符拿去验证就是了。我没看出什么区别######回复 @liujiduo : 可以参考上面的那位给的亚马逊s3的rest api认证。也可以看下openstack的keystone的验证模式。都是一个令牌,就看你怎么用和。简单的就是我前面说的那样,复杂的更安全的就是他们那样。######明白了,谢谢!###### 顶 ######ajax的时候检测客户端用户权限不可以吗?###### Http Digest认证也就是防止重放攻击,如果是局域网项目感觉对认证的要求不用太高,主要还是网络安全和访问的监控和预警,要是互联网的觉得还是非对称签名比较安全,存粹算法决定。###### 引用来自“HandMU”的评论ajax的时候检测客户端用户权限不可以吗? 用户权限是跟用户绑定的,而客户端访问接口可能没有用户的概念,这样就不合适了啊######回复 @HandMU : 你没明白他意思,webapi,可能是非本系统用户######可参考open auth######回复 @liujiduo : 都会有基于用户权限检测的。你钻到死角了。######回复 @HandMU : 是啊,难道对于webapi的安全认证就没有一个好的办法么?不知道淘宝这些网站是怎么做的######ajax理论上还是post、get,依然带上所有你能使用的用户信息。###### 引用来自“刘敬伟”的评论 Http Digest认证也就是防止重放攻击,如果是局域网项目感觉对认证的要求不用太高,主要还是网络安全和访问的监控和预警,要是互联网的觉得还是非对称签名比较安全,存粹算法决定。 不是局域网项目,我是想让某些数据敏感的接口只能被已授权的客户端访问,而不是让别人只要知道了url就能恶意请求和操纵我的接口,我查了Http Basic和Http Digest的认证流程,但就是不清楚怎么应用到项目中来。######我觉得你的思路有点混乱,没搞清楚到底认证什么,怎么认证,认证力度如何。这些都要根据你的网络环境、服务器系统、还有你处理的数据类型有关系。如果不想用第三方安全策略,我建议采用非对称的安全算法,针对用户信息最签名和验证。在这个基础上对你接口接收的用户请求进行监控,如果有必要的话你接收的数据要进行过滤,就像支付宝也不是实时到账,中间肯定有一个审核数据的再次分发的缓冲处理机制。"

montos 2020-06-03 22:34:05 0 浏览量 回答数 0

问题

【精品问答】110+数据挖掘面试题集合

珍宝珠 2019-12-01 21:56:45 2713 浏览量 回答数 3

问题

【精品问答】python技术1000问(2)

问问小秘 2019-12-01 22:03:02 3129 浏览量 回答数 1

回答

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 [编辑本段]基本概念 * 若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数(Hash function),按这个思想建立的表为散列表。 * 对不同的关键字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),这种现象称冲突。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数H(key)和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象” 作为记录在表中的存储位置,这种表便称为散列表,这一映象过程称为散列造表或散列,所得的存储位置称散列地址。 * 若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突。 [编辑本段]常用的构造散列函数的方法 散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位ǐ 1. 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a•key + b,其中a和b为常数(这种散列函数叫做自身函数) 2. 数字分析法 3. 平方取中法 4. 折叠法 5. 随机数法 6. 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。 [编辑本段]处理冲突的方法 1. 开放寻址法:Hi=(H(key) + di) MOD m, i=1,2,…, k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法: 1. di=1,2,3,…, m-1,称线性探测再散列; 2. di=1^2, (-1)^2, 2^2,(-2)^2, (3)^2, …, ±(k)^2,(k<=m/2)称二次探测再散列; 3. di=伪随机数序列,称伪随机探测再散列。 == 2. 再散列法:Hi=RHi(key), i=1,2,…,k RHi均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间。 3. 链地址法(拉链法) 4. 建立一个公共溢出区 [编辑本段]查找的性能分析 散列表的查找过程基本上和造表过程相同。一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。在介绍的三种处理冲突的方法中,产生冲突后的查找仍然是给定值与关键码进行比较的过程。所以,对散列表查找效率的量度,依然用平均查找长度来衡量。 查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。影响产生冲突多少有以下三个因素: 1. 散列函数是否均匀; 2. 处理冲突的方法; 3. 散列表的装填因子。 散列表的装填因子定义为:α= 填入表中的元素个数 / 散列表的长度 α是散列表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。 实际上,散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。 了解了hash基本定义,就不能不提到一些著名的hash算法,MD5 和 SHA-1 可以说是目前应用最广泛的Hash算法,而它们都是以 MD4 为基础设计的。那么他们都是什么意思呢? 这里简单说一下: (1) MD4 MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。 (2) MD5 MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好 (3) SHA-1 及其他 SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。 那么这些Hash算法到底有什么用呢? Hash算法在信息安全方面的应用主要体现在以下的3个方面: (1) 文件校验 我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。 MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。 (2) 数字签名 Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。 对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。 (3) 鉴权协议 如下的鉴权协议又被称作挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。 MD5、SHA1的破解 2004年8月17日,在美国加州圣芭芭拉召开的国际密码大会上,山东大学王小云教授在国际会议上首次宣布了她及她的研究小组近年来的研究成果——对MD5、HAVAL-128、MD4和RIPEMD等四个著名密码算法的破译结果。 次年二月宣布破解SHA-1密码。 [编辑本段]实际应用 以上就是一些关于hash以及其相关的一些基本预备知识。那么在emule里面他具体起到什么作用呢? 大家都知道emule是基于P2P (Peer-to-peer的缩写,指的是点对点的意思的软件), 它采用了"多源文件传输协议”(MFTP,the Multisource FileTransfer Protocol)。在协议中,定义了一系列传输、压缩和打包还有积分的标准,emule 对于每个文件都有md5-hash的算法设置,这使得该文件独一无二,并且在整个网络上都可以追踪得到。 什么是文件的hash值呢? MD5-Hash-文件的数字文摘通过Hash函数计算得到。不管文件长度如何,它的Hash函数计算结果是一个固定长度的数字。与加密算法不同,这一个Hash算法是一个不可逆的单向函数。采用安全性高的Hash算法,如MD5、SHA时,两个不同的文件几乎不可能得到相同的Hash结果。因此,一旦文件被修改,就可检测出来。 当我们的文件放到emule里面进行共享发布的时候,emule会根据hash算法自动生成这个文件的hash值,他就是这个文件唯一的身份标志,它包含了这个文件的基本信息,然后把它提交到所连接的服务器。当有他人想对这个文件提出下载请求的时候, 这个hash值可以让他人知道他正在下载的文件是不是就是他所想要的。尤其是在文件的其他属性被更改之后(如名称等)这个值就更显得重要。而且服务器还提供了,这个文件当前所在的用户的地址,端口等信息,这样emule就知道到哪里去下载了。 一般来讲我们要搜索一个文件,emule在得到了这个信息后,会向被添加的服务器发出请求,要求得到有相同hash值的文件。而服务器则返回持有这个文件的用户信息。这样我们的客户端就可以直接的和拥有那个文件的用户沟通,看看是不是可以从他那里下载所需的文件。 对于emule中文件的hash值是固定的,也是唯一的,它就相当于这个文件的信息摘要,无论这个文件在谁的机器上,他的hash值都是不变的,无论过了多长时间,这个值始终如一,当我们在进行文件的下载上传过程中,emule都是通过这个值来确定文件。 那么什么是userhash呢? 道理同上,当我们在第一次使用emule的时候,emule会自动生成一个值,这个值也是唯一的,它是我们在emule世界里面的标志,只要你不卸载,不删除config,你的userhash值也就永远不变,积分制度就是通过这个值在起作用,emule里面的积分保存,身份识别,都是使用这个值,而和你的id和你的用户名无关,你随便怎么改这些东西,你的userhash值都是不变的,这也充分保证了公平性。其实他也是一个信息摘要,只不过保存的不是文件信息,而是我们每个人的信息。 那么什么是hash文件呢? 我们经常在emule日志里面看到,emule正在hash文件,这里就是利用了hash算法的文件校验性这个功能了,文章前面已经说了一些这些功能,其实这部分是一个非常复杂的过程,目前在ftp,bt等软件里面都是用的这个基本原理,emule里面是采用文件分块传输,这样传输的每一块都要进行对比校验,如果错误则要进行重新下载,这期间这些相关信息写入met文件,直到整个任务完成,这个时候part文件进行重新命名,然后使用move命令,把它传送到incoming文件里面,然后met文件自动删除,所以我们有的时候会遇到hash文件失败,就是指的是met里面的信息出了错误不能够和part文件匹配,另外有的时候开机也要疯狂hash,有两种情况一种是你在第一次使用,这个时候要hash提取所有文件信息,还有一种情况就是上一次你非法关机,那么这个时候就是要进行排错校验了。 关于hash的算法研究,一直是信息科学里面的一个前沿,尤其在网络技术普及的今天,他的重要性越来越突出,其实我们每天在网上进行的信息交流安全验证,我们在使用的操作系统密钥原理,里面都有它的身影,特别对于那些研究信息安全有兴趣的朋友,这更是一个打开信息世界的钥匙,他在hack世界里面也是一个研究的焦点。 一般的线性表、树中,记录在结构中的相对位置是随机的即和记录的关键字之间不存在确定的关系,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较”的基础上,查找的效率与比较次数密切相关。理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。因而查找时,只需根据这个对应关系f找到给定值K的像f(K)。若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此不需要进行比较便可直接取得所查记录。在此,称这个对应关系f为哈希函数,按这个思想建立的表为哈希表(又称为杂凑法或散列表)。 哈希表不可避免冲突(collision)现象:对不同的关键字可能得到同一哈希地址 即key1≠key2,而hash(key1)=hash(key2)。具有相同函数值的关键字对该哈希函数来说称为同义词(synonym)。 因此,在建造哈希表时不仅要设定一个好的哈希函数,而且要设定一种处理冲突的方法。可如下描述哈希表:根据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的“象”作为相应记录在表中的存储位置,这种表被称为哈希表。 对于动态查找表而言,1) 表长不确定;2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字。因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的位置,通常称这个函数f(key)为哈希函数。(注意:这个函数并不一定是数学函数) 哈希函数是一个映象,即:将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的大小不超出允许范围即可。 现实中哈希函数是需要构造的,并且构造的好才能使用的好。 用途:加密,解决冲突问题。。。。 用途很广,比特精灵中就使用了哈希函数,你可 以自己看看。 具体可以学习一下数据结构和算法的书。 [编辑本段]字符串哈希函数 (著名的ELFhash算法) int ELFhash(char *key) return h%MOD; }

晚来风急 2019-12-02 01:22:24 0 浏览量 回答数 0

回答

遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么? 遍历方式有以下几种: for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。 foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。 最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支持 Random Access。 如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读取元素的平均时间复杂度为 O(1),如ArrayList。如果没有实现该接口,表示不支持 Random Access,如LinkedList。 推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。 说一下 ArrayList 的优缺点 ArrayList的优点如下: ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 的缺点如下: 删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。插入元素的时候,也需要做一次元素复制操作,缺点同上。 ArrayList 比较适合顺序添加、随机访问的场景。 如何实现数组和 List 之间的转换? 数组转 List:使用 Arrays. asList(array) 进行转换。List 转数组:使用 List 自带的 toArray() 方法。 代码示例: ArrayList 和 LinkedList 的区别是什么? 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全; 综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。 补充:数据结构基础之双向链表 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。 ArrayList 和 Vector 的区别是什么? 这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。性能:ArrayList 在性能方面要优于 Vector。扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。 Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。 Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。 插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性? ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。 Vector 中的方法由于加了 synchronized 修饰,因此 Vector 是线程安全容器,但性能上较ArrayList差。 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList 插入速度较快。 多线程场景下如何使用 ArrayList? ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样: 为什么 ArrayList 的 elementData 加上 transient 修饰? ArrayList 中的数组定义如下: private transient Object[] elementData; 再看一下 ArrayList 的定义: public class ArrayList extends AbstractList implements List<E>, RandomAccess, Cloneable, java.io.Serializable 可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现: 每次序列化时,先调用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素,然后遍历 elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。 List 和 Set 的区别 List , Set 都是继承自Collection 接口 List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。 Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。 另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。 Set和List对比 Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变 Set接口 说一下 HashSet 的实现原理? HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。 HashSet如何检查重复?HashSet是如何保证数据不可重复的? 向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较。 HashSet 中的add ()方法会使用HashMap 的put()方法。 HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复( HashMap 比较key是否相等是先比较hashcode 再比较equals )。 以下是HashSet 部分源码: hashCode()与equals()的相关规定: 如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个equals方法返回true 两个对象有相同的hashcode值,它们也不一定是相等的 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖 hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。 ** ==与equals的区别** ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同 ==是指对内存地址进行比较 equals()是对字符串的内容进行比较3.==指引用是否相同 equals()指的是值是否相同 HashSet与HashMap的区别 Queue BlockingQueue是什么? Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。 在 Queue 中 poll()和 remove()有什么区别? 相同点:都是返回第一个元素,并在队列中删除返回的对象。 不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。 代码示例: Queue queue = new LinkedList (); queue. offer("string"); // add System. out. println(queue. poll()); System. out. println(queue. remove()); System. out. println(queue. size()); Map接口 说一下 HashMap 的实现原理? HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 HashMap的数据结构: 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。 HashMap 基于 Hash 算法实现的 当我们往Hashmap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。 需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn) HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底层实现 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做拉链法的方式可以解决哈希冲突。 JDK1.8之前 JDK1.8之前采用的是拉链法。拉链法:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。 JDK1.8之后 相比于之前的版本,jdk1.8在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。 JDK1.7 VS JDK1.8 比较 JDK1.8主要解决或优化了一下问题: resize 扩容优化引入了红黑树,目的是避免单条链表过长而影响查询效率,红黑树算法请参考解决了多线程死循环问题,但仍是非线程安全的,多线程时可能会造成数据丢失问题。 HashMap的put方法的具体流程? 当我们put的时候,首先计算 key的hash值,这里调用了 hash方法,hash方法实际是让key.hashCode()与key.hashCode()>>>16进行异或操作,高16bit补0,一个数和0异或不变,所以 hash 函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或,目的是减少碰撞。按照函数注释,因为bucket数组大小是2的幂,计算下标index = (table.length - 1) & hash,如果不做 hash 处理,相当于散列生效的只有几个低 bit 位,为了减少散列的碰撞,设计者综合考虑了速度、作用、质量之后,使用高16bit和低16bit异或来简单处理减少碰撞,而且JDK8中用了复杂度 O(logn)的树结构来提升碰撞下的性能。 putVal方法执行流程图 ①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; ②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; ③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; ④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤; ⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可; ⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。 HashMap的扩容操作是怎么实现的? ①.在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容; ②.每次扩展的时候,都是扩展2倍; ③.扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。 在putVal()中,我们看到在这个函数里面使用到了2次resize()方法,resize()方法表示的在进行第一次初始化时会对其进行扩容,或者当该数组的实际大小大于其临界值值(第一次为12),这个时候在扩容的同时也会伴随的桶上面的元素进行重新分发,这也是JDK1.8版本的一个优化的地方,在1.7中,扩容之后需要重新去计算其Hash值,根据Hash值对其进行分发,但在1.8版本中,则是根据在同一个桶的位置中进行判断(e.hash & oldCap)是否为0,重新进行hash分配后,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上 HashMap是怎么解决哈希冲突的? 答:在解决这个问题之前,我们首先需要知道什么是哈希冲突,而在了解哈希冲突之前我们还要知道什么是哈希才行; 什么是哈希? Hash,一般翻译为“散列”,也有直接音译为“哈希”的,这就是把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值(哈希值);这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 所有散列函数都有如下一个基本特性**:根据同一散列函数计算出的散列值如果不同,那么输入值肯定也不同。但是,根据同一散列函数计算出的散列值如果相同,输入值不一定相同**。 什么是哈希冲突? 当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。 HashMap的数据结构 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址容易,插入和删除困难;链表的特点是:寻址困难,但插入和删除容易;所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做链地址法的方式可以解决哈希冲突: 这样我们就可以将拥有相同哈希值的对象组织成一个链表放在hash值所对应的bucket下,但相比于hashCode返回的int类型,我们HashMap初始的容量大小DEFAULT_INITIAL_CAPACITY = 1 << 4(即2的四次方16)要远小于int类型的范围,所以我们如果只是单纯的用hashCode取余来获取对应的bucket这将会大大增加哈希碰撞的概率,并且最坏情况下还会将HashMap变成一个单链表,所以我们还需要对hashCode作一定的优化 hash()函数 上面提到的问题,主要是因为如果使用hashCode取余,那么相当于参与运算的只有hashCode的低位,高位是没有起到任何作用的,所以我们的思路就是让hashCode取值出的高位也参与运算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动,在JDK 1.8中的hash()函数如下: static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);// 与自己右移16位进行异或运算(高低位异或) } 这比在JDK 1.7中,更为简洁,相比在1.7中的4次位运算,5次异或运算(9次扰动),在1.8中,只进行了1次位运算和1次异或运算(2次扰动); JDK1.8新增红黑树 通过上面的链地址法(使用散列表)和扰动函数我们成功让我们的数据分布更平均,哈希碰撞减少,但是当我们的HashMap中存在大量数据时,加入我们某个bucket下对应的链表有n个元素,那么遍历时间复杂度就为O(n),为了针对这个问题,JDK1.8在HashMap中新增了红黑树的数据结构,进一步使得遍历复杂度降低至O(logn); 总结 简单总结一下HashMap是使用了哪些方法来有效解决哈希冲突的: 使用链地址法(使用散列表)来链接拥有相同hash值的数据;使用2次扰动函数(hash函数)来降低哈希冲突的概率,使得数据分布更平均;引入红黑树进一步降低遍历的时间复杂度,使得遍历更快; **能否使用任何类作为 Map 的 key? **可以使用任何类作为 Map 的 key,然而在使用之前,需要考虑以下几点: 如果类重写了 equals() 方法,也应该重写 hashCode() 方法。 类的所有实例需要遵循与 equals() 和 hashCode() 相关的规则。 如果一个类没有使用 equals(),不应该在 hashCode() 中使用它。 用户自定义 Key 类最佳实践是使之为不可变的,这样 hashCode() 值可以被缓存起来,拥有更好的性能。不可变的类也可以确保 hashCode() 和 equals() 在未来不会改变,这样就会解决与可变相关的问题了。 为什么HashMap中String、Integer这样的包装类适合作为K? 答:String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况 内部已重写了equals()、hashCode()等方法,遵守了HashMap内部的规范(不清楚可以去上面看看putValue的过程),不容易出现Hash值计算错误的情况; 如果使用Object作为HashMap的Key,应该怎么办呢? 答:重写hashCode()和equals()方法 重写hashCode()是因为需要计算存储数据的存储位置,需要注意不要试图从散列码计算中排除掉一个对象的关键部分来提高性能,这样虽然能更快但可能会导致更多的Hash碰撞; 重写equals()方法,需要遵守自反性、对称性、传递性、一致性以及对于任何非null的引用值x,x.equals(null)必须返回false的这几个特性,目的是为了保证key在哈希表中的唯一性; HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标 答:hashCode()方法返回的是int整数类型,其范围为-(2 ^ 31)~(2 ^ 31 - 1),约有40亿个映射空间,而HashMap的容量范围是在16(初始化默认值)~2 ^ 30,HashMap通常情况下是取不到最大值的,并且设备上也难以提供这么多的存储空间,从而导致通过hashCode()计算出的哈希值可能不在数组大小范围内,进而无法匹配存储位置; 那怎么解决呢? HashMap自己实现了自己的hash()方法,通过两次扰动使得它自己的哈希值高低位自行进行异或运算,降低哈希碰撞概率也使得数据分布更平均; 在保证数组长度为2的幂次方的时候,使用hash()运算之后的值与运算(&)(数组长度 - 1)来获取数组下标的方式进行存储,这样一来是比取余操作更加有效率,二来也是因为只有当数组长度为2的幂次方时,h&(length-1)才等价于h%length,三来解决了“哈希值与数组大小范围不匹配”的问题; HashMap 的长度为什么是2的幂次方 为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。 这个算法应该如何设计呢? 我们首先可能会想到采用%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。 那为什么是两次扰动呢? 答:这样就是加大哈希值低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性&均匀性,最终减少Hash冲突,两次就够了,已经达到了高位低位同时参与运算的目的; HashMap 与 HashTable 有什么区别? 线程安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!); 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它; 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。 **初始容量大小和每次扩充容量大小的不同 **: ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。 如何决定使用 HashMap 还是 TreeMap? 对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。 HashMap 和 ConcurrentHashMap 的区别 ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。) HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。 ConcurrentHashMap 和 Hashtable 的区别? ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的; 实现线程安全的方式(重要): ① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16个Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。 两者的对比图: HashTable: JDK1.7的ConcurrentHashMap: JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点): 答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题。但是 HashTable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 底层具体实现知道吗?实现原理是什么? JDK1.7 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。 在JDK1.7中,ConcurrentHashMap采用Segment + HashEntry的方式进行实现,结构如下: 一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。 该类包含两个静态内部类 HashEntry 和 Segment ;前者用来封装映射表的键值对,后者用来充当锁的角色;Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。 JDK1.8 在JDK1.8中,放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现,synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。 结构如下: 如果该节点是TreeBin类型的节点,说明是红黑树结构,则通过putTreeVal方法往红黑树中插入节点;如果binCount不为0,说明put操作对数据产生了影响,如果当前链表的个数达到8个,则通过treeifyBin方法转化为红黑树,如果oldVal不为空,说明是一次更新操作,没有对元素个数产生影响,则直接返回旧值;如果插入的是一个新节点,则执行addCount()方法尝试更新元素个数baseCount; 辅助工具类 Array 和 ArrayList 有何区别? Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。 如何实现 Array 和 List 之间的转换? Array 转 List: Arrays. asList(array) ;List 转 Array:List 的 toArray() 方法。 comparable 和 comparator的区别? comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序 一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort(). 方法如何比较元素? TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进 行排 序。 Collections 工具类的 sort 方法有两种重载的形式, 第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较; 第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。

剑曼红尘 2020-03-24 14:41:57 0 浏览量 回答数 0

问题

图解九大数据结构 6月13日 【今日算法】

游客ih62co2qqq5ww 2020-06-17 13:17:00 29 浏览量 回答数 1

问题

图解!24张图彻底弄懂九大常见数据结构! 7月22日 【今日算法】

游客ih62co2qqq5ww 2020-07-27 13:19:32 6 浏览量 回答数 1

回答

Spring Cloud 学习笔记(一)——入门、特征、配置 0 放在前面 0.1 参考文档 http://cloud.spring.io/spring-cloud-static/Brixton.SR7/ https://springcloud.cc/ http://projects.spring.io/spring-cloud/ 0.2 maven配置 org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE org.springframework.cloud spring-cloud-dependencies Dalston.RELEASE pom import org.springframework.cloud spring-cloud-starter-config org.springframework.cloud spring-cloud-starter-eureka 0.3 简介 Spring Cloud为开发人员提供了快速构建分布式系统中的一些通用模式(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,领导选举,分布式 会话,群集状态)。 分布式系统的协调引出样板模式(boiler plate patterns),并且使用Spring Cloud开发人员可以快速地实现这些模式来启动服务和应用程序。 它们可以在任何分布式环境中正常工作,包括开发人员自己的笔记本电脑,裸机数据中心和受管平台,如Cloud Foundry。 Version: Brixton.SR7 1 特征 Spring Cloud专注于为经典用例和扩展机制提供良好的开箱即用 分布式/版本配置 服务注册与发现 路由选择 服务调用 负载均衡 熔断机制 全局锁 领导人选举和集群状态 分布式消息 2 原生云应用程序 原生云是应用程序开发的一种风格,鼓励在持续交付和价值驱动领域的最佳实践。 Spring Cloud的很多特性是基于Spring Boot的。更多的是由两个库实现:Spring Cloud Context and Spring Cloud Commons。 2.1 Spring Cloud Context: 应用上下文服务 Spring Boot关于使用Spring构建应用有硬性规定:通用的配置文件在固定的位置,通用管理终端,监控任务。建立在这个基础上,Spring Cloud增加了一些额外的特性。 2.1.1 引导应用程序上下文 Spring Cloud会创建一个“bootstrap”的上下文,这是主应用程序的父上下文。对应的配置文件拥有最高优先级,并且,默认不能被本地配置文件覆盖。对应的文件名bootstrap.yml或bootstrap.properties。 可通过设置spring.cloud.bootstrap.enabled=false来禁止bootstrap进程。 2.1.2 应用上下文层级结构 当用SpringApplication或SpringApplicationBuilder创建应用程序上下文时,bootstrap上下文将作为父上下文被添加进去,子上下文将继承父上下文的属性。 子上下文的配置信息可覆盖父上下文的配置信息。 2.1.3 修改Bootstrap配置文件位置 spring.cloud.bootstrap.name(默认是bootstrap),或者spring.cloud.bootstrap.location(默认是空) 2.1.4 覆盖远程配置文件的值 spring.cloud.config.allowOverride=true spring.cloud.config.overrideNone=true spring.cloud.config.overrideSystemProperties=false 2.1.5 定制Bootstrap配置 在/META-INF/spring.factories的key为org.springframework.cloud.bootstrap.BootstrapConfiguration,定义了Bootstrap启动的组件。 在主应用程序启动之前,一开始Bootstrap上下文创建在spring.factories文件中的组件,然后是@Beans类型的bean。 2.1.6 定制Bootstrap属性来源 关键点:spring.factories、PropertySourceLocator 2.1.7 环境改变 应用程序可通过EnvironmentChangedEvent监听应用程序并做出响应。 2.1.8 Refresh Scope Spring的bean被@RefreshScope将做特殊处理,可用于刷新bean的配置信息。 注意 需要添加依赖“org.springframework.boot.spring-boot-starter-actuator” 目前我只在@Controller测试成功 需要自己发送POST请求/refresh 修改配置文件即可 2.1.9 加密和解密 Spring Cloud可对配置文件的值进行加密。 如果有"Illegal key size"异常,那么需要安装JCE。 2.1.10 服务点 除了Spring Boot提供的服务点,Spring Cloud也提供了一些服务点用于管理,注意都是POST请求 /env:更新Environment、重新绑定@ConfigurationProperties跟日志级别 /refresh重新加载配置文件,刷新标记@RefreshScope的bean /restart重启应用,默认不可用 生命周期方法:/pause、/resume 2.2 Spring Cloud Commons:通用抽象 服务发现、负载均衡、熔断机制这种模式为Spring Cloud客户端提供了一个通用的抽象层。 2.2.1 RestTemplate作为负载均衡客户端 通过@Bean跟@LoadBalanced指定RestTemplate。注意URI需要使用虚拟域名(如服务名,不能用域名)。 如下: @Configuration public class MyConfiguration { @LoadBalanced @Bean RestTemplate restTemplate() { return new RestTemplate(); } } public class MyClass { @Autowired private RestTemplate restTemplate; public String doOtherStuff() { String results = restTemplate.getForObject(" http://stores/stores", String.class); return results; } } 2.2.2 多个RestTemplate对象 注意@Primary注解的使用。 @Configuration public class MyConfiguration { @LoadBalanced @Bean RestTemplate loadBalanced() { return new RestTemplate(); } @Primary @Bean RestTemplate restTemplate() { return new RestTemplate(); } } public class MyClass { @Autowired private RestTemplate restTemplate; @Autowired @LoadBalanced private RestTemplate loadBalanced; public String doOtherStuff() { return loadBalanced.getForObject(" http://stores/stores", String.class); } public String doStuff() { return restTemplate.getForObject(" http://example.com", String.class); } } 2.2.3 忽略网络接口 忽略确定名字的服务发现注册,支持正则表达式配置。 3 Spring Cloud Config Spring Cloud Config提供服务端和客户端在分布式系统中扩展配置。支持不同环境的配置(开发、测试、生产)。使用Git做默认配置后端,可支持配置环境打版本标签。 3.1 快速开始 可通过IDE运行或maven运行。 默认加载property资源的策略是克隆一个git仓库(at spring.cloud.config.server.git.uri')。 HTTP服务资源的构成: /{application}/{profile}[/{label}] /{application}-{profile}.yml /{label}/{application}-{profile}.yml /{application}-{profile}.properties /{label}/{application}-{profile}.properties application是SpringApplication的spring.config.name,(一般来说'application'是一个常规的Spring Boot应用),profile是一个active的profile(或者逗号分隔的属性列表),label是一个可选的git标签(默认为"master")。 3.1.1 客户端示例 创建以Spring Boot应用即可,添加依赖“org.springframework.cloud:spring-cloud-starter-config”。 配置application.properties,注意URL为配置服务端的地址 spring.cloud.config.uri: http://myconfigserver.com 3.2 Spring Cloud Config 服务端 针对系统外的配置项(如name-value对或相同功能的YAML内容),该服务器提供了基于资源的HTTP接口。使用@EnableConfigServer注解,该服务器可以很容易的被嵌入到Spring Boot 系统中。使用该注解之后该应用系统就是一个配置服务器。 @SpringBootApplication @EnableConfigServer public class ConfigApplicion { public static void main(String[] args) throws Exception { SpringApplication.run(ConfigApplicion.class, args); } } 3.2.1 资源库环境 {application} 对应客户端的"spring.application.name"属性 {profile} 对应客户端的 "spring.profiles.active"属性(逗号分隔的列表) {label} 对应服务端属性,这个属性能标示一组配置文件的版本 如果配置库是基于文件的,服务器将从application.yml和foo.yml中创建一个Environment对象。高优先级的配置优先转成Environment对象中的PropertySource。 3.2.1.1 Git后端 默认的EnvironmentRepository是用Git后端进行实现的,Git后端对于管理升级和物理环境是很方便的,对审计配置变更也很方便。也可以file:前缀从本地配置库中读取数据。 这个配置库的实现通过映射HTTP资源的{label}参数作为git label(提交id,分支名称或tag)。如果git分支或tag的名称包含一个斜杠 ("/"),此时HTTP URL中的label需要使用特殊字符串"(_)"来替代(为了避免与其他URL路径相互混淆)。如果使用了命令行客户端如 curl,请谨慎处理URL中的括号(例如:在shell下请使用引号''来转义它们)。 Git URI占位符 Spring Cloud Config Server支持git库URL中包含针对{application}和 {profile}的占位符(如果你需要,{label}也可包含占位符, 不过要牢记的是任何情况下label只指git的label)。所以,你可以很容易的支持“一个应用系统一个配置库”策略或“一个profile一个配置库”策略。 模式匹配和多资源库 spring: cloud: config: server: git: uri: https://github.com/spring-cloud-samples/config-repo repos: simple: https://github.com/simple/config-repo special: pattern: special*/dev*,special/dev* uri: https://github.com/special/config-repo local: pattern: local* uri: file:/home/configsvc/config-repo 如果 {application}/{profile}不能匹配任何表达式,那么将使用“spring.cloud.config.server.git.uri”对应的值。在上例子中,对于 "simple" 配置库, 匹配模式是simple/* (也就说,无论profile是什么,它只匹配application名称为“simple”的应用系统)。“local”库匹配所有application名称以“local”开头任何应用系统,不管profiles是什么(来实现覆盖因没有配置对profile的匹配规则,“/”后缀会被自动的增加到任何的匹配表达式中)。 Git搜索路径中的占位符 spring.cloud.config.server.git.searchPaths 3.2.1.2 版本控制后端文件系统使用 伴随着版本控制系统作为后端(git、svn),文件都会被check out或clone 到本地文件系统中。默认这些文件会被放置到以config-repo-为前缀的系统临时目录中。在Linux上,譬如应该是/tmp/config-repo- 目录。有些操作系统routinely clean out放到临时目录中,这会导致不可预知的问题出现。为了避免这个问题,通过设置spring.cloud.config.server.git.basedir或spring.cloud.config.server.svn.basedir参数值为非系统临时目录。 3.2.1.3 文件系统后端 使用本地加载配置文件。 需要配置:spring.cloud.config.server.native.searchLocations跟spring.profiles.active=native。 路径配置格式:classpath:/, classpath:/config,file:./, file:./config。 3.2.1.4 共享配置给所有应用 基于文件的资源库 在基于文件的资源库中(i.e. git, svn and native),这样的文件名application 命名的资源在所有的客户端都是共享的(如 application.properties, application.yml, application-*.properties,etc.)。 属性覆盖 “spring.cloud.config.server.overrides”添加一个Map类型的name-value对来实现覆盖。 例如 spring: cloud: config: server: overrides: foo: bar 会使所有的配置客户端应用程序读取foo=bar到他们自己配置参数中。 3.2.2 健康指示器 通过这个指示器能够检查已经配置的EnvironmentRepository是否正常运行。 通过设置spring.cloud.config.server.health.enabled=false参数来禁用健康指示器。 3.2.3 安全 你可以自由选择任何你觉得合理的方式来保护你的Config Server(从物理网络安全到OAuth2 令牌),同时使用Spring Security和Spring Boot 能使你做更多其他有用的事情。 为了使用默认的Spring Boot HTTP Basic 安全,只需要把Spring Security 增加到classpath中(如org.springframework.boot.spring-boot-starter-security)。默认的用户名是“user”,对应的会生成一个随机密码,这种情况在实际使用中并没有意义,一般建议配置一个密码(通过 security.user.password属性进行配置)并对这个密码进行加密。 3.2.4 加密与解密 如果远程属性包含加密内容(以{cipher}开头),这些值将在通过HTTP传递到客户端之前被解密。 使用略 3.2.5 密钥管理 配置服务可以使用对称(共享)密钥或者非对称密钥(RSA密钥对)。 使用略 3.2.6 创建一个测试密钥库 3.2.7 使用多密钥和循环密钥 3.2.8 加密属性服务 3.3 可替换格式服务 配置文件可加后缀".yml"、".yaml"、".properties" 3.4 文本解释服务 /{name}/{profile}/{label}/{path} 3.5 嵌入配置服务器 一般配置服务运行在单独的应用里面,只要使用注解@EnableConfigServer即可嵌入到其他应用。 3.6 推送通知和总线 添加依赖spring-cloud-config-monitor,激活Spring Cloud 总线,/monitor端点即可用。 当webhook激活,针对应用程序可能已经变化了的,配置服务端将发送一个RefreshRemoteApplicationEvent。 3.7 客户端配置 3.7.1 配置第一次引导 通过spring.cloud.config.uri属性配置Config Server地址 3.7.2 发现第一次引导 如果用的是Netflix,则用eureka.client.serviceUrl.defaultZone进行配置。 3.7.3 配置客户端快速失败 在一些例子里面,可能希望在没有连接配置服务端时直接启动失败。可通过spring.cloud.config.failFast=true进行配置。 3.7.4 配置客户端重试 添加依赖spring-retry、spring-boot-starter-aop,设置spring.cloud.config.failFast=true。默认的是6次重试,初始补偿间隔是1000ms,后续补偿为1.1指数乘数,可通过spring.cloud.config.retry.*配置进行修改。 3.7.5 定位远程配置资源 路径:/{name}/{profile}/{label} "name" = ${spring.application.name} "profile" = ${spring.profiles.active} (actually Environment.getActiveProfiles()) "label" = "master" label对于回滚到之前的版本很有用。 3.7.6 安全 通过spring.cloud.config.password、spring.cloud.config.username进行配置。 答案来源于网络

养狐狸的猫 2019-12-02 02:18:34 0 浏览量 回答数 0

问题

Android安全开发之通用签名风险

移动安全 2019-12-01 21:14:31 4210 浏览量 回答数 1

问题

【企业IT管理员必读】WanaCrypt0r 2.0和ONION等勒索软件病毒应急处置方案

正禾 2019-12-01 21:59:41 8997 浏览量 回答数 4

问题

大数据被用来犯罪怎么办

游客ftkex2f22paya 2019-12-01 19:34:14 2 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅