方法
方法在调用时会在JVM栈空间内创建栈帧用于存储方法内所有数据
在编程过程中难免在实现功能上出现重复代码,从而导致代码过于冗长,不易于阅读理解
此时善用方法可以达到提高代码的可重复利用性
通过传入数据进行数据处理,可传回数据,也可以不传回(由其返回值类型决定)
main方法是一个典型的方法(程序的主入口)
方法的定义与声明
方法名命名遵循命名规则(小驼峰命名法)
方法需要定义在类中
权限修饰符 + static + 返回值类型 + 函数名称(参数列表){方法代码块}
权限修饰符:
public:公开的,类内类外谁都可以访问
private:私有的,仅供类内访问
protected:对同一包内所有类,子类均可访问
静态类型:
static:静态的,可从类外部直接访问,声明为静态的方法只能访问类内的静态变量,可选
返回值类型:
void 无返回值,此处为返回值类型,决定返回的处理后数据类型,可以是可接受的数据类型,如果是其他类型,则方法语句中需要return值,如果return后不加任何东西,则直接退出方法,如:
public static void fanc(){
代码块;
return;//return后不加任何值即代码运行到此处直接退出方法,可不加
}
public static int fanc(){
代码块;
return 0;//返回值为0,此时方法结束,在外围的运行到此处则为return值,返回的值的类型要和上面声明方法时所声明的返回类型相同
}
public static void main(String[] args){//main方法
int i = fanc();//声明一个变量i的值为Fanc方法的返回值,调用该方法时运行方法内代码并返回值,此时Fanc() = 0,所以最后的语句等效于int i = 0;
}
参数列表:
参数列表可有可无,决定调用时需要传入的数据及类型和数量,用逗号隔开(如果有多个),为局部变量
形参和实参完全独立,因其会开辟独立的内存空间,直接复制一份为副本并对副本进行操作,具体如下图
分为形参和实参(实际传给函数的数据):
public static int fanc(int numIn){//这里numIn是形参,形参可以和外部变量名相同,但是形参间不能同名
return = numIn++;//这里在方法调用之初会在栈中单独开辟一个空间等待传入参数
}
public static void main(String[] args){
fanc(10);//这里的10为实参
}
方法在调用过程中的内存变化为:
public static int calculate(int numInOne , int numInTwo ){//假设创建一个方法用于计算总和,这里引用的参数为两个int整型
int sum = numInOne + numInTwo;//创建sum整型存储和
return sum;//返回sum值
}
public static void main(String[] args){
int numPressOne = 1;//声明变量
int numPressTwo = 2;
System.out.println(calculate(numPressOne , numPressTwo));//打印调用方法后的结果
}
/*打印结果为
3
*/
需要注意的是,如果传入参数是引用类型,那么如果在方法内对其进行更改那么在全局就会改变
因为引用数据类型传入的是引用,即对象的内存地址,所以,如果方法内对该地址的内容进行更改,由于在外部的对象也指向这个地址,所以外部读取该内存的数据就是改变后的了,如:
public static void main(String[] args){
int[] Array = new int[]{1,2,3,4,5};//创建数组对象,Array本身不含数据,只是存了数据在堆中的内存地址,假设其地址为0x123
changeArray(Array);//将数组传入方法
}
public static void changeArray(int[] arr){//传入的实际为数组地址,arr为副本数组内容也为0x123
arr[4] = 100;//在方法体内更改数组,实际上是直接对堆内数据进行操作,对0x123地址上的数据进行更改
}
System.out.println(Array[4]);//输出为100,读取0x123上的数据
用个简单的例子来比喻的话就是两个拆迁队他们手中有相同的地址,即引用对象本身的地址和副本内的地址,其中一个拆迁队将其拆除,那另一队到达时已经是废墟了,即,如果在方法内把这个地址的建筑物拆除了,到方法外的那个拆迁队到达的那个地址已经是拆迁后的建筑物了
具体调用过程如下图:
如果需要防止这种事情发生,可以在方法内主动创建副本改变指向地址,从而达到对数组数据进行操作而不改变原数组:
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5};//创建一个数组,此时为地址一
changeArray(arr);//调用方法
System.out.println(Arrays.toString(arr));//返回地址一的数组数据
}
public static void changeArray(int[] arrIn){//调用方法后,传入arrIn的为地址一
int[] arrDeal = new int[arrIn.length];//创建一个新的数组,长度与原数组相同,其地址为地址二
System.arraycopy(arrIn, 0, arrDeal, 0, arrIn.length);//将原数组数据传入新数组
arrIn = arrDeal;//将地址二赋值给arrIn
arrIn[4] = 100;//改变地址二内的数据
System.out.println(Arrays.toString(arrIn));//返回地址二的数组数据
}
/*
结果如下:
[1, 2, 3, 4, 100] 方法内的数组
[1, 2, 3, 4, 5] 方法结束后的原始数组
*/
em.out.println(Arrays.toString(arrIn));//返回地址二的数组数据
}
/*
结果如下:
[1, 2, 3, 4, 100] 方法内的数组
[1, 2, 3, 4, 5] 方法结束后的原始数组
*/