8.方法
方法简述:
概念:特定功能的代码块。
优点:减少了代码的冗余。
方法的分类:静态方法、成员方法、构造方法(此节主要在静态方法的基础上使用)
注意:
- 方法编写的位置:类里,与main方法并立。
- 方法与方法之间是平级关系(不能在一个方法中声明另一个方法)。
- 方法不被调用,永远不会主动执行。
8.1 静态方法(static)
注:只能使用类名调用,无法使用类对象调用。
8.1.1 无返回值无参数的方法
语法结构:
访问修饰符 static void 方法名(){
…代码块… }
示例:
public static void hello(){ System.out.println("Hello World!"); }
在main方法中可以直接通过方法名调用------ hello();
8.1.2.带有参数的方法
语法结构:
访问修饰符 static void 方法名(参数类型 变量名){
…代码块…
}示例:
public static void printStar(int num,String str){ for(int i = 0;i<num;i++){ for(int j = 0;j<=i;j++){ System.out.print(str); } System.out.println(); } }
main()方法中调用printStar方法时,需要传递实参给printStar方法。
printStar(5,"*")
输出:
* ** *** **** *****
注意:
- 形参:形式参数,方法声明时,规定调用时要传入的数据类型及接收数据的变量
- 实参:实际参数,调用方法时传入的具体数据
- 实参与形参类型必须兼容
- 多个参数用逗号分隔
8.1.3.带有返回值的方法
语法结构:
public static 返回值类型 方法名([参数]){
…代码块…
return 返回数据;
}示例:
//计算两个int类型的和。 public static int add(int a,int b){ int result = a+b; return result;//返回具体参数 }
注意:
- return下面不能接执行语句,因为return表示结束当前方法(如果存在分支,不是每个分支都存在return时,主干函数必须需要一个return语句。)。
- 声明方法时规定返回值类型,return后面接的是要返回的具体数据,返回的数据类型和定的返回值类型必须兼容。
- 方法中的变量为局部变量,作用域在该方法内,不影响其他方法中的变量。
8.1.4.方法的重载
含义:方法与方法之间的关系
好处:系统会根据实参类型自动匹配到对应方法
条件:
1.在同一个类里
2.方法名一致
3.参数列表的个数或者类型不一致
4.与访问修饰符,返回值无关
应用场景:
在同一个类里,有多个方法功能一致,细节实现不一样,就可以考虑使用重载(例如:多个整数求最大值。)示例:
public static void main(String[] args){ System.out.println(getMax(10,20)); System.out.println(getMax(10,20,30,40)); } public static int getMax(int a,int b){ return (a>b)?a:b; } public static int getMax(int a,int b,int c){ int max = getMax(a,b); max = getMax(max,c); return max; } public static int getMax(int a,int b,int c,int d){ int max = getMax(a,b); max = getMax(max,c); max = getMax(max,d); return max; } /* 20 40 */
8.1.5 递归的使用
概念:方法调用方法自身。
要点:
- 找规律(找出联系)。
- 找出口(结束的标志)。
示例:
Fibonacci 数列: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
找出规律和联系: a1=1,a2=1,an=a(n-1)+a(n-2)(n>=3,n∈N*)
找出结束的标志: a1=1,a2=1。
public static void main(String[] args){ System.out.println(fibonacci(10)); } public static int fibonacci(int n){ if(n==1 || n==2){ return 1; }else{ return fibonacci(n-1) + fibonacci(n-2); } } /* 输出结果: 55 */
注意:
方法没有出口就会导致死循环,直到栈内存溢出报错(调用方法时,会在栈内存中开辟空间,用于存放该方法的局部变量,死循环的调用方法,栈内存就会满载并溢出)。
8.1 成员方法
含义:表示对象所具有的功能。
作用:
调用时与静态方法不同,需要使用类的对象来调用。
对象可以多次调用成员函数,
可以有返回值,也可以为void类型。
方法名可以和类名相同,但当此成员函数没有返回类型时为构造函数。
8.2 构造方法
格式:
构造方法和类名相同,并且没有返回类型和返回值。
一个类可以有多个构造函数,但要求他们满足方法的重载。
构造函数与其他方法一样可以有0个、1个、或多个参数。
作用:
构造方法在创建对象时被调用,一个对象的建立只能调用一个构造函数,可用于初始化对象。
注:编译程序如果类中没有构造函数,系统会自动加入构造函数,为此类的默认构造函数。
8.3 main方法
- 格式:
public static void main(String[] args) { //代码块 }
- 含义:
在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法。
这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是public static void 类型的,方法必须接收一个字符串数组的参数。
main方法中的args参数:
main方法中还有一个输入参数,类型为String[],这个是java的规范,main()方法中必须有一个入参,类型必须String[],命名为args,则是多数人的习惯。
使用示例:
public static void main(String[] args){ for(String str : args){ System.out.println(str); } }
编译过程:
拓展:
由于JVM在运行这个Java应用程序的时候,首先会调用main方法,调用时不会实例化这个类的对象,而是通过类名直接调用因此main方法需要是限制为public static。(类名.main()) ,且不能有返回值,所以返回类型为void。
9. 数组
9.1一维数组
概念:一组数据的容器(数组可以存放多个数据)
注意:
1.数组是引用数据类型
2.数组中的数据又叫做元素
3.每个元素都有编号叫做下标/索引(index)
4.下标从0开始
5.数组初始化后,会在内存中开辟一连串连续的空间
6.数组一旦初始化后长度不可以改变(数组没有扩容和删除)
7.数组的操作:添加、修改、查询声明: 数据类型[] 数组名;
9.1.1 静态初始化
数据由程序员指定,长度由系统分配。
静态初始化的三种方式:
示例:
//静态初始化1 String[] str1 = new String[]{"a111","a222","a333","a444"}; //静态初始化2 String[] str2; str2 = new String[]{"b111","b222","b333","b444"}; //静态初始化3 String[] str3 = {"c111","c222","c333","c444"};
9.1.2 动态初始化
数据由系统指定,长度由程序员分配。
注:
默认指定类型:
整数类型:0
浮点类型:0.0
字符类型:’ ’
布尔类型:false
引用类型:null示例:
//动态初始化 String [] str =new String[5]; //赋值 str[0]="111"; str[1]="222"; str[2]="333"; str[3]="444"; str[4]="555";
动态初始化和静态初始化:
一开始就知道数据,采用静态初始化,反之,只知道数据长度(个数)就采用动态初始化。
9.1.3 数组相关操作
9.1.3.1 获取和修改数组内容
- 通过索引能够指定获取数组元素和修改数组元素。
示例(参照动态初始化化的str):
System.out.println(str[2]);//333 String a="dididi"; str[2]=a; System.out.println(str[2]);//dididi /* 输出结果: 333 dididi */
通过length获取数组元素个数。
int len = str.length; System.out.println(len); /* 5 */
for循环遍历
for(int i = 0;i<str.length;i++){ System.out.println(str[i]); } /* 111 222 dididi 444 555 */
增强for循环遍历(foreach)
for(String s:str){ System.out.println(s); } /* 111 222 dididi 444 555 */
注:
遍历是如果需要使用下标,通过for循环遍历,如果不需要使用下标就采用foreach遍历数组。
9.1.3.2 数组的排序(数值型)
冒泡排序:
int[] num = {2,7,5,4,8,6}; for(int i = 0;i<num.length-1;i++){ for(int j = 0;j<num.length-1-i;j++){ if(num[j] > num[j+1]){ int temp = num[j]; num[j] = num[j+1]; num[j+1] = temp; } } }
使用Arrays工具类方法排序(后续9.1.6详细介绍Arrays工具类)
//导包 import java.util.Arrays; //使用 Arrays.sort(num);
9.1.3.3 数组的查找
顺序查找(遍历查找)
for(int i = 0;i<num.length;i++){ if(num[i] == numbers){ System.out.println("查找到了"); } }
二分法查找(使用对象:有序的数组)
int start = 0; //数组首端 int end = num.length-1; //数组末端 int numbers=7; //查询目标 while(start <= end){ int mid = (start+end)/2; if(numbers >num[mid]){ start = mid+1; }else if(numbers < num[mid]){ end = mid-1; }else{ System.out.println("查找到了"); break; } }
9.1.3.4 数组的扩充
String [] names={"aa","bb","cc"}; //静态初始化数组。
int capacity = names.length + (names.length<<1); //拓展容量(增加原来的2倍)
String [] newNames = new String [capacity];
//复制数据
for(int i = 0;i<names.length;i++){
newNames[i] = names[i];
}
names= newNames; //将扩充之后的数组给原数组。
for (String string : newNames) {
System.out.println(string);
}
/*
aa
bb
cc
null
null
null
null
null
null
*/
9.1.3.5 数组的复制
直接复制。
String [] names = {"11","22","33","55"}; //准备复制的原字符数组 String [] newNames = names; //新的字符数组 for(String str : newNames){ //遍历 System.out.print(str+" "); } System.out.println(); names[2]="aa"; //将原字符数组改变。 for(String str : newNames){ //遍历 System.out.print(str+" "); } } /* 输出结果: 11 22 33 55 11 22 aa 55 */
注意:当采用这种方式复制字符数组时,修改原数组,新的数组内容也随之改变。(当names赋值给newNames时,只是将字符数组的地址传递给新数组,所以两个数组操作的其实是一片空间。)
只复制内容。
当复制一个数组只是为了获取其中的数据时,就可以采取动态初始化,对新建的字符数组单个赋值,从而避免了多个数组操作同样的一组数据。
String [] names = {"11","22","33","55"}; //准备复制的原字符数组 String [] newNames =new String[names.length]; for(int i = 0;i<names.length;i++){ newNames[i] = names[i]; } for(String str : newNames){ //遍历 System.out.print(str+" "); } names[2]="aa"; System.out.println(); for(String str : newNames){ //遍历 System.out.print(str+" "); } /* 输出结果: 11 22 33 55 11 22 33 55 */
原数组的变化,不会对新数组产生影响。
9.1.3.6 删除数组内容
数据外部迁移(将需要删除的数据舍弃,获得新数组。)
String [] names ={"11","22","33","44"}; //需要删除的数据为22 String [] newNames =new String[names.length-1]; int index=0; //新数组的索引,从0开始 for (String string : names) { if(!string.equals("22")){ newNames[index++]=string; } } names = newNames; //将新数组的地址赋值给源数组 for (String string : names) { System.out.println(string); } } /* 输出结果: 11 33 44 */
注:这种方法会使原本的数组空间减小
数据内部迁移(在数组内部将需要删除的数据覆盖。)
String [] names ={"11","22","33","44"}; //需要删除的数据为22 //"22"的索引为1,for循环从1开始,直到names.length-1结束。 for (int i = 1; i < names.length-1; i++) { names[i]=names[i+1]; } //删除一个数据后,依次向前覆盖,数组最后一位置为空。 names[names.length-1]=null; for (String string : names) { System.out.println(string); } } /* 输出结果: 11 33 44 null */
注:数组的长度不会经历变化。
9.1.4 数组作为参数和返回值
示例:长传一组数据,返回最大值和最小值。
public static void main(String[] args) { int [] num={1,2,3,4,5}; //采用静态初始化 int [] get = getMaxMin(num); System.out.println("最小值为:"+get[0]+" 最大值为:"+get[1]); } public static int [] getMaxMin(int [] num){ int min = num[0]; int max = num[0]; for (int i = 0; i < num.length; i++) { if(min>num[i])min=num[i]; if(max<num[i])max=num[i]; } return new int[]{min,max}; } /* 输出结果: 最小值为:1 最大值为:5 */
9.1.5 可变参数
示例:设计方法,传入任意个int值,求和。
public static void main(String[] args) { int sum=add(1,2,3,4,5,6); int sum1=add(1,2,3,4,5); System.out.println(sum); System.out.println(sum1); } public static int add(int...is){ //求和函数 int sum =0; for (int i : is) { //遍历相加 sum+=i; } return sum; } /* 输出结果: 21 15 */
由此可见:可变参数的底层就是数组。
注意:
可变参数后不能接其他参数,但之前可以。
例:
public static void method(int a,String... ss)
一个方法的参数中,不能同时出现两个可变参数(即便类型不同)。
9.1.6 Arrays工具类
Arrays: java 给我们提供的专门操作数组的工具类。(其中的方法定义和使用详见API-----java类使用说明书)
常见示例:
int[] is = {39,77,27,20,45,62};
//由小到大排序
Arrays.sort(is); //20 27 39 45 62 77
//查找1(含有查找的元素)
int index = Arrays.binarySearch(is,45);
System.out.println("查找元素的下标为:" + index); //查找元素的下标为:3
//查找2(未含有查找的元素)
int index = Arrays.binarySearch(is,42);
System.out.println("查找元素的下标为:" + index); //查找元素的下标为:-4
/*
注:binarySearch方法,如果元素在数组中就返回下标,否则返回 (-插入点)-1
*/
//替换
Arrays.fill(is,100); //100 100 100 100 100 100
Arrays.fill(is,1,4,666); //100 666 666 666 100 100
//拷贝
int[] copyOf = Arrays.copyOf(is,is.length*2);
for ( int i : copyOf) {
System.out.print(i+" "); //100 666 666 666 100 100 0 0 0 0 0 0
}
int[] copyOfRange = Arrays.copyOfRange(is,3,8);
for (int i : copyOfRange) {
System.out.print(i+" "); //666 100 100 0 0
}
9.2 二维数组
注:二维数组整体学习和一维数组类似,可参照学习。
含义:包含了多个一维数组
声明:数据类型 [ ] [ ] 数组名;
9.2.1 二维数组的初始化
静态初始化:数据由程序员指定,长度由系统自动分配
//方式1 String [][] names1=new String [][] {{"aaa","bbb","ccc"},{"111","222","333","444"}}; //方式2 String [][] names2; names2 = new String [][] {{"aaa","bbb","ccc"},{"111","222","333","444"}}; //方式3 String [][] names3={{"aaa","bbb","ccc"},{"111","222","333","444"}};
动态初始化:长度由程序员指定,数据由系统自动分配(默认分配方式见9.1.2)
//动态初始化1 String[][] names1 = new String[2][3];// 含义:2个一维数组,每个一维数组中有3个元素 //动态初始化2 String[][] names2; names = new String[2][3]; //动态初始化3 String[][] names3 = new String[2][];//含义:标注二维数组中有2个一维数组 //把长度为3的一维数组赋值给二维数组中下标为0的位置 names3[0] = new String[3]; //把长度为4的一维数组赋值给二维数组中下标为1的位置 names3[1] = new String[4];
二维数组的循环遍历(采用循环嵌套)
String [][] names={{"aaa","bbb","ccc"},{"111","222","333","444"}};//静态初始化 //遍历 - for循环 for (int i = 0; i < names.length; i++) { for (int j = 0; j < names[i].length; j++) { System.out.print(names[i][j]); } System.out.println(); } System.out.println("------------"); //遍历 - foreach for (String[] strings : names) { for (String string : strings) { System.out.print(string); } System.out.println(); } /* aaabbbccc 111222333444 ------------ aaabbbccc 111222333444 */