Java的三大分支
-
JavaSE
JavaSE(Java Platform,Standard Edition) :Java 平台标准版。它是 JavaEE 和 JavaME 的基础。
用来开发C/S 架构软件
JavaSE 包含 Java 语言基础、JDBC(Java 数据库连接性)操作、I/O(输出输出)操作、网络通信、多线程等技术它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础。
-
JavaEE
Java EE(Java Platform,Enterprise Edition):Java 平台企业版。
主要针对企业应用的开发,例如,电子商务网站、ERP 系统,也包括 Web 开发等方面。
Java EE 是在 JavaSE 的基础上构建的提供 Web 服务、组建模型、管理和通信 API(Application Programming Interface,应用程序接口),可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web 应用程序。
-
JavaME
Java ME(Java Platform,Micro Edition): Java 平台微型版。
它是一套运行专门为嵌入式设备设计的 API 接口规范。
Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。
Java ME 包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对可以动态下载的联网和离线应用程序的丰富支持。基于 Java ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。
总结:
①JavaSE:开发电脑上运行的软件(针对桌面程序的开发)
②JavaEE:开发网站(针对企业级应用的开发)
③JavaME:开发手机软件(APP,针对嵌入式设备软件的开发)
java编译方式
java 是面向对象的高级语言,高级语言的运行方式:
- 编程:java程序员写的.java源代码
- 编译:把.java文件转化成机器认识的格式
- 运行:让机器执行编译后的指令
java 的编译运行方式是混合型的,即根据 .java文件编译出一个 .class的二进制字节码文件 ,通过这个文件到JVM 中中进行翻译成二进制让机器处理。
-
java 不是直接运行在系统中的,而是运行在 jvm 虚拟机中的。
-
java 语言的跨平台是通过不同的 JVM 虚拟机实现的。

JDK和JRE

JRE 和 JDK 的区别是,JDK 是给开发人员使用的,里面包含了开发工具。JRE 是给用户使用的,里面包含了运行工具。
Java内存分配

其中在 JVM 虚拟机中

jvm 的内存分为五个部分:
这个只是在 JDK8 之前的 JVM 内存图
在 JDK8 开始:取消了方法区,增加了元空间,把原来的方法区的多种功能进行拆分,有的功能放在了堆空间中,有的放在了元空间
-
栈:方法运行时使用的内存,比如 main 方法运行,进入方法栈中执行
方法开始执行会进栈,执行完毕会出栈(栈是一种数据结构,具体去学数据结构)
-
堆:存储对象或数组,new 创建的东西都存在堆内存中
new 出来的东西都会在这个内存中开辟空间并且产生地址值
-
方法区:存储可以运行的 class 文件(jdk8 开始将方法区拆解了,新增元空间,并且元空间存储可以运行的 class 文件)
-
本地方法栈:JVM 在使用操作系统功能的时候使用
-
寄存器:给 CPU 使用
数组的内存图
举例:
public static void main(String[] args){
int[] arr=new int[2];
sout(arr);
sout(arr[0]);
sout(arr[1]);
arr[0]=11;
arr[1]=22;
sout(arr[0]);
sout(arr[1]);
int[] arr2={33,44,55};
sout(arr2);
sout(arr1[0]);
sout(arr2[1]);
sout(arr2[2]);
}
上述代码执行流程:
-
main 方法压入栈内存中
-
执行 int[] arr=new int[2];
具体执行:
在堆内存中创建数组空间并产生地址值
把这个地址值赋值给 arr

-
执行代码 sout(arr) 此时是打印出了 arr 的地址值
-
执行代码 sout(arr[0])通过 arr 找到数组在堆内存中的地址,通过 [0] 找到对应地址中对应的数据
-
sout(arr[1]) 同理
-
arr[0]=11; 如果 arr[0] 找到堆内存中开辟的空间中的对应数值存放地点,并且给他赋值 11
-
arr[1]=22 同理
-
执行代码 int[] arr2={33,44,55}; 虽然没有 new 但是实质还是在堆空间中创建内存
这俩个内存之间互不干扰
-
具体如下

注:如果是这种情况
public static void main(String[] args){
int[] arr=new int[2];
int[] arr2=arr;
//这个代表的是把arr的地址值赋值给arr2
//此时修改arr的内容同时arr2也会改变!因为arr2存储的只是地址值!!!
}
方法的内存图
方法调用的内存原理
public class Test{
public static void main(String[] args){
eat();
}
public static void eat(){
study();
sout("吃饭");
sleep();
}
public static void sleep(){
sout("睡觉");
}
public static void study(){
sout("学习");
}
}
方法被调用后就会进栈运行
当方法执行完毕后,方法会出栈,此时栈内开辟的变量也随着销毁
上面代码执行后如图

