Java基础
JDK下载
http://www.oracle.com
安装路径统一,不要包含中文和空格
长期支持版本(LTS)
Java5.0 8.0 17.0
JDK安装
程序运行
程序编写(写代码)、编译(转换成机器语言)、运行(执行编译后的指令)
Java/jdk-17/bin/javac.exe编译
Java/jdk-17/bin/java.exe运行
编译.java文件生成.class文件(自解码文件)
javac Helloworld.java
运行.java文件
java Helloworld
环境变量
配置java.exe、javac.exe全局变量 bilibili
编译器
Notepad++
Java类型及应用
Java SE: Java语言标准版,用于桌面应用的开发。是其它两种版本的基础。
Java ME: Java语言小型版,用于嵌入式电子设备或者小型移动设备(已凉凉)
Java EE: Java语言企业版,用于Web网站开发(浏览器+服务器),领域No.1
桌面应用开发:各种税务管理软件、IDEA、Clion、Pycharm
企业级应用开发:微服务、spingcloud
移动应用开发:鸿蒙、android、医疗设备
科学计算:Matlab
大数据开发:hadoop
游戏开发:我的世界、MineCraft
Java特性
- 面向对象:根据要求创建对象
- 安全性
- 多线程:同时做多件事情
- 简单易用
- 开源:安装包+代码
- 跨平台:Windows、Mac、Linux(通过虚拟机实现跨平台)
高级语言类型
- 编译型:通过Arm/X86平台编译器整体翻译为机器指令执行(C)
- 解释型:通过Arm/X86平台编译器按行翻译(Python)
- 混合型:整体编译为字节码,通过平台执行器翻译,到Java提供的虚拟机执行机器指令(Java)
JRE
Java的运行工具,包括JVM、核心类库、开发工具
JDK
Java开发工具包,包括:
JVM虚拟机:java程序运行的地方
核心类库:java已经写好的东西,可以直接使用
开发工具:javac、java、jdb、jhat…
JDK>JRE>JVM
Java基础语法
注释
// 单行注释
/*多行注释*/
/**文档注释*/
关键字
关键字字母全部小写
class
用于创建/定义一个类,类是Java最基本的组成单元
public class Helloworld{
// 类名要和文件名完全一致
}
字面量
数据在程序中的书写格式
整数类型:-88
小数类型:-5.21
字符串类型:“hello”、“我们”、" "(双引号)
字符类型:‘A’、‘我’(单引号,单个内容)
布尔类型:true、false
特殊字符:制表符(\t、\n、)、空类型(null)
变量
变量定义格式:
数据类型 变量名 = 数据值;
int a = 10;
变量使用:打印、计算、更新赋值
System.out.println(a);
int b = 20;
System.out.println(a + b);
a = 30;
变量注意事项
只能存一个值
不允许重复定义
一条语句可以定义多个变量
变量使用前一定要赋值
变量作用域
int c = 1, d = 2, e = 3;
数据存储
System.out.println(17); //十进制
System.out.println(017); //八进制
System.out.println(0b123); //语法错误
System.out.println(0x123); //十六进制
进制转化(x转十):系数*基数的权次幂 相加
101 = 1*2^2 + 0*2^1 + 1*2^0 = 4 + 0 + 1 = 5
进制转化(十转x):除基取余
除以基数,将余数倒着拼起来
RGB(0 ~ 255)(00 ~ FF)
数据类型
基本数据类型
整数、浮点数、字符、布尔
定义long类型变量,需要在数据值后面加一个L(大小也都可)作为后缀
定义folat类型变量,需要在数据值后面加一个F(大小也都可)作为后缀
取值范围:
double > float > long > int > short > byte
引用数据类型
标识符
给类、方法、变量等起的名字
命名规则
由数字、字母、下划线_和美元符$组成
不能以数字开头
不能是关键字
区分大小写
命名建议
见名知意
- 小驼峰命名法:方法、变量
单个单词小写name,多个单词首字母小写其它单词大写firstName
- 大驼峰命名法:类名
单个单词首字母大写Student,多个单词每个单词首字母大写GoodStudent
键盘录入
导包Scanner
import java.util.Scanner // 写在类定义上面
创建对象
Scanner sc = new Scanner(System.in);
// sc为变量,其它不变
接受数据
int i = sc.nextInt();
// i为变量,其它不变
IDEA
IntelliJ IDEA,用于Java语言开发的集成环境,把代码编写、编译、执行、调试等集成到一起的开发工具。
下载:https://www.jetbrains.com/idea/
IDEA项目结构:project、module、package、class
快捷输入:
psvm (public static void main(String[] args) )
sout (System.out.println();)
100.fori (for (int i; i<100; i++))
数组名.fori (遍历数组)
ctrl + alt + M 自动抽取方法
运算符
运算符:对字面量或者变量进行操作的符号
+ // 算术运算符
表达式:用运算符把字面量或者变量连接起来符合java语法的式子就可以称为表达式。不同运算符连接的表达式体现的是不同类型的表达式。
a+b // 算数表达式
算数运算符
+、-、*、/、%
// 代码中有小数参与计算,结果有可能不精确
1.1 + 1.1 = 2.2
1.1 + 1.01 = 2.110000000003
// 整数除法结果为整数,小数计算结果可能不精确
10 / 3 = 3
10.0 / 3 = 3.33333333333
// 取模(取余数),判断整数、奇偶、斗地主玩家
10 % 2 = 0
10 % 3 = 1
数值拆分
需求:键盘录入一个三位数,将其拆分为个位、十位、百位后,打印在控制台
输入整数:123
个位:数值 % 10
十位:数值 /10 % 10
百位:数值 /100 % 10
package test;
import java.util.scanner;
public class Test1 {
public static void main(string[] args){
//健盘录入一个三位数,获取其中的个位,十位,百位
//1.键盘录入
Scanner sc = new Scanner(System.in);
System.out.println("诸输入一个三位数");
int number = sc.nextInt();
//2.获取个位,十位,百位
int ge = number % 10;
int shi = number / 10 % 10;
int bai = number / 100 % 10;
System.out.println(ge);
System.out.println(shi);
System.out.println(bai);
类型转换
隐式转换(自动类型提升):取值范围小 → 大
强制转换:取值范围大 → 小
byte < short < int < long < float < double
隐式转换的两种提升规则
取值范围小的,和取值范围大的进行运算,小的会先提升为大的,再进行运算(不同类型不能直接计算)
byte short char 三种类型的数据在运算的时候,都会直接先提升为int,然后再进行运算
byte a = 10;
byte b = 20;
c = a + b // 此时c为int
强制转换
如果把一个取值范围大的数值,赋值给取值范围小的变量,是不允许直接赋值的。如果一定要这么做就需要加入强制转换
格式:
目标数据类型 变量名 = (目标数据类型) 被强转的数据;
byte b1 = 10; // 0000 1010
byte b2 = 20; // 0001 0100
byte r = (byte) (b1 + b2)
30
int a = 200;
b = (byte) a
-56 // 转换数据过大,结果错误
// a 0000 0000 0000 0000 0000 0000 1100 1000
// b 1100 1000
字符串+
当“+”操作中出现字符串时,这个“+”是字符串连接符,而不是算术运算符了会将前后的数据进行拼接,并产生一个新的字符串。
“123” + 123 → “123723”
“abc” + true → “abctrue”
连续进行"+"操作时,从左到右逐个执行。
1 + 99 + “年黑马” → "100年黑马”
字符+
字符+字符、字符+数字时,会把字符通过ASCII码(American Standard Code for Information Interchange)表查询到对应的数字再进行计算
A:65 a:97
1 + 'a' → 98
自增自减运算符
++和–既可以放在变量的前边,也可以放在变量的后边,单独写一行的结果一样
int a = 10;
++a; // 11
a++; // 12
a--; // 11
--a; // 10
参与计算时,放前后的计算结果不同
// 先用后加
int a = 10;
int b = a++; // b = 10, a = 11
// 先加后用
int a = 10;
int b = ++a; // b = 11, a = 11
赋值运算符
+=、-=、*=、/=、%= 隐藏了一个强制类型转换
short s = 1;
s += 1;
// 等同于 s = (short) (s + 1);
关系运算符
关系运算符/比较运算符
关系运算符的结果都是boolean类型,要么是true,要么是false。千万不要把“==”误写成“=”
逻辑运算符
短路逻辑运算符
A && B // A=True才判断B,A=False时B不用判断
A || B // A=True直接为True,A=False时才判断B
三元运算符
格式:关系表达式? 表达式1: 表达式2
// 获取两个数的较大值
int max = a > b ? c : d
计算规则:
首先计算关系表达式的值
如果值为true,表达式1的值就是运算结果
如果值为false,表达式2的值就是运算结果
运算符优先级
小括号优先于所有
原码、反码、补码
原码:十进制数据的二进制表现形式,最左边是符号位,0为正,1为负
56 → 0011 1000
8 bit = 1字节
一个字节最大值为 0111 1111 → +127
一个字节最小值为 1111 1111 → -127
1个字节范围为-128 ~ +127
但是如果是负数计算,结果就出错,实际运算的结果,跟我们预期的结果是相反的。
反码:正数的补码反码是其本身,负数的反码是符号位保持不变,其余位取反
正数的反码不变,负数的反码在原码的基础上符号位不变
数值取反,0变1,1变0。
补码:正数的补码是其本身,负数的补码是在其反码的基础上+1
为了解决负数计算时跨0的问题而出现的。
-128没有原码和反码,补码为1000 0000
流程控制语句
顺序结构
顺序结构语句是Java程序默认的执行流程,按照代码的先后顺序,从上到下依次执行
分支结构
if语句
if语句1
if (关系表达式) {
语句体;
}
// 如果只有一句代码可以不写大括号(一行不一定算一句),一般建议加大括号
if (关系表达式)
语句体;
if语句2
if (关系表达式) {
语句体;
} else {
语句体;
}
if语句3
if (关系表达式1) {
语句体1;
} else if (关系表达式2) {
语句体2;
}
...
} else {
语句体 n;
}
switch语句
switch (表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n;
break;
}
表达式取值为byte、short、int、char,JDK5以后可以是枚举,JDK7以后可以是String
case后面的值只能是字面量,不能是变量,且不允许重复
default位置不一定写最下面,习惯写最下面,省略不会有语法问题。
case穿透:语句体没有写break,会继续执行下一个case语句,直到break或大括号
// JDK12的switch新特性
int num = 1;
switch (num){
case 1-> {
system.out.println("yi")
}
case 2-> {
system.out.println("er")
}
default -> {
system.out.println("没有该选项")
}
}
// 单语句可省略括号
int num = 1;
switch (num){
case 1-> system.out.println("yi")
case 2-> system.out.println("er")
default -> system.out.println("没有该选项")
}
循环结构
for循环
for (初始化语句 ; 条件判断语句 ; 条件控制语句){
循环体语句;
}
while循环
初始化语句;
while (条件判断语句){
循环体语句;
条件控制语句;
}
相同点:运行规则都是一样的
for 和 while 的区别:
for循环中,控制循环的变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了
while循环中,控制循环的变量,对于while循环来说不归属其语法结构中,在while循环结束后,该变量还可以继续使用(书上错不严谨的说法)
初始化语句
for ( ; 条件判断语句 ; 条件控制语句){
循环体语句;
}
-
for循环中:知道循环次数或者循环的范围
-
while循环:不知道循环的次数和范围,只知道循环的结束条件
do…while循环
初始化语句;
do {
循环体语句;
条件控制语句;
} while(条件判断语句);
无限循环
// for无限循环
for (;;) {
System.out.println("hello");
}
// while无限循环
while (true){
System.out.println("hello");
}
// do...while无限循环
do {
System.out.println("hello");
} while(true);
无限循环下面不写代码了,代码执行不到
跳转控制语句
// 跳过本次循环
for (int i=1; i<=5; i++){
if(i==3){
continue;
}
System.out.println(i);
}
// 结束整个循环
for (int i=1; i<=5; i++){
if(i==3){
break;
}
System.out.println(i);
}
continue:跳过本次循环,继续执行下次循环。
break:结束整个循环。
获取随机数
import java.util.Random
Random r = new Random();
int number = r.nextInt(bound: 100); // [0, 99]
数组
可以用来存储同种数据类型的多个值
数组容器在存储数据的时候,需要结合隐式转换考虑。
例如:int类型的数组容器(boolean× byte√ short√ int√ double×)
double类型的数组容器(byte√ short√ int√ long√ double√)
建议:容器的类型,和存储的数据类型保持一致
数组的定义
// 格式一:数据类型[] 数组名
int [] array
// 格式二:数据类型 数组名[]
int array[]
数组初始化
初始化就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程
// 数据类型[] 数组名=new 数据类型[]{元素1,元素2,元素3...};
int[] array = new int[]{11, 22, 33};
double[] array2 = new double[]{11.1, 22.2, 33.3};
// 简写格式
int[] array = {11, 22, 33};
double[] array2 = {11.1, 22.2, 33.3};
初始化后数组长度不会再发生变化
数组地址值
数组的地址值表示数组在内存中的位置
int[] arr = {1,2,3,4,5};
System.out.println(arr); // [I@6d03e736
// [表示当前是一个数组
// D表示当前数组内元素都是double类型,I为int
// @表示一个间隔符号,固定格式
// 6d03e736才是数组真正地址值,十六进制
// 平时习惯把整体叫做地址值
索引
也叫做下标,角标。从0开始,逐个+1增长,连续不间断
// 获取数组元素及赋值
int[] arr = {1, 2, 3, 4, 5};
int num = arr[0];
// 存储和覆盖
arr[0] = 100;
遍历
将数组中所有的内容取出来,取出来之后可以(打印,求和,判断…)
遍历指的是取出数据的过程,不要局限的理解为遍历就是打印!
for (int i=0; i<arr.length; i++){
System.out.println(arr[i])
}
// IEDA快捷语句 数组名.fori
数组动态初始化
初始化时只指定数组长度,由系统为数组分配初始值。
数据类型[] 数组名 = new 数据类型[数组长度];
int[] arr = new int[3];
默认初始化值
int 0
小数 0.0
字符 ‘/u0000’ (空格)
布尔 false
引用 null
动态初始化:手动指定数组长度,由系统给出默认初始化值。
(只明确元素个数,不明确具体数值,推荐使用动态初始化)
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度,
(需求中已经明确了要操作的具体数据,直接静态初始化即可。)
数组内存图
Java内存分配
-
栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行
-
堆:存储对象或者数组,new来创建的,都存储在堆内存
-
方法区:存储可以运行的class文件
-
本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
-
寄存器:给CPU使用,和我们开发无关
-
只要是new出来的一定是在堆里面开辟了一个小空间
-
如果new了多次,那么在堆里面有多个小空间,每个小空间中都有各自的数据
// 两个数组指向同一个空间的内存图
int[] arr1 = {11, 22};
int[] arr2 = arr1;
当两个数组指向同一个小空间时,其中一个数组对小空间中的值发生了改变,那么其他数组再次访问的时候都是修改之后的结果了。
常见问题
索引越界异常
常见操作
求最值
int[] arr = {1, 33, 5};
int max = arr[0]; // max的初始化值一定是数组中的值
// 从1开始循环,提高效率(0是跟自己比)
for (int i=1; i<arr.length; i++){
if (arr[i] > max){
max = arr[i];
}
}
求和
// 生成1~100的随机数保存到数值,并求和
// 定义随机数
int[] arr = new int[10];
Random r = new Random();
// 将随机数保存到数组
for (int i=0; i<arr.length; i++){
int number = r.nextInt(100) + 1;
arr[i] = number;
}
// 求数组中的元素和
int sum = 0;
for (int i=0; i<arr.length; i++){
sum = sum + arr[i];
}
交换数据
int[] arr = {1, 2, 3, 4, 5};
for (int i=0, j= arr.length -1; i<j; i++, j--){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
打乱数据
int[] arr = {1, 2, 3, 4, 5};
Random r = new Random();
for (int i=0; i<arr.length; i++){
// 生成一个0 ~ arr.length-1的随机索引
int randomIndex = r.nextInt(arr.length);
int temp = arr[i];
arr[i] = arr[randomIndex];
arr[randomIndex] = temp;
}
方法
方法(method)是程序中最小的执行单元。
重复的代码、具有独立功能的代码可以抽取到方法中。
可以提高代码的复用性、可以提高代码的可维护性
方法的格式
public class demo{
public static void main(String[] args){
// 调用
方法名();
}
}
// 定义
public static void 方法名(){
方法体(就是打包起来的代码);
}
带参数的方法
public class demo{
public static void main(String[] args){
// 带参数方法的调用(个数、类型对应)
method(10, 20); // 实参
}
}
// 带参数方法定义
// 形参
public static void method(int numl, int num2){
int result = num1 + num2;
System.out.println(result);
}
带返回值的方法(完整定义)
方法的返回值其实就是方法运行的最终结果。
调用处拿到方法的结果之后,才能根据结果进行下一步操作
public static 返回值类型 方法名(参数){
方法体;
return 返回值;
}
调用
// 直接调用
方法名(实参);
// 赋值调用
整数类型 变量名 = 方法名(实参);
// 输出调用
System.out.peintln(方法名(实参));
形参和实参
形参:全称形式参数,是指方法定义中的参数
实参:全称实际参数,方法调用中的参数
方法定义:
我要干什么(方法体)
干这件事需要什么才能完成(形参)
注意事项
-
方法不调用就不执行
-
方法与方法是平级关系,不能互相嵌套定义
-
方法定义在main前后都行,一般放后面,不能放在main里面
-
方法编写顺序与执行顺序无关
-
方法的返回值类型为void,表示该方法没有返回值,没有返回值的方法可以省略return语句不写。如果要编写return,后面不能跟具体的数据。
public static viod 方法名(参数){
方法体;
return;
}
- return语句下面,不能编写代码,因为永远执行不到,属于无效的代码
return关键字
- 方法没有返回值:可以省略不写。如果书写,表示结束方法
- 方法有返回值:必须要写。表示结束方法和返回结果
方法的重载
在同一个类中,定义了多个同名的方法,这些同名的方法具有同种的功能。
每个方法具有不同的参数类型或参数个数,这些同名的方法,就构成了重载关系
简单记:同一个类中,方法名相同,参数不同(包括数目和类型)的方法。与返回位无关。
Java虚拟机会通过参数的不同来区分同名的方法
return break关键字的区别
return:其实跟循环没有什么关系。跟方法有关的,表示1结束方法2返结果
如果方法执行到了return。那么整个方法全部结束。里面的循环也会随之结束了
break关键字:其实跟方法没有什么关系。结束循环或者switch的。
方法的内存
- 方法调用的基本内存原理
栈:先进后出,根据程序运行顺序进出栈
基本数据类型:数据值是存储在自己的空间中(特点:赋值给其他的变量,也是赋的真实的值)
int a = 10;
int b = a;
引用数据类型:数据值是存储在其它空间中,自己空间中存储的是地址值(特点:赋值给其它变量,赋的是地址)
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;
- 方法传递基本数据类型的内存原理
栈内存
传递基本数据类型时,传递的是真实的数据,形参的改变,不影响实际参数的值
- 方法传递引用数据类型的内存原理
引用数据类型中,变量存储的是地址值
引用:使用了其它空间中的数据
传递引用数据类型时,传递的是地址值,形参的改变,影响实际参数的值
IDEA快捷键
ctrl + alt + M 自动抽取方法
shift + F6 选中相同变量
ctrl + alt + t 加上while循环
二维数组
数组中存数组,分组管理数据
静态初始化
数据类型[][] 数组名 = new 数组类型[][]{{元素1, 元素2}, {元素1, 元素2}};
// 简写
int[][] arr = {{11, 22}, {33, 44}}; // 阿里巴巴编码规范
int arr[][] = {{11, 22}, {33, 44}};
动态初始化
数据类型[][] 数组名 = new 数组类型[m][n]:
// m表示这个二维数组,可以存放多少个一维数组
// n表示每一个一维数组,可以存放多少个元素
二维
数组内存图
特殊情况
// 1. 不定义一维数组长度
int[][] arr = new int[2][];
int[] arr1 = {11, 22};
int[] arr2 = {44, 55, 66};
arr[0] = arr1;
arr[1] = arr2;
// 2. 一维数组被覆盖和替换
int[][] arr = new int[2][3];
int[] arr1 = {11, 22};
int[] arr2 = {44, 55, 66};
arr[0] = arr1;
arr[1] = arr2;
面向对象
面向对象编程:拿东西过来解决问题
学习获取已有对象并使用
自己设计对象并使用(面向对象的语法)
设计对象并使用
类和对象
类(设计图):是对象共同特征的描述;
对象:是真实存在的具体东西。