首页 文章 精选 留言 我的

精选列表

搜索[JDK 25],共10000篇文章
优秀的个人博客,低调大师

小知识 - JDK 奇数版本和偶数版本的区别(你用对了吗?)

Java CPU 和 PSU 版本解释 从 2014 年 10 月发布 Java SE 7 Update 71 (Java SE 7u71) 开始,Oracle 将在发布重要补丁更新 (CPU) 的同时发布相应的 Java SE 7 补丁集更新 (PSU)。 我应当选择哪个 Java 版本:CPU 还是 PSU? Oracle 强烈建议所有 Java SE 用户升级到相应版本系列的最新 CPU 版本。大多数用户应当选择 CPU 版本。 仅当用户受到版本说明中所述的该版本所修复的其他漏洞的影响时才应使用相应的 PSU 版本。 后续 CPU 版本将包含当前 PSU 的所有修复。鉴于此,组织应当测试其环境中的当前 PSU,这些修复将包含在下一个 CPU 中。 Java CPU 与 PSU 之间的区别? Java SE 重要补丁更新 (CPU) 包含安全漏洞修复和重要漏洞修复。Oracle 强烈建议所有 Java SE 用户及时升级到最新的 CPU 版本。Java SE CPU 版本号采用奇数编号(即 7u71、7u65 — 有关 Java SE 版本编号方式的详细信息,请点击这里)。 Java SE 补丁集更新 (PSU) 包含相应 CPU 中的所有修复以及其他非重要修复。仅当您受到该版本中其他漏洞的影响时才应当使用 Java PSU。版本说明列出了 Java SE PSU 中的其他修复。 CPU 版本的发布周期会改变吗? 与以往一样,根据常规Oracle 重要补丁更新计划,Java SE CPU 版本将在距 1 月、4 月、7 月和 10 月的第 17 日最近的星期二发布。 从 2014 年 10 月发布 Java SE 7u71 (CPU) 和 Java SE 7u72 (PSU) 开始,Oracle 计划为每个 Java SE 7 CPU 额外发布一个相应的 PSU。除了相应 CPU 中的重要修复之外,PSU 版本将为组织和开发人员提供一些非重要修复。 一句话:我们应该使用奇数版本 官方链接:https://www.oracle.com/technetwork/cn/java/javase/cpu-psu-explained-2331472-zhs.html

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

Java技术专题-JVM研究系列(25)你真正掌握了Java对象创建的流程吗?

