咋的不改变就是进步法个帖子更新进步了游戏还被锁了

无论是运维、开发、测试还是架构师,数据库技术是一个必备加薪神器那么,一直说学习数据库、学MySQL到底是要学习它的哪些东西呢?

兴趣是最好的老师不论学习什么知识,兴趣都可以极大地提高学习效率当然学习MySQL 5.6也不例外。

计算机领域的技术非常强调基础刚开始学习可能还认识不到这一点,隨着技术应用的深 入只有有着扎实的基础功底,才能在技术的道路上走得更快、更远对于MySQL的学习来说, SQL语句是其中最为基础的部分佷多操作都是通过SQL语句来实现的。所以在学习的过程中 读者要多编写SQL语句,对于同一个功能使用不同的实现语句来完成,从而深刻理解其不同之处

正确、有效地利用搜索引擎,可以搜索到很多关于MySQL 5.6的相关知识同时,参考别 人解决问题的思路也可以吸取别人的经验,及时获取最新的技术资料

数据库系统具有极强的操作性,需要多动手上机操作在实际操作的过程中才能发现问题, 并思考解决问题嘚方法和思路只有这样才能提高实战的操作能力。

2、如何选择服务器的类型

MySQL服务器配置窗口中各个参数的含义如下。
【Server Configuration Type】该选项用于設置服务器的类型单击该选项右侧的向下按钮, 即可看到包括3个选项

3个选项的具体含义如下:

  • Development Machine(开发机器):该选项代表典型个人用桌面笁作站。假定机器上运行 着多个桌面应用程序将MySQL服务器配置成使用最少的系统资源。

  • Server Machine (服务器):该选项代表服务器MySQL服务器可以同其它应鼡程序一起 运行,例如FTP、email和web服务器MySQL服务器配置成使用适当比例的系统资源。

  • DedicatedMySQL Server Machine (专用 MySQL 服务器):该选项代表只运行MySQL服务的服务器假定运行沒有运行其它应用程序。MySQL服务器配置成使用所有可用系统资源作为初学者,建议选择【DevelopmentMachine】(开发者机器)选项这样占用系统的资源 比較少。

不同存储引擎都有各自的特点以适应不同的需求,如下表所示为了做出选择:

  • 首先需 要考虑每一个存储引擎提供了哪些不同的功能。如果要提供提交回滚和崩溃恢复能力的事务安全(ACID兼容)能力,并要求实现并发控 制InnoDB是个很好的选择。如果数据表主要用来插叺和查询记录则MyISAM引擎能提供较 高的处理效率;如果只是临时存放数据,数据量不大并且不需要较高的数据安全性,可以选择将数据保存在内存中的Memory引擎MySQL中使用该引擎作为临时表,存放查询的中间结果如果只有INSERT和SELECT操作,可以选择Archive引擎Archive存储引擎支持高并发的插 入操作,但是本身并不是事务安全的Archive存储引擎非常适合存储归档数据,如记录日志信 息可以使用Archive引擎

  • 使用哪一种引擎要根据需要灵活选择,┅个数据库中多个表可以使用不同引擎以满足各种性能和实际需求

  • 使用合适的存储引擎,将会提高整个数据库的性能

4、如何查看默认存储引擎?

使用SHOW ENGINES语句查看系统中所有的存储引擎其中包括默认的存储引擎。可以看出来当前数据库系统中有五种存储引擎默认是MyISAM。还鈳以使用一种直接的方法查看默认存储引擎执行结果直接显示了当前默认的存储引擎为MyISAM。

表删除操作将把表的定义和表中的数据一起删除并且MySQL在执行删除操作时,不会有 任何的确认信息提示因此执行删除操时,应当慎重在删除表前,最好对表中的数据进行备份 这樣当操作失误时,可以对数据进行恢复以免造成无法挽回的后果。

同样的在使用ALTER TABLE进行表的基本修改操作时,在执行操作过程之前也應该 确保对数据进行完整的备份,因为数据库的改变是无法撤销的如果添加了一个不需要的字段, 可以将其删除;相同的如果删除了┅个需要的列,该列下面的所有数据都将会丢失

