首页 文章 精选 留言 我的

精选列表

搜索[图像理解],共10000篇文章
优秀的个人博客,低调大师

MySQL专题——从认识索引到理解索引「索引优化」

认识索引 认识索引是什么东西非常关键,一个非常恰当的比喻就是书的目录页与书的正文内容之间的关系,为了方便查找书中的内容,通过对内容建立索引形成目录。因此,首先你要明白的一点就是,索引它也是一个文件,它是要占据物理空间的。 比如对于MyISAM存储引擎来说: .frm后缀的文件存储的是表结构。 .myd后缀的文件存储的是表数据。 .myi后缀的文件存储的就是索引文件。 如下图所示: 对于InnoDB存储引擎来说: .frm .ibd后缀的文件存放索引文件和数据(需要开启innodb_file_per_table参数) 如下图所示: 因此,当你对一张表建立索引时,索引文件的大小也会改变,当你数据表中的数据因为增删改变化时,索引文件也会变化的,只不过MySQL会自动维护索引,这个过程不需要你介入,这也是为什么不恰当的索引会影响MySQL性能的原因。 总结: 1. 索引是按照特定的数据结构把数据表中的数据放在索引文件中,以便于快速查找; 2. 索引存在于磁盘中,会占据物理空间。 索引的类型 B-Tree 索引 以 B-Tree 为结构的索引是最常见的索引类型,比如 InnoDB 和 MyISAM 都是以 B-Tree 为索引结构的索引,事实上是以 B+ Tree 为索引结构,B-Tree 和 B+Tree 区别在于,B+ Tree 在叶子节点上增加了顺序访问指针,方便叶子节点的范围遍历。这里主要介绍一下 InnoDB 和 MyISAM。 InnoDB InnoDB 支持聚簇索引,聚簇索引和非聚簇索引严格来说不是一种索引,而是一种数据存储方式,这个名字跟它本身的存储方式有关系,“聚簇“表示数据行和相邻的键值存储在一起,简单的说,就是叶子节点中存储的实际是真实的数据。InnoDB 通过主键聚集数据,所以一个表只能有一个聚簇索引,且必须有主键,如果没有定义主键,且不存在非空索引可以代替,InnoDB 会隐式定义一个主键作为聚簇索引。 聚簇索引的二级索引存储的不是指向行的物理位置的指针,而是行的主键值,所以如果通过二级索引查找行,需要找到二级索引的叶子结点获得对应的主键值,然后再去查找对应的行。对于 InnoDB,自适应哈希索引可以减少这样的重复工作。 锁 InnoDB 使用的是行锁,所以支持事务,而 MyISAM 使用的是表锁,不支持事务。 适用范围 B-Tree 索引适用于区间查询,因为 B-Tree 存储后的叶子节点本身就是有序的,并且 B+ Tree 结构还增加了叶子节点的连续顺序指针,对于区间查询来说就更加方便了。 哈希索引 哈希索引是基于哈希表实现的,只有精确匹配索引所有列的查询才有效。方法是,对所有的索引列计算一个 hash code,hash code 作为索引,在哈希表中保存指向每个数据行的指针。 优点 索引本身只存储 hash code,所以结构很紧凑,并且查找速度很快 限制 索引中的 hash code 是顺序存储的,但是 hash code 对应的数据并不是顺序的,所以无法用于排序 不支持部分索引列匹配查找,因为哈希索引是使用索引列的全部内容来计算 hash code 只支持等值比较,不支持范围查询 如果哈希冲突严重时,必须遍历链表中所有行指针 哈希冲突严重的话,索引维护操作的代价也很高 InnoDB 的自适应哈希索引 首先,请注意,自适应哈希索引对于用户来说是无感知的,这是一个完全自动、内部的行为,用户无法控制或者配置,但是可以关闭。 当 InnoDB 注意到某个索引值被使用的非常频繁时,它会在内存中基于 B-Tree 索引之上再创建一个哈希索引,这样 B-Tree 也可以具有哈希索引的一些优点,比如快速的哈希查找。 当然如果存储引擎不支持哈希索引,用户也可以自定义哈希索引,这样性能会比较高,缺陷是需要自己维护哈希值,如果采用这种方法,不要使用 SHA1() 和 MD5() 作为哈希函数,因为这两个是强加密函数,设计目标是最大限度消除冲突,生成的 hash code 是一个非常长的字符串,浪费大量的空间,哈希索引中对于索引的冲突要求没有那么高。 索引的优点 使用索引可以减少服务器需要扫描的数据量 使用索引可以帮助服务器避免排序和临时表 使用索引可以将随机 I/O 变为顺序 I/O 但是不是所有情况下,索引都是最好的解决方案,对于非常小的表来说,大部分情况下简单的全表扫描更高效,对于中到大型表,索引就比较有效,对于特大型的表来说,分区会更加有效。 常见优化方法 联合索引最左前缀原则 复合索引遵守「最左前缀」原则,查询条件中,使用了复合索引前面的字段,索引才会被使用,如果不是按照索引的最左列开始查找,则无法使用索引。 比如在(a,b,c)三个字段上建立联合索引,那么它能够加快a|(a,b)|(a,b,c)三组查询的速度,而不能加快b|(b,a)这种查询顺序。 另外,建联合索引的时候,区分度最高的字段在最左边。 不要在列上使用函数和进行运算 不要在列上使用函数,这将导致索引失效而进行全表扫描。 例如下面的 SQL 语句: select * from artile where YEAR(create_time) <= '2018'; 复制代码 即使 date 上建立了索引,也会全表扫描,可以把计算放到业务层,这样做不仅可以节省数据库的 CPU,还可以起到查询缓存优化效果。 负向条件查询不能使用索引 负向条件有:!=、<>、not in、not exists、not like 等。 select * from artile where status != 1 and status != 2; 复制代码 可以使用in进行优化: select * from artile where status in (0,3) 复制代码 使用覆盖索引 所谓覆盖索引,是指被查询的列,数据能从索引中取得,而不用通过行定位符再到数据表上获取,能够极大的提高性能。 可以定义一个让索引包含的额外的列,即使这个列对于索引而言是无用的。 避免强制类型转换 当查询条件左右两侧类型不匹配的时候会发生强制转换,强制转换可能导致索引失效而进行全表扫描。 如果phone字段是varchar类型,则下面的SQL不能命中索引: select * from user where phone=12345678901; 复制代码 可以优化为: select * from user where phone='12345678901'; 复制代码 范围列可以用到索引 范围条件有:<、<=、>、>=、between等。 范围列可以用到索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列,如果查询条件中有两个范围列则无法全用到索引。 更新频繁、数据区分度不高的字段上不宜建立索引 更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能。 「性别」这种区分度不大的属性,建立索引没有意义,不能有效过滤数据,性能与全表扫描类似。 区分度可以使用 count(distinct(列名))/count(*) 来计算,在80%以上的时候就可以建立索引。 索引列不允许为null 单列索引不存null值,复合索引不存全为null的值,如果列允许为 null,可能会得到不符合预期的结果集。 避免使用or来连接条件 应该尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描,虽然新版的MySQL能够命中索引,但查询优化耗费的 CPU比in多。 模糊查询 前导模糊查询不能使用索引,非前导查询可以。 需要学习更多java相关知识请关注我,或者查看我的往期发布哦 欢迎工作一到五年的Java工程师朋友们加入Java架构开发:468947140 点击链接加入群聊【Java-BATJ企业级资深架构】:https://jq.qq.com/?_wv=1027&k=5zMN6JB 本群提供免费的学习指导 架构资料 以及免费的解答 不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导

