java概述
cmd命令
指定位置快捷打开cmd:在文件夹下的路径上直接输入cmd
回车打开
环境变量:就是把文件/软件所在的路径记录下来,从而在任何地方都能够打开。(一般是添加到系统环境变量中的path
,直接把软件的完整路径复制就行,而不是添加到用户环境变量)
|
|
java安装和运行
(建议把所有开发相关的软件放在同一文件夹下)
1、下载和安装JDK
2、下载IDEA
java最好用的集成开发环境(编译、调试等),下载时下载收费版的exe文件(zip文件会包含一些说明文档,这些我们不需要),然后傻瓜式安装即可
- 输入
psvm
或main
会自动生成main语句- 输入
so
会自动生成输出语句
(javac、java工具都在jdk文件下的
bin
目录下,安装时自动配置了环境变量,所以在命令行任何地方都能使用)运行java程序包含三个步骤:
- 编写代码
- 编译文件(即翻译成机器认识的语言)
- javac是jdk提供的一个编译工具,编译后生成
.class
文件- 运行程序
- java也是jdk提供的一个工具,用来运行程序(运行时不加后缀)
Idea UI的一些使用步骤:
- 项目是整体的大文件(微信);项目中模块是相互独立的(聊天、好友、朋友圈、我);模块中有多个包组成,即文件夹;在包里面有一个或多个类用来写java代码
- 注意:包的命令是有规范的,一般用公司域名的反写+包的作用命名,如
com.itheima.demo1
- 配置:设置字体(consolas)、字号(18)、自动导包、不区分大小写、背景图片
项目模块相关操作:
- 类的操作:新建类、删除类、修改类
- 修改类需要在类的文件右键重命名进行修改,而不能直接在代码里直接修改类名(要和文件名保持一致)
- 模块的操作:新建、删除、修改、导入
- 项目的操作:新建、打开、关闭、修改
配置环境变量
为java相关的软件单独配置一个路径:
JAVA_HOME
这样配置其实也就等价于直接置环境变量
E:\develop\jdk\bin
了(只不过path
里面有很多环境变量,可能会操作到其他变量,如果不小心修改就完了)
java历史和分类
java历史
JDK(Java Development Kit)是Java开发工具包的缩写,主要组成部分有:
- java运行环境 –JRE
- java虚拟机 –JVM
- java工具 –如javac、java、javap等
- java基础类库 –如rt.jar
长期支持版本:
- JDK 8 发布于2014年
- JDK 11 发布于2018年
- JDK 17 发布于2021年
- JDK 21 发布于2023年
java分类
- Java SE:java语言标准版,是其他两个版本的基础,用于桌面应用的开发
- Java ME:java语言的小型版,用于嵌入式设备开发(可忽略)
- Java EE:java语言的企业版,在SE基础上添加了一些企业级开发的规范和框架(最火爆)
java跨平台原理
java语言的跨平台是通过虚拟机实现的
java语言不是直接运行在操作系统里面的,而是运行在虚拟机中的
针对不同的操作系统(平台),安装不同的虚拟机就可以了
jdk和jre
java历史中已经简单介绍了,现在详细介绍一下:
- JDK:java开发工具包,用于开发和运行java程序代码
- JVM虚拟机:java程序运行的地方
- 核心类库:各种类
- 开发工具:javac、java、jdb、jhat
- JRE:java运行环境,用来运行java代码,相当于从JDK取了一部分出来
- JVM
- 核心类库
- 部分运行工具
关系:JDK包含JRE,JRE包含JVM
IDEA快捷键
1 2 3 4 5 6 7 8 9 10 11 12
Ctrl + alt + L 自动格式化代码(排版) main 打印主函数语句 so/sout 打印输出语句 5.fori / arr.fori 打印for循环语句,循环5次 / 数组遍历 arr.forr 倒着遍历 ctrl+alt+v 自动补全代码 ctrl+alt+t 选择用if还是while等包裹一段代码 ctrl+p 查看(自定义方法)形参、参数等 ctrl+alt+M 自动抽取方法(选中代码,按快捷键自动抽取) alt + insert 构造方法、set/get生成 ctrl + b 查看(类方法-API)源码 alt + enter 打开红色报错
常用库
Scanner
1 2 3
import java.util.Scanner; //导包 Scanner sc = new Scanner(System.in); //创建对象 int i = sc.nextInt(); //接收数据
Random
1 2 3 4 5 6 7
import java.util.Random; //导包(自动) Random r = new Random(); //创建对象 int number = r.nextInt(终止范围); //生成随机数,左闭右开,一定是从0开始 //实现任意数到任意数的范围,如7-15(对应0-8) Random r = new Random(); int number = r.nextInt(9) + 7;
java语法基础
常量、变量、数据类型
(1)注释和关键字
- 注释分为单行注释、多行注释和文档注释
- 关键字:程序根据关键字知道要做什么事情
(2)第一个关键字-class
class关键字表示定义一个类,后面跟随类名。那如何理解类呢?可以把类当成人体的细胞,一个java程序由超级多的类组成,编写代码的时候看需要那个细胞就编写那个细胞,从而组成一个完整的人
注:类名要和文件名保持一致
(3)常量/字面量
- 字面量分类:整数、小数、字符串、字符、布尔、空(null)
- 一些特殊的字面量:制表符
\t
、空类型null
1 2 3 4 5 6
null不能直接打印,只能用字符串的形式打印,如System.out.println("null"); 直接输出会导致编译错误:System.out.println(null); 制表符的作用是把前面的字符串长度补齐到8,或者8的倍数,从而想表格一样整齐,如 System.out.println("name"+"\t"+"tom"); 补4个空格 System.out.println("age"+"\t"+"23"); 补5个空格
(4)变量
- 变量可以重复使用,但不能重复定义,即不能写两次
int a = xxx;
- 变量使用之前一定要进行赋值
- 变量的作用域范围:只在当前所属的大括号内有效
- 一条语句中可以定义多个变量,如
int d=100,e=200,f=300;
(5)数据类型-1
- java中的数据类型分为:基本数据类型(四类八种)和引用数据类型【string是典型的引用数据类型】
- 【四类八种外加引,1+1+2+4】
1 2 3 4
注意事项: 定义long类型变量:需在数值后面加入L作为后缀(大小写均可) long a = 99999L; 定义float类型变量:需在数值后面加入F作为后缀(大小写均可) float a = 23.3F; 如果不加后缀的话使用的是默认的数据类型(int和double)
(6)计算机中的数据存储
- 二进制:
0b
开头; 十进制; 八进制:0
开头; 十六进制:0x
开头- 之所以使用二进制是因为:二进制很好区分,以前是有孔和没孔,现在是高压和低压
- 我们知道,计算机中任何数据都是二进制存储。可以把计算机中所有数据归为:文本、图片、声音三类数据,那这三类数据是如何存储的呢?
文本
:又包括数字、字母、汉字三类,字母和汉字都是通过码表先转换为十进制数字,然后用二进制存储在计算机中,如Unicode编码表包含了世界各国语言对应的数字
图片
:图片就是一个一个的像素(分辨率)组成,一个像素对应一个数字(对于灰度图,数字范围是0-255表示不同灰度等级)存储在计算机;而如果是彩色图片,无非就是每一个像素搭配了不同的三原色RGB实现存储(RGB红绿蓝,一个像素点对应三个数字)
声音
:也是类似,对声音的波形图进行采样再进行存储,即将声音的波形图划分,图上每一个点对应一个数字(类似码表的一一映射)。日常生活中的声音无损和有损就是采样点的多少,采样的多就和真实没啥区别。图片的有损和无损也是同样道理。(7)标识符-2
标识符/变量名命令建议(阿里规范)
(8)键盘录入-3
Java有一个类叫
Scanner
,这个类就可以接受键盘输入的数字。(变量i记录键盘所敲的数字)类–>对象–>多个实例
(9)输出语句
1 2 3
System.out.println(arr[i]); //打印后换行 System.out.print(arr[i] + " "); //打印不换行 System.out.println(); //只进行换行,不输出内容
运算符🌙
(9)数值拆分
使用运算符进行数值拆分
1 2 3 4 5
1234 个位:数值 % 10 十位:数值 / 10 % 10 百位:数值 / 100 % 10 千位:数值 / 1000 % 10
自增自减运算符:a++先用后加,a的值发生改变;++a先加后用,a的值发生改变
1 2 3 4
int x = 10; int y = x++; int z = ++x; 最终x=12,y=10,z=12
扩展赋值运算符:
+=、-=、*=、/=、%=
底层都隐藏了一个强制类型转换
1 2 3
short s = 1; s += 1; //先进行s+1,为int类型,然后强转后赋值 等同于s = (short)(s + 1);
逻辑运算符:
短路逻辑运算符:
因为逻辑运算符效率比较低(无论左边能不能确定结果,右边都要判断),所以之后常用的是短路逻辑运算符来提高效率。
举个例子:登陆时需要输入用户名和密码,使用逻辑运算符&时无论用户名输入是否正确,密码都需要判断;而使用短路逻辑运算符&&时,如果用户名输入错误,那无论密码正确与否都不重要的,即不用判断密码了,代码只判断用户名错误就结束了
三元运算符:
关系表达式 ? 表达式1 : 表达式2;
先执行关系表达式,结果如果为真,则输出表达式1,结果如果为假,则输出表达式2
(10)运算符优先级
所有数学运算基本都是从左往右进行的;只有单目运算符、赋值运算符和三目运算符例外(从右往左)
Tip:注意最后一行的扩展赋值运算符是从右往左执行的;记死小括号最高,扩展赋值最低
在大部分编程语言中,都是这样的:有些远算符是从左到右,有些是从右到左(如赋值)(11)类型转换
byte、short、char三种类型的数据在运算的时候,都会直接提升为int,然后再进行运算(隐式)
- 数字相加
- 字符串相加:当执行“+”操作时,只要出现字符串,就不是运算操作,而是拼接操作了
- 字符相加:先把字符通过ascii转为数字在相加
1 2 3 4 5 6 7 8 9 10
byte b1 = 10; byte b2 = 20; byte result = (byte)(b1+b2); b1+b2在计算前都会先转成int,相加后也是int类型,而最终要赋给byte类型,因此要用强转 byte b1 += 10; //这个不用强转也不报错,原因见上面 1+99+"xxcjw"+1 //输出结果是"100xxcjw1" true+"xxcjw" //输出结果是"truexxcjw" 连续+操作时,从左到右依次执行;当+前后有字符串时,就是拼接操作
字符相加
1
System.out.printIn('0'+0); //
字符在运算时都会先转换成数字在运算(查码表),所以这里有个操作就是如果想知道某个数字字符对应的数字,可以通过
+0
实现,因为0不会改变运算的结果
原码、反码、补码
- 正数的原码、反码、补码就是其本身,不变
- 原码:数据的二进制表现形式,最左边是符号位
- 弊端:如果是负数计算,运算方向和实际相反,导致结果错误
- 反码:(负数反码为)符号位不变,其余数值取反
- 出现目的:为了解决原码不能计算负数的问题出现
- 弊端:0有两种表示,如果负数运算时跨0,与实际结果会有1的偏差
- 补码:负数的补码在反码的基础上+1
- 为了解决负数反码计算时跨0的问题而出现
- 计算机中的存储和计算都是以补码形式进行的(核心!)
1 2 3 4 5
看个例子: int a = 300; //0000 0000 0000 0000 0000 0000 1100 1000 byte b = (byte)a; //1100 1000 所以b就是1100 1000,注意啦,这个数值在计算机是以补码存储的,正数无所谓, 但此时这个是负数,将补码转为原码最终就是-56,所以b=-56
计算总结:
从位的角度理解逻辑运算符(以原码反码补码解释)
流程控制语句
分支结构
(1)if语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
if( xxxx ) { # 第一种结构 xxxxx; } if( xxxx ) { # 第二种结构 xxxxx; } else { xxxx; } if( xxxx ) { # 第三种结构 xxxxx; } else if { xxxxx; } else { xxxxx; }
(2)switch语句
注意一点:case后面的值只能是常量而不能是变量;switch后面的表达式通常是变量,来表示各种情况
default可以写在任意位置,但习惯写在最后来表示异常情况
case穿透:就是去掉了break语句导致的
- 拿表达式的值和下面每一个case的值匹配,如果匹配上,则执行相应语句,如果有break,则结束
- 如果没有发现break,那么程序会继续执行下一下case的语句体,一直遇到break为止
switch新特性,即优化了写法(JDK12及以后)
- 在 Java 12 及以后的版本中,
switch
语句引入了新的语法形式,即使用->
箭头语法,这种语法下不会发生case
穿透。if第三种结构适用于范围判断;switch适用于枚举,把有限的数据一一列举出来
1 2 3 4 5 6 7 8 9 10 11 12
switch(表达式){ case 值1: 语句1; break; case 值2: 语句2; break; ... default: 语句n+1; break; }
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
case穿透实例:输入日期,如果是1-5,则是工作日;如果是6-7,则是休息日 //比如输入2,和case 1不匹配;和case 2匹配,则执行case 2的语句体,发现没有break,则会继续往下执行case的语句体(就不用匹配了),直到遇见break,即执行完case 5的语句体结束 //1、键盘录入 Scanner sc = new Scanner(System.in); System.out.println("请录入一个整数表示星期"); int week = sc.nextInt(); //2、利用switch语句选择 switch (week){ case 1: case 2: case 3: case 4: case 5: System.out.println("工作日"); break; case 6: case 7: System.out.println("休息日"); break; default: System.out.println("没有这个星期"); break; } //简化代码 switch (week){ case 1,2,3,4,5: System.out.println("工作日"); break; case 6,7: System.out.println("休息日"); break; default: System.out.println("没有这个星期"); break; }
switch新特性:(不会触发case穿透)
- 不用写
break
(把break简化了,不用手动写l);也不会触发case穿透
1 2 3 4 5 6 7 8
int number = 1; switch (number){ case 1 -> {System.out.println("一");} case 2 -> {System.out.println("二");} case 3 -> {System.out.println("三");} default -> {System.out.println("没有这个选项");} } // 输出为“一”
循环结构
(1)for循环
1 2 3 4 5 6 7
for(初始化语句;条件判断语句;条件控制语句){ 循环体语句; } for(int i = 0;i <= 10;i++){ System.out.println("xxcjw"); }
- 变量的作用范围只在变量所属的大括号中有效
- 之后如果要写累加求和的变量,可以把变量定义在循环的外面。当把变量定义在循环里时,当前变量只在本次循环中有效,当本次循环结束时,变量会消失;当下次循环开始时,又会重新定义一个该变量
- for循环中的累加思想:定义一个变量在循环外,循环内
+=
- for循环中的统计思想:统计个数用自增运算符,循环外定义一个变量,循环内自增
(2)while循环
1 2 3 4 5 6 7 8 9 10 11
初始化语句; while(条件判断语句){ 循环体语句; 条件控制语句; } int i =1; while(i <= 100){ System.out.println(i); i++; }
(3)for和while区别
- 初始化语句中变量的作用域区别(不绝对)
- 开发中根据情况使用
跳转控制语句⭐
- continue:跳出本次循环,继续下次循环
- break:跳出整个循环
⭐在for循环或while循环中,适当使用跳转控制语句可以大大提高效率,要把循环语句和跳转控制语句绑在一起,提起一方就想到另一方。比如循环100次,但在第10次就得到结果了(求平方根),那使用break后面就不用在执行了,提高效率。
⭐比如经常碰见的场景:(猜数字)不知道循环多少次,那就写死循环,直到相等时break退出就行
⭐注意:这两个语句都和判断语句if无关
一些思想😊
倒序输出思想、标记思想、统计思想
练习两道力扣题:(1)回文数(2)判断质数(3)猜数字
1、回文数(注意与数值切分的区别,倒序输出思想)
1 2 3 4 5 6 7 8 9 10 11 12
//回文数:正着读和反着读都一样,如121,1221 //思路:把数字倒过来跟原来的数字进行比较(容易想到的是数值切分和拼接,但有很多细节) int x =12345; int temp = x; //临时变量记录原来输入的值,用于最后比较,因为x会变化 int num = 0; //记录倒过来之后的值 while(){ //一开始不知道循环结束条件可以先不写 int ge = x % 10; //从右往左获取每一位数字 x = x / 10; num = num * 10 + ge; //拼接 } System.out.println(num == temp); //比较
2、判断是否为质数(用到了标记思想)
标记思想通常用于数据筛选与过滤中,比如筛选特定数据、路径搜索与图算法中的节点状态deng
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
//判断一个属是否为质数(只能被1和它本身整除) //1、键盘录入一个整数 Scanner sc = new Scanner(System.in); System.out,println("请输入一个正整数"); int number = sc.nextInt(); //表示最初就认为是一个质数,标记思想 boolean flag = true; //2、for循环判断 for (int i = 2;i < number;i++){ //number.fori快捷键 if(number % i == 0){ flag = false; System.out.println(number + "不是一个质数"); break; } } if(flag){ System.out.println(number + "是一个质数"); }else{ System.out.println(number + "是一个质数"); }
进一步优化:
1 2 3
//上述代码,如果输入的数很大,则需要循环很多次,下面进行优化 //思路:如果一个数不是质数,则它的因子中必定有一个是小于其平方根的,如81,只需要循环到9 // for(int i = 2;i <= number的平方根;i++)
3、猜数字游戏【注:统计思想和求和思想见for循环】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
//1、生成1-100之间的随机数字 Random r = new Random(); int number = r.nextInt(100) + 1; //2、键盘录入 Scanner sc = new Scanner(System.in); int count = 0; while(true){ //死循环,和break配合 System.out.println("输入你猜的数字:"); int guessNumber = sc.nextInt(); //3、判断,给出提示 if(guessNumber > number){ System.out.println("大了"); } else if(guessNumber < number) { System.out.println("小了"); } else { System.out.println("猜中了"); break; } //4、保底机制 count++; if(count == 3){ System.out.println("猜中了"); break; } }
数组
定义和初始化
1、定义
数组就是一种容器,可以用来存储多个同种类型数据
2、静态初始化
1 2 3 4 5 6 7 8 9
//完整格式(了解) 数据类型[] 数组名 = new 数据类型[]{num1,num2...} int[] array = new int[]{11,22,33}; //简化格式(掌握) 数据类型[] 数组名 = {num1,num2...} int[] array = {11,22,33}; double[] array = {11.1,22.2,33.3}; string[] array = {"张三","李四","王五"};
3、数组元素访问
数组的长度属性:
数组名.length arr.length
1 2 3 4 5 6 7 8 9 10 11 12 13
//直接打印数组名输出的是数组的地址值 int[] array = {11,22,33}; System.out.println(array); //输出 [D@776ec8df //[-表示是一个数组;D-表示数组里面元素是double类型;@-间隔符号,固定格式;776ec8df-地址值 //用索引数组实现元素访问 System.out.println(array[0]); //打印第一个元素 array[0] = 100; //修改数组元素 //循环遍历 for(int i = 0;i < array.length;i++){ System.out.println(array[i]); }
小技巧:一个循环尽量只干一件事情;比如一个循环修改数组元素值,用另一个循环打印输出
4、动态初始化
定义:初始化时只指定数组长度,系统为该数组分配初始值
格式:
数据类型[] 数组名 = new 数据类型[数组长度]
1 2 3 4 5 6 7 8 9 10 11
//动态初始化 String[] arr = new String[50]; //添加数据 arr[0] = "张三"; arr[1] = "里斯"; /* 引用数据类型 默认初始化为null 整数数据类型 默认初始化为0 浮点数数据类型 默认初始化为0.0 char数据类型 默认初始化为空格 */
5、区别
数组常见操作
(1)求最值
思路:定义一个变量存储最值(参照物),拿数组中的元素比较
1 2 3 4 5 6
int max = arr[0]; for(int i = 1;i < arr.length;i++){ if(arr[i] > max){ max = arr[i]; } }
(2)随机生成+求和
1 2 3 4 5 6 7 8 9 10 11 12 13 14
int[] arr = new int[10]; //动态初始化 Random r = new Random(); //生成10个随机数 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 += arr[i]; }
(3)交换数据
思路:定义两个变量分别从前往后和从后往前记录索引
1 2 3 4 5 6 7 8 9 10 11 12 13
//输入12345,输出54321 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; } for(int i = 0;i < arr.length;i++){ System.out.print(arr[i] + " "); }
(4)打乱数据
关键问题:获取随机索引;对每个元素进行随机交换数据
1 2 3 4 5 6 7 8 9 10 11
int[] arr = {1,2,3,4,5}; Random r = new Random(); for(int i = 0;i < arr.length;i++){ //定义随机索引 int randomIndex = r.nextInt(arr.length); //交换数据 int temp = arr[i]; arr[i] = arr[randomIndex]; arr[randomIndex] = temp; }
(5)打印数组+逗号
1 2 3 4 5 6 7 8 9
//将数组打印至一行,并以逗号相隔 for(int i = 0;i < arr.length;i++){ if(i == arr.length - 1){ System.out.print(arr[i]); } else { System.out.print(arr[i] + ","); } }
6、copy数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
//将数组arr从索引from开始,到索引to结束(不包含)的元素复制到新数组中 int[] arr = {1,2,3,4,5,6,8,7}; int[] copyArr = copyOfRange(arr,3,7); //定义方法来做这件事 public static int[] copyOfRange(int[] arr,int from,int to){ int[] newArr = new int[to - from]; int index = 0; //伪造索引的思想 for(int i = from;i < to;i++){ newArr[index] = arr[i]; //这里需要注意,新数组的下标不是从0开始 index++; } return newArr; }
数组内存图
(1)java(虚拟机)内存分配
一看见new就知道是存储在堆中的,堆中的每一个对象/数组都对应一个地址值(即只要是new出来的一定在堆里面开辟了一个小空间)
方法以及方法内的变量都存储在栈中
(2)例子:数组内存图