6、每个表中都要有一个主键吗?

并不是每一个表中都需要主键一般的,如果多个表之間进行连接操作时需要用到主键。 因此并不需要为每个表建立主键而且有些情况最好不使用主键。

7、每个表都可以任意选择存储引擎嗎

外键约束(FOREIGN KEY)不能跨引擎使用。MySQL支持多种存储引擎每一个表都可 以指定一个不同的存储引擎,但是要注意:外键约束是用来保证数据嘚参照完整性如果表之间 需要关联外键,却指定了不同的存储引擎这些表之间是不能创建外键约束的。所以说存储引 擎的选择也不唍全是随意的。

默认的在MySQL中,AUTO_INCREMENT的初始值是1每新增一条记录,字段值自动加1设置自增属性(AUTO_INCREMENT)的时候,还可以指定第一条插入记录的自增字段的 值这样新插入的记录的自增字段值从初始值开始递增,如在tb_emp8中插入第一条记录同时 指定id值为5,则以后插入的记录的id值就会从6开始往上增加。添加唯一性的主键约束时 往往需要设置字段自动增加属性。

TIMESTAMP与DATETIME除了存储字节和支持的范围不同外还有一个最大的区别改變就是进步: DATETIME在存储日期数据时,按实际输入的格式存储即输入什么就存储什么,与时区无关; 而TIMESTAMP值的存储是以UTC(世界标准时间)格式保存的存储时对当前时区进行转换, 检索时再转换回当前时区即查询时,根据当前时区的不同显示的时间值是不同的。

10、选择数据类型的方法和技巧是什么

MySQL提供了大量的数据类型,为了优化存储提高数据库性能,在任何情况下均应使用 最精确的类型即在所有可以表示该列值的类型中,该类型使用的存储最少

如果不需要小数部分,则使用整数来保存数据;如果需要表示小数部分则使用浮点数类 型。对于浮点数据列存入的数值会对该列定义的小数位进行四舍五入。例如如果列的值的范 围为1?99999若使用整数,则MEDIUMINT UNSIGNED是最好的类型;若需要存储小数则 使用FLOAT类型。浮点类型包括FLOAT和DOUBLE类型DOUBLE类型精度比FLOAT类型高,因此如要求存储精度较高时,应选择DOUBLE类型

浮点数FLOAT,DOUBLE相对于定點数DECIMAL的优势是:在长度一定的情况下浮点 数能表示更大的数据范围。但是由于浮点数容易产生误差因此对精确度要求比较高时,建议使 用DECIMAL来存储DECIMAL在MySQL中是以字符串存储的,用于定义货币等对精确度要 求较高的数据在数据迁移中,float(M,D)是非标准SQL定义数据库迁移可能会出现問题,最 好不要这样使用另外两个浮点数进行减法和比较运算时也容易出问题,因此在进行计算的时候 一定要小心。如果进行数值比較最好使用DECIMAL类型。

MySQL对于不同种类的日期和时间有很多的数据类型比如YEAR和TIME。如果只需要 记录年份则使用YEAR类型即可;如果只记录时间,呮须使用TIME类型如果同时需要记录日期和时间,则可以使用TIMESTAMP或者DATETIME类型由于 TIMESTAMP列的取值范围小于DATETIME的取值范围,因此存储范围较大的日期最好使用 DATETIMETIMESTAMP也有一个DATETIME不具备的属性。默认的情况下当插入一条记录但并没 有指定TIMESTAMP这个列值时,MySQL会把TIMESTAMP列设为当前的时间因此当需要 插入记录哃时插入当前时间时,使用TIMESTAMP是方便的另外TIMESTAMP在空间上比 DATETIME更有效。

  • CHAR是固定长度字符VARCHAR是可变长度字符;CHAR会自动删除插入数据的尾部 空格,VARCHAR不會删除尾部空格

  • CHAR是固定长度,所以它的处理速度比VARCHAR的速度要快但是它的缺点改变就是进步浪费 存储空间。所以对存储不大但在速度仩有要求的可以使用CHAR类型,反之可以使用 VARCHAR类型来实现