优秀的个人博客,低调大师

如何理解数据虚拟化的不同形式

【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 数据虚拟化可以为企业带来诸多好处。例如,从大数据的安全性和完整性到增强与内部和外部合作伙伴的协作。数据虚拟化的正确应用可以使在困境中挣扎的企业变成一个有利可图的成功企业。 实际上,数据虚拟化有许多不同的形式。虽然一些形式比其他的形式更有用,但对于不熟悉这些选择的人来说,他们都会面临同样的困惑。 1.数据混合 大多数现代商业智能包都包含某种形式的数据混合。简单来说,数据混合描述了来自两个或多个源的信息合并为一个有用数据的恒定流的过程。 但重要的是要了解过程之间的差异,如数据混合和数据集成。人们经常会将这二者混淆,特别是SQL查询编程,但是它们描述了不同的过程。传统的数据集成(也称为提取、转换和加载过程)是一种非常标准化的方法。数据混合是一个为现代数据分析人员提供更大的灵活性和可定制性的过程。 与其他形式的虚拟化和数据收集相比,典型的数据混合过程相对快速和高效。当许多不同的数据源发挥作用时会出现并发问题,但推出的下一代软件使其工作变得更加容易。一些***的数据混合工具包括以下内容: Tableau:总部位于华盛顿州西雅图的Tableau软件公司使用高度互动的下一代数据可视化技术来提供翔实和可操作的商业智能。他们的软件在大规模数据混合操作中很常见。 Alteryx Designer:专注于为当今的数据分析师提供全面的解决方案,Alteryx Designer经常用于数据混合、数据准备和统计分析,以在竞争中发现新的见解和趋势。 Datawatch Monarch:Monarch专门从事数据采集,准备,管理和整理,这是一组统称为数据清理的过程。商业世界中一些***的公司使用Datawatch的软件,包括摩根大通、施乐、Equifax等等。 而有兴趣进行数据混合的企业还有很多。 2.数据服务模块 数据服务模块通常包含在数据仓库合同中。因此,许多不同的模块可用于公共消费。例如,Bing空间数据服务模块可以轻松上传数据,以便在依赖Bing地图服务的基于云计算的应用程序中使用。用户可以选择将其数据源标记为公开,以允许任何人使用适当的密钥进行访问。 3.SQL功能 单一查询语言(或SQL)是用于高级和高度复杂数据库结构的编程语言,但它在数据虚拟化中也占有一席之地。通过对现代大数据技术进行虚拟化,就像从Hadoop供应商那里看到的那样,它们可以与SQL文件或文件夹相结合,并通过标准SQL查询。 上面链接中给出的示例演示了如何使用Angular JS为API创建可重用数据服务模块,但是数据虚拟化以多种方式受益于SQL编程,其中包括: 简单直接地访问几乎任何形式的数据的能力。 针对跨多个系统存在的较大数据集启用查询,从而无需将它们重新定位到可能有或没有足够可用磁盘空间的单个系统。 直接和无缝地访问存在于不同系统或组织不同部门的数据集和数据源。 与云计算和大多数数据中心环境完全集成,其中包括企业级环境。 将更大的计算需求(如非常大的数据集)卸载到功能更强大的外部系统。在此过程中保持无缝进行至关重要。 SQL是一种多功能编程语言,为那些在数据库结构或数据虚拟化项目中使用SQL的人提供了许多好处。 4.云数据服务 虽然本地数据库仍然很流行,尤其是在数据虚拟化方面,基于云计算的系统获得一定的发展势头。尽管它们不代表真正的数据虚拟化,但云计算数据服务通常以软件即服务包的形式出现,以实现许多相同的目标,所有这些都在下一代云中实现。其中一些主要目标包括: 为客户提供各种不同的分析服务。 保持与各种云平台的兼容性。 使用开源编程来促进新的和一致的开发。 提供既经济又安全的平台。 由于云计算服务在五年或十年前尚未广泛推出,它们有可能改变人们所知道的数据虚拟化的整个范围。只有时间才能证明真正的影响,但行业专家已经对云计算及其所提供的一切寄予厚望。 5.数据虚拟化平台 定制的数据虚拟化平台也是可用的。思科公司的IT团队最近设计了一个数据虚拟化软件套件,旨在降低IT成本,加强信息可访问性,并加强数据完整性。拥有超过400个数据库和大约3000个应用程序以及超过50 PB容量的数据存储需求,这是一个巨大的升级,将显著改变他们的业务方式。 克服困惑,选择正确的途径 许多人对数据虚拟化有一些误解,但这并不是因为缺乏尝试。有了如今许多不同形式的数据虚拟化,以及与设备或驱动器虚拟化等其他策略相比差异显著,新手和专家们常常会感到困惑。 了解这些差异不仅使企业更容易选择最适合自己的方法,而且最终还可以为企业节省大量费用,并减少挫折。

