对象实例化【JVM】

news2024/12/23 13:37:48

JVM对象实例化

    • 简介/背景
    • 一、创建对象的方式
        • 1. new
        • 2. Class对象的newInstance方法
        • 3. Construstor对象的newInstance(xx)方法
        • 4. 使用clone方法
    • 二、创建对象的步骤
        • 1. 判断对象是否已经加载、链接、初始化
        • 2. 为对象分配内存
        • 3. 处理并发安全问题
        • 4. 初始化分配到的空间
        • 5. 设置对象的对象头
        • 6. 执行init方法进行初始化
    • 总结

简介/背景

本篇文章为博主学习JVM教程时,记录的笔记,主要介绍了一下Java对象创建的几种方式和创建对象的步骤。

在这里插入图片描述
tips: 思维导图

一、创建对象的方式

创建对象课程中提到了六种方式,这里针对前面四种方式进行举例介绍。

1. new

在java中使用new关键字进行创建对象,有以下三种形式。

形式一
使用最普通的new的形式,举例如下:

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
    }
}

形式二
通过静态方法创建对象

public class Test {
    public static void main(String[] args) {
        Student student = Student.newInstance();
    }
}

class Student {
    public Integer id;

    public static Student newInstance() {
        return new Student();
    }

    public Integer getId() {
        return id;
    }

    public Student setId(Integer id) {
        this.id = id;
        return this;
    }
}

形式三
通过build()方法构建对象

public class Test {
    public static void main(String[] args) {
        Student student = new Student.Builder().build();
    }
}
class Student {
    static class Builder {
        public Student build() {
            return new Student();
        }
    }
}

2. Class对象的newInstance方法

通过获取类的Class对象,来创建对象实例。

