先举一个生活中的例子:你买了一袋面粉,想用来揉几个包子,发几个馒头……可以把面粉当成原始数据,包子、馒头是你运用你的技能加工之后的成品数据。这里的技能相当于开发者的编程能力。但是!元数据到底是什么!!!买面粉的时候面粉袋上有很多说明,面粉出自何地、面粉的净重量有多少……这些信息对于你的加工过程有很大的参考价值。面粉的出生地让你知道什么地方出产的面粉适合做馒头、什么地方出产的面粉适合做面包……净重量能告诉你最后能生产几个包子、几个馒头……如果人多,就应该多买几袋,至少能让你在款待客人时表现的美丽又大方。元数据的标准概念是用来描述数据的数据!换一句容易理解的话,面粉是数据,用来包装面粉的面粉袋上的说明信息就是元数据。大家知道持久化对象吧:POJO+XML。XML描述的映射信息就是用来描述学生对象数据的元数据。
在本节的开头,我们来谈一谈为什么开发程序需要使用锁?如果你有一点并发编程的基础,又或者对多线程有一点熟悉,那么你肯定知道答案,那就是数据竞争。
相信搞前端的大多数都听过雪碧图这么一个神奇的名字,有些人知道它是做什么的,但是有些人不知道它为什么叫雪碧图,今天我就带领大家来重新认识一下雪碧图: (鼠标点击可以互动)
说这么多,那么什么是 Ajax 呢?简单来讲,Ajax 就是 JavaScript 基于 XMLHttpRequest 对象与服务端进行交互,向服务端发送一个请求,并且获取和处理服务器返回的内容。在这个过程中,我们可以使用 XML ,HTML 和 JSON 等格式的数据进行交互。并且,Ajax 拥有异步特质,我们可以在不刷新页面的情况下,通过交互数据,在页面上做局部的刷新等数据处理。
什么是 RabbitMQ 呢?在 RabbitMQ 官网中是这么介绍的:一场使用消息进行通信的高可用和数据安全的在线会议. —官网上述定义是官网的抽象描述,添加了一些官网的色彩在里面,同学们可能不太理解,下面我对定义进行一些必要的解释。通俗来讲,我们可以这样理解:RabbitMQ 是一种消息通信方式,采用消息队列的形式,来将消息进行传递与发送,RabbitMQ 在通过消息队列传递消息时,可以保证消息的高可用性、消息中数据的安全性。也就是说,RabbitMQ 是一种高可用且数据安全的消息通信中间件。
什么是延迟加载?前面的测试结论已经给出了答案。使用 Hibernate 获取数据时,有时,Hibernate 并不急着去数据库,而是等到开发者真正需要数据时才会跑一趟数据库。load() 方法 和 get() 方法的基础区别:load() 支持延迟加载(Lazy);意思是,别急,你需要时我再去拿数据。如果没有拿到数据,则会抛出异常。get() 方法不支持延迟加载,而是(Fetch),如果没有拿到数据,则返回 null 。什么时候使用 get(),什么时候使用 load()。只有需求才能告诉你如何权衡,没有绝对的忠告。
接口(软件类接口)是指对协定进行定义的引用类型。其他类型实现接口,以保证它们支持某些操作。接口通常用 API 替代。这个概念不太好理解,接下来,我们用一个例子帮助大家更好地理解什么是接口。假如在一个学生管理系统中,我们想要查询一个学生的信息,我们输入http://www.demo.com/students/2020,此时我们将获得编号为 2020 的学生信息。我们通过链接与服务器交互,并获取到了想要的数据,那么与服务器交互的这个链接就可以称作是一个接口(API)。
泛型不只是 Java 语言所特有的特性,泛型是程序设计语言的一种特性。允许程序员在强类型的程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须做出声明。我们在上一小节已经了解到,Java 中的集合类是支持泛型的,它在代码中是这个样子的:代码中的<Integer>就是泛型,我们把类型像参数一样传递,尖括号中间就是数据类型,我们可以称之为实际类型参数,这里实际类型参数的数据类型只能为引用数据类型。那么为什么需要泛型呢?我们马上就见分晓。
关于数据增强,我们可以在 TensorFlow API 之中看到相关的定义:A technique to increase the diversity of your training set by applying random (but realistic) transformations.翻译一下就是:数据增强是一种通过应用随机(但现实)的变换来增加训练集的多样性的技术。简单来说,通过数据增强,我们可以将一些已经存在的数据进行相应的变换(可以选择将这些变换之后的数据增加到新的原来的数据集之中,也可以直接在原来的数据集上进行变换),从而实现数据种类多样性的增加。数据增强常见于图像领域,因此这节课我们会以图像处理为例来解释如何在 TensorFlow 之中进行数据增强。对于图片数据,常见的数据增强方式包括:随机水平翻转:随机的裁剪;随机调整明亮程度;其他方式等。
首先,我们大概了解什么是协议,协议可以把它认为是一种规则而不是技术,约束客户端和服务端之间通讯,数据组装和拆分的一种规范。客户端安装某种规范去组装数据,把数据传输给服务端,服务端再安装这种规范拆解数据,那么这就是一种协议,可以根据实际业务区指定符合自身的协议,其实基于 Netty 去制定的私有协议,我个人接触过的是传输车辆 GPS 数据的 809 协议,在和 GPS 服务器通讯时,必须按照该协议去进行封装和解析数据,否则通讯异常。其实,类似的规则还有很多,从开发的角度来说,都是各种规则和约束,比如说:前面提到的序列化技术,序列化其实就是把数据按照某种规则去转换成 byte 数字,而反序列化就是按照这种规则再去把字节流转换成对应的类型数据。这些都是基于某种规则的基础上,使用技术的手段去封装的结果。
一个应用程序,当功能越来越庞大、逻辑越来越复杂、代码越来越多时,必然会采用分而治之的方案。分,容易,如何分才能分得清晰、便于维护,这是一个与管理有关的学问。MVC 提出了一种分离的策略,这种想法或思想一问世,便让世人茅塞顿开。MVC 的分离思想:把整个应用程序中和用户进行交互的功能代码归纳在一起,这部分代码整体称为 V (View 或叫视图层);把专门用来进行数据传递或数据逻辑处理的功能代码归纳在一起,称其为 M(Model 或叫l模型层)。C 指的是哪一部分功能代码呢?因为V 和 M 是要经常交流、沟通的,V 需要展示 M 处理过的数据,同时,M 也可能需要 V 提供的用户交互时输入的数据。虽然分了,但两者之间存在依赖关系。我们不让 V 和 M 直接交流,而是在两者之间引入了一个叫做 C(控制器)的对象,所以说 C 就是 V 和 M 之间的桥梁!这个 C(控制器)对象感觉在硬生生的拆散别人,不过这种拆分是善意且友好的。为什么这么说?满足 OOP 中的低耦合性原则,解耦 V 和 M 之间的关系;M 需要用户交互时输入的数据时,可以不用管 V 是谁,只要有控制器传数据就可以;同时,V 也不用关心 M 在哪里,只要有数据提供给自己就可以。如果现在要编写一个 WEB 视图和 Swing 视图的双客户端应用程序时,只需要换一个 C 就可以,M 可以重用。
微分是所有目前几乎所有机器学习的基础,也是 TensorFlow 与 Pytorch 等框架的基础。我们对模型进行优化的过程大致可以分为以下三个步骤:数据通过模型得到输出;我们通过计算得到模型中每个参数的梯度;确定学习的步长(学习率);按照梯度的方向和学习率对每个参数进行优化。我们可以很清楚的看到,最后的两步是关键的优化部分,而第二步 —— 求得梯度的一步就是这两个关键步骤的前提和基础。因此我们要首先了解什么是 “梯度”。梯度的本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值 —— 百度百科。简单来说,就是梯度是一个方向,它会指明某一个参数在哪个方向上面变化地更快。或者不恰当地说(但是却非常容易理解),梯度可以理解为一个参数的导数。因此我们可以通过梯度就可以得到模型的参数在哪个方向上面变化,会使得最终的结果的 Loss 变小;进而我们就可以进行模型的优化工作。举个例子:y = x**2 + 4这是一个很简单的赋值公式:我们将 x 的平方加上 4 ,然后将其赋给 y 。那么 y 对于 x 求导数,便得到:dy_dx = 2*x因此我们在 x 取任意一个值的时候便可以得到 y 对于 x 的梯度。比如当 x 为 5 的时候,那么 y 对于 x 的梯度便为 2 * 5 = 10 。
与其他语言一样,Shell 也有运算符,在 Shell 中其根据类型不同也有不少运算符分类,那么什么是运算符呢?例如大家都知道在算术运算中的加减乘除,+ 就是我们 Shell 中的算术运算符的一种,当然还有很多其他的功能各异的运算符,作为条件判断与算术操作等重要功能,构成了 Shell 中的基本元素。
“TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。” ——Wiki百科这种过于官方化的定义可能比较难于理解,于是我们给出一个比较容易理解的解释:TensorFlow 就是一个开源的用于机器学习的框架,我们可以使用 TensorFlow 来快速地构建神经网络,同时快捷地进行网络的训练、评估与保存。也正是因为 TensorFlow 是一个开源的软件库,因此只要我们安装了 TensorFlow,我们就可以使用import 的方式来引入。import tensorflow as tf那么具体说来 TensorFlow 可以干什么呢?简单的回答是:TensorFlow 主要负责机器学习的每一个步骤,具体包括:模型的构建;模型的训练;模型的保存与加载;模型的评估;使用加速器提升性能;在生产环境中部署网络;对模型的数据进行可视化(TensorBoard);其他功能。通过这样的梳理我们可以发现,TensorFlow 可以满足我们在机器学习中的从模型构建到模型的部署的绝大部分的工作需求。
什么是 Vue 呢?Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。 —官网
来自百度百科的解释 —— 控制反转(IoC):(Inversion of Control,缩写为 IoC),是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称 DI),还有一种方式叫 “依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。慕课解释如何理解好 IoC 呢?上一个小节中,我们使用简单的语言对它做了一个描述 —— IoC 是一种设计模式。将实例化对象的控制权,由手动的 new 变成了 Spring 框架通过反射机制实例化。那我们来深入分析一下为什么使用 IoC 做控制反转,它到底能帮助我们做什么。我们假设一个场景:我们在学习 Web 阶段的过程中,一定实现过数据的查询功能,那么这里我就举一个实例:我们有这样几个类:UserServletUserService 接口 UserServiceImpl 接口的实现类 UserDao代码如下:/*UserServlet 作为控制器 接收浏览器的请求*/public class UserServlet extends HttpServletRequest { //用户的业务类 提供逻辑处理 用户相关的方法实现 private UserService userService; public void service(HttpServletRequest request,HttpServletResponse response){ //手动实例化UserService接口的实现类 userService = new UserServiceImpl(); List<User> list = userService.findAll(); //省略结果的跳转代码 } }/*用户的业务接口UserService*/public interface UserService{ public List<User> findAll(); }/*UserServiceImpl 作为用户的业务实现类 实现类UserService的接口*/public class UserServiceImpl implements UserService{ //用户的Dao private UserDao userDao; public List<User> findAll(){ //手动实例化Dao userDao = new UserDao(); return userDao.findAll(); }}问题分析:上面的代码有什么问题吗? 按照我们学习过的知识… 答案是没有。因为 Dao 只要数据源编写代码正确, 完全可以实现数据的增删改查 ,对吗?但是分析分析它我们发现:代码耦合性太强 不利于程序的测试:因为 userServlet 依赖于 userService ,而 userService 依赖于 userDao , 那么只要是被依赖的对象,一定要实例化才行。所以我们采取在程序中硬编码,使用 new 关键字对对象做实例化。 不利于测试,因为你不能确保所有使用的依赖对象都被成功地初始化了。有的朋友很奇怪,对象实例化有什么问题吗? 如果构造参数不满足要求,或者你的构造进行了逻辑处理,那么就有可能实例化失败;代码也不利于扩展:假设一下,我们花了九牛二虎外加一只鸡的力气,整理好了所有的类使用的依赖,确保不会产生问题,那么一旦后续我们的方法进行扩充,改造了构造函数,或者判断逻辑,那么是不是所有手动 new 对象的地方都需要更改? 很明显这就不是一个优雅的设计。解决方式:Spring 的 IoC 完美的解决了这一点, 对象的实例化由 Spring 框架加载实现,放到 Spring 的容器中管理,避免了我们手动的 new 对象,有需要用到对象实例依赖,直接向 Spring 容器要即可,而一旦涉及到对象的实例修改,那么 只需更改 Spring 加载实例化对象的地方,程序代码无需改动,降低了耦合,提升了扩展性。
明白了办公自动化,就是解决了我们在办公过程中,提高工作效率、简化工作流程的方法。那 Python 办公自动化又是指什么呢?首先 Python 作为一种跨平台的计算机程序设计语言,在最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python 中有强大的内置库和丰富的第三方库,所有你能想到的功能都可以利用 Python 快速、高效的解决,所以 Python 也越来越成为办公自动化的首选。简而言之,Python 办公自动化就是通过 Python 编写程序来解决办公过程中所遇到的问题。如果看到这里你还不太理解 Python 办公自动化是什么,那可以想象以下场景:需要你将 1000 个 Excel 文件中的数据进行统计;打开有 10W+ 条数据的一份 Excel 文件进行数据的统计;根据已有数据快速制作大量图表到 PPT 中;已经完成的 1000 份 Word 文件中,公司名称变更,需要批量更改;对于上述的工作场景,如果不通过编程的方式我们怕不是要一条条数据,一个个文件进行修改,既费时又费力。而使用了 Python 之后上面这些场景很可能只需要短短几行代码就能快速完成。
作为机器学习中最基本的数据集合之一, fashion_mnist 数据集一直是入门者做程序测试的首选的数据集,相比较传统的 mnist 数据集而言,fashion_mnist 数据集更加丰富,能够更好的反映网络模型的构建的效果。fashion_mnist 数据集合是一个包含 70000 个数据的数据集合,其中60000 条数据为训练集合,10000 条数据为测试集合;每个数据都是 28*28 的灰度图片数据,而每个数据的标签分为 10 个类别。其中的几条数据具体如下图所示(图片来自于 TensorFlow 官方 API 文档)。我们要做的就是如何根据输入的图片训练模型,从而使得模型可以根据输入的图片来预测其属于哪一个类别。fashion_mnist 数据集合的 10 个类别为:["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
我们知道了 Shell 是一个用户与 Linux 系统内核的通讯的桥梁后,那么 Shell 脚本是什么呢?Shell 脚本就是操作 Shell 的指令集合编写成的一段实现目的需求的代码,也为一种管理 Linux 系统的脚本语言,我们可以简单地将其理解为,Linux 的各种指令加上一些流程控制和数据的集合,因为它还有不少的语法及格式,后面我们来通过学习,详细剖析其内在精髓。
那究竟什么是 Maven 呢,在 Maven 的官网上可以看到如下的解释:Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.翻译过来就是:Maven 是一个软件工程的项目管理工具,基于工程对象模型(POM),Maven 可以从中央信息篇中来构建项目,生成报告和文档。从上面的介绍中,我们可以看到 Maven 的主要功能是管理项目,构建项目。关于 Maven 的由来,据其创始人者 Jason Van Zyl 描述,是为了更加便利地建设 Jakarta Turbine 项目而创立的一个项目。在当时,比较流行的项目构建工具是 Ant,但是,在这个阶段中,各种 Java 项目之间是没有什么规范的,新创建项目的时候,就需要重新编写对应的构建脚本。Jason 就相对应设计出一套标准的项目结构,标准的构建方式,用来简化项目的构建。2003 年的时候,Maven 已经是 Apache 基金会的顶级项目了。
什么是 Zookeeper 呢?我们先来看一下 Zookeeper 的官网介绍:原文直接翻译过来的概念很抽象,那我们简单的解释一下。在分布式环境中,存在着大量的服务,服务与服务之间难以做到彼此协调,也不便于开发人员对服务进行维护管理,而 Zookeeper 使用它简单的结构和 API ,协调服务与服务之间的关系,让开发人员专注于应用程序的核心业务逻辑,更方便的对应用程序的服务进行管理维护。所以我们可以把 Zookeeper 叫做分布式协调服务。简单介绍了 Zookeeper 是什么,接下来我们就来了解一下 Zookeeper 具体的应用场景。
顾名思义,数组就是一系列数据的集合,这个数据就是我们之前学习的存储单个元素的最小单元变量,也就是说将一些列的元素整合到一个集合内,这个集合的名称就叫数组。当然与其他语言一样,数组具备几个条件,在 Shell 中数组仅支持一维数组,数组元素的下标从 0 开始,数组元素没有最大限制等。
数组是相同类型的数据按照顺序组成的一种引用数据类型。Java 中有基本数据类型和引用数据类型两种数据类型。数组就是引用数据类型。
在说 Sass 之前不得不说到 CSS,相信你在看这篇文章之时一定是了解 CSS 的,以前的前端开发中我们一般是通过 CSS 来编写样式,而在现代化的前端开发中我们大多数企业中都在使用 Sass 来编写样式。那什么是 Sass 呢?我们引用 Sass 官网的一段话:Sass is the most mature, stable, and powerful professional grade CSS extension language in the world. — 官网这段话中最关键的一处 CSS extension language , 翻译过来就是 CSS 扩展语言,这段话的总体意思就是说 Sass 是一个稳定的、强大的、专业级的 CSS 扩展语言。所以说,它是基于 CSS 扩展出来的,也有另一个叫法,Sass 是一个 CSS 预处理器,所以说 Sass 是需要编译后转换为 CSS 的,它一定是在你的项目编译时去做处理,而不是在运行时,了解这一点很重要!
说起 AMQP 协议,我们可能会感到有点陌生,那么为什么还要了解 AMQP 协议呢? 因为了解什么是 AMQP 协议可以为我们学习 RabbitMQ 打下知识基础,让我们很清楚的知道 RabbitMQ 是用来做什么的。AMQP 协议,即 Advanced Message Queuing Protocol,直译为高级消息队列协议,我们只要知道 AMQP 协议就是一个高级消息队列协议就行了。
我们已经了解过如何简单地去声明一个类型 typealias 以及为什么需要 typealias,那么接下来会一起研究 typealias 原理是什么。当处理类型别名的时候,我们有两个类型需要去思考:别名 (alias) 底层类型 (underlying type)可以把上述例子理解为本身是一个别名 (如 UserId), 或者包含别名 (如 List) 的缩写类型,当 Kotlin 编译器编译代码时,所有使用到的相应缩写类型将会扩展成原来的全类型。一起看个完整的例子class UniqueIdentifier(val value: Int)typealias UserId = UniqueIdentifierval firstUserId: UserId = UserId(0)当编译器处理上述代码时,所有对 UserId 的引用都会扩展成 UniqueIdentifier,换句话说,在编译期间,编译器大部分是做了类似于在代码中搜索别名 (UserId) 所有用到的地方,然后将代码中用到的地方逐字地将其别名替换成全称类型名 (UniqueIdentifier) 的工作。可能已经注意到我说的是大部分场景。 这是因为除了逐字替换原理,有一些特殊情况下 Kotlin 不完全是通过逐字替换原理来实现。但是大部分场景下,我们只需记住 typealias 是基于逐字替换原理即可。顺便说一下,IntelliJ IDEA 和 AndroidStudio 已经很智能了,它门会对类型别名有一些很好的支持。例如,可以在代码中看到别名和底层类型:并且能够给出很好文档和代码提示总结下,实际上 typealias 别名并不会去真的创建一个新的类型,而仅仅是取了一个别名,然后在编译器编译期间,把别名又类似逐字替换原理换回实际的类型,这样就能保证编译正常也不会产生新的类型。
Java 注解(Annotation)又称为 Java 标注,是 Java5开始支持加入源代码的特殊语法元数据。Java 语言中的类、方法、变量、参数和包等都可以被标注。Java 标注可以通过反射获取标注的内容。在编译器生成class文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容。注解是一种用于做标注的“元数据”,什么意思呢?你可以将注解理解为一个标签,这个标签可以标记类、方法、变量、参数和包。回想我们学习继承时,子类若重写了父类的方法,可以在子类重写的方法上使用@Override注解:将@Override 注解标注在子类重写的方法上,可检查该方法是否正确地重写了父类的方法,如有错误将会编译报错。
什么是算法呢?在维基百科中这样定义的:在数学和计算机科学中,算法是一个有限的、定义明确的、可在计算机上实现的指令序列,通常是为了解决一类问题或进行计算。算法总是不含糊的,是作为执行计算、数据处理、自动推理等任务的规范。 — 维基百科通俗一点来说,算法就是用来解决一类问题或者进行计算的,但是需要有一个明确的数学或者计算机科学定义,可以在计算指令上实现。
最大子数组(Max Subarray)问题,是计算机科学与技术领域中一种常见的算法问题,主要可以利用分治思想进行快速实现。最大子数组问题描述如下:假如我们有一个数组,数组中的元素有正数和负数,如何在数组中找到一段连续的子数组,使得子数组各个元素之和最大。最大子数组问题在生活中有很多实际情况可以与其对应,比如说我们观察某一股票在一段时间内的走势,请问如何找出在哪一天买入,哪一天卖出可以赚到最大差价(这里假设你已经知道股票的价格走势)?为了实现最大化的股票收益,我们需要考虑的是买进和卖出时候的价格变化幅度,因此从该股票的每日变化幅度来考虑这个问题更加合适。所以,我们可以将这个问题稍作变形:将股票价格走势对应为每日股票价格涨跌,涨记为正值,跌记为负值,然后一段时间就对应一个正负数数组,并试图找到该数组的最大子数组,就可以获得最大收益。接下来,就让我们看看如何利用分治算法求解最大子数组问题吧。
雪碧图乍一听可能不知所然,因为雪碧是一种汽水,和图片又有什么关系呢?那我们就来讲一讲它到底是个什么?它其实就是把很多小图片集合在一起放到了一张大图片里面,就像下面这样:可以看到通常都是一些图标类的图片,这是因为图标一般比较符合“小”图片的定义:然后用到哪个图的时候就用背景图定位来定位到具体的位置:当然了,黑框只是个示意,实际上既不会让用户看见黑框,也不会让用户看到其他的图片,就像这样: