多个jvm实例_java类的实例

多个jvm实例_java类的实例一、概述我们知道,一个对象在可以被使用之前必须要被正确地实例化。而实例化实际指的就是以一个java类为模板创建对象/实例的过程。比如说常见的Person=newPerson()代码就是一个将

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、概述

我们知道,一个对象在可以被使用之前必须要被正确地实例化。而实例化实际指的就是以一个java类为模板创建对象/实例的过程。比如说常见的 Person = new Person()代码就是一个将Person类实例化并创建引用的过程。

对于类的实例化,我们关注两个问题:

  • 如何实例化?(类的四种实例化方式)
  • 什么时候实例化?(类的一个初始化过程和对象的三个初始化过程)

二、类的四种实例化方式

1.使用new关键字

这也是最常见最简单的创建对象的方法。通过这种方法,我们可以借助类的构造函数实例化对象。

Parent p = new Parent();

2.使用newInstance()方法

我们可以先通过类的全限定名获取类,然后通过Class类的newInstance()方法去调用类的无参构造方法创建一个对象:

Class p = Class.forName("com.huang.Parent");
Parent parent = (Parent) p.newInstance();

或者通过java.lang.relect.Constructor类里的newInstance()方法去构造对象,这个方法比起Class自带的更强大:

它可以调用类中有参构造方法私有构造方法创建对象!

//Parent私有的含参构造方法
public Parent(int a) {
    System.out.println("Parent创建了!");
}

//通过Constructor调用
Class p = Class.forName("com.huang.Parent");
Constructor<Parent> parentConstructor = p.getConstructor(int.class);
Parent parent = (Parent) p.newInstance();

3.使用clone()方法

当我们调用clone方法,JVM会帮我们创建一个新的、一样的对象,特别需要说明的是,用clone方法创建对象的过程中并不会调用任何构造函数。这里涉及到一个深拷贝和浅拷贝的知识点,我会另起一篇随笔介绍,这里就多费笔墨了。

Parent parent = new Parent();
Parent p2 = (Parent) parent.clone();

4.使用反序列化机制

当我们反序列化一个对象时,JVM会给我们创建一个单独的对象,在此过程中,JVM并不会调用任何构造函数。

Parent parent = new Parent();

// 写对象
ObjectOutputStream outputStream = new ObjectOutputStream(
    new FileOutputStream("parent.bin"));
outputStream.writeObject(parent);
outputStream.close();

// 读对象
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(
    "parent.bin"));
Parent parent2 = (Parent) inputStream.readObject();

三、类实例化的过程

我们以 Person p = new Person()这条语句为例,当这条语句执行的时候,jvm进行了四步操作:

  • 先执行new语句,以Person类为模板,在堆中创建Person对象
  • 为Person对象执行构造方法(如果有父类会先执行父类构造方法)
  • 创建Person类的引用变量p
  • 将引用变量p指向内存中Person对象

我们不难看出,其实实例化的过程其实就是第一和第二步,在这两步里,jvm其实也进行了四步操作:

  • Person的初始化
  • Person对象变量的初始化(如果有父类会先执行父类变量的初始化)
  • Person对象代码块的初始化
  • Person对象构造函数的初始化(如果有父类会先执行父类初始化)

1.类的初始化

对于第一次被实例化的对象,第一步是必定是类的初始化,所以静态变量和静态代码块中的代码必然被赋值和执行。

这点在我关于类加载机制的文章中已有解释,这里就不多费笔墨。

2.对象变量的初始化

我们在定义对象中的变量的同时,还可以直接对对象变量进行赋值。它们会在构造函数执行之前完成这些初始化操作

//父类
public class Parent{
    int i = 1;
    int j = i + 1;
    
    public Parent() {
        System.out.println("Parent的构造方法执行了!");
        j += 10;
    }
}

//子类
public class Child extends Parent {

    int k = 1;
    int l = k + 1;

    public Child() {
        System.out.println("i:"+i);
        System.out.println("j:"+j);
        System.out.println("k:"+k);
        System.out.println("l:"+l);
        System.out.println("Child的构造方法执行了!");
        k += 8;
        System.out.println("k:"+k);
        System.out.println("l:"+l);
    }
}

public static void main( String[] args ) {
    Child child = new Child();
}
//执行结果
Parent的构造方法执行了!
i:1
j:12
k:1
l:2
Child的构造方法执行了!
k:9
l:2

我们可以知道执行顺序是这样的:

  • 父类的变量初始化i = 1,j=2;
  • 执行父类的构造函数j = 2 + 10 = 12;
  • 子类的变量初始化k = 1,l = 2;
  • 执行子类构造函数k = 1 + 8 = 9

这里有人认为父类的变量初始化了,而且父类的构造函数也执行了,那父类是不是也一起实例化了?

答案是没有,我们可以认为实例化的时候子类从父类一起拷贝了一份变量,构造函数的执行也是为了能让父类的变量初始化,最后实例化放到内存里的其实是子类+父类的一个混合体!

3.代码块的初始化

我们一般指的代码块是构造代码块和静态代码块,静态代码块在类初始化时就执行,而构造代码块在类一创建就执行,也优先于构造方法

我们举个例子:

//父类
public class Parent{
    {
        System.out.println("Child的代码块被执行了!");
    }
    public Parent() {
        System.out.println("Parent创建了!");
    }
}

//子类
public class Child extends Parent {

    public Child() {
        System.out.println("Child创建了!");
    }

    static {
        System.out.println("Child的构造方法执行了!");
    }

    {
        System.out.println("Child的代码块被执行了!");
    }
}

//执行代码
public static void main( String[] args ) {
    Child child = new Child();
}

//打印结果
Parent的代码块被执行了!
Parent的构造方法执行了!
Child的代码块被执行了!
Child的构造方法执行了!

我们可以知道执行顺序是这样的:

  • 父类代码块
  • 父类的构造方法
  • 子类的代码块
  • 子类的构造方法

4.构造函数的初始化

我们可以从上文知道,实例变量初始化与实例代码块初始化总是发生在构造函数初始化之前,那么我们下面着重看看构造函数初始化过程。众所周知,每一个Java中的对象都至少会有一个构造函数,如果我们没有显式定义构造函数,那么它将会有一个默认无参的构造函数。在编译生成的字节码中,这些构造函数会被命名成<init>()方法。

事实上,Java强制要求Object对象之外的所有对象构造函数的第一条语句必须是父类构造函数的调用语句,如果没有就会默认生成讴歌构造函数。这就保证了不管要实例化的类继承了多少父类,我们最终都能让实例继承到所有从父类继承到的属性。

5.小结

结合以上文,我们可以看出类的实例化其实是一个递归的过程。

从子类不断向上递归,然后一直递归到直到抵达基类Object,然后一层一层的返回,先完成类的初始化:

  • 如果有类未初始化就先初始化(初始化静态块)

再回到Object类,往下一层一层的返回,完成对象的三个初始化:

  • 初始化变量
  • 初始化代码块
  • 初始化构造函数

类实例化的递归过程

所以最终我们可以总结出类初始化过程中类的各种代码块的执行顺序:

  • 父类静态块
  • 子类静态块
  • 父类代码块
  • 父类构造函数
  • 子类代码块
  • 子类构造函数

验证一下:

//父类
public class Parent{
    static {
        System.out.println("Parent的静态块执行了!");
    }

    public Parent() {
        System.out.println("Parent的构造方法执行了!");
    }

    {
        System.out.println("Parent的代码块被执行了!");
    }
}

//子类
public class Child extends Parent {
    static {
        System.out.println("Child的静态块执行了!");
    }

    public Child() {
        System.out.println("Child的构造方法执行了!");
    }

    {
        System.out.println("Child的代码块被执行了!");
    }
}

public static void main( String[] args ) {
    Child child = new Child();
    System.out.println();
}

//输出结果
Parent的静态块执行了!
Child的静态块执行了!
Parent的代码块被执行了!
Parent的构造方法执行了!
Child的代码块被执行了!
Child的构造方法执行了!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170793.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • php对接亿乐社区,亿乐社区对接教程

    php对接亿乐社区,亿乐社区对接教程###:-:**亿乐社区**###1、打开网站网站:[http://www.124sq.cn/](http://www.124sq.cn/)有账号的直接登录,没有账号的注册一个###2、选择商品ID在左侧目录栏选一个,这里选择的是`刷名片赞专区`,然后选择一个商品点开![](https://img.kancloud.cn/b3/9f/b39f76546ed13c86ab2153247bc…

  • Linux中修改文件权限方法「建议收藏」

    Linux中修改文件权限方法「建议收藏」​一、文件类型在Linux操作系统中,一切皆文件,Linux不以扩展名来区分文件类型,而是在文件属性中有一列专门记录文件类型。普通文件:.c.cpp.h.txt.pdf用’-‘表示目录文件(文件夹):用’d‘表示管道文件(用于进程间通信的一种文件):用’p’表示链接文件(相当于Windows上的快捷方式):用’l’表示设备文件:字符设备文件(c)块设备文件(b)套接字(s)用ls-l查看文件属性信息

  • 非常详细的sklearn介绍

    非常详细的sklearn介绍0引言Sklearn(全称Scikit-Learn)是基于Python语言的机器学习工具。它建立在NumPy,SciPy,Pandas和Matplot…

  • 课程设计—飞机订票系统

    课程设计—飞机订票系统1. 题目 本课程设计的题目为:飞机订票系统。2. 项目描述 基于目前人们外出远行频繁,为方便乘客提前买票及优化飞机航空订票服务,需要开发一个飞机订票系统,此程序就是要实现航班情况的录入,查询,订票,退票以及航班的查询和修改等基本功能。 3. 数据及其逻辑结构分析 (1)航班的信息:航班的情况存储结构采用单链表,每个元素表示一个航班的情况,包括航班号、起飞时间、降落时间、起

  • docker安装mysql后无法登录_docker启动不起来

    docker安装mysql后无法登录_docker启动不起来Differentlower_case_table_namessettingsforserver(‘1’)anddatadictionary(‘0’).

  • docker上传镜像到私有仓库_docker仓库的创建

    docker上传镜像到私有仓库_docker仓库的创建Docker私有仓库的搭建、配置,镜像上传至私有仓库案例演示。

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号