public class Test {
    public static void main(String[] args) {
        try {
            Student student = Student.class.newInstance();           
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
class Student {
}

3. Construstor对象的newInstance(xx)方法

因为Class对象的newInstance方法只能使用默认的构造方法产生对象,所以java已经不建议使用了,建议用Contrustor对象的newInstance方法,有参或者无参的构造方法都可以使用。

public class Test {
    public static void main(String[] args) {
        try {
            Constructor<Student> constructor = Student.class.getConstructor(Integer.class);
            Student student = constructor.newInstance(123);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
class Student {
    public Integer id;
    public Student(Integer id) {
        this.id = id;
    }
}

4. 使用clone方法

通过实现Cloneable接口,重写clone方法来产生类。

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        Student newStudent = student.clone();
    }
}
class Student implements Cloneable {
    public Student() {}
    @Override
    public Student clone() {
        try {
            Student clone = (Student) super.clone();
            // TODO: copy mutable state here,
            //       so the clone can't change the internals of the original
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

二、创建对象的步骤

1. 判断对象是否已经加载、链接、初始化

JVM的类加载机制,是按需加载的方式。就是我们需要使用该类的时候,才会将生成的class文件加载到内存当中生成class对象。
如果要创建一个对象,首先要判断相应的class文件是否已经生成了class对象,如果虚拟机还没有生成Class对象,类加载子系统就会去加载。

2. 为对象分配内存

首先计算对象占用空间的大小,接着在堆中划分一块内存给到新对象,如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小。这里分为两种情况,如果内存是规整的,采用的是指针碰撞的方法。如果内存不是规整的采用的空闲列表分配的方法。

指针碰撞法

如果内存是规整的,那么虚拟机将采用指针碰撞法(Bumo The Pointer)来为对象分配内存。
意思是所有用过的内存在一边,空闲的内存在另一边,中间放着一个指针作为分界点的指示器,分配内存就仅仅是把指针向空闲那边挪动一段与对象大小相等的距离罢了。如果垃圾收集器选择的是Serial、ParNew这种基于压缩算法的,虚拟机采用这种分配方式。一般使用带有Compact(整理)过程的收集器时,使用指针碰撞。

空闲列表法

应用场合:堆内存不规整(虚拟机维护一个可以记录内存块是否可以用的列表来了解内存分配情况)。
即在开辟内存空间时候,找到一块足够大的内存块分配给该对象即可,同时更新记录列表。
将堆内存这样划分的代表的GC收集器算法有:CMS

3. 处理并发安全问题

这一步,有的文章会合并在上一步里来说,这里把它拆出来说明一下。
如果是在多线程的情况下,分配内存就会存在并发安全的问题,那么JVM是如何处理的呢?

多线程分配内存时,虚拟机为每个线程分配了不同的空间,这样每个线程在分配内存时只是在自己的空间中操作,从而避免了上述问题,不需要同步。当然,当线程自己的空间用完了才需要需申请空间,这时候需要进行同步锁定。为每个线程分配的空间称为“本地线程分配缓冲(TLAB)”,是否启用TLAB需要通过 -XX:+/-UseTLAB参数来设定。

4. 初始化分配到的空间

虚拟机需要将分配到的内存空间都进行初始化(即给一些默认值),这将做是为了保证对象实例的字段在Java代码中可以在不赋初值的情况下使用。程序可以访问到这些字段对用数据类型的默认值。

5. 设置对象的对象头

虚拟机对对象进行一些简单设置,如标记该对象是哪个类的实例,这个对象的hash码,该对象所处的年龄段等等(这些可以理解为对象实例的基本信息)。这些信息被写在对象头中。jvm根据当前的运行状态,会给出不同的设置方式。

6. 执行init方法进行初始化

最后执行由开发人员编写的对象的初始化方法,把对象按照开发人员的设计进行初始化,一个对象便创建出来了。

总结

本篇文章大概介绍了JVM创建对象的几种方式,以及创建对象的步骤主要有:
1. 判断对象是否已经加载、链接、初始化
2. 为对象分配内存
3. 处理并发安全问题
4. 初始化分配到的内存空间
5. 设置对象头
6. 执行init方法进行初始化。


❤️ 博主笔力尚浅,文中有疏漏之处还请流言指正,不胜感激。❤️ 谢谢大家。❤️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/386593.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tech Lead如何引导团队成员解决问题?

作为一个开发团队的Tech Lead&#xff0c;当团队成员向你寻求帮助时&#xff0c;你有没有说过下面这些话&#xff1f; 你别管了&#xff0c;我来解决这个问题你只要。。。就行了你先做其他的吧&#xff0c;我研究一下&#xff0c;然后告诉你怎么做 当我们说这些话时&#xff…

腾讯免费企业邮箱迁移记录

本文记录在重新申请腾讯企业邮箱的过程。 背景 很多年前&#xff0c;将域名latelee.org 迁移到了阿里云&#xff0c;当时因政策原因无法实名&#xff0c;但能使用。去年3月&#xff0c;阿里云提示无法续费&#xff0c;紧急将其转到外面某服务&#xff0c;继续使用&#xff0c;…

IP地址的工作原理

如果您想了解特定设备为何未按预期方式进行连接&#xff0c;或者想要排查网络无法正常工作的可能原因&#xff0c;它可以帮助您了解 IP 地址的工作原理。互联网协议的工作原理与任何其他语言相同&#xff0c;即使用设定的准则进行通信以传递信息。所有设备都使用此协议与其他连…

jq获取同级或者下级的dom节点的操作

1.使用find找到对应的class或者其他 var class_dom1 obj.find(.class名称);或者 find(span .class名称)2.使用添加背景颜色来确定当前的查找位置 class_dom1.css(background,red);3.通过parent来找到它的上级的dom节点 var parent_li_dom1 class_dom1.parent(li.parent_li…

进阶指针——(2)

本次讲解重点&#xff1a; 6. 函数指针数组 7. 指向函数指针数组的指针 8. 回调函数 在前面我们已经讲解了进阶指针的一部分&#xff0c;我们回顾一下在进阶指针(1)我们学过的难点知识点&#xff1a; int my_strlen(const char* str) {return 0; }int main() {//指针数…

创宇盾重保经验分享,看政府、央企如何防护?

三月重保已经迫近&#xff0c;留给我们的准备时间越来越少&#xff0c;综合近两年三月重保经验及数据总结&#xff0c;知道创宇用实际案例的防护效果说话&#xff0c;深入解析为何创宇盾可以在历次重保中保持“零事故”成绩&#xff0c;受到众多部委、政府、央企/国企客户的青睐…

HACKTHEBOX——Irked

nmapnmap -sV -sC -Pn -T4 -oA nmap 10.10.10.117可能是因为网络原因&#xff0c;与目标链接并不稳定&#xff0c;因此添加了参数-Pn&#xff0c;也只扫描了常见的端口扫描可以看到只开启了3个端口&#xff0c;22,80和111。但是在访问web时&#xff0c;页面提示运行着irc因此再…

WebRTC新增FFmpeg视频编解码模块

1、整体描述目前webrtc内置的视频编解码器包括&#xff1a;VP8、VP9、AV1和H264。一般情况下载pc端基本可以满足大部分的需求&#xff0c;但是有时候为了进行编解码器的扩展包括支持H265或者是支持硬件编解码以提升效率时需要新增编解码模块。2、新增外部编码器编码器实现的要点…

亿万级海量数据去重软方法

文章目录原理案例一需求&#xff1a;方法案例二需求&#xff1a;方法&#xff1a;参考原理 在大数据分布式计算框架生态下&#xff0c;提升计算效率的方法是尽可能的把计算分布式话、并行化&#xff0c;避免单节点计算过载&#xff0c;把计算分摊到各个节点。这样解释小白能够…

最新|移动机器人导航定位技术概述

前言目前工业界广泛落地使用的移动机器人&#xff0c;除了应用场景在餐厅、酒店、超市等小范围室内送餐机器人和消毒机器人外&#xff0c;另外一个“大赛道”应用场景就是在工厂、制造装配车间、电站或车站的物流搬运机器人和巡检机器人了。而在最开始&#xff0c;一切都得从AG…

spring cloud gateway (五)

Gateway简介 Spring Cloud Gateway是Spring公司基于Spring 5.0&#xff0c;Spring Boot 2.0 和 Project Reactor 等技术开发的网关&#xff0c;它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代Netflix Zuul&#xff0c;其不仅提供统一的路由方式…

java 字典

java 字典 数据结构总览 Map Map 描述的是一种映射关系&#xff0c;一个 key 对应一个 value&#xff0c;可以添加&#xff0c;删除&#xff0c;修改和获取 key/value&#xff0c;util 提供了多种 Map HashMap: hash 表实现的 map&#xff0c;插入删除查找性能都是 O(1)&…

MySQL跨服务器数据映射

MySQL跨服务器数据映射环境准备1. 首先是要查看数据库的federated引擎 开启/关闭 状态2. 打开任务管理器&#xff0c;并重启mysql服务3. 再次查看FEDERATED引擎状态&#xff0c;引擎已启动映射实现问题总结在日常的开发中经常进行跨数据库进行查询数据。 同服务器下跨数据库进…

【SpringCloud】SpringCloud详解之Feign实战

目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.使用Feign远程调用(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽…

STM32之 串口

串口通信串行接口简称串口&#xff0c;也称串行通信接口或串行通讯接口&#xff08;通常指COM接口&#xff09;&#xff0c;是采用串行通信方 式的扩展接口。串行接口&#xff08;Serial Interface&#xff09;是指数据一位一位地顺序传送。其特点是通信线路简 单&#xff0c;只…

Vue基础入门讲义(三)-指令

文章目录1.什么是指令&#xff1f;2.插值表达式2.1.花括号2.2.插值闪烁2.3.v-text和v-html3.v-model4.v-on4.1.基本用法4.2.事件修饰5.v-for5.1.遍历数组5.2.数组角标5.3.遍历对象6.key7.v-if和v-show7.1.基本使用7.2.与v-for结合7.3.v-else7.4.v-show8.v-bind8.1. 属性上使用v…

服务器处理发生异常:java.text.ParseException: Unparseable date

测试上传报文的时候遇见报错 服务器处理发生异常:java.text.ParseException: Unparseable date: “2023/03/03” 错误报文 实际需要的报文 错误原因 上传时间字段&#xff0c;与Date字段数据位数不匹配&#xff0c;Java类型&#xff1a;Date默认带有年月日 时分秒yyyy-mm-dd…

十年业务开发总结,如何做好高效高质量的价值交付

作者&#xff1a;杨博林 阿里大淘宝场景金融团队 软件交付是一个非常复杂的过程和体系&#xff0c;需要保障好每个阶段的质量和效率才能保障最终的质量和效率。本文将尝试从需求交付的前、中、后三个环节来阐述一下如何做高效高质量的价值交付。 一、背景 转眼间已经做了十年的…

JavaScript基础内容

日升时奋斗&#xff0c;日落时自省 目录 1、基础语法 2、DOM 2.1、选中页面元素 2.2、获取/修改元素内容 3、JS案例 3.1、网页版本猜数字 3.2、网页版表白墙 JS最初只是为了进行前端页面的开发后来JS也被赋予了更多的功能&#xff0c;可以用来开发桌面程序&#xff0c;手…

RHCSA-重置root密码(3.3)

方法1&#xff1a;rd.break &#xff08;1&#xff09;首先重启系统&#xff0c;在此页面按e键&#xff0c;在屏幕上显示内核启动参数 &#xff08;2&#xff09;知道linux这行&#xff0c;末尾空格后输入rd.break&#xff0c;然后按ctrlx &#xff08;3&#xff09;查看&#…