JVM类加载机制详解
Java在运行期才对类进行加载到内存、连接、初始化过程。这使得Java应用具有极高的灵活性和拓展性,可以依赖运行期进行动态加载和动态连接。
主要加载哪些?Java中的数据类型分为基本数据类型和引用数据类型,基本数据类型由虚拟机预先定义,而引用数据类型需要进行类的加载。
注:对于同一个类加载器,类只加载一次,但对于不同的类加载器可以将类多次加载到内存并相互隔离
1 装载阶段:Loading
装载阶段,简言之,查找并加载类的二进制数据,生成该类的数据结构和Class的实例。
字节码文件加载到内存中的类模版结构存储在方法区,class的实例存储在堆空间。
1、在加载类时,Java虚拟机必须完成以下3件事情:
- 通过类的全名,获取类的二进制数据流。
- 解析类的二进制数据流为方法区内的数据结构(Java类模型)。
- 创建java.lang.Class类的实例,表示该类型。作为方法区这个类的各种数据的访问入口。
说明:
(方法区,1.8之前常被称为永久代,1.8之后被元空间所取代)
(如果用一个变量clazz接收这个Cl ass类的实例,这个变量在栈中,并保存了实例的地址)
(创建Class的实例的构造方法是私有的,只有JVM能够创建,同时也是实现反射的关键)
2、二进制流的获取方法
对于类的二进制数据流,虚拟机可以通过多种途径产生或获得。(只要所读取的字节码符合JVM规范即可)
- 虚拟机从文件系统读入一个class后缀的文件。(最常见)
- 读入jar、zip等归档数据包,提取类文件。(jar包)
- 事先存放在数据库中的类的二进制数据
- 使用类似于HTTP之类的协议通过网络进行加载
- 在运行时生成一段Class的二进制信息等
在获取到类的二进制信息后,Java虚拟机就会处理这些数据,并最终转为一个java.lang.Class的实例。
如果输入数据不是ClassFile的结构,则会抛出ClassFormatError。
3、数组的加载
创建数组类的情况稍微有些特殊,因为数组类本身并不是由类加载器负责创建,而是由JVM在运行时根据需要而直接创建的,但数组的元素类型仍然需要依靠类加载器去创建。创建数组类(下述简称A)的过程:
- 如果数组的元素类型是引用类型,那么就遵循定义的加载过程递归加载和创建数组A的元素类型;
- JVM使用指定的元素类型和数组维度来创建新的数组类。
- 如果数组的元素类型是引用类型,数组类的可访问性就由元素类型的可访问性决定。否则数组类的可访问性将被缺省定义为public。
2 链接阶段:Linking
2.1 验证:Verify
它的目的是保证加载的字节码是合法、合理并符合规范的。
验证的内容则涵盖了类数据信息的格式验证、语义检查、字节码验证,以及符号引用验证等。
当类加载到系统后,就开始链接操作,验证是链接操作的第一步。格式验证会和装载阶段一起执行。符号引用验证在解析环节才会执行。
2.2 准备:Prepare
为类的静态变量分配内存,并将其初始化为默认值。
(注意区分,这里虽然用了初始化,是给变量赋默认值,但是后面还有初始化阶段,是给变量显式赋值,这两个初始化是不同的概念)
private static int num = 1;
// 这个静态成员变量在准备阶段会赋0,初始化阶段赋1;
注意:
- 这里不包含基本数据类型的字段用static final修饰的情况(即常量),因为final在编译的时候就会分配了,准备阶段会显式赋值。
- 注意这里不会为实例变量(即非静态变量)分配初始化,实例变量是会随着对象一起分配到Java堆中。
- 在这个阶段并不会像初始化阶段中那样会有初始化或者代码被执行。
- Java并不支持boolean类型,对于boolean类型,内部实现是int,由于int的默认值是0,故对应的,boolean的默认值就是false。
说明:常量在编译阶段会存入到调用这个常量的方法所在类的常量池中。
// 即对于下面这个字符串常量,在编译阶段就已经为其分配好了内存和值,在字节码文件加载后直接将其显式赋值
public class MyTest2 {public static void main(String[] args) {System.out.println(MyParent2.str);}
}class MyParent2 {public static final String str = "hello world";static {System.out.println("MyParent2 static block");}
}// 输出 hello world
// 但也有例外情况,如果常量的值并不是字面量,并非编译期间可以确定的,那么其值就不会被放到调用类的常量池中,这时在程序运行时,会导致主动使用这个常量所在的类,显然会导致这个类会初始化。(在初始化阶段才会显示赋值,clinit()方法
public class MyTest3 {public static void main(String[] args) {System.out.println(MyParent3.str);}
}class MyParent3 {public static final String str = UUID.randomUUID().toString();static {System.out.println("MyParent3 static block");}
}// 常量的值在运行时才会确定
// 输出
//MyParent3 static block
//4e5bc60b-ec26-40c1-aeea-a5eddcb2dbaf
2.3 解析:Resolve
将类、接口、字段和方法的符号引用转为直接引用。
1.具体描述
符号引用就是一些字面量的引用,和虚拟机的内部数据结构和和内存布局无关。比较容易理解的就是在Class类文件中,通过常量池进行了大量的符号引用。但是在程序实际运行时,只有符号引用是不够的,比如当如下println()方法被调用时,系统需要明确知道该方法的位置。
以方法为例,Java虚拟机为每个类都准备了一张方法表,将其所有的方法都列在表中,当需要调用一个类的方法的时候,只要知道这个方法在方法表中的偏移量就可以直接调用该方法。通过解析操作,符号引用 --> 目标方法在类中方法表中的位置,从而使得方法被成功调用。
2.小结
所谓解析就是将符号引用转为直接引用,也就是得到类、字段、方法在内存中的指针或者偏移量。因此,可以说,如果直接引用存在,那么可以肯定系统中存在该类、方法或者字段。但只存在符号引用,不能确定系统中一定存在该结构。
不过Java虚拟机规范并没有明确要求解析阶段一定要按照顺序执行。在HotSpot VM中,加载、验证、准备和初始化会按照顺序有条不紊地执行,但链接阶段中的解析操作往往会伴随着JVM在执行完初始化之后再执行(解析操作并不一定按照上述顺序执行)。
3 初始化阶段:Initializing
始化阶段,简言之,为类的静态变量赋予正确的初始值。(显式初始化)
- 具体描述
类的初始化是类装载的最后一个阶段。如果前面的步骤都没有问题,那么表示类可以顺利装载到系统中。此时,类才会开始执行Java字节码。(即:到了初始化阶段,才真正开始执行类中定义的 Java 程序代码,代码块、静态代码块、构造器。或者说此时才是开发者可控的范围,之前的都由虚拟机自动完成)
- clinit()方法
- 初始化阶段的重要工作是执行类的初始化方法:<clinit>()方法。
- 该方法仅能由Java编译器生成并由JVM调用,程序开发者无法自定义一个同名的方法,更无法直接在Java程序中调用该方法,虽然该方法也是由字节码指令所组成。
- 它是由类静态成员的显示赋值语句以及static语句块合并产生的。(静态变量不赋值、非静态变量、常量都不能生成clinit()方法)
- 一个类的clinit()方法在多线程执行时会加同步锁,保证只有一个线程执行这个方法,如果clinit()方法中有较耗时的内容,将会造成阻塞,无法执行初始化后的内容。但一般来说一个类只会初始化一次。
<clinit>() : 只有在给类的中的静态变量显式赋值或在静态代码块中赋值了,才会生成此方法,这个方法不是必需的。
<init>() 一定会出现在Class的method表中。(非静态变量的显式赋值、非静态代码块、构造器)
// clinit
private static int a = 1;
static{a=2;
}
/*
* a=1会被a=2覆盖,静态代码块和变量赋值同等优先度,按顺序执行,
* 但由于只能访问在它之前被定义的静态变量,所以一般静态代码块晚于静态变量赋值
* 对于非静态变量的显式赋值与非静态代码块的执行顺序也是如此
*/
注意:非静态成员变量在初始化时不会分配内存空间,也不会赋默认值。非静态成员变量只有在类被创建实例对象的时候才会一起创建。如果是由于创建对象触发的类的加载,则会在初始化后紧接着创建类的实例和成员变量,并对变量赋默认值。然后,相继执行非静态变量、构造方法对非静态变量进行初始化。注意区分类的初始化和创建类的实例。
在静态代码块中只允许有局部变量和静态变量,不允许操作非静态成员变量。
常量如果被赋字面量的值,在链接的准备阶段就被赋值,在初始化阶段不再需要clinit来初始化,但如果常量被赋的值不是字面量,需要初始化阶段才能确定,则会延后到初始化阶段赋值。
- 触发类的加载、初始化的时机?
主动使用:完成装载、验证、准备和初始化一套流程(解析可能会在运行时才开始)
- 当创建一个类的实例时,比如使用new关键字,或者通过反射、克隆、反序列化。
- 当调用类的静态方法时,即当使用了字节码invokestatic指令。
- 当使用类、接口的静态字段时(final修饰特殊考虑),比如,使用getstatic或者putstatic指令。
- 当使用java.lang.reflect包中的方法反射类的方法时。比如:Class.forName(“com.atguigu.java.Test”)
- 当初始化子类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
static class Parent{public static int A = 1;static {A = 2;}
}
static class Sub extends Parent {public static int B = A;public static void main(String[] args){System.out.println(Sub.B);}
}// 初始化子类前先初始化父类,父类的静态代码块先于子类的显式赋值的执行,输出2
- 如果一个接口定义了默认方法,那么直接实现或者间接实现该接口的类的初始化,该接口要在其之前被初始化。
- 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
特别说明:初始化父接口的子接口或接口的实现类时,并不会像父子类一样先初始化这个父接口**。只有调用接口的具体静态常量、静态方法或被实现的接口有默认方法时才会初始化。(接口内没有常量外的其他变量,也没有起初始化作用的代码块)
执行的主类在运行前会先完成类的装载、验证、准备和初始化,然后在程序的入口main()开始执行,main()方法内使用到其他的类同样会触发类的加载。也即主类的静态代码块会早于main()执行,但同上面所说的,非静态代码块会在创建实例时才会执行。
static String a = "a";
static {a="aa";
}
{a="aaa";
}
public static void main (String[] args){System.out.println(a);
}
// 输出 aa
// 如果main()中加入a="aaaa",则最终输出aaaa,但无论如何不会输出aaa因为没有创建实例。
被动使用:类可能被加载,但不会初始化。
- 当访问一个静态字段时,只有真正声明这个字段的类才会被初始化。当通过子类引用父类的静态变量,不会导致子类初始化。
- 通过数组定义类引用,不会触发此类的初始化。
- 引用常量不会触发此类或接口的初始化。因为常量在链接阶段就已经被显式赋值了。
- 调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。
被动的使用,意味着不需要执行初始化环节,意味着没有<clinit>()的调用。
4 类的卸载
通过前面的几个阶段,类已经可以被正常使用,梳理一下这过程中产物:
装载阶段将字节码文件读入生成对应类的Class实例(堆中)以及类的结构和常量(方法区),而其实这个过程是由类的加载器(Class Loader)实现的,所以在此之前会先生成加载该类的加载器对象(堆中)。链接阶段和初始化阶段主要是除了给变量赋值没有产生新的东西。
如果初始化阶段一并new了类的对象,则会生成类的实例对象,类的成员变量等结构。
堆中一共产生了3个类的对象,这三个对象之间也有关联关系,同时也可以用变量去引用它们,如下图所示。
那么什么时候回触发类的卸载呢?当类卸载后,代表该类的Class对象不再被引用或unreachable,其在堆空间和方法区内的数据也会被清空。
引用变量可以为null,类的实例对象也可以被销毁,但是由于Class类对象被加载器引用,一般除特殊处理类是被系统加载器加载,而系统加载器在JVM运行期间很难会不再使用,所以类的卸载往往是不确定的,也很难会被卸载。
所以,类的卸载需要同时满足下面三个条件:
- 该类所有的实例都已经被回收。也就是Java堆中不存在该类及其任何派生子类的实例。
- 加载该类的类加载器已经被回收。这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。
- 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
注意:Java虚拟机只是允许对满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是和对象一样,没有引用了就必然会回收。
可以得到的结论是:一个已经加载的类型被卸载的几率很小至少被卸载的时间是不确定的。也因此开发者在开发代码时候,不应该在对虚拟机的类型卸载做任何假设前提下,来实现系统中的特定功能(不应该设计一种代码逻辑是在类卸载后执行,因为往往是不可靠的)。也正因为类很难被卸载,所以类虽然可以被创建多个实例,但往往只加载一次。
相关文章:
JVM类加载机制详解
Java在运行期才对类进行加载到内存、连接、初始化过程。这使得Java应用具有极高的灵活性和拓展性,可以依赖运行期进行动态加载和动态连接。 主要加载哪些?Java中的数据类型分为基本数据类型和引用数据类型,基本数据类型由虚拟机预先定义&…...
【MATLAB实战】基于UNet的肺结节的检测
数据: 训练过程图 算法简介: UNet网络是分割任务中的一个经典模型,因其整体形状与"U"相似而得名,"U"形结构有助于捕获多尺度信息,并促进了特征的精确重建,该网络整体由编码器,解码器以及跳跃连接三部分组成。 编码器由…...
Elasticsearch基础(五):使用Kibana Discover探索数据
文章目录 使用Kibana Discover探索数据 一、添加样例数据 二、数据筛选 三、保存搜索 使用Kibana Discover探索数据 一、添加样例数据 登录Kibana。在Kibana主页的通过添加集成开始使用区域,单击试用样例数据。 在更多添加数据的方式页面下方,单击…...
爬取百度图片,想爬谁就爬谁
前言 既然是做爬虫,那么肯定就会有一些小心思,比如去获取一些自己喜欢的资料等。 去百度图片去抓取图片吧 打开百度图片网站,点击搜索xxx,打开后,滚动滚动条,发现滚动条越来越小,说明图片加载…...
HTTP 缓存
缓存 web缓存是可以自动保存常见的文档副本的HTTP设备,当web请求抵达缓存时,如果本地有已经缓存的副本,就可以从本地存储设备而不是从原始服务器中提取这个文档。使用缓存有如下的优先。 缓存减少了冗余的数据传输缓存环节了网络瓶颈的问题…...
设计模式实战:图形编辑器的设计与实现
简介 本篇文章将介绍如何设计一个图形编辑器系统,系统包括图形对象的创建、组合、操作及撤销等功能。我们将通过这一项目,应用命令模式、组合模式和备忘录模式来解决具体的设计问题。 问题描述 设计一个图形编辑器系统,用户可以创建并操作图形对象,将多个图形对象组合成…...
.NET 情报 | 分析某云系统添加管理员漏洞
01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失…...
vue检测页面手指滑动距离,执行回调函数,使用混入的语法,多个组件都可以使用
mixin.ts 定义滑动距离的变量和检测触摸开始的方法,滑动方法,并导出两个方法 sendTranslateX.value > 250 && sendTranslateY.value < -100是向上滑动,满足距离后执行回调函数func,并在一秒内不再触发,一…...
opencv 优势
OpenCV(开源计算机视觉库)是一个广泛使用的计算机视觉和机器学习软件框架。它最初由Intel开发,后来由Itseez公司维护,最终于2015年成为非营利组织OpenCV.org的一部分。OpenCV的目的是实现一个易于使用且高效的计算机视觉框架,支持实时视觉应用。 以下是关于OpenCV的一些关…...
1-如何挑选Android编译服务器
前几天,我在我的星球发了一条动态:入手洋垃圾、重操老本行。没错,利用业余时间,我又重新捣鼓捣鼓代码了。在接下来一段时间,我会分享我从服务器的搭建到完成Android产品开发的整个过程。这些东西之前都是折腾过的&…...
【JS逆向课件:第十六课:Scrapy基础2】
ImagePipeLines的请求传参 环境安装:pip install Pillow USER_AGENT Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36需求:将图片的名称和详情页中图片的数据进行爬取&a…...
使用 PowerShell 自动化图像识别与鼠标操作
目录 前言功能概述代码实现1. 引入必要的程序集2. 定义读取文件行的函数3. 定义加载图片的函数4. 定义查找小图像在大图像中的位置的函数5. 定义截取全屏的函数6. 定义模拟鼠标点击的函数7. 定义主函数 配置文件示例运行脚本结语全部代码提示打包exe 下载地址 前言 在日常工作…...
组队学习——支持向量机
本次学习支持向量机部分数据如下所示 IDmasswidthheightcolor_scorefruit_namekind 其中ID:1-59是对应训练集和验证集的数据,60-67是对应测试集的数据,其中水果类别一共有四类包括apple、lemon、orange、mandarin。要求根据1-59的数据集的自…...
【数据中心】数据中心的IP封堵防护:构建网络防火墙的基石
数据中心的IP封堵防护:构建网络防火墙的基石 引言一、理解IP封堵二、IP封堵的功能模块及其核心技术三、实施IP封堵的关键策略四、结论 引言 在当今高度互联的世界里,数据中心成为信息流动和存储的神经中枢,承载着企业和组织的大量关键业务。…...
LangChain的使用详解
一、 概念介绍 1.1 Langchain 是什么? 官方定义是:LangChain是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序,它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供…...
Modbus转BACnet/IP网关快速对接Modbus协议设备与BA系统
摘要 在智能建筑和工业自动化领域,Modbus和BACnet/IP协议的集成应用越来越普遍。BA(Building Automation,楼宇自动化)系统作为现代建筑的核心,需要高效地处理来自不同协议的设备数据,负责监控和管理建筑内…...
万字长文之分库分表里无分库分表键如何查询【后端面试题 | 中间件 | 数据库 | MySQL | 分库分表 | 其他查询】
在很多业务里,分库分表键都是根据主要查询筛选出来的,那么不怎么重要的查询怎么解决呢? 比如电商场景下,订单都是按照买家ID来分库分表的,那么商家该怎么查找订单呢?或是买家找客服,客服要找到对…...
如何查看jvm资源占用情况
如何设置jar的内存 java -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:AlwaysPreTouch -XX:ReservedCodeCacheSize128m -XX:InitialCodeCacheSize128m -Xss512k -Xmx2g -Xms2g -XX:UseG1GC -XX:G1HeapRegionSize4M -jar your-application.jar以上配置为堆内存4G jar项…...
科研绘图系列:R语言TCGA分组饼图(multiple pie charts)
介绍 在诸如癌症基因组图谱(TCGA)等群体研究项目中,为了有效地表征和比较不同群体的属性分布,科研人员广泛采用饼图作为数据可视化的工具。饼图通过将一个完整的圆形划分为若干个扇形区域,每个扇形区域的面积大小直接对应其代表的属性在整体中的占比。这种图形化的展示方…...
ReadAgent,一款具有要点记忆的人工智能阅读代理
人工智能咨询培训老师叶梓 转载标明出处 现有的大模型(LLMs)在处理长文本时受限于固定的最大上下文长度,并且当输入文本越来越长时,性能往往会下降,即使在没有超出明确上下文窗口的情况下,LLMs 的性能也会随…...
构建智能:利用Gradle项目属性控制构建行为
构建智能:利用Gradle项目属性控制构建行为 Gradle作为一款强大的构建工具,提供了丰富的项目属性管理功能。通过项目属性,开发者可以灵活地控制构建行为,实现条件编译、动态配置和多环境构建等高级功能。本文将详细解释如何在Grad…...
如何通过smtp设置使ONLYOFFICE协作空间服务器可以发送注册邀请邮件
什么是ONLYOFFICE协作空间 ONLYOFFICE协作空间,是Ascensio System SIA公司出品的,基于Web的,开源的,跨平台的,在线文档编辑和协作的解决方案。在线Office包含了最基本的办公三件套:文档编辑器、幻灯片编辑…...
SQL labs靶场-SQL注入入门
靶场及环境配置参考 一,工具准备。 推荐下载火狐浏览器,并下载harkbar插件(v2)版本。hackbar使用教程在此不做过多描述。 补充:url栏内部信息会进行url编码。 二,SQL注入-less1。 1,判断传参…...
HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 单选题序号4
基础认证题库请移步:HarmonyOS应用开发者基础认证题库 注:有读者反馈,题库的代码块比较多,打开文章时会卡死。所以笔者将题库拆分,单选题20个为一组,多选题10个为一组,题库目录如下,…...
使用LSTM完成时间序列预测
c 在本教程中,我们将介绍一个简单的示例,旨在帮助初学者入门时间序列预测和 PyTorch 的使用。通过这个示例,你可以学习如何使用 LSTMCell 单元来处理时间序列数据。 我们将使用两个 LSTMCell 单元来学习从不同相位开始的正弦波信号。模型在…...
《数据结构:顺序实现二叉树》
文章目录 一、树1、树的结构与概念2、树相关术语 二、二叉树1、概念与结构2、满二叉树3、完全二叉树 三、顺序二叉树存储结构四、实现顺序结构二叉树1、堆的概念与结构2、堆的实现3、堆的排序 一、树 1、树的结构与概念 树是一种非线性的数据结构,它是由nÿ…...
【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式结构重用
【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式&结构重用 渲染控制包含了条件渲染和循环渲染,所谓条件渲染,即更具状态不同,选择性的渲染不同的组件。 而循环渲染则是用于列表之内的、多个重复元素组成的结构中。 …...
【防火墙】防火墙NAT、智能选路综合实验
实验拓扑 实验要求 7,办公区设备可以通过电信链路和移动链路上网(多对多的NAT,并且需要保留一个公网IP不能用来转换) 8,分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的http服务器 9,多出口环境基于带宽比例进行选路…...
VUE之---slot插槽
什么是插槽 slot 【插槽】, 是 Vue 的内容分发机制, 组件内部的模板引擎使用slot 元素作为承载分发内容的出口。slot 是子组件的一个模板标签元素, 而这一个标签元素是否显示, 以及怎么显示是由父组件决定的。 VUE中slot【插槽】…...
linux、windows、macos,命令终端清屏
文章目录 LinuxWindowsmacOS 在Linux、Windows和macOS的命令终端中,清屏的命令或方法各不相同。以下是针对这三种系统的清屏方法: Linux clear命令:这是最常用的清空终端屏幕的命令之一。在终端中输入clear命令后,屏幕上的所有内容…...
wordpress弹窗广告/长沙关键词优化公司电话
【出版商】贝哲斯咨询 【免费目录下载】台式杯封口机使用整个过程实现自动化完成,可定量灌装,利用光电定位控制器来确定封口位置,准确无误、生产效率高。塑料复合膜或铝塑复合膜被用来进行自动热封和自动切边,经包装后的产品外形…...
网站的优化公司/引流推广营销
点击打开链接 思路: lis的变形,唯一不同的是条件a[i] - i > a[j] - j 1,i>j。因为要确保这两个元素之间能插入i - j 1个元素 每个数先减去它的下标,防止下面的情况发生: 加入序列是1,2,2,2,3,这样求上升子序列是3…...
杭州企业网站开发/站长工具综合查询系统
有时候我们自己内心经常在斗争,经常有两种声音在争论,比如 是看书呢?还是看电影呢?其实这是一个很大的话题,感性与理性的较量,而今天所说的就是认识到产生这种现象的原因。我们在一定程度上被原始社会进化的…...
网站方案书免费/怎么让百度收录自己的网站
Python与开源GIS教程的内容,开发了单独的内容,请打开https://www.osgeo.cn/pygis/查看。本页面的内容不再更新。GIS数据除了图形要素之外,更重要的就是属性数据了。关于GIS数据的属性,完全可以用关系型数据库的观点来看待。不过在…...
万网域名注册官网中文域名/成都爱站网seo站长查询工具
Worksheet 对象的 rows 属性和 columns 属性得到的是一 Generator 对象,不能用中括号取索引。可先用列表推导式生成包含每一列中所有单元格的元组的列表,在对列表取索引。Worksheet 的 rows 属性亦可用相同的方法处理。补充:python之表格数据…...
郑州的网站建设/关键词搜索方法
1.Comparable 接口的定义:public interface Comparable{public int compareTo(T o)}接口中只有一个 compareTo 方法,该方法返回一个 int 类型的数据,但是 int 的值只能是3种:*1:表示大于*-1:表示小于*0&…...