优秀的个人博客,低调大师

理解Python中的类对象、实例对象、属性、方法

class Animal(object): # 类对象 age = 0 # 公有类属性 __like = None # 私有类属性 def __init__(self): # 魔法方法 self.name = 'haha' # 公有实例属性 self.__sex = 'man' # 私有实例属性 def smile(self): # 公有方法 self指向实例对象 pass def __jump(self): # 私有方法 pass @classmethod def run(cls): # 类方法 cls 指向类对象 pass @staticmethod def msg(): # 静态方法,可以没有参数 pass ''' # 类对象: 将具有相似属性和方法的对象总结抽象为类对象,可以定义相似的一些属性和方法,不同的实例对象去引用类对象的属性和方法,能减少代码的重复率。 # 类属性: 类对象所有的属性,类对象和实例对象均可以访问,被它们共同拥有; # 公有类属性: 可以在类外修改类属性,需要通过类对象引用直接修改; 类内可以通过类方法修改类属性。 如果通过实例对象来引用类属性,相当于实例对象在实例方法中创建了一个和类属性相同的名字,等同于局部变量实例属性,和类属性无关; # 私有类属性: 类外通过类对象引用不能直接更改,只能通过实例方法调用类对象更改。 # 类方法: 需要修饰器@classmethod,标示其为类方法,类方法的第一个参数必须为类对象,一般用cls表示,通过cls引用的必须是类属性和类方法。 # 静态方法: 需要修饰器@staticmethod,标示其为静态方法。需要做一些功能,和类相关,但不需要类和对象参与,此时可以使用静态方法,静态方法可以不需要参数。 # 实例对象: 通过类对象创建的实例对象 # 实例属性: 通过方法定义的属性 # 私有实例属性: __开头定义的变量名;只能通过方法调用来更改 公有实例属性: 可以通过实例对象重新定义 # 实例方法: 第一个参数公认为self,可以调用类对象和实例对象。 # 私有方法: 只能在类内调用,如果类外调用,则需要类内的公有方法调用类内的私有方法,在类外调用这个公有方法,则间接调用了私有方法。 一个程序中最核心的内容,不能随意调用,可以设置为私有方法,通过公有方法的判断去调用私有方法! # 公有方法: 可以在类内类外随意调用。 # 魔法方法: 例如__init__方法,用两个__前后包裹的方法 ''' -------知识无价,汗水有情,如需搬运请注明出处,谢谢!