当所有方法进栈之后,就会开始执行了,执行完毕后会一个个出栈
对象内存图
-
一个对象的内存图
Student s=new Student();- 加载class文件
- 声明局部变量
- 在堆内存中开辟一个空间
- 默认初始化or显示初始化(如果在类中给变量赋值了就加载显示初始化,否则加载默认初始化)
- 构造方法初始化
- 将堆内存中的地址值赋值给左边的变量

当 main 方法也出栈的时候,此时没东西指向堆内存。故会自动销毁
类中的方法是先在方法区中加载,然后随着顺序执行的时候。
调用该方法才进栈
- 两个对象的内存图

和一个对象的内存图区别就是,方法区只需要加载一次!堆内存 new 几次开辟几次
- 两个引用指向同一个对象

this的内存原理
thi 作用:区分局部变量和成员变量
this 本质:所在方法调用者的地址值

字符串相关底层原理
-
字符串存储的内存原理
-
直接赋值会复用字符串常量池中的字符串
串池中有才会复用,没有则会在串池中新建对应的字符串
-
new 出来的不会复用,而是在堆内存中开辟一个新空间
-
-
== 号比较的到底是什么
-
基本数据类型比较的是数据值
-
引用数据类型比较的是地址值
一般用 equals 方法来比较而不是 ==
-
-
字符串拼接的底层原理
-
等号右边没有变量

-
等号右边有变量
-
在 jdk8 之前

-
在 jdk8 之后
jvm 会先预估字符串的长度,然后创建数组字符串,然后把数组变成字符串
综上!字符串不建议直接用 + 这样即使底层有优化但是还是很慢非常影响效率!一般用 StringBuilder 进行拼接
-
-
-
StringBuilder 源码分析
- 默认创建一个长度为16的字节数组
- 添加内容长度小于16直接保存
- 添加内容大于16扩容!(原容量*2+2)
- 如果还是不够就以实际为准
继承的内存图
例:
public class Fu{
String name;
int age;
}
public class Zi extends Fu{
String game;
}
public class Tesx{
public static void main(String[] args){
Zi z=new Zi();
sout(z);
z.name="张三";
z.age=23;
z.game="王者荣耀";
sout(z.game);
}
}
执行过程:
-
在方法区中加载 Test.clss 文件
-
在栈内存中加载 Main 方法入栈,开始执行 main 方法内部代码
-
Zi z=new Zi();在方法区中加载 Zi.clss 和 Fu.clss 文件在对内存中开辟空间并将地址值赋值给 z
注:因为 Fu 和 Zi 是继承关系,就会在这个开辟的空间中分割出俩个小空间,一半为父类的一半为子类的
-
输出 z 的地址值
-
z.name="张三"先在子类空间中找 name 这个成员变量,找不到了再去父类空间中查找并且赋值 -
z.age=23和z.game同理 -
输出
z.game的内容 -
main 方法执行完毕,出栈
-
对内存因为没有指针指向了,自动销毁
-
方法区自动销毁
图:

在继承体系中成员方法的继承原理:
在继承中,子类只能继承父类中的非私有成员方法
例:
假设一个继承结构:A 继承 B,B 继承 C
A a=new A();
a.C中方法();
java 会从最顶级父类开始:创建一个虚方法表!
虚方法表内存储的方法要求:非 private,非 static,非 final,这些方法统称虚方法
java 会把虚方法抽取并放入虚方法表中,并把虚方法表交给子类,子类的虚方法表就是在父类的虚方法表的继承上添加自己的虚方法
如图:

方法重写,如果重写的是虚方法那么子类的虚方法会覆盖从父类中获得的那个虚方法
BigInteger底层存储方式
- 对于计算机来说,没有数据类型的概念,都是01组成的
- 数据类型是编译语言自己定义的
下图是 BigInteger 的源码:

其中 signum 存储的是正负号
mag 数字存储的是数据,BigInteger 在存储数据的时候会将数据拆分为多段,然后每段都单独放入数组中
存储方式图:

把数据转化为二进制补码,以 32 位一组,转化位十进制,其中符号位单独存储
- BigInteger的存储上限
数组中最多存储元素个数:21 亿多
数组中每一位可以表示的数:42 亿多
BigInteger 能表示的最大数为:42 亿的 21 亿次方
BigDecimal底层存储方式

如图:将字符串拆解并转化为 ACII 表的数值存入 byte 数组中进行存储,符号当然也占一个位