软件工程用例图与类图

一,用例图之间的的关系 1,泛化关系: 空心箭头代表泛化关系的的代表。(箭头一般是子类指向父类) 2,包含关系(虚线表示) 3,扩展关系 同时也用到了包含关系 注释:重构系统的功能需求模型是前面几种关系的组合,这里不多讲 二,类 类关系的含义及其表示方法 1,泛化关系 注释:空心箭头由子类指向父类 2,实现关系 3,依赖关系(虚线) 4,关联关系 (1):双向关联(无箭头) (2)单向关联(实心箭头) (3)聚集关联(其中空心菱形代表着整体) 聚集关联代表两个类之间的整体与局部的关系 (4)组成关系(部分不能独立与整体而存在)用实心菱形表示 实心菱形也表示的是整体 (5)自身关联 (6)三元关联

js删除字符串最后一个字符的几种方式

JavaScript 中有多种方式可以删除字符串的最后一个字符: 使用 substring() 方法:这个方法可以截取字符串的一部分,从而删除最后一个字符。例如: javascriptCopy codelet str = "Hello World"; str = str.substring(0, str.length - 1); console.log(str); // 输出 "Hello Worl" 使用 slice() 方法:这个方法也可以截取字符串的一部分。只需要将起始索引设置为 0,将结束索引设置为字符串的长度减一即可。例如: javascriptCopy codelet str = "Hello World"; str = str.slice(0, -1); console.log(str); // 输出 "Hello Worl" 使用 substr() 方法:这个方法可以从字符串中提取一个指定长度的子字符串,可以设置起始位置和子字符串的长度。将起始位置设置为 0,将子字符串的长度设置为字符串的长度减一即可。例如: javascriptCopy codelet str = "Hello World"; str = str.substr(0, str.length - 1); console.log(str); // 输出 "Hello Worl" 使用 slice 和 join 方法:将字符串转换为数组,删除最后一个元素,然后将数组转换回字符串。例如: javascriptCopy codelet str = "

链表的创建和遍历

一:链表是什么 链表是多个不连续的内存空间去存储数据的 二:链表是如何进行创建,遍历,插入的 1、我们在写代码的时候都会用到头文件,也就是我们的库函数(以下是我所写的库函数,仅供参考) #include<stdio.h> #include<math.h> #include<string.h> #include<stdlib.h> #include<ctype.h> #include<Windows.h> 2、链表是由结点组成的,结点又分成了数据域和指针域,显而易见,数据域是存储数据的,指针域是存放指针的,所以在这里我们就需要用到结构体,结构体的定义如下所示: typedef struct Node{ int data; struct Node *next; }Node , *LinkList ; 3、首先我们需要创建一个头结点,并为头结点动态申请空间,头结点的数据域是没有数据的,指针域为NULL int main(){ LinkList head=(Node *)malloc(sizeof(Node)); head->next=NULL; 4、接下来我们创建链表,在这里我调用了子函数创建函数(create),需要用到头结点,所以在这里我把头结点当成参数传递给了create,首先需要判断头结点是否为空,不为空则往下面走,我用到了键盘录入(5个数据),我们学到的插入数据有头插法还有尾插法,我这里运用到了链表的头插法 //创建链表 int create(LinkList head){ //判断头结点是否为空 if(head==NULL){ printf("空间申请失败!"); return 0; } int i; for(i=0;i<5;i++){ LinkList p=(Node *)malloc(sizeof(Node)); printf("请输入第%d个数据:",(i+1)); scanf("%d",p->data); p->next=NULL; p->next=head->next; head->next=p; } } 4.1 利用尾插法,运行的结果如下: 5、创建链表并输入数据之后,我们需要遍历链表,我调用了print函数来遍历链表,首先还是判断头结点是否为空,在这里我们需要定义一个指针p来指向head的指针域,判断当p不为空时,即遍历链表 int print(LinkList head){ //判断头结点是否为空,为空即终止函数 if(head==NULL){ return 0; } LinkList p=head->next; //当p不为空时,遍历链表 while(p!=NULL){ printf("

【左手代码右手诗】JAVA学习第八篇:抽象类与接口

