day3--java基础编程:方法,重载,可变参数,递归,数组,冒泡排序
3 Day04–循环
3.1 循环结构1:for
3.1.1 概述
循环结构是指在程序中需要反复执行某个功能而设置的一种程序结构。它由循环体中的条件,判断继续执行某个功能还是退出循环。根据判断条件,循环结构又可细分为先判断后执行的循环结构和先执行后判断的循环结构。
for循环的优点:for循环语句是支持迭代的一种通用结构,是最有效,最灵活的循环结构。
循环三要素:
- 循环变量的初始化
- 循环的条件,是布尔类型 (以循环变量为基础)
- 循环变量的改变(向着循环的结束变)
循环变量:在整个循环过程中所反复改变的那个数.
3.1.2 形式
for(开始条件;循环条件;更改条件){
循环体代码…
}
For循环的特殊用法:
1. 死循环
For(; ;){ //死循环
}
2. 可以拆开写
int i=1;
for(;i<10;i++){ //向上拆
}
for(int i=1;i<10;){ //向下拆
i++; //注意这个地方多了个分号(;)}
3. 可以同时声明2个数:
for(int i=1,j=6;i<6;i+2,j--){
} //for中表达式一和表达式三可以使用逗号,而表达式二多个只能使用 &&, || ,!(且,或,非)
3.1.3 练习1:打印0到10
package cn.tedu.fordemo;
//测试for循环
public class Test8_For {
public static void main(String[] args) {
//for( 开始条件 ; 判断条件 ; 更改条件 ){ 循环体 }
// 打印0到10
//i用来记录每次获取到的值,默认是从0开始
//i定义在for循环里面:在for循环内有效。出了for循环就失效了。
for( int i = 0 ; i <= 10 ; i++){
System.out.println(i);
}
}
}
3.1.4 练习2:打印10到0
//从10开始,只要>=0,就打印,打印的数据依次递减
for( int i = 10 ; i >= 0 ; i-- ){
System.out.println(i);
}
3.1.5 练习3:打印8,88,888,8888
for( int i = 8 ; i <= 8888 ; i=i*10+8 ){
System.out.print(i+",");//同行展示数据。如8,88,....
}
3.1.6 练习4:求【1,100】中,奇数的个数,偶数的个数
int count = 0,为什么不是int count而要多赋值为0呢??在day03异常时讲的.
int count = 0;//定义变量,记录奇数的个数
int oucount = 0;//定义变量,记录偶数的个数,(定义为0,下面赋值不会影响程序)
for(int i = 1 ; i <= 100 ; i++) {
//判断,如果是奇数
if( i % 2 == 1 ) { //也可以写!=0
count++;//每次遇到一个奇数就+1
}
//判断,如果是偶数
if( i % 2 == 0 ) {
oucount++;//每次遇到一个偶数就+1
}
}
System.out.println("奇数的个数是:"+count+",偶数的个数是:"+oucount);
3.1.7 练习5:求【1,100】中,偶数的和奇数和
int sum = 0;//定义变量,记录偶数和
int jisum = 0;//定义变量,记录奇数和
for(int i = 1 ; i <= 100 ; i++) {
//判断,如果是偶数
if(i % 2 == 0) {
//对获取到的每个偶数求和
sum = sum + i;
}
//判断,如果是奇数
if(i % 2 == 1) { //或则i%2!=0也行
jisum = jisum + i;//把每个奇数求和
}
}
System.out.println("偶数和是:"+sum+",奇数和是:"+jisum);
3.2 嵌套for循环
3.2.1 概述
根据外层的条件,判断里层能否执行,如果能执行,就把里层代码都循环完毕后,再继续执行外层,继续判断。。
3.2.2 形式
for(…){
for(…){
}
}
3.2.3 入门案例
package day0000;
/*
嵌套循环的使用
1.嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环
2.
外层循环:循环结构B
内层循环:循环结构A
3. 说明
① 内层循环结构遍历一遍,只相当于外层循环循环体执行了一次
② 假设外层循环需要执行m次,内层循环需要执行n次。此时内层循环的循环体一共执行了m * n次
4. 技巧:
外层循环控制行数,内层循环控制每行的列数
*/
public class T {
public static void main(String[] args) {
// f1();
f2();
}
//总结1:当i=1时,j取到了所有满足条件的数据,1,2,3,4,5。
//也就是说外循环执行1次,内循环执行多次
private static void f1() {
for(int i=1;i<=3;i++){//外循环
System.out.println("i="+i);//1,2,3
for(int j=1;j<=5;j++){//内循环
System.out.println("j="+j);//1,2,3,4,5
}
}
}
//总结2:外循环控制行,内循环控制列
private static void f2() {
for(int i=1;i<=3;i++){
for(int j=1;j<=5;j++){
System.out.print("*");
}
System.out.println();
}
}
}
3.2.4 练习1:打印正方形
****
****
****
****
for(int i=1;i<5;i++){
for(int j=1;j<5;j++){
System.out.print("*");
}
System.out.println();
}
3.2.5 练习2:打印左直角三角形
*
**
***
****
*****
//正直角三角形
private static void f4() {
for (int i = 0; i < 5; i++) {//外循环,控制行,是一定的
for (int j = 0; j <= i; j++) {//内循环,列是不固定的,是递增的
System.out.print("*");//保证第一行打印出来一个*,注意条件
}
System.out.println();
}
}
3.2.6 练习3:打印99乘法表
//99乘法表 正序
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
private static void f4() {
for (int i = 1; i < 9; i++) {//外循环,控制行,是一定的
for (int j = 1; j <= i; j++) {//内循环,列是不固定的,是递增的
System.out.print(i+"*"+j+"="+i*j+" ");//保证第一行打印出来一个*,注意条件
}
System.out.println();
}
}
//乘法表倒序
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*4=4 2*4=8 3*4=12 4*4=16
1*3=3 2*3=6 3*3=9
1*2=2 2*2=4
1*1=1
for(int i=9;i>=1;i--) {
for(int j=1;j<=i;j++) {
System.out.print(j+"*"+i+"="+i*j+"\t");
}
System.out.println();
}
3.2.7 练习4:打印右直角三角形
打印右直角
*
**
***
****
*****
package day999;
public class a {
public static void main(String[] args) {
//输出5行
for(int i=1;i<=5;i++){
//空格三角
for(int x=5;x>i;x--){//还可以改为:for(int x=1;j<=5-i;x++)
System.out.print(" ");
}
//*号三角
for(int j=1;j<=i;j++){
System.out.print("*");
}
System.out.println();
}
}
}
3.2.8 练习5:打印全三角形
打印全三角
*
***
*****
*******
*********
package day999;
public class a {
public static void main(String[] args) {
//打印5行
for(int i=1;i<=5;i++){
//打印空格的倒三角(原理是:每轮输出一个空格)
for(int j=5;j>=i;j--){ //可换:for(int j=1;j<=5-i;j++)
System.out.print(" ");
}
//打印*号的正三角
for(int k=1;k<=i*2-1;k++){
System.out.print("*");
}
System.out.println();
}
}
}
3.3 增强for循环
package lianxi;
import java.util.Random;
import java.util.Scanner;
public class Ta {
public static void main(String[] args) {
int [] numbers = {10,20,50,7,0,9,22,11};//定义一个数组
for (int aa: numbers) {
System.out.println(aa);
}
}
}
3.4 break和continue
用来终止循环,可以用这两种方式。
注意事项:break,continue直接项后面不能声明语句,否则编译或报错。如下图:
3.4.1 形式
break: 中断当前循环,简单粗暴
for(){
代码1
if(条件){
代码3…
break;//如果成立,直接跳出这个for循环
}
代码2…
}
continue:跳出本次循环,进入下一轮
for(){
代码1
if(条件){
代码3…
continue;//如果成立,跳出本次for循环,进入下一轮
}
代码2…
}
3.4.2 练习1:找数字88
接收用户输入的100次数字,如果不是88继续输入,找到88就返回
package cn.tedu.breakdemo;
import java.util.Scanner;
//测试break和continue
//总结:break和continue都可以结束循环。
//1,break可以立刻结束循环简单粗暴。continue是结束当前循环可以继续下一次循环。
//2,break和continue之后都不能出现代码,出现了也是不可到达的代码
public class Test3_Break {
public static void main(String[] args) {
for(int i = 1 ; i <= 100 ; i++) {
//1,接受用户输入的数字
int input = new Scanner(System.in).nextInt();
//2,判断是不是88
if(input == 88) {//是88
System.out.println("中了");
break;//程序结束
}else if(input != 88) {//不是88
continue;//继续输入
}
}
}
}
3.5 循环结构2:while
先判断,再执行
3.5.1 格式
while(执行条件){
代码…
}
3.5.2 练习1:产生随机数1~100,猜数字
产生一个随机数,和用户一直在输入的数字比较。
生成随机数具体查看Api
package cn.tedu.whiledemo;
import java.util.Random;
import java.util.Scanner;
/**
*测试while循环
*总结:
* 1.while也是一种循环结构:while(循环条件){循环体}
* 2.while(true)是简单的实现了死循环的形式,for也可以实现代码显得复杂一些。
* 3.这种结构 -- 先判断,再执行
*/
public class Test4_While {
public static void main(String[] args) {
/**
* 产生随机数的2种方法:
* 第1种:int num=(int)(Math.random()*1000+1); 生成随机数1~1000
* 解释:Math.random()返回的是0(包含)到1(不包含)之间的double值,转化为整数需要强转。
* 第2种:int random = new Random().nextInt(100) +1; 生成随机数1~100
* 解释:要产生m以内的随机数,默认从0开始 ,不包括m 如:0~100 不包括100(0~99)可以加个1变为(1~100)
*/
//1,让程序产生随机数
int random = new Random().nextInt(100) +1;
System.out.println(random);
//2,开始猜 --重复做a b的事情,放入循环结构中
//while(random > 50) {
//for形式的死循环:让循环条件一直为true就行
//for(int i = 1; i >= 1 ; i++ ) {
while(true) { //死循环 -- 必须设置程序的出口!!
//a,接受键盘输入的值
int input = new Scanner(System.in).nextInt();
//b,拿到输入的值,和 ,random去比
if(input > random) {
System.out.println("大了");
}else if(input < random) {
System.out.println("小了");
}else if(input == random) {
System.out.println("中了");
break;//程序结束 -- 死循环的出口!!!
}
}
}
}
3.5.2 练习2:产生随机数10~100
//如何获取一个随机数:10 - 99
// [0.0,1.0) --> [0.0,90.0) --->[10.0, 100.0) -->[10,99]
/*解释:
Math.random()生成double类型的值:[0.0,1.0),包含0无限接近于1。
乘以90变为[0.0,90.0),包含0无限接近于90。
加10变为[10.0, 100.0),包含10无限接近于100(99.99999999...)。
在强转为int类型,舍弃掉小数位变成-->[10,99]
*/
int value = (int)(Math.random() * 90 + 10);
System.out.println(value);
//公式:[a,b] : (int)(Math.random() * (b - a + 1) )+ a
3.6 循环结构3:do-while
先执行,再判断
3.6.1 格式
do{
代码…
}while(执行条件); //注意这里有个分号
3.6.2 练习1:猜数字
产生一个随机数,和用户一直在输入的数字比较。
package cn.tedu.whiledemo;
import java.util.Random;
import java.util.Scanner;
//测试do...while循环
//总结:
//do...while 结构,保证循环体代码 ,最少,执行一次
//能不能继续循环,要看能不能满足循环条件
public class Test5_Dowhile {
public static void main(String[] args) {
int random = new Random().nextInt(100) + 1;
System.out.println(random);
do {
// a,接受键盘输入的值
int input = new Scanner(System.in).nextInt();
// b,拿到输入的值,和 ,random去比
if (input > random) {
System.out.println("大了");
} else if (input < random) {
System.out.println("小了");
} else if (input == random) {
System.out.println("中了");
break;// 程序结束 -- 死循环的出口!!!
}
}while (random > 50);//明确循环条件
}
}
3.7 总结:三种循环的区别
三种循环都可以互相代替
1、for:知道循环次数(应用率最高)
2、while/do while:当循环次数不确定时
3、while:先判断,不符合规则,不执行代码(有可能一次都不执行)
4、do while:代码最少被执行一次,再去判断,符合规则,再次执行代码。
如何判断是用哪个循环?
1.如果与次数有关则用for循环
2.在判断条件1和条件3是否相同:如果相同则用do while 不同则用while (变量初始化,条件, 改变量)
4 Day05–方法+数组
4.1 方法
4.1.1 概述:方法(函数,过程)
1.方法:封装一段特定的业务逻辑功能。
2.方法尽可能的独立,一个方法只干一件事。
3.方法可以被反复多次调用。
4.减少代码的重复,有利于代码的维护,有利于团队的协作。
5.方法可以有参,也可以无参,多个参数用逗号隔开(看需求)。
6.方法与方法是同级并列关系。
7. 方法名命名规则:驼峰命名法。
8. 方法里面可以调用别的方法,但是方法里面不能定义方法。
4.1.2 形式
修饰符 返回值类型 方法名(参数列表){
方法体;
return 返回值;// void(无返回值) int,double,String…有返回值
}
4.1.3 练习1:方法调用
方法调用:根据方法的签名来调用。
方法的签名:方法名+参数列表
语法:
- 无返回值类型(void):
方法名(有参传参);
- 有返回值类型:
数据类型 变量 = 方法名(有参传参);
注意:
- 在一个类中,不可以有2个方法的签名完全相同。
- 只要返回值类型不为void,就一定有返回值retuen,接收时就需要声明一个数据类型来接收。
- 实参: 在调用方法时传递的参数(可以是确定的数 也可以是不确定的数)
- 形参: 定义方法时,在方法的参数列表定义的参数。
- 在方法调用时,会将实际的参数值传递给方法的参数变量。必须保证传递参数的类型和个数符合方法的声明。
说明:下面的调用都是在同一个类
中方法之间的调用,并且需要把方法修饰为static静态资源,因为静态方法之间可以相互调用。
如果想要在静态资源中调用非静态资源可以通过创建对象的方式调用。
package cn.tedu.method;
//包名可以直接在代码上修改,鼠标放上去会提示创建没有的包。
//同理 :类也一样
//测试方法的使用+-------------------------------
public class Test6_Method {
public static void main(String[] args) {
System.out.println(1);
function();//调用了指定的function()
System.out.println(2);
}
//创建function() 如果没有在main方法中调用方法,则程序不会主动执行这个方法。
//修饰符 返回值 方法名(参数列表){方法体}
public static void function() {
System.out.println(3);
System.out.println(4);
System.out.println(5);
}
}
通过创建对象可以在静态调用非静态:
package com.cn.ins;
//包名可以直接在代码上修改,鼠标放上去会提示创建没有的包。
//同理 :类也一样
//测试方法的使用+-------------------------------
public class Test6_Method {
public static void main(String[] args) {
System.out.println(1);
// function();//调用了指定的function()
System.out.println(2);
Test6_Method a=new Test6_Method();
a.function();
}
//创建function() 如果没有在main方法中调用方法,则程序不会主动执行这个方法。
//修饰符 返回值 方法名(参数列表){方法体}
public void function() {
System.out.println(3);
System.out.println(4);
System.out.println(5);
}
}
4.1.4 练习2:方法传参
package cn.tedu.method;
//测试方法的使用
public class Test6_Method {
public static void main(String[] args) {
System.out.println(1);
// function();//调用了指定的function()
// param(10);//方法传参
// param2("jack",10);//传两参数--叫实参
//注意:调用方法时传的参数叫做实参,不管是数字还是一个变量都是实参
// param3(5,10,"jack"); 参数的个数和类型相同,但是顺序不同也代表参数列表不同,方法不同。
param4("jack",5,10);
System.out.println(2);
//在括号外面赋值,与方法内直接赋值一样。
int m=10;
String n=”rose”;
Param5(m,n);
}
//创建param5的方法
public static void param5(inta,String b) {
System.out.println(a+b+);
}
//TODO 创建param4("jack",5,10) --方法传参:参数类型必须匹配
public static void param4(String a,int b,int c) {
System.out.println(a+b+c);//jack510
}
//TODO 创建param3(5,10,"jack") --方法传参:参数类型必须匹配
//多个参数之间用”,”隔开。
public static void param3(int a,int b,String c) {
//+在数字间是加法运算,和字符串+是拼接字符串
System.out.println(a+b+c);//15jack
}
//创建param2("jack",10) --方法传参:参数类型必须匹配
//String n,int a -- 叫形参:方法里面的参数叫形参
public static void param2(String n,int a) {
System.out.println(n);
System.out.println(a);
}
//创建param() --方法传参:参数类型必须匹配
//修饰符 返回值 方法名(参数列表){方法体}
// public static void param(参数类型 参数名) {
public static void param(int num) {
System.out.println(num);
}
//创建function()
//修饰符 返回值 方法名(参数列表){方法体}
public static void function() {
System.out.println(3);
System.out.println(4);
System.out.println(5);
}
}
4.1.5 练习3:方法返回值
return 返回值;
:方法结束后可以返回一个数据,称之为返回值,方法在声明时必须指定返回值的类型。
注意:
- 方法可以有返回值,也可以没有返回值(void)。
- return直接项之后不可以声明执行语句类似于break和continue,否则编译就会报错。
何时有返回值?何时无返回值?
当方法执行结束时:
- 若还需要用到方法中的某一个数据----有返回值(返回值类型不能为void,和return连用,有返回值就需要定义一个变量或数组来接受它。)
- 若不在需要用到方法中的某一个数据----没有返回值(返回值类型为void,不需要写return.)
Return两种形式的作用?
第一种:return 值 ;
1.结束方法的执行
2.返回给调用方。(注意:只要有返回值类型一定有return 数值)
第二种: return ;
3.结束方法的执行(注意:无返回值类型不需要写return,因为程序执行完照样结束,直接写没有意义。有时可以和if分支结构连用,用于跳出程序。)
package cn.tedu.method;
//测试方法返回值
public class Test7_Method2 {
public static void main(String[] args) {
//result记录着method()的执行结果a b的和
int result = method(10,5);
System.out.println(result);
//TODO
String name = method2("jack","rose","jerry");
System.out.println(name);
}
//TODO 创建 method2("jack","rose","jerry")
public static String method2(String a,String b,String c){
return a+b+c;//返回值不单单是一个变量,数。也可以返回一个式子
}
//创建method(10,5)
//注意:方法的返回值要和result变量的类型一致
public static int method(int a,int b) {
//通过 return 可以把方法执行的结果,返回给,调用位置!!
return a+b;
}
}
//注意:例子,返回的是不同类型看是否是字符串拼接,用String
String sum2=method("jack",10,5);
System.out.println(sum2);
public static String method(String c,int a,int b) {
return c+a+b; //这里是一个字符串的拼接所以用String类型。返回值类型与return后的类型一致。
}
4.2 方法的重载Overload
4.2.1 概念
1.方法重载是指在同一个类中,方法名相同,参数列表不同,方法体一般不同,相同没啥意义。重载和方法体没有关系。
2.编译器在编译期间会根据方法的签名自动绑定调用不同的方法。(我们可以把重载的方法可以看成是完全不同的方法,只不过恰恰好方法名相同而已。
3.重载针对的是方法。
注意:判断方法重载跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
重载的意义:对于程序员而言,需要记忆的方法名很简单只需要记住一个名字的方法,方法的参数可以很灵活的传入。
参数列表不同:包括参数类型,顺序,个数。
4.2.2 练习1:数字求和
package cn.tedu.overload;
//测试方法重载:
//要求:方法名相同+参数列表不同
//意义:由于用户在使用时,传入的参数我们不知道,为了体现我的程序非常的灵活
//尽量多提供一些参数不同,名字相同的方法
public class Test8_Overload {
public static void main(String[] args) {
add(5);
add(10,5);
add("jack",5);
add(10,"rose");
//TODO
print(10);
print("jerry");
print('中');
}
//创建add(10,"rose")
public static void add(int a,String b) {
System.out.println(a+b);//10rose
}
//创建add("jack",5)
public static void add(String a,int b) {
System.out.println(a+b);//jack5
}
//创建add(10,5)
public static void add(int a,int b) {
System.out.println(a+b);
}
//创建add(5)
public static void add(int a) {
System.out.println(a*a);
}
}
//总结:方法,传参,数据类型与参数列表保持一致,(即:个数,类型,顺序保持一致)。
//返回值:若有返回值应与返回值类型,返回值接收的类型保持一致。
//如:
public static void main(String[] args) {
//方法练习
method(2,3,"小明");
String aa=method2(2,3,"小红");
System.out.println(aa);
}
public static void method(int a,int b,String c) {
System.out.println(a+b+c);
}
public static String method2(int a,int b,String c) {
return a+b+c;//有String类型,int 类型。它拼接的是字符串类型,所以应该用String作为它的返回值类型,它的接受值也是String类型。
}
4.2.3 练习2:数据的打印
package day004;
public class Test07 {
public static void main(String[] args) {
// TODO Auto-generated method stub
print(10);
print(2.2);
print(true);
print("jack");
}
public static void print(int a) {
System.out.println(a);
}
public static void print(double a) {
System.out.println(a);
}
public static void print(boolean a) {
System.out.println(a);
}
public static void print(String name) {
System.out.println(name);
}
}
4.2.4 练习3:重载的自动类型提升
方法重载时,如果调用方法时输入的实参没有对应的方法,而恰好又满足自动类型转换,则会调用符合条件的大类型的方法。
package com.cn.ca;
public class StudentTest {
public static void main(String[] args) {
Teacher teacher = new Teacher();
/*解释:自动类型提升
* getSum方法没有注释之前根据方法的调用规则,调用getSum(int i,int j)输出为1
* getSum方法没有注释之后虽然调用时输入的值为int类型,但会自动类型提升,调用getSum(double d1,double d2)输出为2
*/
teacher.getSum(1, 5);
}
}
class Teacher{
// public void getSum(int i,int j){
// System.out.println("1");
// }
public void getSum(double d1,double d2){
System.out.println("2");
}
}
4.3 可变参数
可变参数本质上是数组。
package com.cn.ca;
/*
* 可变个数形参的方法
*
* 1.jdk 5.0新增的内容
* 2.具体使用:
* 2.1 可变个数形参的格式:数据类型 ... 变量名
* 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
* 2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
* 2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
* 2.5 可变个数形参在方法的形参中,必须声明在末尾
* 2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参。
* 2.7 同一类型普通方式优先级比可变参数更高
* 2.8 遍历方式和数组相同
*
*
*/
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest test = new MethodArgsTest();
test.show(12);
// test.show("hello");
// test.show("hello","world");
// test.show();
//调用方法形参是数组相比是可变参数更麻烦些,当然这个数组的调用方式也可以调用可变参数
test.show(new String[]{"AA","BB","CC"});
}
public void show(int i){
}
public void show(String s){//同一类型普通方式优先级比可变参数更高
System.out.println("show(String)");
}
public void show(String ... strs){//调用时输入的参数可以是0个,可以是多个
System.out.println("show(String ... strs)");
for(int i = 0;i < strs.length;i++){//遍历方式和数组相同
System.out.println(strs[i]);
}
}
/*不能与上一个方法同时存在String[] strs和String ... strs,
编译器认为方法名相同 参数列表相同的数组和可变参数是同一个方法,不能共存。
*/
// public void show(String[] strs){
//
// }
//The variable argument type String of the method
//show must be the last parameter
// public void show(String ...strs,int i){ 多个参数,可变参数只能声明在最后
//
// }
}
4.4 方法的值传递
4.4.1 回顾:变量的赋值操作
package com.cn.ca;
/*
*
* 关于变量的赋值:
*
* 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
* 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
*
*/
public class ValueTransferTest {
public static void main(String[] args) {
System.out.println("***********基本数据类型:****************");
int m = 10;
int n = m;
System.out.println("m = " + m + ", n = " + n);//m = 10, n = 10
n = 20;
System.out.println("m = " + m + ", n = " + n);//m = 10, n = 20
System.out.println("***********引用数据类型:****************");
Order o1 = new Order();
o1.orderId = 1001;
Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);//o1.orderId = 1001,o2.orderId = 1001
o2.orderId = 1002;//改变了o2的值 o1也随之改变
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);//o1.orderId = 1002,o2.orderId = 1002
}
}
class Order{
int orderId;
}
4.4.2 同理:方法的形参赋值操作–基本数据类型
package com.cn.ca;
/*
* 方法的形参的传递机制:值传递
*
* 1.形参:方法定义时,声明的小括号内的参数
* 实参:方法调用时,实际传递给形参的数据
*
* 2.值传递机制:
* 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
* 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
*
*/
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("m = " + m + ", n = " + n);//m = 10, n = 20
//交换两个变量的值的操作
// int temp = m ;
// m = n;
// n = temp;
ValueTransferTest1 test = new ValueTransferTest1();
test.swap(m, n);
System.out.println("m = " + m + ", n = " + n);//m = 10, n = 20 此时仍输出的是main中的m n而不是swap方法中的m n
}
public void swap(int m,int n){//相当于是把10 20赋值给了新的变量m n,形参是局部变量出了方法就失效
//如果复制的是引用地址,堆的数据只有一份可以交换成功,出了方法也不会失效
int temp = m ;
m = n;
n = temp;
System.out.println("m = " + m + ", n = " + n);//m = 20, n = 10
}
}
4.4.3 同理:方法的形参赋值操作–引用数据类型
package com.cn.ca;
public class ValueTransferTest2 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println("m = " + data.m + ", n = " + data.n);//m = 10, n = 20
//交换m和n的值
// int temp = data.m;
// data.m = data.n;
// data.n = temp;
ValueTransferTest2 test = new ValueTransferTest2();
test.swap(data);
System.out.println("m = " + data.m + ", n = " + data.n);//m = 20, n = 10交换成功
}
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
4.5 递归
注意:
- 递归层级不能太多,如果过多会导致电脑效率大大降低。
- 能不用递归就不用,可以通过其它一些算法来实现。
4.5.1 递归案例练习
package com.atguigu.java2;
/*
* 递归方法的使用(了解)
* 1. 递归方法:一个方法体内调用它自身。
* 2. 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无需循环控制。
* 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
*
*/
public class RecursionTest {
public static void main(String[] args) {
// 例1:计算1-100之间所有自然数的和
// 方式一:for循环
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println(sum);
// 方式二:递归
RecursionTest test = new RecursionTest();
int sum1 = test.getSum(100);
System.out.println(sum1);
System.out.println("*****************");
int value = test.f(10);
System.out.println(value);
}
// 例1:计算1-n之间所有自然数的和
public int getSum(int n) {// 3
if (n == 1) {
return 1;
} else {
return n + getSum(n - 1);
}
}
// 例2:计算1-n之间所有自然数的乘积:n! 阶乘如5*4*3*2*1
public int getSum1(int n) {
if (n == 1) {
return 1;
} else {
return n * getSum1(n - 1);
}
}
//例3:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
//其中n是大于0的整数,求f(10)的值。
public int f(int n){
if(n == 0){
return 1;
}else if(n == 1){
return 4;
}else{
// return f(n + 2) - 2 * f(n + 1);
return 2*f(n - 1) + f(n - 2);
}
}
//例4:斐波那契数列
//例5:汉诺塔问题
//例6:快排
}
4.6 数组
4.6.1 数组的概述和分类
概述:数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
数组的分类:
- ① 按照维数:一维数组、二维数组,…
- ② 按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
4.6.2 数组相关的概念
数组Array的标志是:[ ]
获取数组中的元素值:可以通过元素的下标来获取,下标是从0开始的,下标的最大值是它的长度-1。
下标:又叫作角标、索引
数组的长度:元素的个数
数组的类型:数组 Array是引用类型,储存的是地址,地址在空间中占得内存很少(就是一串数字)。数组的元素,既可以是基本数据类型,也可以是引用数据类型
4.6.3 数组的特点
- 数组是有序排列的。
- 创建数组对象会在内存中开辟一整块连续的空间。
- 数组的长度是确定的,一旦创建,就不能修改。
- 数组中的元素是相同类型,不允许出现混合类型。
- 数组属于引用数据类型的变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型。
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的的成员变量。
数组本身就是对象,java中对象是在堆中,因此数组数组无论保存原始类型还是其它对象类型,数组对象本身是在堆中的。
4.6.4 一维数组的声明
一般分为动态初始化和静态初始化.
语法:
数组类型[ ] 数组名 = 数组对象;//推荐使用
或者
数组类型 数组名[ ] = 数组对象;//不推荐使用,这是c++语言的习惯,早期为了c++的程序员学习java创建的。
案例:
动态初始化:先声明后赋值,需要指定存入的元素个数。
int[] a = new int[4];//数组的类型应该与所存入的每一个数据类型一致
a[0] =1;
a[1] =4;
a[2] =7;
a[3] =5;
静态初始化:声明数组的同时赋值
int[] b = new int[]{1,2,3,4,5};//数组之间的元素用逗号隔开。
int[] c = {1,2,3,4,5};//简写形式
数组的默认初始化:数组是引用类型,它的元素相当于类的实例化变量,因此数组已经分配空间,其中每个元素也按照实例变量同样的方式被隐式初始化。
int[] aa = new int[5];
此时已经在内存中分配好空间了,每个元素的默认值都为int类型的值 0.
4.6.5 数组的长度
- length属性获取数组长度。
- 数组一旦创建,长度不可变 ,即:数组是定长的。
- 允许0长度的数组。
4.6.6 数组的边界
4.6.7 练习1:数组中存入hello
package cn.tedu.array;
import java.util.Scanner;
//这个类用来测试数组的创建
public class Test1_Array {
public static void main(String[] args) {
//1,创建数组。存入hello
//确定数组类型,数组长度
// 静态
//因为每个格子放一个字符,所以用char类型。
char[] a = new char[] {'h','e','l','l','o'};
char[] b = {'h','e','l','l','o'};
System.out.println(a);
System.out.println(b);
// 2,动态 创建数组,需要,指定数组的长度!!
char[] c = new char[5];
//注意:存字符串是用的char 数组。不是string
//3,数组中的元素都有下标,默认从0开始
c[0]='h';//给第1个元素,也就是下标为0的元素,赋值
c[1]='e';//给第2个元素,也就是下标为1的元素,赋值
c[2]='l';//给第3个元素,也就是下标为2的元素,赋值
c[3]='l';//给第4个元素,也就是下标为3的元素,赋值
c[4]='o';//给第5个元素,也就是下标为4的元素,赋值
//4,java.lang.ArrayIndexOutOfBoundsException数组下标越界异常
//原因是数组的长度如果是5,最大下标是4,根本不存在下标为5的情况,下标5超出范围
//c[5]='o';//给第6个元素,也就是下标为5的元素,赋值 --- 报错!!
System.out.println(c);
}
}
4.7 数组的遍历
从头到尾,依次访问数组的位置。
4.7.1 形式
1.普通for循环
for(从下标为0的位置开始;到数组长度-1结束;下标++){
循环体代码
}
2.增强for循环,但是取不到下标。
for(声明语句:表达式){
循环体代码
}
4.7.2 练习1:增强for循环遍历
package lianxi;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Ta {
public static void main(String[] args) {
int[] arrays = {1,3,6,3,8,9,0};
for(int aa:arrays) {
System.out.println(aa);
}
}
}
4.7.3 练习2:输出每个月的天数
package cn.tedu.array;
//数组练习
public class Test2_Array2 {
public static void main(String[] args) {
method();// 输出每个月的天数
}
// 创建method()
public static void method() {
// 1,静态创建数组
int[] days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// 2,用下标遍历数组
// i代表了下标
// int i = 0 ,从下标 0开始
// i <= days.length-1,到下标的最大值结束
// i++,依次向后遍历
for (int i = 0; i <= days.length - 1; i++) {
// days[i] 指days数组中,每个下标存着的值
System.out.println((i + 1) + "月有" + days[i] + "天");
}
}
}//直接输出数组则输出的是地址,输出对应的下标才是它代表的元素
依次输出数组中每个下标代表的元素。
4.7.4 练习3:遍历数组,存入1到10
package lianxi;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Ta {
public static void main(String[] args) {
//1,动态 创建数组
int[] a = new int[10];
System.out.println(Arrays.toString(a));//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
//2,遍历数组,存数据
for(int i = 0 ; i <= a.length-1 ; i++ ) {
//获取每个元素a[i]
a[i] = i+1;
}
//3,查看数组中的元素
System.out.println(a);//[I@659e0bfd]
/**
* 除了char数组可以直接输出里面的元素,其它的数组都是地址.
* 想看不是char[]的数组里的元素是啥--Arrays工具类 toString()可以将指定的数组数据显示成一个字符串
*/
System.out.println(Arrays.toString(a));//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
}
直接输出数组:
4.7.5 练习4:创建随机数组
获取100以内的随机值的数组:new Random()方式
// 创建method3()
public static void method3() {
//1, 动态 创建数组
int a[] = new int[10];
//2. 遍历数组,重新赋值
for(int i = 0 ; i <= a.length-1 ; i++) {
//a[i]获取元素
a[i]=new Random().nextInt(100);
}
//3. 查看数组里的元素
System.out.println(Arrays.toString(a));
}
4.7.6 练习5:创建随机数组求 最大 最小 平均数
获取[10,99]以内的随机值的数组:new Random()方式
package com.atguigu.java;
/*
* 算法的考查:求数值型数组中元素的最大值、最小值、平均数、总和等
*
* 定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,
* 然后求出所有元素的最大值,最小值,和值,平均值,并输出出来。
* 要求:所有随机数都是两位数。
*
* [10,99]
* 公式:(int)(Math.random() * (99 - 10 + 1) + 10)
*
*/
public class ArrayTest1 {
public static void main(String[] args) {
int[] arr = new int[10];
for(int i = 0;i < arr.length;i++){
arr[i] = (int)(Math.random() * (99 - 10 + 1) + 10);
}
//遍历
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
System.out.println();
//求数组元素的最大值
int maxValue = arr[0];//注意这个地方写 0,如果里面的值都是负数无法比较。
for(int i = 1;i < arr.length;i++){
if(maxValue < arr[i]){
maxValue = arr[i];
}
}
System.out.println("最大值为:" + maxValue);
//求数组元素的最小值
int minValue = arr[0];
for(int i = 1;i < arr.length;i++){
if(minValue > arr[i]){
minValue = arr[i];
}
}
System.out.println("最小值为:" + minValue);
//求数组元素的总和
int sum = 0;
for(int i = 0;i < arr.length;i++){
sum += arr[i];
}
System.out.println("总和为:" + sum);
//求数组元素的平均数
int avgValue = sum / arr.length;
System.out.println("平均数为:" + avgValue);
}
}
4.7.7 练习6:数组的赋值解释
package com.atguigu.exer;
/*
* 使用简单数组
(1)创建一个名为ArrayExer2的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。
(2)使用大括号{},把array1初始化为8个素数:2,3,5,7,11,13,17,19。
(3)显示array1的内容。
(4)赋值array2变量等于array1,修改array2中的索引元素,使其等于索引值(如array[0]=0,array[2]=2)。打印出array1。
*
* 思考:array1和array2是什么关系?array1和array2地址值相同,都指向了堆空间的唯一的一个数组实体。
* 拓展:修改题目,实现array2对array1数组的复制
*/
public class ArrayExer2 {
public static void main(String[] args) { //alt + /
int[] array1,array2;
array1 = new int[]{2,3,5,7,11,13,17,19};
//显示array1的内容
for(int i = 0;i < array1.length;i++){
System.out.print(array1[i] + "\t");
}
//赋值array2变量等于array1
//不能称作数组的复制。
array2 = array1;
/*修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)
即下标为偶数时,元素值等于它本身的下标值。
*/
for(int i = 0;i < array2.length;i++){
if(i % 2 == 0){
array2[i] = i;
}
}
System.out.println();
//打印出array1,发现结果和修改后的array2结果相同
for(int i = 0;i < array1.length;i++){
System.out.print(array1[i] + "\t");
}
}
}
解释:因为只new了一次对象,堆里面只有一个值。
array1 = new int[]{2,3,5,7,11,13,17,19};
array2 = array1;
这2步表示把堆得地址值赋给array1,再把array1的地址值赋值给array2,array1 array2此时地址值相同。而修改array2的值也就是堆得值只有一个,那么array1的值当然也发生了变化。
现实类比:相当于在磁盘创建一个文件,之后发送桌面快捷方式。你在桌面打开和在磁盘打开的文件里的内容相同。
4.7.8 练习7:数组的复制 反转 查找(线型 二分)
package com.atguigu.java;
/*
* 算法的考查:数组的复制、反转、查找(线性查找、二分法查找)
*
*
*/
public class ArrayTest2 {
public static void main(String[] args) {
String[] arr = new String[]{"JJ","DD","MM","BB","GG","AA"};
//数组的复制(区别于数组变量的赋值:arr1 = arr)
//相当于磁盘文件复制到桌面一份,对桌面的文件进行修改
String[] arr1 = new String[arr.length];
for(int i = 0;i < arr1.length;i++){
arr1[i] = arr[i];
}
//数组的反转
/*方法一:不管是除进还是除不尽都不影响,除于2是因为 第一步第一个元素和最后一个进行交换
最后一步 最后一个与第一个进行交换,相当于交换了2次。*/
// for(int i = 0;i < arr.length / 2;i++){
// String temp = arr[i];
// arr[i] = arr[arr.length - i -1]; 把最后元素赋值给第一个
// arr[arr.length - i -1] = temp; 把第一个交换给第二个
// }
//方法二:
// for(int i = 0,j = arr.length - 1;i < j;i++,j--){
// String temp = arr[i];
// arr[i] = arr[j];
// arr[j] = temp;
// }
//遍历
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + "\t");
}
System.out.println();
//查找(或搜索)
//线性查找:重头到尾依次查找
String dest = "BB";
dest = "CC";
boolean isFlag = true;
for(int i = 0;i < arr.length;i++){
if(dest.equals(arr[i])){
System.out.println("找到了指定的元素,位置为:" + i);
isFlag = false;
break;
}
}
if(isFlag){
System.out.println("很遗憾,没有找到的啦!");
}
//二分法查找:(熟悉)先分为2半,如果查找的第1份有对应值,则另一份就不找了。效率更高
//前提:所要查找的数组必须有序。
int[] arr2 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
int dest1 = -34;
dest1 = 35;
int head = 0;//初始的首索引
int end = arr2.length - 1;//初始的末索引
boolean isFlag1 = true;
while(head <= end){
int middle = (head + end)/2; //4
if(dest1 == arr2[middle]){
System.out.println("找到了指定的元素,位置为:" + middle);
isFlag1 = false;
break;
}else if(arr2[middle] > dest1){
end = middle - 1;
}else{//arr2[middle] < dest1
head = middle + 1;
}
}
if(isFlag1){
System.out.println("很遗憾,没有找到的啦!");
}
}
}
4.8 数组工具类Arrays
java.util.Arrays:操作数组的工具类,里面定义了很多操作数组的方法
说明:像数组的排序,复制,二分算法等封装好了,我们用的时候直接调用工具类方法即可,不像在上面自己手写。开发中如果工具类有对应的方法使用工具类没有的在自己手写。
4.8.1 Arrays.toString(数组)
把数组里的数据,用逗号连接成一个字符串。(返回值是String)
格式:[10, 14, 20, 46, 51]
package day006;
import java.util.Arrays;
public class Test02 {
public static void main(String[] args) {
// to String
method();
}
public static void method() {
int[] aa= {1,2,3,4,5,6};
//直接输出整个数组不需要遍历,之前遍历是插入。
// for(int i=0;i<aa.length-1;i++) {
// }
//直接打印是地址值如:[I@15db9742使用工具类后是:[1, 2, 3, 4, 5, 6]
System.out.println(Arrays.toString(aa));
}
}
4.8.2 Arrays.sort(数组)
对数组升序排序:对于基本类型的数组使用优化后的快速排序算法,效率高。对引用类型数组,使用优化后的合并排序算法。
无返回值。
例子:
package lianxi;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Ta {
public static void main(String[] args) {
int[] as = {4,9,4,1,2,5,9,6,4,5,2};
Arrays.sort(as);
System.out.println(Arrays.toString(as));
}
}
4.8.3 Arrays.copyOf(数组,新的长度)
把数组复制成一个指定长度的新数组。(改变的只是新数组,原数组没有发生变化)
新数组长度大于原数组,相当于复制,并增加位置。-- 数组的扩容
新数组长度小于原数组,相当于截取前一部分数据。-- 数组的缩容
有返回值。
4.8.4 测试toString, sort, copyOf
package cn.tedu.array;
import java.util.Arrays;
//测试数组工具类
//为什么sort()没有返回值是,void
//为什么copyOf()有返回值,如:int[]
//原因是:sort()在原数组基础上,把数组调整位置
//copyOf():数组一旦创建,长度不可变!!!所以必须把产生的新数组返回/而这里改变了长度。
public class Test4_Arrays {
public static void main(String[] args) {
int[] a = {97, 7, 41, 37, 55, 3, 3, 34, 34, 83};
// sortArray(a);//a是实参,给无序数组排序
int[] newA = copyArray(a);//数组复制a是原数组
// [97, 7, 41, 37, 55, 3, 3, 34, 34, 83, 0, 0, 0, 0, 0]
// [97, 7, 41, 37, 55]
System.out.println(Arrays.toString(newA));
}
//创建copyArray第一种方式,可以扩容,缩容(及新数组的长度大于小于新数组的长度都可以)
public static int[] copyArray(int[] from) {
//copyOf(from,num)--from是原数组名,num是新数组长度 -- 新数组长度 > 原数组长度 -- 扩容
int[] to = Arrays.copyOf(from, 15);
// [97, 7, 41, 37, 55, 3, 3, 34, 34, 83, 0, 0, 0, 0, 0]
//from是原数组名,5是新数组长度 -- 新数组长度 < 原数组长度 -- 缩容 --相当于截取数据。
int[] to2 = Arrays.copyOf(from, 5);
// [97, 7, 41, 37, 55]
return to2;
}
//创建sortArray
public static void sortArray(int[] a) {//形参
//sort()用来对无序数组进行排序
Arrays.sort(a);//底层源码
// [3, 3, 7, 34, 34, 37, 41, 55, 83, 97]
//toString()对指定的数组内容,显示成字符串
System.out.println(Arrays.toString(a));
}
}
例子:
//数组的复制 第2种arraycopy 都是在新的数组上改变,注意两者写法的区别。
int [] we= {4,8,5,8,9}; //新数组小了自动截取,大了会自动填充。
int[] we1=Arrays.copyOf(we, 4);
System.out.println(Arrays.toString(we));
System.out.println(Arrays.toString(we1));
System.out.println("11111111111");//打桩
int[] we2=new int[5];//这个是新数组长度小则会有数组下标越界异常。那个不会。优点是显得更灵活。
System.arraycopy(we,0,we2,0,5);
System.out.println(Arrays.toString(we2));
//数组的扩容
int we3[]=Arrays.copyOf(we, we.length+1);
System.out.println(Arrays.toString(we3));
4.8.5 Arrays.equals
//boolean equals(int[] a,int[] b):判断两个数组是否相等。
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = new int[]{1,3,2,4};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals);//false
4.8.6 Arrays.fill
int[] arr1 = new int[]{1,2,3,4};
//void fill(int[] a,int val):将指定值填充到数组之中。
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));//[10, 10, 10, 10]
4.8.7 Arrays.binarySearch二分算法查找
//int binarySearch(int[] a,int key)
int[] arr3 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
int index = Arrays.binarySearch(arr3, 210);
if(index >= 0){//返回值为整数代表找到,为什么正负代表找到没找到,因为源码是这样设计的
System.out.println(index);
}else{//返回值为负数没找到
System.out.println("未找到");
}
4.9 数组常见异常
package com.atguigu.java;
/*
* 数组中的常见异常:
* 1. 数组角标越界的异常:ArrayIndexOutOfBoundsExcetion
*
* 2. 空指针异常:NullPointerException
*
*/
public class ArrayExceptionTest {
public static void main(String[] args) {
//1. 数组角标越界的异常:ArrayIndexOutOfBoundsExcetion
int[] arr = new int[]{1,2,3,4,5};
// for(int i = 0;i <= arr.length;i++){
// System.out.println(arr[i]);
// }
// System.out.println(arr[-2]);
// System.out.println("hello");
//2.2. 空指针异常:NullPointerException
//情况一:原来有地址,现在改为Null了没有地址,在根据地址值找对的值
// int[] arr1 = new int[]{1,2,3};
// arr1 = null;
// System.out.println(arr1[0]);
//情况二:
// int[][] arr2 = new int[4][];
// System.out.println(arr2[0][0]);
//情况三:
String[] arr3 = new String[]{"AA","BB","CC"};
arr3[0] = null;
System.out.println(arr3[0].toString());
}
}
4.10 拓展:
4.10.1 了解二维数组
存放数组的数组,也就是说数组里存的还是数组的数据形式。
案例1:
public class Test06 {
//ctrl +n 快捷键相当于new在用上下键 (创建项目,包,类全程不用鼠标)
public static void main(String[] args) {
// 二维数组: 数组套数组
//格式: 定位:如,c[0][1] 遍历2次.
int [][] c={{1,2},{3,4},{5,6}};//声明形式
for(int i=0;i<=c.length-1;i++) {//遍历外层数组
for(int j=0;j<=c[i].length-1;j++) { //遍历内层数组
System.out.println(c[i][j]);//输出形式
}
}
案例2:
package com.atguigu.java;
/*
* 二维数组的使用
*
* 1.理解:
* 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。
* 其实,从数组底层的运行机制来看,其实没有多维数组。
*
* 2. 二维数组的使用:
* ① 二维数组的声明和初始化
* ② 如何调用数组的指定位置的元素
* ③ 如何获取数组的长度
* ④ 如何遍历数组
* ⑤ 数组元素的默认初始化值 :见 ArrayTest3.java
* ⑥ 数组的内存解析 :见 ArrayTest3.java
*
*
*/
public class ArrayTest2 {
public static void main(String[] args) {
//1.二维数组的声明和初始化
int[] arr = new int[]{1,2,3};//一维数组
//静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
//动态初始化1
String[][] arr2 = new String[3][2];
//动态初始化2
String[][] arr3 = new String[3][];
//错误的情况
// String[][] arr4 = new String[][4];
// String[4][3] arr5 = new String[][];
// int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};
//也是正确的写法:
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};
//2.如何调用数组的指定位置的元素
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//null
arr3[1] = new String[4];
System.out.println(arr3[1][0]);
//3.获取数组的长度
System.out.println(arr4.length);//3
System.out.println(arr4[0].length);//3
System.out.println(arr4[1].length);//4
//4.如何遍历二维数组
for(int i = 0;i < arr4.length;i++){
for(int j = 0;j < arr4[i].length;j++){
System.out.print(arr4[i][j] + " ");
}
System.out.println();
}
}
}
案例3:
package com.atguigu.java;
/*
* 二维数组的使用:
* 规定:二维数组分为外层数组的元素,内层数组的元素
* int[][] arr = new int[4][3];
* 外层元素:arr[0],arr[1]等
* 内层元素:arr[0][0],arr[1][2]等
*
* ⑤ 数组元素的默认初始化值
* 针对于初始化方式一:比如:int[][] arr = new int[4][3];
* 外层元素的初始化值为:地址值
* 内层元素的初始化值为:与一维数组初始化情况相同
*
* 针对于初始化方式二:比如:int[][] arr = new int[4][];
* 外层元素的初始化值为:null
* 内层元素的初始化值为:不能调用,否则报错。
*
* ⑥ 数组的内存解析
*
*/
public class ArrayTest3 {
public static void main(String[] args) {
int[][] arr = new int[4][3];
System.out.println(arr[0]);//[I@15db9742
System.out.println(arr[0][0]);//0
// System.out.println(arr);//[[I@6d06d69c
System.out.println("*****************");
float[][] arr1 = new float[4][3];
System.out.println(arr1[0]);//地址值
System.out.println(arr1[0][0]);//0.0
System.out.println("*****************");
String[][] arr2 = new String[4][2];
System.out.println(arr2[1]);//地址值
System.out.println(arr2[1][1]);//null
System.out.println("*****************");
double[][] arr3 = new double[4][];
System.out.println(arr3[1]);//null
// System.out.println(arr3[1][0]);//报错
}
}
4.10.2 了解冒泡排序
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
冒泡排序解释:
- 比较数组中2个相邻的元素,如果第一个数比第二个数大,我们就交换他的位置。
- 每一次比较都会产生一个最大或者最小的数字。
- 下一轮则可以减少一次排序。
- 依次循环直到结束。
冒泡排序的优化:有很多,最基础的可以通过变量标识进行判断,如果排序正确则,没有必要进行比较
4.10.3 冒泡排序代码
package cn.tedu.bubble;
//第一种 20个数比 20轮 每轮比-i-1次
//第二种 20个数比19轮 每轮比-i次
import java.util.Arrays;
//这个类用来测试冒泡排序算法
public class Test3_Bubble {
public static void main(String[] args) {
//1,定义无序数组
int[] a = {21, 94, 21, 58, 47, 16, 10, 9, 50, 44};
//2,排序
//5个数,比4轮。外循环控制轮数,让外循环执行4次
//i < a.length-1 a.length是5,-1 就是 4,i<4,外循环执行4次
for(int i = 0 ; i < a.length-1 ; i++ ) {
//内循环控制每轮需要相邻比较多少次
//-i :第1轮,需要比4次,五个数参与比较 -0,
//第2轮,需要比3次,四个数参与比较 -1,(因为第一轮沉出来一个大值不参与比较)
//第3轮,需要比2次,四个数参与比较 -2,(因为前两轮沉出来两个大值不参与比较)
//第4轮,需要比1次,四个数参与比较 -3,(因为前三轮沉出来三个大值不参与比较)
for(int j = 0 ; j < a.length-1 - i; j++ ) {
//1,相邻元素比较
//前一个值a[j]大于后面的值a[j+1]
if(a[j]>a[j+1]) {
//2,交换顺序s
int t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
System.out.println(Arrays.toString(a));
}
}
4.10.4 冒泡排序代码优化写法
package lianxi;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Ta {
public static void main(String[] args) {
//1,定义无序数组
int[] a = {21, 94, 21, 58, 47, 16, 10, 9, 50, 44};
//2,排序
//5个数,比4轮。外循环控制轮数,让外循环执行4次
//i < a.length-1 a.length是5,-1 就是 4,i<4,外循环执行4次
for(int i = 0 ; i < a.length-1 ; i++ ) {
boolean flag=false;//通过flag标识减少没有意义的比较
//内循环控制每轮需要相邻比较多少次
//-i :第1轮,需要比4次,五个数参与比较 -0,
//第2轮,需要比3次,四个数参与比较 -1,(因为第一轮沉出来一个大值不参与比较)
//第3轮,需要比2次,四个数参与比较 -2,(因为前两轮沉出来两个大值不参与比较)
//第4轮,需要比1次,四个数参与比较 -3,(因为前三轮沉出来三个大值不参与比较)
for(int j = 0 ; j < a.length-1 - i; j++ ) {
//1,相邻元素比较
//前一个值a[j]大于后面的值a[j+1]
if(a[j]>a[j+1]) {
//2,交换顺序s
int t = a[j];
a[j] = a[j+1];
a[j+1] = t;
flag=true;
}
}
if(flag==false) {
break;
}
}
System.out.println(Arrays.toString(a));
}
}
4.10.5 了解其他算法
如:合并算法,二分算法,快速算法等,冒泡最常见,也是面试中出现率最高的
4.10.6 稀疏数组
B站狂神稀疏数组视频连接:https://www.bilibili.com/video/BV12J41137hu?p=59&spm_id_from=pageDriver
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!