每日一句 拥有梦想只是一种智力,实现梦想才是真正的能力 前提概要 我们都知道类的装载过程中,分为 加载、链接(校验、准备、解析)、初始化(类的初始化),此处初始化主要是代表着类的初始化操作,之后会进入装载阶段之外的操作【类的实例化】 类初始化 类的创建的触发操作 在Java代码中,有很多行为可以引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象,这种方式在Java规范中被称为 :由执行类实例创建表达式而引起的对象创建。除此之外,我们还可以使用反射机制(Class类的newInstance方法、使用Constructor类的newInstance方法)、使用Clone方法、使用反序列化等方式创建对象。 使用new关键字创建对象 这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们可以调用任意的构造函数(无参的和有参的)去创建对象。比如: Student student = new Student(); 使用Class类的newInstance方法(反射机制) 我们也可以通过Java的反射机制使用Class类的newInstance方法来创建对象,事实上,这个newInstance方法调用无参的构造器创建对象,比如: Student student2 = (Student)Class.forName("Student类全限定名").newInstance(); Student stu = Student.class.newInstance(); 使用Constructor类的newInstance方法(反射机制) java.lang.relect.Constructor类里也有一个newInstance方法可以创建对象,该方法和Class类中的newInstance方法很像,但是相比之下,Constructor类的newInstance方法更加强大些,我们可以通过这个newInstance方法调用有参数的和私有的构造函数,比如: public class Student { private int id; public Student(Integer id) { this.id = id; } public static void main(String[] args) throws Exception { Constructor<Student> constructor = Student.class .getConstructor(Integer.class); Student stu3 = constructor.newInstance(123); } } 使用newInstance方法的这两种方式创建对象使用的就是Java的反射机制,事实上Class的newInstance方法内部调用的也是Constructor的newInstance方法。 使用Clone方法创建对象 无论何时我们调用一个对象的clone方法,JVM都会帮我们创建一个新的、一样的对象,特别需要说明的是,用clone方法创建对象的过程中并不会调用任何构造函数。简单而言,要想使用clone方法,我们就必须先实现Cloneable接口并实现其定义的clone方法,这也是原型模式的应用。比如: public class Student implements Cloneable{ private int id; public Student(Integer id) { this.id = id; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } public static void main(String[] args) throws Exception { Constructor<Student> constructor = Student.class .getConstructor(Integer.class); Student stu3 = constructor.newInstance(123); Student stu4 = (Student) stu3.clone(); } } 使用(反)序列化机制创建对象 当我们反序列化一个对象时,JVM会给我们创建一个单独的对象,在此过程中,JVM并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口,比如: public class Student implements Cloneable, Serializable { private int id; public Student(Integer id) { this.id = id; } @Override public String toString() { return "Student [id=" + id + "]"; } public static void main(String[] args) throws Exception { Constructor<Student> constructor = Student.class .getConstructor(Integer.class); Student stu3 = constructor.newInstance(123); // 写对象 ObjectOutputStream output = new ObjectOutputStream( new FileOutputStream("student.bin")); output.writeObject(stu3); output.close(); // 读对象 ObjectInputStream input = new ObjectInputStream(new FileInputStream( "student.bin")); Student stu5 = (Student) input.readObject(); System.out.println(stu5); } } 使用Unsafe类创建对象 Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的,官方文档也几乎没有。Oracle正在计划从Java 9中去掉Unsafe类,如果真是如此影响就太大了。 我们无法直接创建Unsafe对象。这里我们使用反射方法得到 private static Unsafe getUnsafe() { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); return unsafe; } catch (Exception e) { e.printStackTrace(); } return null; } 拿到这个对象后,调用其中的native方法allocateInstance 创建一个对象实例 Object event = unsafe.allocateInstance(Test.class); 从Java虚拟机层面看,除了使用new关键字创建对象(<init>(invokespecial))的方式外,其他方式全部都是通过转变为invokevirtual指令直接创建对象的。 类的初始化与实例化 概念介绍 Java对象的创建过程往往包括类初始化和类实例化两个阶段。类的初始化在前、类的实例化在后。 注意:这与spring的bean正好相反,spring的bean的生命周期,主要是先进行实例化java对象,然后在进行操作属性、最后进行初始化,这里初始化并不是java对象的初始化,而是spring的参数的初始化(initMethod、afterPropertiesSet)等。(@PostConstruct是前置拦截初始化方法)。 类的初始化 主要职责: 类的构造器调用(<clinit>),初始化相关静态代码块以及静态变量的赋值 对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的。在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。 注意:可以看到类的初始化主要到类构造器变量结束执行的时间点。 类的实例化 主要职责:实例的构造器调用(<init>)、分配内存、属性值得定制化赋值机制。 类的实例化本身意义就是对象的概念,其实就是实例化对应的对象的过程。 实例对象内存的分配、实例对象参数的默认初始化+实例对象参数的实例化(就是按开发要求的实现调用,例如调用构造器<init>等) 此时一般处于在装载阶段的初始化完成之后,使用之前的阶段,接下来就要进行类的实例化操作 类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化,首先会有一下几个步骤: java虚拟机就会为其分配内存来存放自己及其从父类继承过来的实例变量 为这些实例变量分配内存的同时,这些实例变量先会被赋予默认值(零值)【这个零值与加载阶段中的准备很相似,就是先赋值语义级别的默认值,而并非参数真正的初始化】 在内存分配完成之后调用<init>方法,Java虚拟机执行构造代码块、构造方法等,方法参数执行等。才会对新创建的对象赋予我们程序给定的值 小结:创建一个对象包含下面两个过程: 类构造器完成类初始化(赋予静态变量默认值) 类实例化(分配内存、赋予默认值、执行定制化赋值操作) 类实例化过程 检测类是否被加载 Java虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过**。如果没有,那必须先执行相应的类加载过程**。 为新生对象分配内存 在类加载并完成类初始化之后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载及初始化完成后便可完全确定。 确定对象内存大小 对象的大小在类加载完成后就已经确定,对象在内存中可以分为三块。 对象头 大小确定 与类无关 与操作系统有关,包括标记字段和类型指针 实例数据 即使父类的实例字段被子类覆盖或者被private修饰,都照样为其分配内存,相同宽度的字段会分配在一起,其次,父类的字段在子类之前赋值和初始化。 对齐填充 满足虚拟机对8的倍数的要求 对象分配内存的方式。 假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那么分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”。 如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”。 选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。 对象创建在虚拟机执行的过程中是非常频繁的行为,仅仅修改一个指针所指向的位置,在并发情况下不是线程安全的。因此也有两种解决方案: 使用CAS并配上失败重试的方式保证更新操作的原子性。 (TLAB)给每一个线程在Java堆中预先分配线程私有分配缓冲区,哪个线程需要分配内存,只要在线程私有分配缓冲区中分配即可以。 初始化零值 将分配到的内存空间初始化零值,这保证了实例字段不赋值可以直接使用。如果使用了TLAB,这一步可以提前到TLAB分配的时候进行。 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。 进行必要的对象头设置 虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中,主要负责的5个点。 对象是哪个类的实例; 如何找到类的元数据信息; 对象的哈希码; 对象的GC分代年龄信息; 锁的标识等; 执行完以上步骤,从虚拟机角度,一个对象已经产生了,但是对于java程序而言,构造函数还没有开始执行。接下来按照构造函数的要求,对对象进行初始化即可。 对象头主要包含两类信息。第一类是用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针。 类型数据部分是对象真正存储的有效信息,即程序代码中定义的各种类型的字段内容。 对齐填充:任何对象的大小都必须是8字节的整数倍。 对象的访问定位 使用句柄访问的话,Java堆中将可能会划分出来一块内存来作为句柄池。Reference变量中存放的是句柄池的地址,句柄池中存放有到对象实例数据的指针以及到对象类型数据的指针。 使用直接访问的话,reference变量中存放的是对象的实例数据、对象的实例数据中包含有到对象类型数据的指针。 执行init方法 在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从Java程序的视角来看,对象创建才刚开始,<init>方法还没有执行,所有的字段都还为零。所以一般来说,执行new指令之后会接着执行<init>方法,把对象按照程序的进行初始化,这样一个真正可用的对象才算完全产生出来。 总结创建一个对象的过程 检测类是否被加载没有加载的先加载→为新生对象分配内存→将分配到的内存空间都初始化为零值→**对对象进行必要的设置(对象头)**→执行<init>方法把对象进行初始化 扩展延伸 需要类初始化的五种情况(有且仅有这五种) 。 遇到new getstatic putstatic invokestatic这四个指令时,如果类没有初始化,则会触发类的初始化。 四个指令对应的最常见的情况为使用new关键字实例化对象,读取静态变量,设置静态变量(编译期结果放入常量池的除外,会触发前几个阶段) ,调用类的静态方法。 使用java.lang.reflect包的方法对类进行反射调用 初始化一个类时 如果父类未初始化 则初始化父类 常见的不会触发初始化的引用方式 通过子类引用父类的静态变量 只会初始化父类 不会初始化子类 创建类的数组 引用常量池内的变量 总体流程图 加载 通过名字获取类的二进制流并在内存中生成class对象。 验证 验证二进制流的正确性和安全性 包括文件格式验证,元数据验证,字节码验证以及符号引用验证四个步骤。 准备 给类变量(static)分配空间并完成初始化 注意:如果不是final变量,值均为零值。 解析 将符号引用解析为直接引用,包括类或接口的解析,字段解析,类方法解析,接口方法解析。 初始化 执行类的<cinit>()方法,这个方法由所有对静态变量的赋值操作和所有静态代码块组成,虚拟机会保证父类的<cinit>()方法在子类的方法开始之前结束,并且提供线程安全的保证(类似于double check,多个线程同时初始化时只有一个线程进入方法,其他线程阻塞,执行完成后其他线程不会再进入方法) 类加载器-双亲委派模型 Java推荐的类加载器的实现模型,除了启动类加载器(bootstrap classLoader)以外的所有类加载器都应该拥有父加载器,这个关系不是通过继承来实现,而是通过组合的方式。类加载器收到加载请求时,首先请求父加载器进行加载,如果父加载器不能加载则调用自己的加载方法。 遵从双亲委派模型:自定义类加载器时如果我们希望则重写findClass()方法。 不想遵循双亲委托型:方案即重写loadClass()方法 类加载器-分类 遵循双亲委派从上到下可以分为 启动类加载器 (Bootstrap classLoader) 加载<JAVA_HOME>\lib下的指定文件名的类 扩展类加载器 (Extension classLoader) 加载<JAVA_HOME>\lib\ext下的类 系统类加载器(应用类加载器) 加载Classpath内的类 自定义类加载器 不遵循双亲委派的常见类加载器: SPI (Service Provider Interface)加载器 - 线程上下文加载器 实现父加载器向子加载器请求加载 OSGi模块化加载器 每个模块拥有一个自定义类加载器 网状结构的加载过程 分配内存 内存分配与内存回收紧密相关,根据不同的回收策略也有不同的分配策略。 如果采用的是具有压缩过程的垃圾回收策略,如Serial,ParNew,则Java堆中的内存是规整的,我们只需要将内存指针向后移内存大小的位置即可,这种方式称为指针碰撞(Bump the Pointer)。如果采用的回收策略没有压缩过程,如CMS,那虚拟机就需要维护一个列表,记录哪些内存是可用的,这种方式称为空闲列表(Free List) 其次,对象创建也需要考虑线程安全的问题,一种方案是采用CAS+失败重试的方法来保证线程安全,另一种方法则是为每一个线程提前分配一块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer , TLAB),线程创建对象时优先在自己的TLAB上分配。 对象头 对象头包括 MarkWord 32bit/64bit 取决于操作系统 类型指针 指向类元数据的指针 数组长度 如果是数组的话 我们主要介绍MarkWord 根据锁状态的不同,markword会复用自己的空间,分别记录一些不同的信息。 我们注意到 轻量级锁和重量级锁状态时,会将分代年龄覆盖掉,那当锁状态解除时,要怎么恢复呢? 答案是上锁时,锁的数据中会保存一份原markword的备份

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

Python爬虫入门教程 25-100 知乎文章图片爬取器之一

1. 知乎文章图片爬取器之一写在前面 今天开始尝试爬取一下知乎,看一下这个网站都有什么好玩的内容可以爬取到,可能断断续续会写几篇文章,今天首先爬取最简单的,单一文章的所有回答,爬取这个没有什么难度。 找到我们要爬取的页面,我随便选了一个 https://www.zhihu.com/question/292393947 1084个回答,数据量可以说非常小了,就爬取它吧。 2. 知乎文章图片爬取器之一选取操作库和爬取地址 爬取使用requests 存储使用 mongodb 就可以了 爬取地址经过分析之后,找到了一个可以返回json的数据接口 提取链接,看一下各参数的意思,方便我们程序模拟 https://www.zhihu.com/api/v4/questions/292393947/answers?include=data%5B%2A%5D.is_

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

3月25日云栖精选夜读 | 2019阿里云峰会·北京 十年再出发

【点击订阅云栖夜读周刊】 十年做到3件事 在阿里云的推动下,云作为全新的技术在十年间发生了巨大的变化。过去十年,云在中国经历了飞跃性的变化,人们讨论的话题已从十年前的“为什么上云”演变为如今的“为什么不上云”。也就是在这十年,阿里云主要做了三件事: 战略加速的四级火箭 阿里云智能总裁张建锋首次系统性阐述了阿里云战略加速的四级火箭:“达摩院加持的云、数据智能的云、最佳实践的云和被集成的云”,从技术、产品、商业和生态层面开启阿里云的下一个十年。 热点热议 2019阿里云峰会·北京 | 十年再出发 作者:阿里云头条 阿里云人脸识别使用流程简介 作者:taro_秋刀鱼 Java技术周刊第1期:JAVA反射原理以及一些常见的应用 作者:李博bluemind 知识整理 mybatis 关联查询 作者:死瘦宅 网站程序有漏洞怎么修复和查找漏洞 作者:网站安全 Java深拷贝和浅拷贝 作者:潇湘剑雨 SAP权限对象的校验 作者:pandamonica Spring Cloud微服务之 sleuth+zipkin日志聚合 作者:游客jgf7utzni7bos 美文回顾 阿里工程师开发了一款免费工具,提升Kubernetes应用开发效率 作者:云效鼓励师 重磅发布:阿里 OpenJDK终于开源啦! 将长期支持版本 Dragonwell 作者:程序员小鱼发表在:终端研发部 大数据入门学习必读好书推荐,请收藏! 作者:小猪佩佩 如何阅读Java源码? 作者:孤独键客 从 0 开始手写一个 Mybatis 框架,三步搞定! 作者:孤独键客 前端面试:谈谈 JS 垃圾回收机制 作者:fundebug 用SpringCloud进行微服务架构演进 作者:james8888 有奖话题讨论 阿里云发布了GPU云产品vGN5i,和哪些行业密切相关? 阿里巴巴小程序繁星计划,你来做最闪亮的那颗星吗? 往期精彩回顾 3月22日云栖精选夜读 | “阿里巴巴小程序繁星计划”:20亿扶持200万小程序开发者和100万商家 3月21日云栖精选夜读 | 重磅发布:阿里开源 OpenJDK 长期支持版本 Alibaba Dragonwell 3月20日云栖精选夜读 | 阿里开源自用 OpenJDK 版本,Java 社区迎来中国力量 3月19日云栖精选夜读 | 单颗GPU计算能力太多、太贵?阿里云发布云上首个轻量级GPU实例 3月18日云栖精选夜读 | 开发者必看!探秘阿里云Hi购季开发者分会场:海量学习资源0元起! 【点击订阅云栖夜读周刊】

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

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

用户登录
用户注册