目录 一、abstract关键字二、抽象类(abstract修饰的类)2.1、abstract方法 三、接口3.1、接口实现3.2、接口特性3.3、接口与抽象类的区别 面向接口编程 一、abstract关键字 abstract,译为抽象,何为抽象: 抽象是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征的过程。具体地说,抽象就是人们在实践的基础上,对于丰富的感性材料通过去粗取精、去伪存真、由此及彼、由表及里的加工制作,形成概念、判断、推理等思维形式,以反映事物的本质和规律的方法。 二、抽象类(abstract修饰的类) 书写格式: /** * 车子类 */ public abstract class Car { public abstract void run(); } /** * 自行车 */ class Bicycle extends Car{ @Override public void run() { System.out.println("人踩着跑。。。"); } } /*** * 汽车 */ class Automobile extends Car{ @Override public void run() { System.out.println("发动机驱动跑。。。"); } } 特点: 1、abstract类中可以有abstract方法,也可以有非abstract方法 2、abstract类不允许用new运算符创建abstract类对象,只允许被子类继承 3、非abstract型的子类必须重写abstract父类的abstract方法,且重写时要去掉方法前面的abstract关键字,如果是abstract型的子类,可以重写abstract方法,也可以直接继承 4、可以运用多态的特性,让abstract类的对象作为子类的上转型对象。 2.1、abstract方法 特点: 只允许声明,不允许实现,不允许与final一起修饰方法或类,也不允许使用static修饰abstract方法。 三、接口 3.1、接口实现 interface Animal { public void eat(); public void travel(); } public class MammalInt implements Animal{ public void eat(){ System.

【左手代码右手诗】JAVA学习第七篇:面向对象三大特性

前言 面向对象: ​ 一种基于面向过程的新编程思想,顾名思义就是该思想是站在对象的角度思考问题,我们把多个功能合理放到不同对象里,强调的是具备某些功能的对象。 具备某种功能的实体,称为对象。面向对象最小的程序单元是:类。面向对象更加符合常规的思维方式,稳定性好,可重用性强,易于开发大型软件产品,有良好的可维护性。 在软件工程上,面向对象可以使工程更加模块化,实现更低的耦合和更高的内聚。 面向对象开发模式更有利于人们开拓思维,在具体的开发过程中便于程序的划分,方便程序员分工合作,提高开发效率。 该开发模式之所以使程序设计更加完善和强大,主要是因为面向对象具有继承、封装和多态 3 个核心特性。 目录 一、封装1、概念2、封装的作用3、封装的实现a、访问修饰符b、this关键字 二、继承1、继承的目的1、继承的实现a、语法规则b、方法的重写c、继承的初始化顺序c、final关键字d、super关键字 三、多态1、概念2、多态的好处3、多态的实现A、引用多态B、方法多态 总结 一、封装 1、概念 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。封装是将代码及其处理的数据绑定在一起的一种编程机制,该机制保证了程序和数据都不受外部干扰且不被误用。 说白了,封装就相当于一个“黑盒子”,程序员将一堆公共功能的实现逻辑代码装到里面去,然后提供一些接口让你可以使用它,比如充电宝,你要充电的时候直接用数据线插入充电宝的USB接口就行了,不用的时候拔掉就行,我们只知道充电宝有充电和放电的功能,根本不需要关心充电宝里面的零部件都是些什么玩意儿。 封装对于用户,就是用它的人来说是很便捷的,但对于设计者,就是根据封装思想设计产品给大众使用的开发者来说是痛苦的。用好封装是程序员必备的技能点。 2、封装的作用 1、保护类中的信息,它可以阻止在外部定义的代码随意访问内部代码和数据。 2、隐藏细节信息,一些不需要程序员修改和使用的信息,把它隐藏起来,比如取款机中的键盘,用户只需要知道按哪个键实现什么操作就可以,至于它内部是如何运行的,用户不需要知道。 3、有助于建立各个系统之间的松耦合关系,提高系统的独立性。当一个系统的实现方式发生变化时,只要它的接口不变,就不会影响其他系统的使用。例如 U 盘,不管里面的存储方式怎么改变,只要 U 盘上的 USB 接口不变,就不会影响用户的正常操作。六个字:低耦合,高内聚。 4、提高软件的复用率,降低成本。每个系统都是一个相对独立的整体,可以在不同的环境中得到使用。例如,一个 U 盘可以在多台电脑上使用。 3、封装的实现 注意:对封装的属性不一定要通过get/set方法,其他方法也可以对封装的属性进行操作。当然最好使用get/set方法,比较标准。 a、访问修饰符 从上到下封装性越来越强。 b、this关键字 this关键字代表当前对象: this.属性:操作当前对象的属性; this.方法:调用当前对象的方法。 封装对象的属性的时候,经常会使用this关键字。当getter和setter函数参数名和成员函数名重合的时候,可以使用this****区别。 二、继承 前些年有一部韩剧非常的火,叫继承者们,应该是在将富二代们为了继承家产而引起的血雨腥风的故事。 一提到继承,首先想到的就是继承家产,继承皇位,继承人,被继承人… JAVA中的继承其实也差不多就是这个意思。 如同生活中的子女继承父母拥有的所有财产,程序中的继承性是指子类拥有父类数据结构的方法和机制,这是类之间的一种关系;继承只能是单继承。 例如: 学生继承了人(父类)的属性和行为,但他又有自己独有的属性和行为,老师继承了人的属性和行为,但他也有自己独有的属性和行为。 1、继承的目的 继承最主要的目的就是提高代码的复用性和扩展性,以前比如编写一个老师类和学生类,他们都有名字,性别,年龄,都会上课,睡觉,吃饭。一样的东西重复的写,不划算,我直接再定义一个父类:人,把老师和学生相同的属性和行为的描述我放到父类里面,然后老师和学生类继承父类就行了,现在我只用写一遍公用代码就行了,再添加一个班主任类,也直接继承就行了,多方便。 1、继承的实现 a、语法规则 b、方法的重写 子类如果对继承的父类的方法不满意(不适合),可以自己编写继承的方法,这种方式就称为方法的重写。当调用方法时会优先调用子类的方法。 注意:返回值类型,方法名,参数类型与个数甚至顺序都要和父类方法相同才能实现重写。 重载和重写的区别: 方法重载:在同一个类中处理不同数据的多个相同方法名的多态手段。 方法重写:相对继承而言,子类中对父类已经存在的方法进行区别化的修改。 c、继承的初始化顺序 1、初始化父类再初始化子类 2、先执行初始化对象中属性,再执行构造方法中的初始化。 基于上面两点,我们就知道实例化一个子类,java程序的执行顺序是: 父类对象属性初始化---->父类对象构造方法---->子类对象属性初始化—>子类对象构造方法 下面有个形象的图: 我们前面讲到了对象的初始化有多种形式以及执行的顺序:静态代码块——>实例代码块——>构造方法 这里差不多也就是这个意思,如果不明白的可以看看我前面的篇章。 c、final关键字 使用final关键字做标识有“最终的”含义。

基于 Android 13 的 Activity 启动流程分析

对于 Android 客户端开发者来说,Activity 是我们再熟悉不过的一个组件了。它是 Android 四大组件之一,是一个用于直接与用户交互的展示型 UI 组件。在开发过程中,启动并创建一个 Activity 流程非常简单,而在系统底层实际上做了大量的工作,之所以使用这么简单,得益于系统底层对于 Activity 的良好封装。本篇内容我们着重来分析一下 Framework 层 Activity 的启动与创建的过程。 一、前言 在 《不得不说的 Android Binder 机制与 AIDL》这篇文章中我们了解了通过如何通过 Binder 与 AIDL 进行跨进程通信,在另一篇文章 《反思 Android 消息机制的设计与实现》深入探讨了 Handler 消息机制的实现原理。这两篇文章,尤其是通过 Binder 与 AIDL 跨进程通信这块内容是理解本篇文章的基础,如果现在还不了解的同学建议先去阅读这两篇文章。 在平时的开发中,启动一个新的 Activity 只需要在当前 Activity 中调用startActivity方法,并传入一个Intent 即可,例如,从 MainActivity 启动一个 TestActivity 代码如下: Intent intent = new Intent(this, TestActivity.class); startActivity(intent); 两行看似简单的代码,实际上经历了与 system_service 进程的数次互相调用,才成功启动了一个 Activity。为方便理解,后文中我们把启动 Activity 的进程称为客户端,把 system_server 进程称为服务端。 二、客户端的调用流程 startActivity 的操作是由客户端发起的,因此当前的代码执行在客户端进程中。追进startActivity即可看到如下源码: // frameworks/base/core/java/android/app/Activity.java ActivityThread mMainThread; @Override public void startActivity(Intent intent) { this.

使用Python语言写一个推箱子游戏

使用Python语言写一个推箱子游戏 本游戏旨在提供一个趣味性的益智游戏,玩家需要通过推动箱子到指定位置来过关。 游戏规则 玩家需要推动一个或多个箱子到指定位置,才能过关。箱子只能向前推,不能拉回来。箱子不允许被推到障碍物、墙壁或其他箱子上。玩家可以通过 UNDO 按钮来撤回上一步操作,最多可以撤回10步。箱子在指定位置时,会变成已完成状态。 游戏界面 游戏界面由以下元素组成: 地图:表示游戏地图,包含空地、障碍物、墙壁、箱子和目标位置。玩家:表示游戏玩家,用于推动箱子。箱子:表示游戏中的箱子,需要被推到目标位置。目标位置:表示箱子需要被推到的位置。按钮:包含开始、暂停、撤回、重新开始等功能按钮。 技术实现 本游戏使用 Python 语言进行开发,采用 Pygame 框架进行图形界面设计和实现游戏逻辑。 结语 推箱子游戏是一款非常经典的益智游戏,通过本项目的开发,我们不仅可以锻炼编程技能,还可以提高逻辑思维和创造力。 程序代码 import pygame import sys # 初始化 Pygame pygame.init() # 定义游戏界面大小 size = width, height = 800, 600 # 定义游戏界面背景颜色 bg = (255, 255, 255) # 创建游戏界面 screen = pygame.display.set_mode(size) pygame.display.set_caption("PushBox") # 载入游戏所需资源图片 player = pygame.image.load("player.png").convert_alpha() box = pygame.image.load("box.png").convert_alpha() target = pygame.image.load("target.png").convert_alpha() wall = pygame.image.load("wall.png").convert_alpha() # 定义游戏地图 # 0 表示空地,1 表示障碍物,2 表示墙壁,3 表示箱子,4 表示目标位置,5 表示玩家 map_data = [ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2], [2, 0, 1, 1, 0, 0, 1, 4, 4, 1, 1, 1, 2, 2, 2], [2, 0, 4, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2], [2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2], [2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2], [2, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2], [2, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 1, 1, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] ] # 定义游戏元素大小 block_size = 50 # 定义玩家初始位置 player_pos = [5, 1] # 定义推箱子游戏类 class PushBoxGame: def __init__(self): self.

Python实现俄罗斯方块

游戏概述 本游戏是一个基于 Pygame 库的俄罗斯方块游戏,玩家需要控制下落的方块,使其拼接成完整的一行或多行并消除,以获得得分 游戏规则 玩家需要控制下落的方块,使其拼接成完整的一行或多行并消除,以获得得分。方块可以左右移动,旋转或加速下落。当方块下落到底部或与其他方块重叠时,就固定在当前位置,不能再移动或旋转。当所有方块堆叠到屏幕顶部时,游戏结束。 游戏界面 游戏界面包括如下元素: 俄罗斯方块区域:用于显示下落的方块和已固定的方块。得分区域:用于显示当前得分。游戏结束提示:当游戏结束时,屏幕上方会显示 GAME OVER。 游戏实现 游戏的实现采用了 Pygame 库,主要包括如下几个部分: 方块类:用于表示每个方块。形状类:用于表示每个下落的形状,包括方块的颜色和位置。碰撞检测:用于检测形状是否与其他方块重叠。游戏逻辑:包括控制形状的移动,旋转和加速下落,以及消除完整的行等。游戏界面:用于显示游戏界面和更新得分等。 运行环境 本游戏需要 Python 3 和 Pygame 库。可以在 Windows、Mac 或 Linux 平台上运行. 运行方法 在安装了 Python 3 和 Pygame 库的环境下,可以直接运行 tetris.py 文件来启动游戏。 代码实现 import pygame import random # 初始化 Pygame pygame.init() # 游戏界面大小 screen_width = 800 screen_height = 600 # 定义颜色 BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (128, 128, 128) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) # 定义方块大小 block_size = 20 # 定义游戏界面 screen = pygame.

VUE中key的作用

Vue 中的 key 是用来给每一个节点做唯一标识的属性,它的作用是帮助 Vue 进行 DOM 元素的复用。具体来说,当 Vue 更新 DOM 时,它会基于新数据生成一棵 Virtual DOM 树,并将其与旧的 Virtual DOM 树进行对比,通过对比找到需要进行更新的节点,从而达到更新视图的目的。在进行对比时,Vue 会根据 key 的值来判断新旧节点是否相同,从而决定是否进行复用,而不是仅根据节点的标签名和属性等静态信息来判断。 在实际使用中,我们可以通过在每个元素上添加 key 属性来指定节点的唯一标识符。通常情况下,我们可以使用数据对象的唯一标识符作为节点的 key 值,例如在使用 v-for 指令时,可以通过 item.id 来作为节点的 key 值。 需要注意的是,key 值必须是唯一的,否则可能会导致 DOM 元素复用错误或者渲染异常。此外,当使用 v-for 渲染动态数据时,为了保证节点的正确复用,不应该直接修改数据源,而是应该使用变异方法或者重新赋值来更新数据。 除了在节点复用时起到关键作用之外,key 还可以在某些特殊的场景下用来强制重新渲染某个组件或元素。例如,当某个组件的数据依赖于外部环境的变化时,我们可以使用 key 来让该组件在每次更新时都重新渲染,从而确保其数据的正确性。另外,在某些需要强制更新的场景下,我们也可以通过动态改变 key 的值来达到重新渲染的目的。 总之,key 属性是 Vue 中一个重要的概念,可以帮助我们优化页面性能,确保数据渲染的正确性。在使用时,需要注意确保 key 值的唯一性,并且避免直接修改数据源。

理解 zk-SNARKs 和 zk-STARKs 的区别

SNARK 和 STARK 是零知识证明技术,允许一方在不透露任何进一步信息的情况下向另一方证明陈述是真实的。 零知识证明 (ZKP) 引起了广泛关注,因其在增强安全性、保护用户隐私和支持第 2 层网络扩展方面都有很大的潜力。 ZKP 使一方能够向另一方证明声明是真实的,而无需透露任何其他信息。ZKP 既有利于增加隐私——因为它们减少了各方之间共享的信息量——也有利于可扩展性,因为它只需要证明而非整个数据集被验证,这样验证速度会更快。 两个最受关注的零知识证明系统是 SNARK 和 STARK。在本文中,我们将深入探讨它们是什么、它们如何工作以及它们的主要区别。 SNARK 是什么? zk-SNARK 全称 Zero-Knowledge Succinct Non-interractive Argument of Knowledge(零知识简洁非交互式知识论证)——它们是在 2012 年由 Nir ​​Bitansky、Ran Canetti、Alessandro Chiesa 和 Eran Tromer 合著的一篇论文中介绍的。 SNARK 使一方能够在不泄露秘密的情况下向另一方证明他们知道秘密。 zk-SNARKs 可以作为零知识证明协议添加到分布式账本解决方案中,以增强隐私性和可扩展性。 Zcash 是 zk-SNARKs 的第一个广泛应用,应用该技术来创建屏蔽交易(shielded transaction),其中发送者、接收者和金额都是保密的。Zcash 中的屏蔽交易可以在区块链上完全加密,但仍然可以通过使用 zk-SNARKs 在网络的共识规则下验证为有效。 一些 SNARK 的一个重要属性是它们要求配置过程是可信任的——在这个过程中,隐私交易的证明和生成证明的密钥会被创建。如果在事件期间用于创建这个密钥的秘密没有被销毁,它们可能被用来创建虚假证明。在涉及加密资产的场景中,这将使参与者能够伪造交易或凭空铸造新通证。由于 SNARKs 固有的隐私性,所以无法验证伪造的证明是否确实是伪造的。 SNARK 的安全级别是通过为找到虚假陈述的证据而必须完成的工作量来衡量的。换句话说,如果 SNARK 在计算上无法产生令人信服的虚假陈述证明,那么它就是安全的。对于需要可信设置才能被认为是安全的 SNARK,仪式中至少有一名参与者必须生成并销毁一个 trapdoor,如果与其他 trapdoor 结合使用的话,否则就有可能危及 SNARK 的安全性。因此,受信任的设置通常需要许多参与者一起运行,以使这种情况发生的可能性足够低。 虽然可信设置仅在最初需要且仅适用于某些 SNARK,但基于 SNARK 的网络的用户必须相信可信设置的仪式(ceremony)已正确执行,并且秘密已被销毁并且不被创建事件的参与者持有。对这种仪式的依赖一直是一些 SNARK 的备受批评的领域,认为它是潜在的安全弱点。

更换 Linux 自带的 jdk 环境

如下,我要把 Linux 默认的 jdk 版本换成我自己的 jdk 版本。 Linux 自带的 jdk 环境: 要更换的 jdk 环境: 操作步骤: 1、使用 su- 命令切换到 root 用户进行操作; 2、在根目录下创建一个 /export/server/ 目录; [root@centos /]# mkdir -p /export/server/ 3、进入该 server 目录; [root@centos /]# cd /export/server 4、使用 rz 命令上传你要上传的 jdk 版本; [root@centos server]# rz 在最右侧的该图标查看下载进度; 5、下载完成之后,使用 ll 命令,查看是否下载成功; 6、在当前目录解压 jdk 安装包; [root@centos server]# tar -zvxf jdk-8u351-linux-x64.tar.gz 解压完成之后,使用 ll 命令,查看是否解压成功; 7、因为 jdk 文件的名字太长了,到时候要使用的时候不方便;所以我创建了一个软链接文件,重新进行命名,到时候要使用该 jdk 的时候就直接使用软链接里面的 jdk 名字就可以了(也可以 7、 的操作); [root@centos server]# ln -s /export/server/jdk1.

git分别手动创建本地仓库和远程仓库默认master分支无法使用其他分支可以使用不能pull也不能push

git 控制台错误信息 13:50:48.820: [practices] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false push --progress --porcelain origin refs/heads/master:master --set-upstream To "仓库地址" ! refs/heads/master:refs/heads/master [rejected] (fetch first) Done error: failed to push some refs to "仓库地址" hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes

numpy中的插值函数interp

作用 根据给定样本点返回指定位置的线性插值。 使用 import numpy as np np.interp(x, xp, fp, left=None, right=None, period=None) 参数 x:用于估计插入值的x坐标值;xp:x轴数据点,若参数period未指定,则该数据点必须是递增的,否则,xp将会以xp = xp % period规范化数据周期边界,然后在周期内进行排序;fp:y轴数据点,长度与xp一致;left:当x小于xp序列的第一个值时,要返回的值,默认返回fp的第一个值;right:当x大于xp序列的最后一个值时,要返回的值,默认返回fp的最后一个值;period:横轴的周期,该参数允许对角度横坐标进行适当的插值,若参数period被指定,则忽略参数left与参数right; 也就是说,该函数通过xp与fp之间的对应函数关系,估计x处的对应值来进行线性插值。 示例 线性数据插值 xp = [1, 2, 3] fp = [3, 2, 0] np.interp(2.5, xp, fp) 返回值: 1.0 理解:通过获取xp与fp的对应线性函数关系,估计在2.5处的函数值。

Windows下后台运行、关闭jar的命令

1.启动 创建bat文件 输入内容如下(java.jar需要改成自己的) javaw 代表后台运行,不会出现黑框框 @echo off start javaw -Dfile.encoding=UTF-8 -jar java.jar exit 运行 jar包,并输出日志 @echo off %1 mshta vbscript:CreateObject("WScript.Shell").Run("%~s0 ::",0,FALSE)(window.close)&&exit java -jar java.jar > D:\test\log\server.log 2>&1 & exit 2.关闭 创建bat文件 杀死java进程 @echo off taskkill /f /im javaw.exe exit

史上最全JVM大全详解!java程序员细节到极致的一次,魔鬼

前言 作为 Java 的从业者,在找工作的时候,一定会被问及关于 JVM 相关的知识。 JVM 知识的掌握程度,在很多面试官眼里是候选人技术深度的一个重要评判标准。而大多数人可能没有对 JVM 的实际开发和使用经验,接下来这一系列文章将带你深入了解 JVM 需要掌握的各个知识点。这也将帮助你完成从初级程序员到高级程序员的转变。 目录 线程(详解) JVM内存区域(详解) JVM运行时内存 垃圾回收与算法 JAVA四种引用类型 GC分代收集算法VS分区收集算法 GC垃圾收集器 JAVA IO/NIO JVM类加载机制 正文 一、线程(详解) 这里所说的线程指程序执行过程中的一个线程实体。JVM 允许一个应用并发执行多个线程。Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系。当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。Java 线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。当线程结束时,会释放原生线程和 Java 线程的所有资源。 Hotspot JVM 后台运行的系统线程主要有下面几个: 二、JVM内存区域(详解) ​ JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区域【JAVA 堆、方法区】、直接内存。 线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 HotspotVM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的生/死对应)。 线程共享区域随虚拟机的启动/关闭而创建/销毁。 直接内存并不是 JVM 运行时数据区的一部分, 但也会被频繁的使用: 在 JDK 1.4 引入的 NIO 提供了基于 Channel 与 Buffer 的 IO 方式, 它可以使用 Native 函数库直接分配堆外内存, 然后使用DirectByteBuffer 对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在 Java堆和 Native 堆中来回复制数据, 因此在一些场景中可以显著提高性能。

JAVA高级编程之多线程(看完这一篇就够了)

目录 一、进程1、进程的由来(为什么会出现进程?)1.1、什么是CPU?1.2、CPU是如何工作的?1.3、如何解决CPU利用率不高的问题? 2、进程的概念2.1、进程三大特性 二、线程1、线程的由来(为什么又会出现线程?)2、线程的概念2.1、线程与进程的区别2.2、线程相比于进程的优势 3、Thread类核心操作3.1、线程创建(1)通过继承Thread的方式创建线程(2)通过实现Runnable的方式创建线程(3)通过实现Callable的方式创建线程(4)通过基于lambda的方式创建线程 4、线程属性4.1、如何中断一个线程4.2、如何等待线程结束4.3、如何获取线程的引用4.4、如何进行线程休眠 5、线程状态及线程状态的相互转换6、线程安全6.1、什么是线程安全6.2、线程不安全的原因有哪些?6.3、如何确保线程安全线程同步死锁问题 7、线程等待/通知7.1、等待唤醒机制wait 内部的工作过程是怎样的为什么 wait 和 notify 要在 synchronized 内部使用 总结 一、进程 这是我们能够最直观的从计算机中看到的进程的样子,你是否会发出这样的疑问:这东西有什么用呢?这东西是个什么玩意儿啊? 别着急,我们带着疑问去深度的了解它。 1、进程的由来(为什么会出现进程?) 1、提到进程,我们不得不从梦想开始的地方讲起,而梦想开始的地方在CPU上; 1.1、什么是CPU? 1、计算机中,按照冯诺依曼体系把计算机硬件分为了5部分,分别对应:存储器、运算器、控制器、输入设备、输出设备;而运算器和控制器就组成了CPU、中文名叫中央处理单元; 2、我们一个程序要想执行,第一步就得把它从磁盘或者其他外存上移到内存中去,这一步操作系统帮我们做了; 3、放到内存之后,控制器负责对程序指令进行解释执行,运算器负责对数据进行运算,而它们的执行过程是如下图的样子: 1.2、CPU是如何工作的? 我们只需要给CPU开始执行第一条指令的位置,也就是PC指针指向的第一个位置后,这条指令就会被控制器解释并执行,就像厨师开了菜谱的第一步之后开始做第一步,然后做完了之后,PC指针就会自动指向下一条指令,然后控制器再一次解释执行,以此类推直到厨师做完这道菜为止;那么整个过程中,控制器就好比厨师的大脑,运算器就好比厨师的双手,菜谱就好比加载到内存中的程序被编译后生成的一条条指令,而PC指针就是厨师的双眼,眼睛看菜谱,大脑调动双手去做菜,最后完成这么一个程序的执行任务。 那么我们既然要用CPU这个东西,我们也必然需要去对它进行正确的管理,不然就会出现问题,比如说:现在我们只给CPU一个PC指针指向的起始位置,然后让CPU自动完成工作,会出现什么问题? 我们下面来看一段程序: 上图程序右边第一个黑框表示的是有IO指令时这段程序的执行时间,第二个黑框表示的是把IO指令换成普通的计算指令后的执行时间,而他们的比值约为1000000:1。 CPU的工作是解释执行程序,然后对数据进行运算,而程序最终结果的打印,也即是IO指令是由外部设备(输入/输出设备)来完成的,也就是说CPU解释执行一条IO语句,那么操作系统就会把控制权转交给外设,而转交需要时间,外设工作需要时间,并且外设的工作时间远比CPU长,CPU是通过电路进行工作的,外设是机器,所以它两的工作效率有天壤之别; 我们想一想,当IO设备在工作的时候,CPU是什么状态? 此时的CPU会等待IO设备执行完成,在此期间,CPU处于空闲状态,由此我们是不是可以发现一个特别重要的问题:那就是CPU的利用率不高。 我们发明计算机的目的就是需要其做大量的复杂的科学计算,而现在它几乎一半的时间是在等待,是在处于空闲状态,这是我们科学家不想要看到的结果。 既然发现了问题,怎么样去解决呢? 1.3、如何解决CPU利用率不高的问题? 这个时候我们就不得不举一个生活中的例子了,比如说: 你现在正开始做饭,然后你首先第一步就是把饭煮上了,在饭煮熟之前的这段时间,你是选择等饭熟了之后再开始炒菜,还是在煮饭的同时,你就开始炒菜?我相信聪明人都应该选择后者,如果你不选,这不能直接说明你不太聪明,但至少可以说明你根本不饿。 那么我们的CPU就是那个聪明的小朋友: 那么我们怎么去具体实现在一个CPU上交替执行多个程序,以此来提高CPU的利用率呢?方案现在给你提出来了,你怎么去执行它? 我们如果单单只是修改PC指针的指向就行了吗?当然是远远不够的,为什么? 程序1的ax它本应该等于2,但由于执行到52行时,PC切出去了,切到了200行,当执行完程序2后,PC指针再切到52行,此时的ax就变成了20,程序1受到了程序2的影响,结果出现了偏差,计算失败告终!!! 所以现在我们需要有一个东西去把程序运行时的每一刻该是什么样子的,给记录下来,就像是看电视剧时按下了暂停键,保护好案发现场,而这个东西就被科学家给创造出来了,它就是PCB,全称process control block,进程控制块。 哦!!!!到这里终于出现了进程两个字了,什么是进程,相信大家都差不多可以猜到了: 我们不难发现,静态的程序和在内存上运行起来的程序是不是完全不同的样子,那么我们该怎么去描述一个程序动态执行的过程?没错,我们给它取了个响当当的名字,那就是进程!!! 2、进程的概念 我们来总结一下什么是进程: 1、一个具有独立功能的程序在一个数据集合上的一次动态执行过程; 2、在操作系统中,每个独立运行的程序就是一个进程,当一个程序进入内存运行时,即变成了一个进程; 3、进程是操作系统进行资源分配和调度的一个独立单位,是具有独立功能切处于运行过程中的程序。 2.1、进程三大特性 1、独立性:每个进程都拥有自己的私有地址空间,其他进程不可以直接访问该地址空间,除非在进程本身允许的情况下; 2、动态性:程序只是一个静态的指令集合,进程是一个正在内存中运行的、动态的指令集合,进程具有自己的生命周期和各种不同状态; 3、并发性:多个进程可以在单个处理机(CPU)上并发执行,多个进程之间互不影响;并发又可以解释位同时出发,交替执行。 二、线程 1、线程的由来(为什么又会出现线程?) 我们来看一个例子: 怎么去开发这个软件?或者说以什么方式去开发这个软件? 方案一: 这个方案播放出来的声音肯定是不连贯的,为什么? CPU会出现长时间空闲状态。 方案二: 这个方案看起来是可行的,分别为三个核心功能模块单独创建一个进程,这样确实可以解决单进程空闲的问题,但是这么做合理吗?有没有不好的地方? 有: 1、进程之间如何通信和共享数据? 我们知道进程它是具有独立性的,要想它们之前互相访问,必须得双方允许才行,可是这样好像有点浪费时间精力吧,你去拿个东西或者办件事,每次都得需要别人同意,每次都需要你把证明准备好,这是不是有点分散精力了,有点本末倒置; 2、维护进程的系统开销较大

Node笔记

一、node概述 1、Chrome 浏览器的v8引擎可以解析JavaScript代码 2、Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 浏览器是 JavaScript 的前端运行环境。 Node.js 是 JavaScript 的后端运行环境。 Node.js 中无法调用 DOM 和 BOM 等浏览器内置 API 3、Node.js 的学习路径: JavaScript 基础语法 + Node.js 内置 API 模块(fs、path、http等)+ 第三方 API 模块(express、mysql 等) 二、 终端中的快捷键 使用 ↑ 键,可以快速定位到上一次执行的命令 使用 tab 键,能够快速补全路径 使用 esc 键,能够快速清空当前已输入的命令 输入 cls 命令,可以清空终端 三、 fs 文件系统模块 1、fs 模块是 Node.js 官方提供的、用来操作文件的模块。使用 fs 模块来操作文件,需要先导入 constfs =require('fs') 2、读取指定文件中的内容 // 导入fs模块 constfs=require('fs') // 读取内容 fs.readFile('./files/11.txt', 'utf8', function(err, dataStr) { if (err) { returnconsole.

【Vue】中Key的作用

Vue中key的作用 虚拟DOM 虚拟DOM 本质上是一个js对象 ,通过对象来表示真实的DOM结构。 key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据 新数据 生成 新的虚拟DOM key的原理及作用 Key是对节点进行的一个标识,在Vue中,Key作为Vue中对比算法的标识,在数据修改后,可以通过Key进行这个唯一标识进行对比虚拟DOM,从而决定对节点的重新加载以及复用 Key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较。 Key的对比规则 旧虚拟DOM中找到了与新虚拟DOM相同的key: 若虚拟DOM中内容没变, 直接使用之前的真实DOM!若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。 旧虚拟DOM中未找到与新虚拟DOM相同的key 创建新的真实DOM,随后渲染到到页面。实例展示 实例展示 前端代码展示 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>key的原理</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <div id="root"> <!-- 遍历数组 --> <h2>人员列表(遍历数组)</h2> <button @click.once="add">添加一个老刘</button> <ul> <li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} <input type="text"> </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { persons: [ { id: '001', name: '张三', age: 18 }, { id: '002', name: '李四', age: 19 }, { id: '003', name: '王五', age: 20 } ] }, methods: { add() { const p = { id: '004', name: '老刘', age: 40 } this.

在 tomcat 内部署简单的 html 网页

一、tomcat 的简单介绍 tomcat 是一个轻量级的免费开源的 Web 应用服务器,对于一个初学者来说,可以这样认为,当在一台机器上配置好 tomcat 服务器,可利用它响应 HTML(标准通用标记语言下的一个应用)页面的访问请求。 二、没有部署 tomcat 后打开 HTML 文件 在本地打开 HTML 文件,访问路径如下(为具体某个盘符): 三、部署 tomcat 后打开 HTML 文件 步骤一、启动 tomcat 在 tomcat 的 bin 目录下的 startup.bat 程序启动。 如下,这是在我电脑内的路径:D:\apache-tomcat-8.5.20\apache-tomcat-8.5.20\bin,然后点击 startup.bat。 如果出现了下图:用红色边框标记的信息,则启动成功!!! 步骤二、在 tomcat 内部署简单的 html 网页 在 tomcat 的 webapps 目录的 ROOT 目录内,把要部署的 html 网页复制到该文件夹内。 如下,这是在我电脑内的路径:D:\apache-tomcat-8.5.20\apache-tomcat-8.5.20\webapps\ROOT 然后就可以通过网页的形式去访问: http://127.0.0.1:8080/网页名.html http:// 为协议; 127.0.0.1 为本地回环地址,指代本机; :8080 为 tomcat 默认使用的端口号,在端口号前面都要加上 ":"; 网页名.html 为 html 网页名; 完。。。