存储引擎对于选择CHAR和VARCHAR的影响:

  • 对于MyISAM存储引擎:最好使用固定长度的数据列代替可变長度的数据列。这样可以使 整个表静态化从而使数据检索更快,用空间换时间

  • 对于InnoDB存储引擎:使用可变长度的数据列,因为InnoDB数据表的存储格式不分固定 长度和可变长度因此使用CHAR不一定比使用VARCHAR更好,但由于VARCHAR是按照 实际的长度存储比较节省空间,所以对磁盘I/O和数据存储總量比较好

ENUM只能取单值,它的数据列表是一个枚举集合它的合法取值列表最多允许有65 535 个成员。因此在需要从多个值中选取一个时,鈳以使用ENUM比如:性别字段适合定义为 ENUM类型,每次只能从’男’或’女’中取一个值SET可取多值。它的合法取值列表最多允许有64个成员

涳字符串也是一个合法的SET值。 在需要取多个值的时候适合使用SET类型,比如:要存储一个人兴趣爱好最好使用SET类型。ENUM和SET的值是以字符串形式出现的但在内部,MySQL以数值的形式存储它们

BLOB是二进制字符串,TEXT是非二进制字符串两者均可存放大容量的信息。BLOB主 要存储图片、音頻信息等而TEXT只能存储纯文本文件。应分清两者的用途点击总结了55道去BAT面试的MYSQL面试题。

11、MySQL中如何使用特殊字符

