• 文章
  • 在线工具
  • 热门 java如何实现栈数据结构

     2021-08-18 16:17  70    
    package com.nanxhs.structure;import java.lang.reflect.Array;/** * 栈实现 * @author 唐海斌 * @version 1.0 * @date 2021/5/19 11:17 */public class Stack<T> { /** * 初始化大小 */ private static final int INIT_ARRAY_SIZE = 10; /** * 栈游标指针,指示当前最新数据的下标 */ private int point = -1; /** * 栈中元素的类型 */ private Class<T> clazz; /** * 元素容器 */ private T[] stack; public Stack(Class<T> clazz) { stack = (T[]) Array.newInstance(clazz, INIT_ARRAY_SIZE); this.clazz = clazz; } /** * 入栈 * @param element */ public void push(T element) { if (element == null) { throw new RuntimeException("element not null"); } if (++point == length() - 1) { dilatation(); } stack[point] = element; } /** * 出栈 * @return */ public T pop() { if (point < 0) { return null; } return stack[point--]; } /** * 清空栈 */ public void clear() { while (point > -1) { pop(); } } /** * 栈的当前容量 * @return */ public int length() { return stack.length; } /** * 栈元素数量 * @return */ public int count() { return point + 1; } /** * 动态扩容 */ private void dilatation() { T[] newStack = (T[]) Array.newInstance(clazz, length() * 2); for (int index = 0; index < stack.length; ++index) { newStack[index] = stack[index]; } stack = newStack; }}测试类import com.nanxhs.structure.Stack;import org.junit.Assert;import org.junit.Test;/** * @author 唐海斌 * @version 1.0 * @date 2021/5/19 11:36 */public class StackTest { @Test public void test() { Stack<String> stack = new Stack<>(String.class); stack.push("+"); stack.push("-"); stack.push("*"); stack.push("/"); Assert.assertEquals(4, stack.count()); Assert.assertEquals(stack.pop(), "/"); stack.clear(); Assert.assertNull(stack.pop()); }}
  • 热门 java实现单向链表数据结构代码

     2021-08-18 13:17  78    
    package com.nanxhs.structure;import java.util.Objects;/** * * 单向链表实现 * @author 唐海斌 * @version 1.0 * @date 2021/5/20 11:16 */public class UnidirectionalLinkList<T> { /** * 表头, 只是标识作用,一个空元素的Node */ private final Node head; /** * 表尾 */ private Node tail; /** * 链表长度 */ private int size; public UnidirectionalLinkList() { head = new Node(null); } /** * 加入表尾 * @param element */ public synchronized void add(T element) { Node node = new Node(element); if (tail == null) { head.next = node; tail = node; } else { Node oldTail = tail; tail = node; oldTail.next = node; } ++size; } /** * 加入表头 * @param element */ public synchronized void addFirst(T element) { Node firstNode = head.next; Node node = new Node(element); if (firstNode == null) { head.next = node; tail = node; } else { head.next = node; node.next = firstNode; } ++size; } /** * 从链表中移除 * @param element */ public synchronized boolean remove(T element) { Node node = head; Node prev; Node currNode; boolean status = false; while (node != null) { prev = node; currNode = node.next; if (currNode == null) { break; } if (Objects.equals(element, currNode.element)) { if (currNode.next == null) { prev.next = null; currNode.element = null; }else { prev.next = currNode.next; } --size; node = prev.next; status = true; } else { node = currNode; } } return status; } /** * 删除指定下标的元素 * @param index * @return */ public synchronized boolean remove(int index) { if (index > size - 1) { throw new RuntimeException("超过链表长度,当前链表的长度为: " + size); } Node node = head; int i = 0; while (node != null) { Node currentNode = node.next; if (currentNode == null) { return false; } if (Objects.equals(i, index)) { node.next = currentNode.next; if (--size == 0) { tail = null; } return true; } node = currentNode; ++i; } return false; } /** * 获取指定下标的元素 * @param index * @return */ public T get(int index) { if (index > size - 1) { throw new RuntimeException("超过链表长度,当前链表的长度为: " + size); } Node node = head; int i = 0; while (node != null) { Node currentNode = node.next; if (currentNode == null) { return null; } if (Objects.equals(i, index)) { return currentNode.element; } node = currentNode; ++i; } return null; } /** * 清空链表 */ public void clear() { for (int index = size; index > 0; --index) { remove(0); } } /** * 获取链表长度 * * @return */ public int getSize() { return size; } @Override public String toString() { StringBuilder dataStr = new StringBuilder(); dataStr.append("["); Node node = head; while ((node = node.next) != null) { dataStr.append(node.element).append(", "); } return dataStr.append("]").toString(); } class Node { /** * 下一个节点 */ private Node next; /** * 当前节点元素 */ private T element; public Node(T element) { this.element = element; } }}测试类import com.nanxhs.structure.UnidirectionalLinkList;import org.junit.Assert;import org.junit.Test;/** * @author 唐海斌 * @version 1.0 * @date 2021/5/20 13:35 */public class UnidirectionalLinkListTest { @Test public void test() { UnidirectionalLinkList<String> unidirectionalLinkList = new UnidirectionalLinkList<>(); unidirectionalLinkList.add("小明"); unidirectionalLinkList.add("张三"); Assert.assertEquals("张三", unidirectionalLinkList.get(1)); unidirectionalLinkList.addFirst("李四"); Assert.assertEquals("李四", unidirectionalLinkList.get(0)); unidirectionalLinkList.remove("张三"); Assert.assertEquals("小明", unidirectionalLinkList.get(1)); unidirectionalLinkList.remove(1); Assert.assertEquals("李四", unidirectionalLinkList.get(0)); unidirectionalLinkList.clear(); Assert.assertEquals(unidirectionalLinkList.getSize(), 0); }}
  • 最新 热门 JWT使用介绍以及工具类

     2021-04-30 11:14  6222    
    一、JWT是什么1.基本介绍JSON Web Token(JWT)是一个非常轻巧的规范。JSON网络令牌,JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式在不同实体之间安全传输信息(JSON格式)2.应用场景允许我们在用户和服务器之间传递安全可靠的加密字符串信息进行认证和授权校验。二、原理1.JWT的构成加密的字符串由三部分组成:头部+载体+签名①.头部(Header)头部用于描述关于该JWT的最基本信息,例如其他类型以及签名所用的算法等。可以被表示成一个json对象。{"typ":"JWT","alg":"HS256"}②.载荷(Payload)载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三部分1)、以下是标准中注册的声明,建议但不强制使用iss:jwt签发者sub:当前令牌描述的说明aud:接收jwt的一方exp:jwt的过期时间,这个过期时间必须要大于签发时间nbg:定义在什么时间之前,该jwt都是不可用的iat:jwt的签发时间jti:jwt的唯一身份表示,主要用啦作为一次性token,从而回避攻击2)、公共的声明(不参与校验)公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分是可以被解密。3)、私有的声明(不参与校验)私有声明是提供者和消费者所共同定义的声明,一般不建议存放铭感信息,Base64是对称解密的。4)定义一个payload:{"sub":"这里是载体内容","name":"JEEM","admin":"true"}③.签证(signature)jwt的第三部分是一个签证信息(校验数据是否正确),这个签证信息由三部分组成header(base64后的)payload(base64后的)secret(秘钥)这个部分需要base64加密后的header和base64加密后的payload。链接组成的字符串,然后通过header声明的加密方式加盐secret组合加密,然后就构成了jwt的三部分。eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. //头部eyJpc3MiOiLlvKDlvLoiLCJuYW1lIjoiNzg5IiwiZXhwIjoxNTI4MzY0MjU5LCJpYXQiOjE1MjgzNjMwNTl9.//载荷574koY-c9SqMNNzfvAWQuKEnimWeZAcoFQ5XudNWF3o //签名注意:secret是秘钥保存在服务端,一定不能泄露。三、如何使用1、引入POM<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version></dependency>2、代码使用import com.auth0.jwt.JWT;import com.auth0.jwt.JWTVerifier;import com.auth0.jwt.algorithms.Algorithm;import com.auth0.jwt.interfaces.DecodedJWT;public class TokenUtil { //默认过期时间设置(7) private static final long expireTime = 1000*60*60*24*7; public static String getToken(Object tokenVo, String tokenSecret){ return build(tokenVo, tokenSecret,expireTime); } public static String getToken(Object tokenVo, String tokenSecret, long expireTime){ return build(tokenVo, tokenSecret,expireTime); } private static String build(Object tokenVo, String tokenSecret, long expireTime){ //过期时间和加密算法设置 Date date=new Date(System.currentTimeMillis()+expireTime); Algorithm algorithm = Algorithm.HMAC256(tokenSecret); //头部信息 Map<String,Object> header=new HashMap<>(2); header.put("typ","JWT"); header.put("alg","HS256"); Map map = new HashMap(); try { map = BeanUtils.describe(tokenVo); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return JWT.create() .withHeader(header) .withClaim("data", map) //自定义载荷 .withExpiresAt(date) //过期时间.sign(algorithm); //加盐 }/** * 解析token */ public static <T> T getTokenData(String token, Class<T> clazz){ DecodedJWT jwt = JWT.decode(token); try { Map map = jwt.getClaim("data").asMap(); T vo = clazz.newInstance(); BeanUtils.populate(vo,map); return vo; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } /** * 获取解析后的JWT */ public static DecodedJWT getDecodedJWT(String token){ return JWT.decode(token); } /** * 验证token * @param token */ public static boolean verifyToken(String token, String tokenSecret){ JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(tokenSecret)).build(); jwtVerifier.verify(token); return true; } public static void main(String[] args){ System.out.println(TokenUtil.getToken(new UserTokenVo(),"123456")); }}
  • 最新 热门 Nginx高迸发访问限流处理方式

     2021-04-26 06:14  9440    
    应用场景:一般情况下,并发量是比较大的数据接口,并且不经常变动的数据,需要做多级缓存,另外没有做缓存的数据接口,用户不断刷新,访问频率过快,有恶意的大量请求爬取数据,会对系统造成影响。而限流就是保护措施之一。限流(迸发访问次数)限制单个ip访问次数 (恶意攻击爬取)队列均速放行(缓冲队列)1.Nginx限流说明: 使用nginx的 ngx_http_limit_req_module模块进行限制的,使用limit_req和limit_req_zone命令来设置;1)http模块下添加:#1.每秒允许10次访问,10M的缓存空间limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;#2.根据某个ip来限制,存储空间大小为1m#limit_req_zone $binary_remote_addr zone=addr:1m$binary_remote_addr:根据请求IP地址进行限流key:定义限流对象, binary_remote_addr,是基于 remote_addr(客户端IP) 来做限流,binary_ 开头的目的是压缩内存占用量zone: 定义共享内存区来存储访问信息, ip_limit:10m表示一个大小为10M,名字为ip_limit的内存区域。1M能存储16000 IP地址的访问信息,10M可以存储16W IP地址访问信息rate: 用于设置最大访问速率,rate=10r/s 表示每秒最多处理10个请求。Nginx 实际上以毫秒为粒度来跟踪请求信息,因此 10r/s 实际上是限制:每100毫秒处理两个请求。这意味着,自上一个请求处理完后,若后续100毫秒内又有请求到达,将拒绝处理该请求。2)location模块下添加limit_req zone=ip_limit burst=15 nodelay;#对应上面的1limit_conn addr 5; #对应上面的2说明:zone=ip_limit对应上面的限流对象地址;bursrt=15表示最大支持15的并发,会有5个请求存在队列中,不会被拒绝;如果不加,则会被拒绝nodelay: 表示并发超出的5个请求,不会被延迟,会被立即执行,如需等待执行的话,配置delay即可。
  • 推荐 热门 CentOS8安装Docker报错package docker-ce-3:19.03.8-3.el7.x86_64 requires containerd.io >= 1.2.2-3

     2020-11-22 49:14  140829  42  
    1、问题描述: CentOS8安装Docker报错package docker-ce-3:19.03.8-3.el7.x86_64 requires containerd.io >= 1.2.2-32、错误展示:[root@iZbp1d8bd3d50zlx7kccj2Z /]# yum -y install docker-ceLast metadata expiration check: 0:09:43 ago on Sun 22 Nov 2020 01:55:52 PM CST.Error: Problem: package docker-ce-3:19.03.13-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but none of the providers can be installed - cannot install the best candidate for the job - package containerd.io-1.2.10-3.2.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.13-3.1.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.13-3.2.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.2-3.3.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.2-3.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.4-3.1.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.5-3.1.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.2.6-3.3.el7.x86_64 is filtered out by modular filtering - package containerd.io-1.3.7-3.1.el7.x86_64 is filtered out by modular filtering(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages)3、解决问题: 由于centos8默认使用podman代替docker,所以需要安装一下containerd.io。 安装前请先执行下面一句 yum install https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpm接着继续安装。
  • 热门 Centos8 Docker CE 安装

     2020-11-22 25:14  131588  5  
    Centos Docker CE 安装Docker有两个分支版本:Docker CE和Docker EE,即社区版和企业版。本教程基于CentOS 安装Docker CE。1、安装Docker的依赖库。yum install -y yum-utils device-mapper-persistent-data lvm22、 添加Docker CE的软件源信息。yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3、安装Docker CE。需要注意,如果是Centos8的话,需要先执行以下一句,否则会报错,centos8默认使用podman代替docker,所以需要安装containerd.io yum install https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpmyum makecache fastyum -y install docker-ce4、启动Docker服务。systemctl start docker
  • 推荐 热门 linux完整简洁笔记

     2020-09-10 07:11  121934  71  
    文件操作一、 文件类型(常见三种)文件表达方式: -目录(类似windows的文件夹)表达方式:d链接(类似windows的快捷方式)表达方式:l二、 文件权限r 可读w 可写x 可执行(脚本,比如shell脚本)- 特殊字符,表示没有任何权限文件的归属拥有者 owner u属于组 group g其他人 other o举例说明[root@iZm5e9tuuj84fiyy7b3bx3Z /]# lldrwxr-xr-x 3 root root 4096 Jun 23 09:04 applrwxrwxrwx 1 root root 7 Apr 26 15:48 bin-rw-r--r-- 1 root root 0 Jul 24 16:10 springboot.log1. 第一部分 drwxr-xr-x10个字符代表着不同意义,将这个10个字符分为4组,第一字符为1组,后面9个字符分3组 d rwx r-x r-x。第一字符表示文件类型后面9个字符表示针对不同用户的的权限关系d //第一个字符是文件类型,d代表着目录rwx //拥有者r-x //属于组r-x //其他人2. 第二部分 root root第一个字符串表示文件拥有者root第二个字符串表示文件所属组root修改权限*需要使用Root用户chmod 命令(change mode)举例说明:对于同组用户,仅仅可读; # chmod g-w 文件名称对于其他用户,既不可读也不可写 # chmod o-r 文件名称改变所属组和拥有者改变拥有者 # chown root /home/a.txt改变所属组 # chgrp root /home/a.txt三、文件查看cat 文件名称查看全部内容,适合内容比较少的方式 # cat a.txt more 文件名翻页查看内容,适合内容比较大的方式 # more a.txttail -f 文件名查看文件末尾的内容,一般查看日志用 # tail -f a.txt # tail -200f a.txt //200行head 文件名称查看文件开头内容,内容模板样式 # head a.txt四、文件创建touch 文件名称 # touch a.txt五、文件修改vim/vi 文件名称vi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,vim 具有程序编辑的能力,可以以字体颜色辨别语法的正确性,方便程序设计 # vim a.txtecho '内容' >> 文件名称文本内容追加 # echo '123456' >> a.txt快捷键(在vi查看模式下)* dd : 表示删除光标所在的行的内容* ZZ : 表示的是保存文件内容* x : 表示将光标处的字符给删除* o : 表示在光标的下一行进行插入内容六、文件的拷贝cp 文件名称 目标目录/名称复制单个文件或文件夹情况下(出现多个文件时报错) # cp a.txt /home/a.txtcp -r 目录 目标目录-r表示递归删除子文件复制目录及目录文件 # cp -r /etc/a.txt /home七、文件移动与重命名mv 文件 目标文件 同目录情况下则是重命名,不同目录则是移动 # mv a.txt b.txt # mv a.txt /home/b.txt八、文件删除rm 单个文件如果删除多个文件则会报错 # rm a.txt # rm filerm -rf filer表示递归删除子文件, f表示强制删除, 一般建议给绝对路径,以免误操作 # rm 九、创建目录mkdir 目录名称只能创建单个目录 # mkdir filemkdir -p 多级目录-p如果父级文件没有则创建,有则不创建 # mkdir -p /a/b/c十、链接软链接 sort link硬链接 hard link区别:删除连接时,是否删除源文件创建软链接 -s代表软连接 # ln -s file/dir linkName创建硬链接 # ln file/dir linkName十一、文件搜索find ~/ -name file~/当前目录,精确搜索 # find ~/ -name a.txtfind ~/ -name file*模糊搜索a开头的文件 # find ~/ -name a*系统管理一、查看系统信息uname[root@izwz9awjm6q5koj7sjg0jsz ~]# unameLinuxuname -r 查看版本[root@izwz9awjm6q5koj7sjg0jsz ~]# uname -r3.10.0-514.26.2.el7.x86_64cat /proc/cpuinfo 查看cpu信息[root@izwz9awjm6q5koj7sjg0jsz ~]# cat /proc/cpuinfoprocessor: 0vendor_id: GenuineIntelcpu family: 6model: 79model name: Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHzstepping: 1microcode: 0x1cpu MHz: 2494.224cache size: 40960 KB...date 查看当前日期cal 2020 查看日历表cat /proc/meminfo 查看内存信息[root@izwz9awjm6q5koj7sjg0jsz ~]# cat /proc/meminfoMemTotal: 1883724 kBMemFree: 118348 kBMemAvailable: 794852 kBBuffers: 77276 kBCached: 709520 kBSwapCached: 0 kBActive: 1339492 kB...df -lh 查看磁盘使用情况[root@izwz9awjm6q5koj7sjg0jsz ~]# df -lhFilesystem Size Used Avail Use% Mounted on/dev/vda1 40G 6.3G 31G 17% /devtmpfs 911M 0 911M 0% /devtmpfs 920M 0 920M 0% /dev/shmtmpfs 920M 508K 920M 1% /runtmpfs 920M 0 920M 0% /sys/fs/cgroupoverlay 40G 6.3G 31G 17% /var/lib/docker/overlay2/784d21c5380dd6edcc5943998078143/merged...du -sh 目录: 查看某个目录磁盘使用情况[root@izwz9awjm6q5koj7sjg0jsz home]# du -sh /home974M/homemount 查看挂在磁盘信息umount 卸载磁盘fdisk -l 修复磁盘,自动修复[root@izwz9awjm6q5koj7sjg0jsz home]# fdisk /homefree -m 看内存使用情况[root@izwz9awjm6q5koj7sjg0jsz ~]# free -m total used free shared buff/cache availableMem: 1839 900 119 0 819 769Swap: 0 0 0sudo设置普通用户权限vi /etc/sudoers//增加到第一行root2 ALL=(root)NOPASSWD:ALL防火墙sudo service iptables status 查看防火墙的状态sudo service iptables stop 停止关闭防火墙sudo service iptables start 启动防火墙sudo service iptables restart 重启防火墙sudo chkconfig iptables off|on 永久关闭|开启防火墙定时调度Crontabcrontab -e 创建定时任务 # crontab -e */1**** /bin/date >> /home/log.txtcrontab -l 查出任务列表crontabl -r 删除所有的任务软件安装1、第一种方式rpm -qa|grep name 检测软件是否安装[root@izwz9awjm6q5koj7sjg0jsz ~]# rpm -qa|grep javarpm -e --nodeps xxxxx 卸载已安装的软件rpm -ivh xxxx.rpm 安装软件2、第二种方式yum3、第三种方式tar 源码 编译 不推荐使用源码编译方式安装软件压缩软件zip压缩软件unzip xxx.zip 解压zip yy.zipe filename 压缩tar压缩软件tar zxvf xxxx.tar.gz 解压tar zcvf xxxx.tar.gz dir/file 压缩shell 编程注意事项编写脚本第一行指定用哪个程序来编译和执行脚本 #!/bin/bash 或者 #!/bin/sh变量名:必须以字母或下划线开头,后面可以跟字母、数字或者下划线。区分大小写敏感 # name=nihao //定义变量 # echo $name 或者 echo ${name} //打印变量 nihao # unset name //清除变量变量类型:根据变量的作用域,变量可以分为本地变量和环境变量;本地变量则是只在创建他们的shell中可用。而环境变量则在Shell中所有的用户进程都可以用,通常称为全局变量位置参量:是一种特殊的内置变量,通常被shell脚本用来从命令行接收参数,或者被函数用来保存传递给他的参数说明$0当前脚本文件名$1-9第 1 个到第 9 个位置参量${10}第 10 个位置参量$#位置参量个数$*以单个字符串显示所有位置参量$@未加双引号时与 $* 含义相同,加双引号时有区别$$脚本运行的当前进程号$!最后一个后台运行的进程的进程号$?显示前面最后一个命令的退出状态。О表示没有错误,其他任何值表示有错误。执行shell脚本时,用户可以通过命令行向脚本传递信息,跟在脚本名后面 以空格隔开每个字符串都称为位置参量例如:$1表示一个参数;$2表示第二个参数;第10个之后参数则用${10} //脚本内容 #!/bin/sh echo "hello ${1} ${2}" # . a.sh word! aaaaa hello word! aaaaa //打印语句执行脚本 # ./a.sh # . a.sh # sh a.shif判断命令关于某个档名的『文件类型』判断,如test -e filename表示存在否-e该『档名』是否存在?(常用)-f该『档名』是否存在且为档案(file)?(常用)-d该『文件名』是否存在且为目录(directory)?(常用)关于档案的权限侦测,如test -r filename表示可读否(但root权限常有例外)-r侦测该档名是否存在且具有『可读』的权限?-w侦测该档名是否存在且具有『可写』的权限?-x侦测该档名是否存在且具有『可执行』的权限﹖关于两个整数之间的判定,例如test ni -eq n2-eq两数值相等(equal)-ne两数值不等(not equal)-gtn1大于n2 (greater than)-ltn1小于n2 (less than)-gen1大于等于n2 (greater than or equal)-len1小于等于n2 (less than or equal)判定字符串的数据test -z string判定字符串是否为О?若string为空字符串,则为 truetest -n string判定字符串是否非为О?若string为空字符串,则为false.test str1 = str2str2判定str1是否等于str2 ,若相等,则回传 truetest str1 != str2判定str1是否不等于str2,若相等,则回传false1、单层、简单条件判断式if[条件判断式];then 当条件判断式成立时,可以进行的指令工作;fi // 将if反过来写,就成为fi啦!结束if之意!2、多重、复杂条件判断式if[条件判断式];then 当条件判断式成立时,可以进行的指令工作;elif[条件判断式];then 当条件判断式不成立时,可以进行的指令工作;else 当条件判断式不成立时,可以进行的指令工作;fi 循环 for var in 1 2 3 4 5 do echo ${var} done num=10 s=0 for((i=0;i<${num};i=i+1)) do s=$((${s}+${i})) done
  • 推荐 热门 易懂JavaNIO非阻塞流介绍

     2020-08-07 02:18  124113  32  
    Java NIO(New IO)简介从Java1.4版本开始引入的一个新的IO API与原来的IO有同样的作用和目的,使用的方式不同。NIO支持面向缓冲区、基于通道的IO操作。NIO将以更加高效的方式进行文件读写操作。传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。NIO和IO的区别IONIO面向流面向缓冲区阻塞IO非阻塞IO(无)选择器缓冲区(Buffer)简介在JavaNIO中负责存取数据,缓冲区就是数组。用于存储不同的数据类型(除了boolean类型),提供了对应的类型的缓冲区。ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer缓冲区的核心属性: capacity:容量,表示缓冲区大小,一旦声明不能改变 limit:界限,表示缓冲区可操作做的数据大小,limit 后面不能进行读写 position:位置,表示缓冲区中正在操作数据的位置。 mark:标记,用于需要记录position的位置。2. 缓冲区的核心方法: ByteBuffer.allocate(int):设置缓冲区大小 put():存数据到缓冲区 get():读取缓冲区数据 flip():切换到读取模式 rewind():可重复读数据,回到最开始读取 clear():回到最开始状态(但是数据不会被清理,处于被遗忘状态,基本属性还原) mark():标记当前的position位置。相当于备份3. 直接缓冲区与非直接缓冲区: a.字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在机 此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。 b.直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法 来创建。此方法返回的 缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区 。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的机 本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。 c.直接字节缓冲区还可以过 通过FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建 。该方法返回MappedByteBuffer 。Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常 d.字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理 。缓冲区Buffer代码使用String str = "abcdef";ByteBuffer b = ByteBuffer.allocate(1024);System.out.println(b.isDirect());b.put(str.getBytes());System.out.println("------------------");System.out.println("capacity: "+b.capacity());System.out.println("limit: "+b.limit());System.out.println("position: "+b.position());System.out.println("---------flip---------");b.flip();//切换读取,否则读取不出System.out.println("capacity: "+b.capacity());System.out.println("limit: "+b.limit());System.out.println("position: "+b.position());System.out.println("---------get---------");byte[] byt = new byte[b.limit()];b.get(byt);//获取System.out.println(""+new String(byt));System.out.println("capacity: "+b.capacity());System.out.println("limit: "+b.limit());System.out.println("position: "+b.position());System.out.println("---------rewind---------");b.rewind();//重读System.out.println("capacity: "+b.capacity());System.out.println("limit: "+b.limit());System.out.println("position: "+b.position());System.out.println("---------clear---------");b.clear();//回到原始状态,但并没有清空数据,数据处于被遗忘状态System.out.println("capacity: "+b.capacity());System.out.println("limit: "+b.limit());System.out.println("position: "+b.position());直接缓冲区(内存映射文件方式)代码使用FileChannel reader = FileChannel.open(Paths.get("D:/c.jpg"), StandardOpenOption.READ);FileChannel writer = FileChannel.open(Paths.get("D:/c3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ, StandardOpenOption.CREATE);MappedByteBuffer inMapper = reader.map(MapMode.READ_ONLY, 0, reader.size());MappedByteBuffer outMapper = writer.map(MapMode.READ_WRITE, 0, reader.size());byte[] bye = new byte[inMapper.limit()];inMapper.get(bye);outMapper.put(bye);reader.close();writer.close();基本正常代码使用FileChannel inChannel = FileChannel.open(Paths.get("D:/a.avi"), StandardOpenOption.READ);FileChannel outChannel = FileChannel.open(Paths.get("D:/a1.avi"), StandardOpenOption.CREATE, StandardOpenOption.WRITE);inChannel.transferTo(0, inChannel.size(), outChannel);outChannel.close();inChannel.close();分散(Scatter)与聚集(Gather)分散读取:将通道中的数据分散到多个缓冲区中聚集写入:将多个缓冲区的数据聚集到通道中按照缓冲区的顺序,从 Channel 中读取的数据依次将 Buffer 填满 (图一、分散读取) (图二、聚集写入) 分散(Scatter)与聚集(Gather)代码FileChannel reader = input.getChannel();FileChannel writer = output.getChannel();ByteBuffer buffer = ByteBuffer.allocate(1024);ByteBuffer buffer1 = ByteBuffer.allocate(2024);ByteBuffer[] buffers = new ByteBuffer[]{buffer,buffer1};reader.read(buffers);//分散读取writer.write(buffers);//聚集写入
  • 最新 热门 git命令使用总结帮助文档

     2020-07-27 17:11  127959  7  
    git的安装与配置安装linux:sudo yum install gitgit安装完成后需要进行配置:由于git是分布式版本控制系统;所以需要设置用户名与email:指定你的机器属于谁(如果使用工具这些就不必使用命令配置;诸如idea这些集成开发环境;可以直接在工具里面操作就可以了)使用命令配置:$ git config –global user.name “jenmi”$ git config –global user.email “tanghaibinhaohan@163.com l”使用上面的配置后在c:Uers用户 下面的.gitconfig文件下面出现以下内容: [user] name = tanghaibin email = tanghaibinhaohan@163.com版本库何为版本库版本库英文名为repository,相当于一个文件夹;里面的每一个文件都会被git管理;文件的修改与删除git都会进行跟踪;以便任何时候都可以追踪历史或者还原创建版本库选择好目录再创建文件夹;例如:这样就创建了一个空的文件夹在f盘mkdir folderNamepwd:用于显示当前在哪一个目录下面如果是windows系统;注意父目录与目录名不要使用中文;避免出现莫名其妙的错误以上只是创建了一个空的目录与普通目录并没有什么区别;要想变成能被git管理的仓库;需要使用以下命令:$ git init这样就初始化了一个空的repository在当前文件下面会出现一个隐藏的.git文件夹;这个目录是git来跟踪管理版本库的;不要随意修改;否则乱了后;git仓库也会被破坏掉在repository下面创建一个文件:例如readme.txt;如果需要把其添加到仓库中;可以使用以下命令:git add readme.txt提交文件到仓库:git commit –m “具体的描述(比如修改了什么)”提交之前先add 再commit也可以不add,可以使用参数的方式:git commit –a –m “description…”;这种方式git会自动把已经跟踪过的文件暂存起来然后提交Git不能commit空的文件夹;至少里面需要有一个文件;提交文件夹其实是提交的里面的文件Git取消跟踪某个文件:git rm –cached fileName重命名文件: git mv oldName newName查看修改查看哪些文件被修改过;使用:git status;出现以下内容:On branch masterChanges not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: init.txt modified: readme.txtno changes added to commit (use "git add" and/or "git commit -a")上述内容表示修改了init.txt和readme.txt 两个文件;并且还没有提交如果想查看具体修改了什么;使用:git diff$ git diffdiff --git a/readme.txt b/readme.txtindex 3cbb000..f35227c 100644--- a/readme.txt+++ b/readme.txt@@ -1,2 +1,3 @@<U+FEFF>唐海斌的学习之路-git学习!!! No newline at end of file+git学习!!!aaaaaa+bbb No newline at end of filegit diff命令只能查看未放到暂存区的修改;如果修改已经放到了暂存区;那么可以带参数的方式查看修改:git diff –cached查看最后一次提交git log -1 HEAD版本回退查看最近到最远的日志:gitlog(当回退到某个版本之后,并且当前窗口已经关闭;使用此命令就只能查询最开始到回退到的那个版本之间的log)回退到上一个版本:gitreset--hardHEAD^回退到指定的版本:gitreset--hardcommit_id的前几个字母查看文件的内容:cat文件名查看所有的日志记录:git reflog (此命令就算回退之后;窗口关闭后也能查询出完整的操作记录)HEAD指向的版本就是当前版本工作区与暂存区工作区被git掌管的文件的根目录文件夹暂存区在工作区下有一个隐藏的文件夹 .git ;此文件夹不算工作区;是git的版本库Git的版本库中存放了很多东西;最重要的就是 stage或者叫index的暂存区,还有git为我们创建的第一个分支 master,以及master的指针 HEAD当我们使用 git add 文件名 其实是添加到暂存区中;当使用git commit –m “”命令后才会提交到分支master上面撤销修改撤销工作区的修改: git checkout fileName撤销暂存区的修改: git reset HEAD fileName如果已经提交到了版本库;则直接使用版本回退删除文件删除工作区的某个文件 : rm fileName当删除后如果还未提交;则可以使用: git checkout – fileName 恢复;checkout就相当于把版本库中的版本替换掉工作区中的版本远程仓库查看远程仓库git remote 列出当前被git管理的文件所有远程仓库的简写git remote –v 列出当前被git管理的文件的所有远程仓库的简写与对应的url添加远程仓库git remote add 仓库地址简写 仓库地址远程仓库的移除与重命名重命名:git remote rename oldName newName移除: git remote rm repositoryName创建远程仓库例子Git 与github之间的传送是通过ssh加密的;所以需要设置ssh①创建ssh key 。在用户主目录下;看有没有.ssh目录;如果有;再看看下面有没有id_rsa 和id_rsa.pub这两个文件,这两个就是ssh密钥对,前者是私钥,后者是公钥;如果没有则创建ssh-keygen -t rsa -C "youremail@example.com"②登录github官网创建ssh key ;其中title随便填;key文本框粘贴上公钥内容;点击add就可以了创建远程仓库:①在github上面create respostory,根据提示使用本地的仓库初始化远程仓库:git remote add origin https://github.com/tanghaibin/learngit.git添加后远程仓库的名字就是origin;这是git的默认叫法;也可以修改②把本地仓库的内容推送到远程仓库 git push –u origin mastergit push其实是把当前分支master推送到远程仓库分支master上面;加上-u的仓库;表示当前分支与远程仓库分支关联起来;以后的拉取与推送可以简化命令;从现在起;只要本地修改了;就可以直直接推送到远程仓库分支master上推送之前需要先提交到本地版本库中;在push到远程克隆远程仓库:git clone 仓库地址分支管理当在分支上更改后如果没有提交commit ;直接切回到其他分支;则在所有分支上面都能看到所做的更改;只有当在分支上修改后并且提交后;其他的分支才看不到解决冲突: 当两个分支修改了同一个文件需要手动解决后add再commit退出vim编辑按下esc ;然后输入”:q!”Git标签列出标签git tag:此命令会以字母的顺序列出标签;git标签的分类轻量标签轻量标签就如同一个不会改变的分支;只是一个提交的引用附注标签附注标签是一个存储在git数据库中的一个完整对象;其中包括 打标签者的名字、电子邮件、日期时间、标签信息;它们是可以被校验的;使用 GNU Privacy Guard (GPG)签名与验证。创建标签附注标签:git tag –a tagName –m “内容”查看标签信息与对应的提交信息: git show tagName轻量标签: git tag tagName后期打标签使用git log 命令找到之前提交的commitid对之前提交的内容打标签:git tag –a tagName commitId推送标签到远程Push命令不会把标签也推送到远程仓库;必须手动推送:git push respositoryName tagName:此命令会把tagName推送到远程仓库git push respositroyName –tags : 此命令会把所有远程仓库中没有的标签都推送到远程仓库检出标签如果想要工作目录与仓库中特定的版本标签完全一致;使用:git chekout –b newBranchName tagName:可以不指定newBranchName ;默认检出的新分支会以tagName为分支名称别名创建别名git config -–global alias.aliasName 被替换掉的命令例子:git config –global alias.ci commit:此命令就将commit替换掉为cigit分支由于 Git 的分支实质上仅是包含所指对象校验和(长度为 40 的 SHA-1 值字符串)的文件,所以它的创建和销毁都异常高效。 创建一个新分支就像是往一个文件中写入 41 个字节(40 个字符和 1 个换行符)在git中;有一个指针HEAD指向当前分支;如图:HEAD指针就指向master分支。每个分支都指向一个提交对象;如图;该master分支指向提交对象id为f30ab的对象,当创建一个testing分支后;那么testing的分支就也指向id为f30ab的提交对象创建分支前:创建分支后:创建分支git branch branchName:创建分支git checkout –b branchName:新建分支并且切换到该分支上切换分支git checkout branchName合并分支git merge branchName删除分支git branch –d branchName修改分支后的状态如果我们在testing分支上做了修改并提交;那么就是这种效果:testing分支向前移动了一步;并且HEAD指针指向testing分支;而master分支还是在原来的位置。当我们切回master分支: git checkout master并且做了修改并且提交;就变成如图这种效果:现在就产生了两个提交;可以在适当的时候进行合并:git merge branchName查看每一个分支的最后提交git branch –v查看尚未合并与已经合并的分支尚未合并git branch --no–merged已经合并git branch --merged远程分支推送分支git默认不会推送本地分支到远程仓库;需要手动指定:git push origin branchName跟踪分支跟踪分支:从远程跟踪分支检出到本地的分支叫做跟踪分支当clone远程仓库到本地;默认会在本地创建一个跟踪origin/master 的master分支如果需要修改跟踪的分支:git checkout -–track origin/branchName:此命令会从远程仓库检出一个名为branchName的分支;检出到本地后本地分支的名字也为BranchNamegit checkout –b localBranchName origin/branchName:此命令会从远程仓库检出一个名为branchName的分支;到本地会创建一个名为localBranchName 的分支git branch –vv:列出所有的本地分支;并且包含一些信息;比如:每个分支跟踪的是哪一个远程分支与本地分支与远程分支是否领先拉取数据git fetch 命令从服务器抓取本地没有的数据;不会改变工作目录的内容;它只会获取数据然后让你自己合并git pull 命令从服务器抓取数据并且合并到分支中;实际上是执行两条命令:① git fetch② git merge删除远程分支git push origin –delete branchName变基在git中整合不同的分支上的修改主要有两种方法:merge 和 rebase; rebase就是所谓的变基。merge是把两个分支的提交与共同的祖先进行三方合并生成一个新的快照变基整合 把一个分支上的历史提交逐个应用到 一个分支上面比如现在有两个分支: dev 与 mastergit checkout dev切换到 dev分支上git rebase master 命令会把master 的提交历史逐个应用到dev分支上变基的原则:只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作协议git可以使用4种主要协议①本地协议②http协议③ssh协议④git协议http协议在git1.6.6 版本之前使用的 http协议 通常是只读模式;称为‘哑协议’;而在之后又推出了更加智能的http协议称为‘智能协议’智能协议:此种协议与ssh和git协议有点类似,只是运行在标准的http/s 端口上;支持各种http各种验证机制;比ssh协议简单的多;比如可以使用用户名密码进行授权,免去了设置的ssh 公钥ssh协议ssh协议是一个验证授权的网络协议;ssh协议所有传输的数据都要经过授权和加密ssh不能进行匿名访问;即便钥读取数据也需要有通过ssh协议访问你主机的权限git协议这是包含在 Git 里的一个特殊的守护进程;它监听在一个特定的端口(9418),类似于 SSH 服务,但是访问无需任何授权。 要让版本库支持 Git 协议,需要先创建一个 git-daemon-export-ok 文件 —— 它是 Git 协议守护进程为这个版本库提供服务的必要条件 —— 但是除此之外没有任何安全措施。 要么谁都可以克隆这个版本库,要么谁也不能。 这意味这,通常不能通过 Git 协议推送。 由于没有授权机制,一旦你开放推送操作,意味着网络上知道这个项目 URL 的人都可以向项目推送数据。git协议是git使用网络传输最快的协议Git 协议也许也是最难架设的。 它要求有自己的守护进程,这就要配置 xinetd 或者其他的程序,这些工作并不简单。 它还要求防火墙开放 9418 端口,但是企业防火墙一般不会开放这个非标准端口。 而大型的企业防火墙通常会封锁这个端口。
  • 最新 推荐 热门 原型模式-JAVA设计模式

     2020-07-27 02:11  127035  48  
    原型模式是允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝他们自己来实施创建原型模式的优点:1.Prototype模式允许动态增加或减少产品类。由于创建产品类实例的方法是产品批类内部具有的,因此增加新产品对整个结构没有影响2.Prototype模式提供简化的 创建结构。工厂方法模式常常需要一个与产品类等级结构相同的等级结构,而 Prototype不需要这样。3.Prototype模式具有给一个应用软件动态加载的新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响老系统4.产品类不需要非得有任何事先确定的等级结构,因为Prototype模式适用于任何的等级结构原型模式的缺点:1.使用原型管理器,体现在系统中原型数目不固定时,可以动态的创建和销毁。2.实现克隆操作3.Prototype模式同样用于隔离类对象的使用者和具体类型之间的耦合关系,它同样要求这些‘容易类’拥有稳定的接口原型模式中对象的拷贝是二进制流的拷贝,并不会执行构造函数,因此要在构造函数中做一些额外操作的对象需要注意此问题因为其忽略了构造函数(包括其访问权限),所以和单例模式是冲突的,因为单例模式将构造函数设为private的.尽量使用深拷贝类防止错误的发生,对于只有值域类型的对象使用浅拷贝原型模式中的原型与clone实例通过equals和==比较返回值都是false有些对象的clone()方法是直接new一个对象,如Intent,需要根据创建对象的复杂程度来决定.对于对象中包含final关键字的拷贝无法编译通过Object中的clone()方法是线程不同步的.在需要线程安全的场景,需要做好同步工作.对象的拷贝还有其他方式,如序列化接口Serializable