控制结构
循环结构:重复执行同一段代码
循环四要素:
1、初始化条件语句:
定义一个变量 通常用于循环条件的控制
2、循环条件:
控制循环是否结束的
结果必须是boolean类型
true:循环继续
false:循环结束
3、循环体:重复执行的代码
4、改变循环条件的语句:
每执行完一次循环体之后 要改变循环条件的结果
案例:
打印100次hello world
循环体:System.out.println(“hello world”);
循环条件:打印次数<=100 num<=100
初始化条件语句:定义变流量表示打印次数 int num = 1;
改变循环条件的语句:num=num+1;或者num++;
分类:while do.while for
while:
格式:
初始化条件语句;
while(循环条件){
循环体;
改变循环条件的语句;
}
执行流程:
1、初始化条件语句
2、循环条件
true:循环体;
改变循环条件的语句;
重复步骤2;
false:循环结束
案例:打印1.。。。99
案例:1+2+3…+10
do.while:
格式:
初始化条件语句;
do{
循环体;
改变循环条件的语句;
}while(循环条件);
分号必须加
执行流程:
1、初始化条件语句
2、循环体;
3、改变循环条件的语句;
4、循环条件
true:重复步骤2
false:结束循环
while和do.while的区别:
当第一次执行循环条件不成立时:
do while一定会先执行一次循环体;
while则一次循环体都不会执行;
do.while无论循环条件是否成立,都会先执行一次循环体;
while循环如果循环条件不成立,则循环体一次都不会执行;
因为循环条件再后面,前面没法判断,判断的语句在后面
案例:
1、循环打印88次hello world
2、打印1 2 3 …99
3、求1+2+3…+10
这是个死循环(循环不会结束,当循环条件一直为true时),因为num一直小于10
要改成下面的
常见的死循环的形式:
while(true){}
for(; ; ){}
使用场景:当用户名不符合条件时,不停的重新输入
注意:如果程序在编译期间可以确定是死循环,则死循环后边的代码编译报错;
for循环
和while循环执行流程完全一致,区别在与格式上略有不同
格式:
for(初始化条件语句;循环条件语句;改变循环条件的语句){
循环体;
}
执行流程:
1、初始化条件语句
2、循环条件
true:循环体;
改变循环条件的语句;
重复步骤2;
false:循环结束
案例:
1、循环打印50次hello world
2、打印1 2 3 …99
3、求1+2+3…+10
下面这种不行,找不到sum
因为sum变量的作用域只在for循环生效,出了for循环没法用(i也是)
变量作用域:变量生效的范围
通常情况下:从变量定义开始到该变量所属的{}结束
当变量所属的{}执行完成,变量的内存空间随之释放;可以提高内存的利用率;
在同一个作用域中变量不能重名;
循环嵌套:循环嵌套if判断语句
将if看做循环体
案例:输出100以内所有能被5整除的整数
5 10 15 20 25 30 …
法1
法2
循环嵌套循环
先执行内层循环,再进行外层循环
将内层循环看做外层循环的循环体
案例:打印99乘法表
给空格对不齐
用/t做缩进
循环控制语句
break:打断
break;–break语句
应用场景:
1、switch case
结束switch case
2、循环
结束循环
i=4的时候不输出了,被break打断了
continue:继续
continue;–continue语句
跳过当次循环 继续下一次循环
应用场景:循环中
i=4的时候,跳过了
return:返回
return;结束方法
return结束方法,main方法也结束了
循环嵌套中 break和continue的用法:
当在循环嵌套中使用break和continue语句时,默认情况下只对它所属的离它最近(就近原则)的循环生效;
idea
调整主题:file->settings->apperance->theme
调整字体大小:file->settings->editor->font
使用步骤:
1、Project–项目 工程
开发的项目名称
需要选择自己安装的JDK
指定项目名称
项目的位置:最好不要放在c盘
项目是硬盘上的一个目录,再该目录下生成了一些文件夹和文件用于idea对当前项目进行管理(.idea javase.iml)
2、Module—模块
例如:淘宝下有购物车 用户 商品模块
在项目上右键选择new module
输入模块名称即可
创建模块其实是在project的目录下又创建了一个子目录用于进一步的区分和管理
3、src目录 源码所在的目录
4、package–包
Java文件进行再次分类管理
在src右键new package
cn.tedu.array
创建包是在src下又创建了cn目录 在cn目录下创建了tedu 在tedu目录下又创建array目录
5、在包里创建java类
指定类名即可
快捷键:
ctrl+/ 添加、取消行注释
ctrl+shift+/ 添加、取消块注释
ctrl+d 快速复制一行
ctrl+x 快速删除一行
ALT+Enter 快速提示
数组
引出:定义变量表示全班同学的年龄
问题:人数多的情况下,需要定义大量变量,操作麻烦
当计算例如平均年龄时,表达式也非常长,不方便使用
概念:可以存储多个同一数据类型的 长度固定 内容可变的容器
定义数组的格式:
格式一:数据类型[] 数组名 = {元素1,元素2,…};
例如:int[] ages = {18,16,88};
特点:当创建数组时确定数组中元素的值时,可以使用这种格式;
数组长度等于元素的个数
格式二:数据类型[] 数组名 = new 数据类型[长度];
例如:
int[] ages = new int[5];
特点:当创建数组时不知道元素的内容时,使用当前方式创建
指定了数组的长度
格式三:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};
例如:int[] ages = new int[]{18,16};
特点:格式一基于格式三来进行简化的
数组长度等于元素的个数
注意:1、数组定义 格式二和格式三支持先声明后赋值,但是简化的格式一不支持;
2、[]可以在数据类型的后边 也可以在变量名的后边(建议放数据类型后边)
//格式二
int[] ages;
ages = new int[5];
//格式三
int[] ages;
ages = new int[]{16,18};
数组基本操作:
索引(下标):元素的编号 范围:0~数组的长度-1
1、获取数组中元素的值
格式:数组名[下标]
例如:ages[0]–获取ages数组的第一个元素
int[] ages = {17,18,19};
System.out.println(ages[0]);
注意:
如果下标超出范围,编译没问题,运行会抛出异常:
ArrayIndexOutOfBoundsException–数组下标越界异常
2、设置数组元素的值/修改元素的数据值也可以
创建数组时没有直接给定元素值,之后需要给元素依次赋值
数组名[下标] = 值;
例如:ages[0] = 10;
int[] ages = new int[5];
ages[0] = 16;
System.out.println(ages[0]);
3、数组的长度
格式:数组名.length
例如:
ages.length
4、遍历数组
法一:通过for while循环
int[] ages = {16,18,20};
for (int i = 0; i <ages.length; i++) {
System.out.println(ages[i]);
}
法二:foreach-增强for循环 JDK1.5版本
应用场景:数组 集合
格式:
for(数据类型 变量名(声明了一个临时变量):数组名){
可以通过变量来使用当前数组元素的值
}
执行流程:
将数组中第一个元素赋值给变量,在循环体中可以通过变量获取到数组的元素值;
将数组中第二个元素赋值给变量,在循环体中可以通过变量获取到数组的元素值
将数组中第三个元素赋值给变量,在循环体中可以通过变量获取到数组的元素值
…
将最后一个元素赋值给变量
//增强for循环 ages数组里的数据依次给age,然后再输出
//int类型要与ages数据一致
for (int age:ages) {
System.out.println(age);
}
法三:Arrays–jdk 提供的数组的一个工具类
Arrays.toString(数组名);
如果只是为了输出打印或者要将数组所有元素都转成一个字符串
例如:
//要导包
System.out.println(Arrays.toString(ages));
//遍历数组并且修改元素的值
for (int i = 0; i <ages.length ; i++) {
ages[i] *=2;
}
System.out.println(Arrays.toString(ages));
for和foreach的区别:如果只是获取数组元素的值,两种都可以;
如果在遍历的过程中,想修改数组中元素的值:
for可以通过下标直接修改元素的值
foreach因为没有下标,当通过变量来修改时 无法影响数组的元素值
问题1:foreach循环不会影响值
for (int age:ages) {
age *= 2;
}
问题2:
直接输出数组名时 得到的值[I@28d93b30
问题3:当创建数组没有指定元素内容时,数组元素的值为什么int 是0,boolean的为false?
数组内存
内存:内存中的数据 一旦计算机重启或者意外宕机,内存中的数据全部丢失。内存处理效率高
硬盘:只要硬盘硬件不损坏,则无论计算机是否重启,数据都不会丢失;处理效率低。
Java程序运行是要占用内存空间;
操作系统在Java运行时都会单独给Java进程开辟一块内存空间;
Java内存:
1、栈内存
2、堆内存
3、方法区
4、本地方法栈
5、寄存器
栈内存:局部变量
每个方法执行时都在栈中有一块单独的空间
当方法执行完成 这块空间就会被释放
堆内存:new出来的对象
对象什么时候释放取决于垃圾回收器
垃圾回收器扫描时会判断当前对象是否还被使用,如果在使用则不会释放,如果没有被使用 则会释放空间;
垃圾回收器不由程序员来控制
空间必须有值,堆会给定默认值
默认值取决于数据类型:
byte short int:0
long:0L
float/double:0.0
char:\u0000 空字符
boolean:false
引用数据类型:null
上图:输出ages【0】时,先去栈内存中找,然后得到地址值,再根据地址值去堆内存中找
下图:用实际值将默认值替换掉
案例:下图是同一个地址值
数组的高级应用:
1、求数组所有元素的和
在遍历数组的过程中累加求和即可
普通for:
public class ArrayDemo {
public static void main(String[] args) {
int[] nums={3,16,17};
//遍历
int sum = 0;
for (int i = 0; i < nums.length ; i++) {
sum +=nums[i];
}
System.out.println("和为"+sum);
}
}
增强for循环(对于没有修改数组里面的值来说合适)
int sum = 0;
for (int num:nums) {
sum +=num;
}
System.out.println("和为"+sum);
}
2、获取数组中元素的最大值/最小值
//求数组的最大值
int[] nums={3,16,17,30,26,-11};
int max = nums[0];
for (int i = 1; i <nums.length ; i++) {
//max与数组每个元素都比较
if (max<nums[i]){
max = nums[i];
}
}
System.out.println(max);
}
}
3、反转数组
a、不改变数组 倒着输出
int[] nums ={3,16,17,30,26,1};
//i=0 nums.length-1
//i=1 nums.length-1-1
//i=2 nums.length-1-2
//i nums.length-1-i
for (int i = 0; i <nums.length ; i++) {
System.out.println(nums[nums.length-1-i]);
}
或者从后面往前输出
for (int i = nums.length-1; i >=0 ; i--) {
System.out.println(nums[i]);
}
b、直接将数组本身反转
在同一个数组中 通过下标控制进行首尾两个元素的交换
//数组反转
//nums[0] nums[nums.length-1]交换
//nums[1] nums[nums.length-1-1]
//nums[i] nums[nums.length-1-i]
// 就像两个变量交换 用临时变量可以
// 再循环交换 i要小于数组长的一半
int[] nums ={3,16,17,30,26,1};
for (int i = 0; i <nums.length/2; i++) {
int temp = nums[i];
nums[i] = nums[nums.length-1-i];
nums[nums.length-1-i] = temp;
}
System.out.println(Arrays.toString(nums));
}
}
c、创建一个新的数组 将原数组的数据倒着赋值给新数组
int[] nums ={3,16,17,30,26,1};
//先创建一个新的数组,新数组的长度由旧数组决定
int[] newNums = new int[nums.length];
for (int i = 0; i <newNums.length ; i++) {
newNums[i] = nums[nums.length-1-i];
}
nums = newNums;//将新newnums的地址给nums 变成想要的数组
System.out.println(Arrays.toString(newNums));
System.out.println(Arrays.toString(nums));
4、查找数组元素
方式一:遍历数组 一一比较(缺点查找效率低)
int [] nums = {1,22,76,45,4,45};
int snum = 45;
for (int i = 0; i <nums.length ; i++) {
if (snum == nums[i]){
System.out.println("该元素为第"+(i+1)+"个元素");
// break;
}
}
方式二:二分查找(折半查找)
前提条件:数组必须有序
int [] nums = {4,5,7,8,16,20,45};
int snum = 45;//要查的数
int min = 0;//最小下标
int max = nums.length-1;//最大下标
while (min<=max){
int mid = (min+max)/2;//中间下标
if (snum==nums[mid]){
System.out.println(mid);
break;
}else if (snum>nums[mid]){
min=mid+1;
}else if (snum<nums[mid]){
max = mid-1;
}
}
5、数组排序–排序算法
a. 冒泡排序
//冒泡排序
int [] nums = {9,2,8,1,3};
for (int i = 1; i <=nums.length ; i++) { //i表示轮数 1-数组的长度-1轮
//第i轮比较
for (int j = 1; j <=nums.length-i ; j++) {//j表示比较次数 1-数组长度-i次
//第i轮的第j次比较
if (nums[j-1]>nums[j]){ //降序把大于号改了即可
//交换位置;
int temp = nums[j-1];
nums[j-1] = nums[j];
nums[j] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
b.选择排序
// 选择升序排序
int [] nums = {9,2,8,1,3};
for (int i = 1; i <=nums.length-1 ; i++) { //i为轮数
//第i轮的比较
for (int j = i; j <=nums.length-1; j++) { //j为次数
if (nums[i-1]>nums[j]){
int temp = nums[i-1];
nums[i-1] = nums[j];
nums[j] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
可以通过每轮比较记录最小值的下标,来实现每轮至多交换一次的效果;可以提高排序的效率
//选择排序的优化
int [] nums = {9,2,8,1,3};
for (int i = 1; i <nums.length ; i++) {
int index = i-1;//表示最小值的下标 初始为当前元素
for (int j = i; j <=nums.length-1 ; j++) {
if (nums[index]>nums[j]){//判断index指向的元素是否为最小值
index = j;//认为j为最小值,给index
}
}
if (index!=i-1){ //判断是否需要交换
//交换
int temp = nums[index];
nums[index] = nums[i-1];
nums[i-1] = temp;
}
}
System.out.println(Arrays.toString(nums));
c.插入排序 快速排序 归并排序(面试前选择一个准备一下)
**但是开发时给了工具类
Arrays.sort(数组名);注意:默认只能升序排序
int [] nums = {9,2,8,1,3};
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
d、数组的"扩容"、复制
int[] ages = new int[10];
数组一旦创建 长度固定不可变
a1、自己实现扩容
创建新的数组 长度为扩容之后的长度
将原来数组的数据拷贝到新数组中
将新数组的地址赋值给原数组
int [] ages = {18,16,29,10,22};//原数组
//假设要在以上数组中增加两个元素
//数组一旦创建长度不变
//创建新的数组
int[] newAges = new int[ages.length+2];
//将原数组的数据拷贝到新数组中
for (int i = 0; i <=ages.length-1 ; i++) {
newAges[i] = ages[i];
}
newAges[5] = 30;
newAges[6] = 31;
System.out.println(Arrays.toString(newAges));
//将新数组赋值给原数组变量
ages = newAges;//把newAges的值赋值给ages
System.out.println(Arrays.toString(ages));
扩容实际是新开辟地址
a2、System.arraycopy() (直接帮我们实现扩容)
src:原数组名
srcPos:原数组起始元素的下标
dest:新数组名
destPos:新数组起始元素的下标
length:元素的个数
int [] ages = {18,16,29,10,22};
int[] newAges = new int[ages.length+2];
System.arraycopy(ages,0,newAges,0,ages.length);
System.out.println(Arrays.toString(newAges));
a3、Arrays.copyOf()
实际底层就是arraycopy方法
int [] ages = {18,16,29,10,22};
//Arrays已经帮你拿到了数组,要想拿这个数组就要赋值给这个数组类型的变量
// int[] newAges = Arrays.copyOf(ages,7);//并不会改变原有的ages数组
// ages = Arrays.copyOf(ages,7);
//长度比原来小是缩容 大是扩容
ages = Arrays.copyOf(ages,3);//新数组地址值赋值给原数组
System.out.println(Arrays.toString(ages));
注意:1、基于System.arraycopy()实现的
2、copyOf支持扩容和缩容
二维数组
概念:数组的每个元素又是一个一维数组的
定义格式:
格式一:数据类型[ ] [ ] 数组名 = {{元素11,元素12,…},{元素21,元素22,…},…};
例如:
int[ ][ ] agess = {{16,18},{12,15,14}};
理解:
1、二维数组包含了两个一维数组
2、第一个一维数组包含了两个元素;第二个一维数组包含了三个元素;
特点:
1、在定义数组时确定每个元素具体的值
2、二维数组的长度:一维数组的个数
格式二:
数据类型[ ][ ] 数组名 = new 数据类型[一维数组的个数] [ 每个一维数组中元素的个数 ];
例如:int[][] agess1 = new int[3][5];
理解:
agess1二维数组包含了3个一维数组
每个一维数组中包含了5个元素
特点:
每个一维数组中元素的个数都是一致
格式三:数据类型 [ ][ ] 数组名 = new 数据类型[一维数组的个数][ ];
例如:int[ ][ ] agess2 = new int[3][ ];
特点:指定当前二维数组包含了几个一维数组 但是每个一维数组元素个数没有指定
基本使用:
1、获取下标对应的一维数组对象
数组名[下标]
int[ ][ ] agess = {{16,18},{12,15,14}};
agess[0]–获取二维数组的第一个一维数组
2、获取下标为i的一维数组的下标为j的元素值
数组名[i][j]
3、二维数组的长度–一维数组的个数
数组名.length
4、取指定一维数组中元素的个数
数组名[下标].length
int[][] ages = {{16,17},{15,20,22}};
System.out.println(ages);
System.out.println(ages[0]);
System.out.println(ages[1]);
//获取第一个一维数组的第一个元素
System.out.println(ages[0][0]);
System.out.println(ages[1][0]);
//获取一维数组的个数
System.out.println(ages.length);
//获取第一个一维数组中元素的个数
System.out.println(ages[0].length);
System.out.println(ages[1].length);//第二个
5、遍历二维数组
普通for循环
二维数组的内存结构: