这个问题要从java代码的两个步骤来回答:编译和运行。
JVM也是java代码可以跨平台运行的关键。(跨平台的是程序,不是JVM,不同的平台有对应不同的JVM)
三者是一个子集包含的关系。
全称:Java Development ToolKit,即Java 开发工具包,是整个Java的核心。
以 JDK 8 的安装目录为例,来认知了解JDK:
主要包含六个文件夹及一些相关配置文件。
6个文件夹各自的作用如下:
目录名 | 作用 |
---|---|
bin | 存储开发工具的.exe可执行文件 |
demo | 一些演示的例子 |
include | 存放c语言的头文件,一些java程序需要用到这些头文件 |
jre | java程序运行环境的根目录 |
lib | 存放jre文件夹中包含的类库外的其他一些类库 |
sample | 一些示例程序 |
**JDK 是整个 Java 的核心:**包括 JRE(Java 运行环境,Java Runtime Envirnment)、Java 工具(可执行程序,比如 javac、java、javap 等等),以及 Java 基础类库(比如 rt.jar)
全称:Java Runtime Environment,即Java运行环境,主要包含JVM的标准实现及Java的核心类库。
JRE只是java的运行环境,不包含任何的开发工具(比如编译器和调试器)
全称:Java Virtual Machine,即Java虚拟机。
它是一个在计算机上运行Java字节码的虚拟机。JVM充当了Java应用程序和底层操作系统之间的中间层,提供了跨平台的特性,使得Java程序可以在不同的操作系统和硬件上运行。
结构关系:
**Project:**项目、工程(苍穹外卖)
解释:
// 单行注释
/*
多行
注释
*/
/**
文档注释
*/
int a = 10; //a为变量,10为字面量
final int b = 10; //b为常量,10为字面量
static str = "Hello World"; //str为变量,Hello World为字面量
字面量:由字母、数字等构成的字符串或者数值,只能在等号右边出现
变量:定义的在特定范围内变化的符号。必须被初始化,可以不被赋初始值
常量:被final修饰的变量。必须赋初值,且其类型和值不能再改变(即不可再被赋值或强转数据类型)
合理的Java命名,需要满足以下要求:
名字只能由数字、字母、下划线、$符号组成
不能以数字开头
名称不能跟Java中的关键字一样
业界约定的一些命名规范:
小驼峰命名,常给变量、方法命名:name、firstName
大驼峰命名,常给类命名:Student、GoodStudent
关键字 | 数据类型 | 内存占用大小(字节) | 补充 |
---|---|---|---|
byte | 整数 | 1 | |
short | 整数 | 2 | |
int | 整数 | 4 | 默认的整数类型 |
long | 整数 | 8 | |
float | 浮点数 | 4 | |
double | 浮点数 | 8 | 浮点数默认类型 |
char | 字符 | 2 | 在程序中用单引号表示(String,字符串,引用数据类型,在程序中是双引号表示) |
boolean | 布尔 | 1 |
简单来说:非基本数据类型的都是引用数据类型
常见的有:类、接口、数组、String字符串、枚举类型、注解类型
两个基本概念:
运算符:对字面量或者变量进行操作的符号
表达式:用运算符把字面量或者变量连接起来符合java语法的式子就可以称为表达式
示例:
int a = 10;
int b = 20;
int c = a + b;
/*
+:是运算符,并且是算术运算符
a + b:是表达式,由于+是算术运算符,所以这个表达式叫算术表达式
*/
符号 | 意义 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余 |
示例:
public class Test {
public static void main(String[] args) {
// 同类别算数运算符,从左到右依次参与运算
System.out.println(1 + 23); // 24
System.out.println("年龄为:" + 23); // 年龄为:23
System.out.println(1 + 99 + "年黑马"); // 100年黑马
System.out.println("练习时长" + 1 + 1.5 + '年'); // 练习时长11.5年(当碰到字符串后,+就变成了字符串连接符,而不是算数运算符)
System.out.println("练习时长" + (1 + 1.5) + '年'); // 练习时长2.5年
}
}
public class Test {
public static void main(String[] args) {
// 单独使用
int a = 10;
a++ // a=11
++a // a=12
// 组合使用
int b;
b = ++a; // a=13, b=13
a++; // a=14
b = a++; // a=15,b=14
}
}
// --运算符计算逻辑同理
隐形转换
【基本隐式转换】取值范围小的数值或者变量,赋值给取值范围大的变量
public class Test {
public static void main(String[] args) {
int a = 10;
double b = a; // b=10.0
}
}
【运算隐式转换-1】取值范围小的数据和取值范围大的数据进行运算,小的提升为大的,再运算
public class Test {
public static void main(String[] args) {
int a = 10;
double b = 12.3;
double c = a + b;
}
}
【运算隐式转换-2】byte、short、char,三者运算时,会先提升为int,再进行运算
public class Test {
public static void main(String[] args) {
int a = 1;
char b = 'a';
int c = a + b;
System.out.println(c); // c=98
}
}
强制转换
1、把一个取值范围大的数值或者变量,赋值给另一个取值范围小的变量,不允许直接赋值,需要强制转换
public class Test {
public static void main(String[] args) {
double b = 12.3;
int a = (int) b; // a=12
}
}
符号 | 意义 |
---|---|
= | 赋值 |
+= | 相加后赋值 |
-= | 相减后赋值 |
*= | 相乘后赋值 |
/= | 相除后赋值 |
%= | 相取余后赋值 |
赋值运算符中,隐含着强制类型转换
符号 | 补充 |
---|---|
== | (可以比较任意基本数据类型)对于基本数据类型,比较的是数值是否一致;对于引用数据类型,比较的是地址值是否一致 |
!= | 比较除了boolean类型外的任意基本数据类型 |
> | 比较除了boolean类型外的任意基本数据类型 |
>= | 比较除了boolean类型外的任意基本数据类型 |
< | 比较除了boolean类型外的任意基本数据类型 |
<= | 比较除了boolean类型外的任意基本数据类型 |
关系运算符处理的结果都是boolean数据类型,结果是true或false
【基本数据类型-字符】的比较
ASCLL码表用来表示:程序中字节到字符之间的映射关系
因此,Java中字符的比较,本质是转为字符对应的字节值大小进行比较
符号 | 意义 | 补充 |
---|---|---|
& | 有false就是false,会进行完整的运算 | |
&& | 有false就是false,且不进行后续关系运算的计算 | 常用 |
| | 有true就是true,会进行完整的运算 | |
|| | 有true就是true,且不进行后续关系运算的计算 | 常用 |
! | true即false,false即true | 常用 |
^ | 异或运算符:相同为false,不同为true |
public class test {
public static void main(String[] args) {
int a = 2;
int v = a == 1 ? 1 : 10;
System.out.println(v); // v=10
}
}
java中一段具有独立功能的代码块,不调用就不执行
称为:function
权限修饰符 返回值类型 方法名(参数1, 参数2, ...){
方法内容
}
public static void method(){} // 无返回值,用void
public static int method(){} // 有返回值,给定具体的返回值类型
内存区域 | 用途 |
---|---|
方法区 | 存储被加载的类信息、常量、静态变量、编译器编译后的代码(.class字节码文件);方法在没有调用时候,就在这里存放。被调用时,进栈执行 |
栈内存 | 存放基本数据类型的数据、引用数据类型的变量名及引用(引用的地址值在这里,引用的数据和对象的内容不在这里,在堆内存中) |
堆内存 | 存放引用数据类型的数据、new的新对象也在这里(只包含其成员变量,成员方法不放在这里) |
示例代码
public class MethodDemo1 {
public static void main(String[] args) {
System.out.println("开始");
getMax();
System.out.println("结束");
}
public static void getMax() {
int num1 = 10;
int num2 = 20;
int max = num1 > num2 ? num1 : num2;
System.out.println(max);
}
}
1、在程序执行前:将待加载的类信息、待执行的方法加载到方法区。此时栈内存是空的
# 方法区
MethodDemo1.class
main
getMax
# 栈内存
2、程序开始执行:首先是main方法入栈
# 方法区
MethodDemo1.class
main
getMax
# 栈内存
main
- System.out.println("开始");
3、执行到另一个方法:getMax,方法入栈,此时main方法还没有执行完毕,不出栈
# 方法区
MethodDemo1.class
main
getMax
# 栈内存
getMax
- int num1 = 10;
- int num2 = 20;
- int max = num1 > num2 ? num1 : num2;
- System.out.println(max);
main
- System.out.println("开始");
- getMax();
4、getMax方法执行完毕,出栈,程序继续执行(main方法后续内容)
# 方法区
MethodDemo1.class
main
getMax
# 栈内存
main
- System.out.println("开始");
- getMax();
- System.out.println("结束");
5、main方法执行完毕,出栈,程序结束
# 方法区
MethodDemo1.class
main
getMax
# 栈内存
算做方法重载的条件:
以下不能算作方法重载:
默认的代码执行结构
public class Test {
public static void main(String[] args) {
System.out.println("A");
System.out.println("B");
System.out.println("C");
}
}
if语句:https://www.runoob.com/java/java-if-else-switch.html
switch语句:https://www.runoob.com/java/java-switch-case.html
https://www.runoob.com/java/java-loop.html
break:强行退出当前循环
continue:仅结束当前循环,并进入下一次循环
一种容器,可以存储同种数据类型的多个值
public class Demo1Array {
public static void main(String[] args) {
int[] array1; // 推荐
int array2[];
System.out.println(array1);
System.out.println(array2);
}
}
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度
// 完整格式:数据类型[] 数组名 = new 数据类型[] { 元素1,元素2,元素3… };
int[] array = new int[]{ 11,22,33 };
// 简化格式:数据类型[] 数组名 = { 元素1,元素2,元素3… };
int[] array = { 11,22,33 };
动态初始化:手动指定数组长度,由系统给出默认初始化值
int[] arr = new int[3];
类型 | 初始化 | 默认值 | 补充 |
---|---|---|---|
整数数组 | int[] arr = new int[5]; | 0 | 基本数据类型 |
浮点数数组 | double[] arr = new double[5]; | 0.0 | 基本数据类型 |
字符数组 | char[] arr = new char[5]; | ‘\u0000’(空白字符) | 基本数据类型 |
布尔数组 | boolean[] arr = new boolean[5]; | false | 基本数据类型 |
(类、接口、数组)数组 | String[] arr = new String[5]; Array[] arr = new Array[1]; | null | 引用数据类型 |
解释:
数组里面存数组,可不是指二维数组。是(一维)数组里面存储的数据类型为数组。
二维数组的长和宽是规范的,但是一维数组中存入数组,每一个存入的数组,其长度可以是任意合理的数字
public class Demo1Array {
public static void main(String[] args) {
int[][] array1; // 推荐
int array2[][];
System.out.println(array1);
System.out.println(array2);
}
}
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度
// 完整格式:数据类型[][] 数组名 = new 数据类型[][] {{元素1,元素2},{元素1, 元素2}};
int[][] arr = new int[][]{{11,22},{33,44}};
// 简化格式:数据类型[][] 数组名 = {{元素1,元素2}, {元素1, 元素2}};
int[][] arr = {{11,22},{33,44}};
动态初始化:手动指定数组长度,由系统给出默认初始化值
int[][] arr = new int[2][3];
public class Demo1Array {
public static void main(String[] args) {
String s1 = "abc"; // 常量池内没有,创建
String s2 = "abc"; // 常量池内有,引用
System.out.println(s1 == s2); // 两者是一个东西,true
}
}
public class Demo1Array {
public static void main(String[] args) {
String s1 = "abc"; // 常量池内没有,创建
String s2 = new String("abc"); // 在堆内存中开辟
System.out.println(s1 == s2); // 两者不是一个东西,false
}
}
public class Demo1Array {
public static void main(String[] args) {
String s1 = "abc"; // 常量池内没有abc,创建
String s2 = "ab"; // 常量池内没有ab,创建
String s3 = s2 + "c"; // 常量池内没有c,创建,StringBuilder内完成相加操作,并在堆内存开辟新的空间存储abc
System.out.println(s1 == s3); // 两者不是一个东西,false
}
}
public class Demo1Array {
public static void main(String[] args) {
String s1 = "abc"; // 常量池内没有,创建
String s2 = "a" + "b" + "c"; // 常量优化机制,等同于abc。常量池内有,引用
System.out.println(s1 == s2); // 两者是一个东西,true
}
}
内容比较:
strs1.equals(strs2)
strs1.equalsIgnoreCase(strs2)
切割、截取、替换、遍历等等:https://blog.csdn.net/Cherils/article/details/105889084
- 提高字符串操作效率:StringBuilder的拼接速度比单纯的字符串运算拼接速度快上一个量级
- 本质是字符串的缓冲区,可以理解为一个容器,其内存储的内容长度可变。任意数据类型进来,都会变成字符串
StringBuilder() // 无参构造,创建空的字符串缓冲区,初始容量16
StringBuilder(String str) // 有参构造,创建一个字符串缓冲区,按照给定的参数完成初始化,初始容量:16+str的长度
完整源码梳理过程:https://blog.csdn.net/qq_44713454/article/details/109090381
总体思路:
添加、反转、转为字符串等等:https://blog.csdn.net/Cherils/article/details/105889084
跟StringBuilder大同小异,只是线程安全,而StringBuilder不是线程安全的