前言
设定目标,收集资料,分析问题,归纳总结
参考资料:
- 官方文档:docs.oracle.com/en/java/ind…
- 对象内存图:m.w3cschool.cn/article/133…
- 关于java对象的理解:blog.csdn.net/f381226200/…
- 避免在循环体中创建对象:blog.csdn.net/weixin_3995…
- 怎么理解 Java 中类和对象的概念:www.zhihu.com/question/20…
- java对象大小如何计算:www.jianshu.com/p/f7fd14d67…
- java程序运行过程:www.cnblogs.com/mylpy/p/153…
- java类加载器有哪些:www.cnblogs.com/zhenhunfan2…
- 什么是双亲委派机制:zhuanlan.zhihu.com/p/367609494
- java类加载机制:baijiahao.baidu.com/s?id=167580… www.jianshu.com/p/b6547abd0…
- java对象创建过程:blog.csdn.net/justloveyou…
- java对象创建的几种方式:www.cnblogs.com/hellojava40…
- JVM运行时的数据区有哪些?有什么作用?blog.csdn.net/zzti_erlie/…
- java中内存溢出和内存泄漏是什么?www.php.cn/java/base/4…
- 常用jvm启动参数有哪些?blog.csdn.net/dajuezhao/a…
- jdk目录介绍:blog.csdn.net/u012965203/…
- jdk包含了哪些内容:www.php.cn/java-articl…
- Java内存模型是什么:blog.csdn.net/IT__learnin…
- 对象之间的关系:www.bilibili.com/video/BV1pq…
- 设计模式:www.runoob.com/design-patt…
确认目标
用自己的话,将上述资料中的内容以某种方式串联起来,谈谈对java对象的理解!
分析过程
语言的逻辑架构: java程序运行过程 -> 解析运行过程中的每个步骤 ->将每个步骤拆解
自我总结
java程序运行过程
- 将.java文件通过javac编译成.class文件
- 将.class字节码文件通过jvm解释器生产机器码
- 最后通过操作系统、硬件就可以运行(备注:至于最后一步,如何在硬件上执行,尚未关心) 既然开头需要一个.java文件,那么就会产生一个问题,如何创建一个.java文件呢?你可以通过记事本创建一个文件,修改后缀的方式,得到一个.java文件;得到之后,通过执行javac的命令,将.java文件转换成.class文件,然后通过java命令执行.java文件;但是很多程序语言都有相关的编辑器工具,可以利用工具来进行这一系列的操作;比如说IDEA或者其他产品工具也是可行的; 接下来就是需要得到这个工具,那么如何才能拿到呢?答案很简单,就是下载桌面应用即可,跟我们平时下载一个360杀毒软件工具一样,下载之后,安装即可;补充说明一点,还可以不用这个工具软件,可以在线编程的形式,也就是网页版,还可以是手机app也可以编写java程序,并运行代码;那么会出产生一个疑问?手机上app的应用或者网页版难道集成了运行java程序所需要的环境,那么他们是如何集成的呢,也需要下载安装jdk吗?
比如IDEA在创建一个java工程时,需要制定jdk的路径,那么jdk又是什么呢? 还是刚刚java程序运行过程,需要执行命令才能进行编译执行,那么jdk其实就是java的开发工具包,里面就包含这些命令;还有一些内容;当安装之后,设置好环境变量,为什么要设置这个环境变量?为了在任何位置执行命令都是可以的正常找到指定目录下的命令,不用全路径;
下载并安装jdk之后呢,查看jdk的目录层级
- bin:该目录下主要存放 JDK 的各种工具命令。
- conf:该目录下主要存放 JDK 的相关配置文件。
- include:该目录下主要存放了一些平台的头文件。
- jmods:该目录下主要存放了 JDK 的各种模块。
- legal:该目录下主要存放了 JDK 各模块的授权文档。
- lib:该目录下主要存放了 JDK 工具的一些补充 jar 包和源代码。 具体详情参考上述jdk目录介绍链接blog.csdn.net/u012965203/…
那么jdk包含了哪些内容呢?其实jdk是一个开发工具包,开发者利用jdk是可以编写代码并允许代码,如果您不是开发,只是想运行java程序,那么只需要jre即可。但是根据程序运行原理,实际执行的是jvm,怎么就编程了jre呢,实际上jre包含了jvm并包含jvm工作所用的lib库;
当你有了这样的可以开发和运行的环境之后,就可以编写java程序了;当编写java程序之后,遵循java语法规则;最后运行我们java代码,就可以了;那么执行java的代码的时候,需要通过类加载器处理.class文件生成Class类型的实例,用于创建对象使用,那么java的类加载器又是什么呢?假如你编写了如下代码:
public class Test {
static class A {
public void test() {
System.out.println("abc");
}
public void test2() {
System.out.println("sodu");
}
}
static class B extends A {
public void test() {
System.out.println("edc");
}
public void test2(){
}
}
public static void main(String[] args) {
A a = new B();
a.test();
a.test2();
}
}
当运行第一段代码new的时候,其实我们的目的就是需要创建对象,那么在jvm中是如何创建对象的呢,就是通过类加载器先得到Class对象,然后交给jvm通过这个class对象来创建对象;那么这里的类加载器有3种:
- 引导类加载器(Bootstrap ClassLoader)
- 拓展类加载器(Extension ClassLoader)
- 应用类加载器(Application ClassLoader)
jvm指定类加载器,而加载的时候时先委托给父类加载,如果父类加载不了,再用自己加载,其过程如下图所示,这就是双亲委派机制,而双亲委派机制的优缺点自行了解一下,并不是重点:
终于有了Class对象了,那么如何创建对象、使用对象,最后如何对象消亡的?整个过程取了一个名字:类加载机制 类加载的机制分为几个步骤:加载,验证,准备,解析,初始化,使用,卸载;其中验证,准备,解析三个步骤统一称之为连接;在这个几个步骤当中,到底做了哪些事情呢?一个一个的来:
- 加载:就是得到Class对象,class对象存放在堆中
- 验证:验证class文件是否满足jvm要求,至于什么要求,参考具体链接即可;
- 准备:类变量分配内存并设置默认值的阶段。这里的类变量指的是被static修饰的变量,而不包括实例变量而类变量被分配到方法区中。
- 解析:解析阶段是将常量池中的符号引用转换为直接引用的过程;至于什么是符号引用和直接引用,参考连接说明即可
- 初始化:这是类加载的最后一步,到这才真正开始执行Java代码。初始化阶段是为类的静态变量赋值,执行类构造器 < clinit > 方法的过程,需要考虑静态代码块,代码块,最后才是执行实例构造器方法;而执行实例构造器优先考虑父类的构造器,和父类的静态代码块,实例代码块;总而言之,执行顺序:
- 父类静态代码块
- 子类静态代码块
- 父类实例代码块
- 父类构造器
- 子类实例代码块
- 子类构造器
当这些值都赋予对象之后,那么这些数据在jvm分布在哪些内存区域呢?那么就需要了解一下jvm运行时的数据区域:
- 方法区
- 堆
- 程序计数器
- 本地方法栈
- 虚拟机栈 重点说一下几个概念:
- 虚拟机栈:存储当前线程运行方法所需要的数据,指令,返回地址,存储局部变量。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程(对于理解递归算法又一定的实际意义)
- 本地方法栈(Native Method Stack)与虚拟机栈锁发挥的作用是非常相似的,他们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。
- 最重要的部分就是:方法区和堆是所有线程共享的数据区。程序计数器,虚拟机栈,本地方法栈是线程隔离的数据区,如下图所示:
- 堆:此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存,成员变量在堆内存中
- 方法区:它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
通过上面方法区和堆是所有线程共享的数据区,而这些数据区包含的遍历又常量,静态变量,而局部变量在栈中,都各自隔离,而成员变量在堆中被线程共享;那么是不是可以联系想一下Java的内存模型呢?参考上述连接;
在这里贴图,不作具体说明,线程章节会具体说明;
当了解对象的创建过程之后,于是就可以创建对象来玩一玩了。而创建对象有几种方式呢?上述链接已经准备答案了。但是如果一些对象构造比较复杂,比如创建肯德基套餐对象,套餐包含有很多,饮料,薯条等,我们又当如何去构建了?答案很简单,其实生活中不管多么复杂的东西,通常都是简单的东西组合而成,程序也是如此。在构造复杂对象时,必须了解对象之间的关系。那么对象之间存在什么关系呢?继承,依赖(关键字用),关联(关键字有);可以参考上述链接学习下对象之间的关系,最终会在构造对象的道路上又踏进了一步。其实构造对象也是存在一定技巧,类似于我们写作文一样,往往都是存在一定的技巧。那么构造对象又有什么技巧了?不得不引入一个概念:设计模式,通常设计模式中提供了常用的创建对象的方式,比如创建复杂的对象,工厂模式,抽象工厂模式;只保留一个对象-单例模式;初始化不同属性的自身对象,建造者模式;关于这些设计模式,网上一搜一大把,你也可以参考上述链接进行学习;经过了解之后,你已经知道了一些构建对象的技巧以及对象创建;
当知道如何构建对象之后,那么可以探索一下对象内部的东西了。比如对象属性,属性字段(比如字符串,数组,集合),而实际上这些都是数据,如此多的数据,那么肯定会进行分类,于是就有了数据类型,不同的数据,有着不一样的数据类型并且还具有不同的结构;对于我们处理现实中的问题有一定的帮助;在数学建模的时候,通常都会将现实的问题抽象成数学模型,而这恰恰需要一些数据结构来对应生活中的元素,比如班级的人数,上体育课人数排队,列方阵等;所以接下来查看下一篇文章:一起来认识Java中的数据