优秀的个人博客,低调大师

java基础4:深入理解final关键字

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a724888/article/details/80048792 这位大侠,这是我的公众号:程序员江湖。 ​微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。(关注公众号后回复”Java“即可领取 Java基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Java学习指南、Java程序员面试指南等干货资源。 本文主要介绍了final关键字的使用方法及原理 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech 文章首发于我的个人博客: https://h2pl.github.io/2018/04/23/javase4 final关键字可以修饰类、方法和引用。 修饰类,该类不能被继承。并且这个类的对象在堆中分配内存后地址不可变。 修饰方法,方法不能被子类重写。 修饰引用,引用无法改变,对于基本类型,无法修改值,对于引用,虽然不能修改地址值,但是可以对指向对象的内部进行修改。 比如char[0] = ‘a’。不改变对象内存地址,只改变了值。 具体看一下下面的栗子: final class Fi { int a; final int b = 0; Integer s; } class Si{ //一般情况下final修饰的变量一定要被初始化。 //只有下面这种情况例外,要求该变量必须在构造方法中被初始化。 //并且不能有空参数的构造方法。 //这样就可以让每个实例都有一个不同的变量,并且这个变量在每个实例中只会被初始化一次 //于是这个变量在单个实例里就是常量了。 final int s ; Si(int s) { this.s = s; } } class Bi { final int a = 1; final void go() { //final修饰方法无法被继承 } } class Ci extends Bi { final int a = 1; // void go() { // //final修饰方法无法被继承 // } } final char[]a = {'a'}; final int[]b = {1}; final修饰类 @Test public void final修饰类() { //引用没有被final修饰,所以是可变的。 //final只修饰了Fi类型,即Fi实例化的对象在堆中内存地址是不可变的。 //虽然内存地址不可变,但是可以对内部的数据做改变。 Fi f = new Fi(); f.a = 1; System.out.println(f); f.a = 2; System.out.println(f); //改变实例中的值并不改变内存地址。 Fi ff = f; //让引用指向新的Fi对象,原来的f对象由新的引用ff持有。 //引用的指向改变也不会改变原来对象的地址 f = new Fi(); System.out.println(f); System.out.println(ff); } final修饰方法 @Test public void final修饰方法() { Bi bi = new Bi(); bi.go();//该方法无法被子类Ci重写 } final修饰基本数据类型变量和引用 @Test public void final修饰基本类型变量和引用() { final int a = 1; final int[] b = {1}; final int[] c = {1}; // b = c;报错 b[0] = 1; final String aa = "a"; final Fi f = new Fi(); //aa = "b";报错 // f = null;//报错 f.a = 1; } 关于字符串的内容可以在上一节查看: https://blog.csdn.net/a724888/article/details/80042298 关于抽象类和接口的内容可以在下一节查看: https://blog.csdn.net/a724888/article/details/80061047

优秀的个人博客,低调大师

对Swoole、Workerman和php自带的socket的理解

为什么php自带的socket不怎么听说,基本都是用swoole,workerman去实现? 1、PHP的socket扩展是一套socket api,仅此而已。 swoole,用C实现,它的socket是C 库的socket,更加底层可控。 workerman,如题主所说,使用PHP实现,那它的socket就是用PHP socket扩展啊。只是对其进行工程化开发,成了一个框架。 2、swoole 框架和 swoole 扩展是不一样的。 swoole 框架也可以脱离 swoole 扩展来使用。 swoole 扩展将进程管理,tcp 监听这些工作在 C 里面做了,以扩展的形式提供给 PHP 一些接口来调用。 workerman 就是原生的使用 php stream 相关的函数来监听 tcp,进行进程管理。 如果你想学习 PHP 开发 tcp 的原理建议看 workerman 的源码,如果你只是想使用,用 swoole 就 OK 了。 3、就是一个底层通信框架,基于socket通信的, 其实PHP 也能做多进程编程(扩展支持,workerman是这方面NO.1),swoole使用C 实现的一套PHP扩展,基于它也是做这方面的功能,因为这两个底层框架的存在,大大扩展了PHP的应用范围,和不错的未来期望 4、php现有的应用方式都是基于http的, 对于需要快速实时响应的情况比较乏力,比如网络游戏或者推送服务一般都需要与用户长期保持一个tcp连接以便实时响应和推送信息。 swoole就是解决这样应用场景的。 这个是让php自身建立一个服务,不需要nginx之类的代理,直接监听端口实现通信。 一种应用方式也可以代替掉nginx做http服务,但一般不会这么用。 5、实际上作为一名PHP程序员,我很清楚PHP的确有很多局限性, 比如Unix系统编程、网络通信编程、异步io,大部分PHPer不懂。PHP界也确实没有这样的东西。Swoole开源项目就是为了弥补PHP在这些方面的缺陷诞生的。与WordPress这些产品不同,swoole实际上是一个网络通信和异步io的引擎,一个基础库。PHPer可以基于swoole去实现过去PHP无法实现的功能。swoole为PHPer打开了通往另一个世界的大门。 6、这2个框架都很出名,它们的出现大大的提高了php的应用范围及知名度 workerman和swoole都是php socket 服务器框架,都支持长连接、tcp和udp、websocket、异步、分布式部署等 workerman纯php写的,swoole是php的c扩展,性能肯定更高,百度、腾讯不少产品的server就是基于swoole的 workerman上手更快,文档更丰富,社区活跃,社区基本做到有问必答,一般的中小型项目也够了,所以初学者最好还是使用workerman,熟了后再根据具体业务权衡(官方网站都有压测数据) 参考文献 [2]H. Berenson, P. Bernstein, J. Gray, J.Melton, E. O’Neil,and P. O’Neil. A critique of ANSI SQL isolation levels. InProceedings of the SIGMOD International Conference on Management of Data, pages1–10, May 1995. [3]Michael J. Cahill, Uwe Röhm, and Alan D.Fekete. 2008. Serializable isolation for snapshot databases. In SIGMOD ’08:Proceedings of the 2008 ACM SIGMOD international conference on Management of data, pages 729–738, New York, NY, USA. ACM. [4]Michael James Cahill. 2009. Serializable Isolation for Snapshot Databases. Sydney Digital Theses. University of Sydney, School of Information Technologies [5] A. Fekete, D. Liarokapis, E. O’Neil, P.O’Neil, andD. Shasha. Making snapshot isolation serializable. www.codexueyuan.com In ACM transactions on database systems, volume 39(2), pages 492–528, June 2005.

优秀的个人博客,低调大师

java面试- 深入理解JVM(七)——Class文件结构

什么是JVM的“无关性”? Java具有平台无关性,也就是任何操作系统都能运行Java代码。之所以能实现这一点,是因为Java运行在虚拟机之上,不同的操作系统都拥有各自的Java虚拟机,因此Java能实现“一次编写,处处运行”。 而JVM不仅具有平台无关性,还具有语言无关性。平台无关性是指不同操作系统都有各自的JVM,而语言无关性是指Java虚拟机能运行除Java以外的代码! 这听起来非常惊人,但JVM对能运行的语言是有严格要求的。首先来了解下Java代码的运行过程。 Java源代码首先需要使用Javac编译器编译成class文件,然后启动JVM执行class文件,从而程序开始运行。也就是JVM只认识class文件,它并不管何种语言生成了class文件,只要class文件符合JVM的规范就能运行。因此目前已经有Scala、JRuby、Jython等语言能够在JVM上运行。它们有各自的语法规则,不过它们的编译器都能将各自的源码编译成符合JVM规范的class文件,从而能够借助JVM运行它们。 纵观Class文件结构 class文件是二进制文件,它的内容具有严格的规范,文件中没有任何空格,全是连续的0/1。class文件中的所有内容被分为两种类型:无符号数 和 表。- 无符号数它表示class文件中的值,这些值没有任何类型,但有不同的长度。根据这些值长度的不同分为:u1、u2、u4、u8,分别代表1字节的无符号数、2字节的无符号数、4字节的无符号数、8字节的无符号数。- 表class文件中所有数据(即无符号数)要么单独存在,要么由多个无符号数组成二维表。即class文件中的数据要么是单个值,要么是二维表。 class文件的组织结构 魔数 本文件的版本信息 常量池 访问标志 类索引 父类索引 接口索引集合 字段表集合 方法表集合 Class文件的构成1:魔数 class文件的头4个字节称为魔数,用来表示这个class文件的类型。 魔数的作用就相当于文件后缀名,只不过后缀名容易被修改,不安全,因此在class文件中标示文件类型比较合适。 class文件的魔数是用16进制表示的“CAFEBABE”,非常具有浪漫主义色彩,谁说程序员的情商都很低! Class文件的构成2:版本信息 紧接着魔数的4个字节是版本号。它表示本class中使用的是哪个版本的JDK。 在高版本的JVM上能够运行低版本的class文件,但在低版本的JVM上无法运行高版本的class文件,即使该class文件中没有用到任何高版本JDK的特性也无法运行! Class文件的构成3:常量池 1. 什么是常量池? 紧接着版本号之后的就是常量池。常量池中存放两种类型的常量: 字面值常量字面值常量即我们在程序中定义的字符串、被final修饰的值。 符号引用符号引用就是我们定义的各种名字: 类和接口的全限定名 字段的名字 和 描述符 方法的名字 和 描述符 2. 常量池的特点 常量池长度不固定常量池的大小是不固定的,因此常量池开头放置一个u2类型的无符号数,用来存储当前常量池的容量。JVM根据这个值就知道常量池的头尾来。注:这个值是从1开始的,若为5表示池中有4个常量。 常量池中的常量由而为表来表示常量池开头有个常量池容量计数器,接下来就全是一个个常量了,只不过常量都是由一张张二维表构成,除了记录常量的值以外,还记录当前常量的相关信息。 常量池是class文件的资源仓库 常量池是与本class中其它部分关联最多的部分 常量池是class文件中空间占用最大的部分之一 3. 常量池中常量的类型 刚才介绍了,常量池中的常量大体上分为:字面值常量 和 符号引用。在此基础上,根据常量的数据类型不同,又可以被细分为14种常量类型。这14种常量类型都有各自的二维表示结构。每种常量类型的头1个字节都是tag,用于表示当前常量属于14种类型中的哪一个。 以CONSTANT_Class_info常量为例,它的二维表示结构如下:CONSTANT_Class_info表: 类型 名称 数量 u1 tag 1 u2 name_index 1 tag表示当前常量的类型(当前常量为CONSTANT_Class_info,因此tag的值应为7,表示一个类或接口的全限定名);name_index表示这个类或接口全限定名的位置。它的值表示指向常量池的第几个常量。它会指向一个CONSTANT_Utf8_info类型的常量,它的二维表结构如下:CONSTANT_Utf8_info表: 类型 名称 数量 u1 tag 1 u2 length 1 u1 bytes length CONSTANT_Utf8_info表示字符串常量;tag表示当前常量的类型,这里应该是1;length表示这个字符串的长度;bytes为这个字符串的内容(采用缩略的UTF8编码) 问:为什么Java中定义的类、变量名字必须小于64K?类、接口、变量等名字都属于符号引用,它们都存储在常量池中。而不管哪种符号引用,它们的名字都由CONSTANT_Utf8_info类型的常量表示,这种类型的常量使用u2存储字符串的长度。由于2字节最多能表示65535个数,因此这些名字的最大长度最多只能是64K。 问:什么是UTF-8编码?什么是缩略UTF-8编码?前者每个字符使用3个字节表示,而后者把128个ASKII码用1字节表示,某些字符用2字节表示,某些字符用3字节表示。 Class文件的构成4:访问标志 在常量池之后是2字节的访问标志。访问标志是用来表示这个class文件是类还是接口、是否被public修饰、是否被abstract修饰、是否被final修饰等。由于这些标志都由是/否表示,因此可以用0/1表示。访问标志为2字节,可以表示16位标志,但JVM目前只定义了8种,未定义的直接写0. Class文件的构成5:类索引、父类索引、接口索引集合 类索引、父类索引、接口索引集合是用来表示当前class文件所表示类的名字、父类名字、接口们的名字。它们按照顺序依次排列,类索引和父类索引各自使用一个u2类型的无符号常量,这个常量指向CONSTANT_Class_info类型的常量,该常量的bytes字段记录了本类、父类的全限定名。由于一个类的接口可能有好多个,因此需要用一个集合来表示接口索引,它在类索引和父类索引之后。这个集合头两个字节表示接口索引集合的长度,接下来就是接口的名字索引。 Class文件的构成6:字段表的集合 1. 什么是字段表集合? 接下来是字段表的集合。字段表集合用于存储本类所涉及到的成员变量,包括实例变量和类变量,但不包括方法中的局部变量。每一个字段表只表示一个成员变量,本类中所有的成员变量构成了字段表集合。 2. 字段表结构的定义 类型 名称 数量 u2 access_flags 1 u2 name_index 1 u2 descriptor_index 1 u2 attributes_count 1 attribute_info attributes attributes_count access_flags字段的访问标志。在Java中,每个成员变量都有一系列的修饰符,和上述class文件的访问标志的作用一样,只不过成员变量的访问标志与类的访问标志稍有区别。 name_index本字段名字的索引。指向一个CONSTANT_Class_info类型的常量,这里面存储了本字段的名字等信息。 descriptor_index描述符。用于描述本字段在Java中的数据类型等信息(下面详细介绍) attributes_count属性表集合的长度。 attributes属性表集合。到descriptor_index为止是字段表的固定信息,光有上述信息可能无法完整地描述一个字段,因此用属性表集合来存放额外的信息,比如一个字段的值。(下面会详细介绍) 3. 什么是描述符? 成员变量(包括静态成员变量和实例变量) 和 方法都有各自的描述符。对于字段而言,描述符用于描述字段的数据类型;对于方法而言,描述符用于描述字段的数据类型、参数列表、返回值。 在描述符中,基本数据类型用大写字母表示,对象类型用“L对象类型的全限定名”表示,数组用“[数组类型的全限定名”表示。描述方法时,将参数根据上述规则放在()中,()右侧按照上述方法放置返回值。而且,参数之间无需任何符号。 4. 字段表集合的注意点 一个class文件的字段表集合中不能出现从父类/接口继承而来字段; 一个class文件的字段表集合中可能会出现程序猿没有定义的字段如编译器会自动地在内部类的class文件的字段表集合中添加外部类对象的成员变量,供内部类访问外部类。 Java中只要两个字段名字相同就无法通过编译。但在JVM规范中,允许两个字段的名字相同但描述符不同的情况,并且认为它们是两个不同的字段。 Class文件的构成7:方法表的集合 在class文件中,所有的方法以二维表的形式存储,每张表来表示一个函数,一个类中的所有方法构成方法表的集合。方法表的结构和字段表的结构一致,只不过访问标志和属性表集合的可选项有所不同。 类型 名称 数量 u2 access_flags 1 u2 name_index 1 u2 descriptor_index 1 u2 attributes_count 1 attribute_info attributes attributes_count 方法表的属性表集合中有一张Code属性表,用于存储当前方法经编译器编译过后的字节码指令。 方法表集合的注意点 如果本class没有重写父类的方法,那么本class文件的方法表集合中是不会出现父类/父接口的方法表; 本class的方法表集合可能出现程序猿没有定义的方法编译器在编译时会在class文件的方法表集合中加入类构造器和实例构造器。 重载一个方法需要有相同的简单名称和不同的特征签名。JVM的特征签名和Java的特征签名有所不同: Java特征签名:方法参数在常量池中的字段符号引用的集合 JVM特征签名:方法参数+返回值 Class文件的构成8:属性表的集合

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册