目录
一、编译和运行
二、JDK,JRE和JVM
三、Java中的基本类型
1. 基本类型的大小
四、JVM内存模型
1. 内存模型
五、JVM虚拟机的组成
1. 虚拟机的5个组成部分
2. 虚拟机栈
3. 栈帧
六、值传递和引用传递
七、变量的默认值
八、String的不可变
九. 包装类和常量池(-128 - 127)
包装类和原生类的比较
a. 使用==进行比较(包装类的拆箱)
b. 使用equals()进行比较(原生类的装箱)
十、格式化输出 和 获取随机数
十一 、阿里编程规范
1. 软编码
2. 卫语句
3. 命名法
十二、调试
1. debug
2. 启动bebug后要查看某个表达式的值
一、编译和运行
- 编译:即通过javac命令将.java代码文件 由Java编译器(javac.exe) 编译成 .class字节码文件。
- 运行:则是把编译生成的.class字节码文件交给Java虚拟机(JVM)执行。
字节码文件由 java虚拟机(JVM) 解释为当前平台能够运行的机器码文件。
所以不同操作系统需要安装不同的虚拟机。(Java最大的优势就在于跨平台。)
Java源码编译器(javac.exe) 通常是 Java开发工具包(JDK) 的一部分,它主要由 javac 命令行工具提供。
二、JDK,JRE和JVM
- JVM:即Java虚拟机,是虚拟出来的一台计算机,将字节码翻译成当前平台的机器码给平台执行;
- JRE:运行JAVA程序的最小环境,JRE等于JVM加Java的基础类库;(如果你只是想运行一个Java程序的机器码,而不需要编译Java代码,那么JRE就足够了。)
- JDK:开发JAVA程序的最小环境,JDK等于JRE加开发工具(编译javac.exe、运行java.exe等)。
JRE = 运行Java应用程序的JVM +库。
JDK = JRE +开发Java应用程序的工具(javac和java)。
总结:开发java程序的最小环境是JDK,运行Java程序的最小环境是JRE,JDK包含JRE,JRE包含JVM。
JVM:Java Virtual Machine - java虚拟机
JRE:Java Runtime Environment - java运行环境
JDK:Java Development Kit - java开发工具
三、Java中的基本类型
1. 基本类型的大小
这个大小是在jvm虚拟机中的大小,所以不管在哪个操作系统下,只要用的是同一个厂商的虚拟机,最后的大小都是一样的。
四、JVM内存模型
1. 内存模型
Java的内存结构主要有五个部分,包括:堆(Heap)、栈(Stack)、方法区(Method Area)、程序计数器(Program Counter Register)以及本地方法栈(Native Method Stack)。
2. jdk1.8后的内存模型
类及成员是蓝图存储在方法区,对象都存储在堆区。
- 方法区在java8以前是放在JVM内存中的,由永久代实现,受JVM内存大小参数的限制,在java8中移除了永久代的内容,方法区由元空间(Meta Space)实现,并直接放到了本地内存中,不受JVM参数的限制(当然,如果物理内存被占满了,方法区也会报OOM),并且将原来放在方法区的字符串常量池和静态变量都转移到了Java堆中。
五、JVM虚拟机的组成
1. 虚拟机的5个组成部分
2. 虚拟机栈
main方法在虚拟机栈中运行。所有方法运行时都会在虚拟机栈中生成一个栈帧。
3. 栈帧
每个栈帧中都有一个局部变量表。
栈帧中有四个东西:
六、值传递和引用传递
- 自定义类型和数组是引用类型,存储的是地址;基本类型的变量,存储的数值。
- 所以引用传递就是使用自定义类型或数组做形参,传的是地址。值传递就是用基本类型变量做形参,传的是数值。
以上只是为了方便记忆,以下是官方说法:
在Java中,所有的参数传递,无论是引用类型还是基本类型,都是通过值传递的。这里的“值”对于基本类型来说就是具体的数值,而对于引用类型来说就是对象引用的地址值。
七、变量的默认值
局部变量没有默认值,因为它在栈中;成员变量和引用类型变量有默认值,因为它们在堆中。
所以局部变量不初始化不能使用,引用类型变量可以。
基本的类型默认值都为0,其中boolean的0是指false,char的0是指ASCII中的0 。
八、String的不可变
修改字符串不会真的改变String对象,而是改变
引用变量
引用的字符对象,一旦尝试改变字符串(+),引用变量就会指向新的String对象。原理是:String类型的底层源码是一个用final修饰的char数组。
面试题】以下程序的输出
public class GoodAndGbc {String str = new String("good");char[] ch = { 'a', 'b', 'c' };public static void main(String[] args) {GoodAndGbc t = new GoodAndGbc();t.change(t.str, t.ch);System.out.print(t.str + " and ");System.out.println(t.ch);}public void change(String str, char ch[]) {str = "test ok";ch[0] = 'g';}}
// 输出:good and gbc
九. 包装类和常量池(-128 - 127)
a. 以下代码的结果是true还是false?
结果为true。
因为有常量池(-128~127)
b. 以下代码的结果是true还是false?
结果为false。
解释:
为什么第一张图的结果为true,第二张图的结果为false。
因为常量池的范围为-128 - 127,第一张图中的包装类赋值为10,在常量池的范围中,所以指向的就是常量池中的10,所以两个包装类指向的是同一个10,地址相同所以输出true。
第二张图中1234常量池中没有,所以要创建一个新对象,所以两个包装类指向不同的对象,故地址不相同所以输出true。
包装类和原生类的比较
a. 使用==进行比较(包装类的拆箱)
提示:包装类和原生类(基本类型)使用==进行比较时,包装类会转化为原生类。
以下代码的结果是true还是false?
结果为true。
以下代码的结果是true还是false?
结果还是true。
只要包装类和基本类型(无论是哪一种基本类型)进行“==”运算符的比较,包装类会先转化为原生类,再去和基本类型变量比较。这就叫包装类的自动拆箱。
b. 使用equals()进行比较(原生类的装箱)
以下代码的结果是true还是false?为什么?
结果为true。
以下代码的结果是true还是false?为什么?
结果为false。
首先要知道一点,如果equals()的参数是原生类,那么会先将原生类转为包装类,再和包装类进行比较。这叫原生类的装箱。
其次观察equals方法的源码:
通过源码可知,只要传入的不是Integer类型(instanceof关键字用于判断当前引用指向对象的真实类型)就不会比较,直接返回false。有了上面的基础请看下面这题:
以下代码的结果是true还是false?为什么?
同理,即使是两个包装类比较,但类型不同也还是false。
equals的底层代码里,优先判断类型,类型不同直接false
十、格式化输出 和 获取随机数
返回随机数的两种方法:
十一 、阿里编程规范
1. 软编码
将要重复打印的语句用变量保存起来,方便以后修改。
2. 卫语句
在函数的开始处检查一个或多个前置条件,如果这些条件不满足,则函数会提前退出,通常是通过返回或抛出异常的方式。这样的设计可以使函数的主要逻辑部分更加清晰和简洁,避免在函数的深处进行条件检查。
3. 命名法
十二、调试
1. debug
不打断点,debug启动后会直接运行到结尾。
2. 启动bebug后要查看某个表达式的值:
------------------------END-------------------------
才疏学浅,谬误难免,欢迎各位批评指正。