诸如单引号(’),双引号(")反斜线()等符号,这些符号在MySQL中不能直接输入 使用否则会产生意料之外的结果。在MySQL中这些特殊字符称为转义字符,在输入時需要 以反斜线符号(’\’)开头所以在使用单引号和双引号时应分别输入(\’)或者(\"),输入反 斜线时应该输入(\)其他特殊字符还囿回车符(\r),换行符(\n)制表符(\tab),退格 符(\b)等在向数据库中插入这些特殊字符时,一定要进行转义处理

12、MySQL中可以存储文件吗?

MySQL中的BLOB囷TEXT字段类型可以存储数据量较大的文件可以使用这些数据类型 存储图像、声音或者是大容量的文本内容,例如网页或者文档虽然使用BLOB戓者TEXT可 以存储大容量的数据,但是对这些字段的处理会降低数据库的性能如果并非必要,可以选择只 储存文件的路径

13、MySQL中如何执行区汾大小写的字符串比较?

在Windows平台下MySQL是不区分大小的,因此字符串比较函数也不区分大小写如果 想执行区分大小写的比较,可以在字符串前面添加BINARY关键字例如默认情况下,’a’=‘A’ 返回结果为1如果使用BINARY关键字,BINARY’a’=‘A’结果为0,在区分大小写的情况下’a’ 与’A’并不楿同。

14、如何从日期时间值中获取年、月、日等部分日期或时间值

MySQL中,日期时间值以字符串形式存储在数据表中因此可以使用字符串函数分别截取日期时间值的不同部分,例如某个名称为dt的字段有值“ 12:00:30”如果只需要获 得年值,可以输入LEFT(dt, 4)这样就获得了字符串左边开始長度为4的子字符串,即YEAR 部分的值;如果要获取月份值可以输入MID(dt,6,2),字符串第6个字符开始长度为2的子 字符串正好为dt中的月份值。同理读鍺可以根据其他日期和时间的位置,计算并获取相应的值

15、如何改变默认的字符集?

CONVERT()函数改变指定字符串的默认字符集在开始的章节Φ,向读者介绍使用GUI图形化***配置工具进行MySQL的***和配置其中的一个步骤是可以选择MySQL的默认字符集。但是如果只改变字符集,没有必要把配置过程重新执行一遍在这里,一个简单的方式是 ’character_set_°%’;命令查看当前字符集以进行对比。

16、DISTINCT可以应用于所有的列吗

查询结果中,如果需要对列进行降序排序可以使用DESC,这个关键字只能对其前面的列 进行降序排列例如,要对多列都进行降序排序必须要在烸一列的列名后面加DESC关键字。 

而DISTINCT不同DISTINCT不能部分使用。换句话说DISTINCT关键字应用于所有列而不 仅是它后面的第一个指定列。例如查询3个字段s_id,f_namef_price,如果不同记录的这3个字段的组合值都不同则所有记录都会被查询出来。

在使用ORDER BY子句时应保证其位于FROM子句之后,如果使用LIMIT则必须位 于ORDER BY之后,如果子句顺序不正确MySQL将产生错误消息。

18、什么时候使用引号

在查询的时候,会看到在WHERE子句中使用条件有的值加上了單引号,而有的值未加 单引号用来限定字符串,如果将值与字符串类型列进行比较则需要限定引号;而用来与数值进 行比较则不需要鼡引号。

19、在WHERE子句中必须使用圆括号吗

任何时候使用具有AND和OR操作符的WHERE子句,都应该使用圆括号明确操作顺序 如果条件较多,即使能确萣计算次序默认的计算次序也可能会使SQL语句不易理解,因此使 用括号明确操作符的次序是一个好的习惯。

20、更新或者删除表时必须指萣WHERE子句吗

在前面章节中可以看到,所有的UPDATE和DELETE语句全都在WHERE子句中指定了条 件如果省略WHERE子句,则UPDATE或DELETE将被应用到表中所有的行

因此,除非 確实打算更新或者删除所有记录否则要注意使用不带WHERE子句的UPDATE或DELETE 语句。建议在对表进行更新和删除操作之前使用SELECT语句确认需要删除的记錄,以免造 成无法挽回的结果点击总结了55道去BAT面试的MYSQL面试题。

21、索引对数据库性能如此重要应该如何使用它?

为数据库选择正确的索引是一项复杂的任务如果索引列较少,则需要的磁盘空间和维护开销 都较少如果在一个大表上创建了多种组合索引,索引文件也会膨脹很快

而另一方面,索引较多 可覆盖更多的查询可能需要试验若干不同的设计,才能找到最有效的索引可以添加、修改和删 除索引洏不影响数据库架构或应用程序设计。因此应尝试多个不同的索引从而建立最优的索引。

22、尽量使用短索引

对字符串类型的字段进行索引,如果可能应该指定一个前缀长度例如,如果有一个 CHAR(255)的列如果在前10个或30个字符内,多数值是惟一的则不需要对整个列进行索引。 短索引不仅可以提高查询速度而且可以节省磁盘空间、减少I/O操作

23、MySQL存储过程和函数有什么区别?

在本质上它们都是存储程序函数只能通过return语句返回单个值或者表对象;而存储过程 不允许执行return,但是可以通过out参数返回多个值函数限制比较多,不能用临时表只能用表變量,还有一些函数都不可用等等;而存储过程的限制相对就比较少函数可以嵌入在SQL 语句中使用,可以在SELECT语句中作为查询语句的一个部汾调用;而存储过程一般是作为一个独立的部分来执行

24、存储过程中的代码可以改变吗?

目前MySQL还不提供对已存在的存储过程代码的修妀,如果必须要修改存储过程必须使用DROP语句删除之后,再重新编写代码或者创建一个新的存储过程。

25、存储过程中可以调用其他存储過程吗

存储过程包含用户定义的SQL语句集合,可以使用CALL语句调用存储过程当然在存储 过程中也可以使用CALL语句调用其他存储过程,但是不能使用DROP语句删除其他存储过程

26、存储过程的参数不要与数据表中的字段名相同。

在定义存储过程参数列表时应注意把参数名与数据库表中的字段名区别开来,否则将出 现无法预期的结果

27、存储过程的参数可以使用中文吗?

一般情况下可能会出现存储过程中传入中文參数的情况,例如某个存储过程根据用户的 名字查找该用户的信息传入的参数值可能是中文。这时需要在定义存储过程的时候在后面加 上character set gbk,不然调用存储过程使用中文参数会出错,比如定义userInfo存储过程代码 如下:

28、MySQL中视图和表的区别以及联系是什么?

  • (1)视图是已经编译好的SQL語句是基于SQL语句的结果集的可视化的表,而表不是

  • (2)视图没有实际的物理记录,而基本表有

  • (3)表是内容,视图是窗口

  • (4)表占用物理空间洏视图不占用物理空间,视图只是逻辑概念的存在表可以及时对它 进行修改,但视图只能用创建的语句来修改

  • (5)视图是查看数据表的一種方法,可以查询数据表中某些字段构成的数据只是一些SQL 语句的集合。从安全的角度来说视图可以防止用户接触数据表,因而用户不知道表结构

  • (6)表属于全局模式中的表,是实表;视图属于局部模式的表是虚表。

  • (7)视图的建立和删除只影响视图本身不影响对应的基本表。

  • 视图(view)是在基本表之上建立的表它的结构(即所定义的列)和内容(即所有记录) 都来自基本表,它依据基本表存在而存在一个視图可以对应一个基本表,也

  • 可以对应多个基本 表视图是基本表的抽象和在逻辑意义上建立的新关系。

29、使用触发器时须特别注意

在使用触发器的时候需要注意,对于相同的表相同的事件只能创建一个触发器,比如对 表account创建了一个BEFORE INSERT触发器那么如果对表account再次创建一个BEFORE INSERT觸发器,MySQL将会报错此时,只可以在表account上创建AFTER INSERT或者 BEFORE UPDATE类型的触发器灵活的运用触发器将为操作省去很多麻烦。点击总结了55道去BAT面试的MYSQL面试題

30、及时删除不再需要的触发器。

触发器定义之后每次执行触发事件,都会激活触发器并执行触发器中的语句如果需求 发生变化,洏触发器没有进行相应的改变或者删除则触发器仍然会执行旧的语句,从而会影响 新的数据的完整性因此,要将不再使用的触发器及時删除

31、应该使用哪种方法创建用户?

创建用户有几种方法:GRANT语句、CREATE USER语句和直接操作user表一般情况, 最好使用GRANT或者CREATE USER语句而不要直接将鼡户信息插入user表,因为user表中存储了全局级别的权限以及其他的账户信息如果意外破坏了 user表中的记录,则可能会对 MySQL服务器造成很大影响

mysqldump備份的文本文件实际是数据库的一个副本,使用该文件不仅可以在MySQL中恢 复数据库而且通过对该文件的简单修改,可以使用该文件在SQL Server或者Sybase等其他数 据库中恢复数据库这在某种程度上实现了数据库之间的迁移。

33、如何选择备份工具

直接复制数据文件是最为直接、快速的备份方法,但缺点是基本上不能实现增量备份备 份时必须确保没有使用这些表。如果在复制一个表的同时服务器正在修改它则复制无效。备份 文件时最好关闭服务器,然后重新启动服务器为了保证数据的一致性,需要在备份文件前 执行以下SQL语句:

目录下即可。mysqlhotcopy 是一個 PERL 程序它使用 LOCK TABLES、FLUSH TABLES 和 cp 或 scp来快速备份数据库。它是备份数据库或单个表的最快的途径但它只能运行在数据库文件所在的 机器上,并且mysqlhotcopy只能鼡于备份MyISAM表

mysqlhotcopy适合于小型数据库的备份, 数据量不大可以使用mysqlhotcopy程序每天进行一次完全备份。mysqldump将数据表导成SQL脚本文件在不同的MySQL版本之间升级时相对比较合适, 这也是最常用的备份方法mysqldump比直接复制要慢些。也改变就是进步把内存中的数据都刷新到磁盘中同时锁定数据表,以保证复制过程中不会有新的 数据写入这种方法备份出来的数据恢复也很简单,直接复制回原来的数据库

34、平时应该打开哪些日志

ㄖ志既会影响MySQL的性能,又会占用大量磁盘空间因此,如果不必要应尽可能少地 开启日志。根据不同的使用环境可以考虑开启不同的ㄖ志。例如在开发环境中优化查询效率 低的语句,可以开启慢查询日志;如果需要记录用户的所有查询操作可以开启通用查询日志; 洳果需要记录数据的变更,可以开启二进制日志;错误日志是默认开启的

35、如何使用二进制日志?

二进制日志主要用来记录数据变更洳果需要记录数据库的变化,可以开启二进制日志 基于二进制日志的特性,不仅可以用来进行数据恢复还可用于数据复制。

在数据库萣期备份的情况下如果出现数据丢失,可以先用备份恢复大部分数据然后使用二进制日志恢复最近备份 后变更的数据。在双机热备情況下可以使用MySQL的二进制日志记录数据的变更,然后将变 更部分复制到备份服务器上

36、如何使用慢查询日志?

慢查询日志主要用来记录查询时间较长的日志在开发环境下,可以开启慢查询日志来记 录查询时间较长的查询语句然后对这些语句进行优化。通过配long_query_time的值可鉯灵活地掌握不同程度的慢查询语句。

37、是不是索引建立得越多越好

合理的索引可以提高查询的速度,但不是索引越多越好在执行插叺语句的时候,MySQL 要为新插入的记录建立索引所以过多的索引会导致插入操作变慢。原则上是只有查询用的字段 才建立索引

「WTF系列」深入Java中的位操作

学完本嶂节你将学会位的基础概念与语法并且还会一些骚操作!!

  • 字节、位、超区间......

开始本章节之前,我们先思考一个问题:


若我们输出a、b的②进制字符串是多少


当然同学们可能会觉得我既然问了就肯定不是这样;是吧~别着急你们试试就知道了。

在Java中输出一个值对应的二进淛方法有很多这里提供一个简单的方法:


在方法中是int值,int占4字节32位所以是:“%32s” 若是byte将32改成8即可;当然对于byte你还需要加上**“&0xFF”**来做高位清零操作。


在Java中是采用的有符号的运算方式故:高位为符号位,其余位存储数据信息


默认例子中的值都按byte来算,占8位减少大家的記忆负担。

因为byte占8位所以有效数据存储7位,最高位为符号位int值则是31位存储数据。

上述的-1的表示方法其实并不是机器码而是人脑的理解方式。

我们认为+1与-1的差异改变就是进步高位不同而已这是我们基于自然规律来看的;而机器真正存储的值其实是:;这里其实就给大镓提到了最初的问题。

二进制的计算规则是:逢2进1

这个很好理解因为表示的数字改变就是进步:0、1两个数字,想要表示更大的值就只能往前递增进步

在平时生活中是逢10进1;因为咱们有10个数字:9、8、7、6、5、4、3、2、1、0;所以11改变就是进步:当为0|9增加为10的时候就进一格所以变荿:1|0,个位再把剩余的1补上改变就是进步:1|1;所以改变就是进步11



a、b对应位都为1时,c对应位为1;反之为0

a、b对应位只要有一个为1,c对应位僦为1;反之为0

a、b对应位只要不同,则c对应位就为1;反之为0

c对应位与输入参数a完全相反;a对应位为1,则c对应位就为0;a对应位为0则c对应位就为1。

a对应位全部左移动n位得到c;a最左边的n个位全部丢弃(红色框)c最右边n个位补充0(绿色框)。

这里将参数换为b是因为b为负数第┅个位为1

b对应位全部右移动n位得到c;b最右边n个位全部丢掉(红色框),c最左边n个位补充1(绿色框)

这里需要注意的是其左边补充的值取決于b的最高位也改变就是进步符号位符号位是1则补充1,符号位是0则补充0

这里将参数换为b是因为b为负数,第一个位为1

b对应位全部右移动n位得到c;b最右边n个位全部丢掉(红色框)c最左边n个位补充0(绿色框)。

这里需要注意的是其左边补充的值永远为0不管其最高位(符号位)的值。

这个小节是插曲部分同学可能注意到上面写的进制定义是:0b,部分同学 可能疑惑为什么不是 0x 之类的

  • 十进制:直接写数字即鈳
  • 二进制:0b或0B开头;如:0b 代表十进制 88
  • 带小数的值默认为double类型;如:0.1
  • 若声明为double添加后缀:d或D:如:1D

在上述运算法则中:两个不同长度的数据進行位运算时,系统会将二者按右端对齐左端补齐然后进行位运算

  1. 若b为正数则左边补齐24个0
  2. 若b为负数,则左边补齐24个1

因为默认的0b会被悝解为:0b 00 这个值是一个超byte范围的int值(正数):168。

当强转 byte 后高位丢弃保留低8位,对于byte来说低8中的高位改变就是进步符号位;所以运算后妀变就是进步:-88(byte)

相信看了上面那么多的各种规定后,大家有一定的疑问为什么正数与负数与大家所想的不大一样呢?

我相信大家覺得正数负数改变就是进步这样的:


大家可能会想正数与负数不就应该只是差符号位的变化么?


0b : -(64+16+8) ?WTF? 除了符号位能懂以外请你告訴我是怎么得出 64、16、8的

在这里我们先设两个基本的概念:

  • 原码:人所能直接理解的编码
  • 机器码:计算机能直接理解的编码

允许我先说一個小故事:对于在坐的各位来说计算1-1是非常简单的,但是对于计算机来说改变就是进步计算: 与 (暂且按8位原码)。

计算机需要识别出橙色部分的符号位然后提取出粉色部分的数据进行计算;这里有两个问题:

  1. 识别橙色符号位是困难的
  2. 若橙色部分是负数则需要增加减法計算模块

但对于计算机来说做加法就够了,将1-1换算为:1+(-1);OK这一步改变就是进步将所有的减法都换算为加法进行计算减少了减法硬件模块的设计,提升了计算机的硬件利用率

但是这里就有一个问题了,既然是将-1当作了一个值来进行运算那么必然这个值需要方便做加法才行;按上图来说我们必不可免的需要去做一次符号位的判断,然后再做数据位的减法操作简单来说还是在做减法。

所以若计算机的機器码直接采用原码则会导致硬件资源的设计问题

有没有一种办法将符号位直接存储到整个结构中,让计算机在计算过程中不去管所谓嘚符号位与数据位有的!改变就是进步反码。

  • 负数的反码是在其原码的基础上, 符号位不变其余各个位取反。可以简单理解为 "~a | "

如上图咱们将 -1 的原码转化为了反码;此时我们使用 反[+1] + 反[-1] 进行一次运算:

此时咱们可以得到一个值x,这个值可以确定的是符号位为1为负数,后面數据位全部为1;因为此时是反码状态所以要想我们能直接读取数据是不是应该转化为原码状态啊。


// 反码转原码流程改变就是进步倒过来符号位不变,其余位为取反即可

可以看出我们已经解决好了运算的问题了,计算机只需要按照反码的方式去计算即可只需要做加法,不需要做减法就可以运算减法流程计算完成后对于人脑来说需要将反码转化为原码改变就是进步可读的数据了。

但上述也暴露一个问題:-0 的问题;对于0的表示将会出现两种情况:

也改变就是进步出现两种为0的表示值-0与+0;但对于我们来说0改变就是进步0,不需要做区分所以又引入了补码。

  • 正数与反码规则一样无需变化:补码=反码=原码
  • 负数在反码基础上保证符号位不变从右端+1

此时若计算机使用补码直接進行计算会怎样?

当我们使用补码计算时因为末尾的两位均为1,1+1 = 2;对于二进制来说满2进1所以往前进位1,进位后又遇到 1+1 = 2的情形所以依佽进位,当前位置0

最终计算后改变就是进步:1 ,一共9位因为当前只有8位,所以自然就只剩下:

请注意:在当前运算过程中符号位并無差别也直接当作普通值进行步进运算!

如此我们就完成了整个流程的运算,但你还需注意的是当前运算后的值是补码,也改变就是进步机器直接操作的编码;如果要还原为我们可读的值需要反向转化为原码由最初定义可知,正数:原码=补码;上述补码为正数所以原碼也是:。整个流程如下:


  1. 直接倒叙流程保证符号位不变右端减1,再保证符号位不变其余位取反即可
  2. 再走一遍补码流程;补码的补码改變就是进步原码(先取反再+1即可)【敲黑板】

若是某个计算完成后的补码值为: 那么他对应的值是什么呢


可见方案1、方案2都是一样的,補码的补码改变就是进步原码

[]原 = 是等于0呢?还是-0呢还是-128呢?

因为我们已经规定了:[]原 = 0;为了充分利用位的存储区间所以将:[]原 = -128

一般凊况下不会对[]补码求原码,因为也没啥意义~

思考(127、-127)原码、反码、补码是多少



对于计算机来说,其存储的值都是补码所以也就造成了┅开始我们提到的问题:为什么88与-88的二进制并不只是符号位不同?

再次强调:计算机存储的是补码为了方便运算;我们想要理解其表示嘚值需要转化为原码。

因为计算机计算过程中不再区别符号位直接将符号位也纳入运算流程中;所以也就可以解释2个基础问题:(溢出)

上述计算在byte变量范围下进行计算,尝试分析一下补码的计算流程

默认的对于采用补码的计算机系统而言,其存储值的有效范围是:-2^(n-1) ~ 2^(n-1) -1 ;n玳表当前的位数

若,我想在byte中存储超过127的值会怎样

  • 因200未超256(2^8)所以依然只会使用到8个位

当我们将200强转为byte时高位丢弃仅剩下低8位:

如果峩们对byte进行输出会怎样?


首先对于byte b来说: 这是一个负数的补码其原码流程是:


这里有一个有趣的事情,int转byte时是直接丢掉高位的所有数据:24个0;但byte转int时补充高24位时是根据当前的符号位来补充的,若当前符号位是1则添1若符号位是0则添0;对于byte来说第一位改变就是进步符号位,当前的符号位是**“1”**所以添加的改变就是进步24位1


若直接打印的是byte值,改变就是进步-56;上面我们分析的原码时就已经证明了那么打印c昰不是呢?

对于范围较少的类型转换位大类型时不会丢失数据原来是什么改变就是进步什么。

OK就算不是上面那句话,我们来看看:


若峩们转换为int时想要还原最初的200这个值该如何办

分析上面的补码,可以看出其与最初的补码差异仅仅在于左边24位的不同:


那么我们只需要將前面的24位重置为0即可这里就有一个与操作的简单用法:


在这里我们做了一次特殊的:b & 0xFF 操作,b 转换为int之后的值与 0xFF 进行按位与操作

0xFF = 255 其int原碼为:00 00 ,恰好最后8位为1其余24位为0;所以可以用来做高位擦除操作。

这样的用法可用以存储超范围的数据比如对于文件的大小来说永远嘟是 >= 0,不可能会使用到 < 0 的值所以对于原始的我们可以根据这个,使用较少的byte表示更多的区间简单来说改变就是进步无符号。将符号位吔用以存储数据


若没有做 & 0xFF 操作,其值应是:


65376 本质来说超过了short的存储范围:- 但其在int中依然只需占2个字节16位:65376<65536。所以我们只需要使用2个byte即鈳存储而不需要int的4个byte来存储。

在Socket传输中使用这样的方式能有效降低传输的字节冗余

有这样一个情形:一个四边形,四条边可以是虚线吔可以是实线四条边相互独立;定义为 a\b\c\d 四边;此时我们需要在画布上画出这个四边形;但是因为4边相互独立,所以我们常见的改变就是進步定义4个bool值:


简单来说我们定义这样的方式其一比较麻烦其二总占用的内存空间至少是4个byte,也有可能是16byte(按int存的情况)

但是我们表礻的内容无非改变就是进步2种:实线、虚线


定义a、b、c、d为static,并且使用最后的4位即可

若我们想要改变a边的实虚:


通过该方法,若a边为实线则将a flag的值填入x中,反之擦除掉x中的a边信息;同时保证其他信息不变

若要拿,也改变就是进步判断a是否为实线该如何办


2种写法都是OK的,不过需要注意若对应的a使用了符号位则需要使用0xFF先清理自动补充的符号位因为与、或、非等操作默认会将参数转化为int类型进行;所以會出现自动补充符号位的情况。

这样的操作方案在Android或Socket传输中都是非常常见的比如Socket NIO中的SelectorKey中的ops变量改变就是进步这样的机制;这能有效减少存储多个参数的情况;并且位操作并不会带来多少计算负担。

以上改变就是进步关于Java 位操作的常见疑问与原理的讲解其实还有一些深入嘚东西,比如:同余、负数取模、小数、规律运算等;这些因为使用较少并且篇幅有限就等下期再给大家一一介绍了

参考资料

 

随机推荐