调用方法时,方法的参数类型是基本类型、String、还未分配内存的对象。方法定义时对声明参数的修改,不会改变方法调用处传入参数的值。
public class Main{
//该注解能抑制IDE的预编译报错,此处不加该注解,arr1.length语句会出现警告提示
@SuppressWarnings("null")
public static void main(String[] args) {
String s1 = "abcdef";
int a1 = 18;
int arr1[] = null;
m1(s1, a1, arr1);// 方法m1中对声明参数的修改,对传入的变量无影响。
System.out.println(s1);// run后控制台打印:abcdef
System.out.println(a1);// run后控制台打印:18
System.out.println(arr1.length);// 运行报错java.lang.NullPointerException
// arr1 is null,代码报错位置是在m1方法内arr1[0] = 4;处
}
// 方法头变量名s1声明新的String对象,初值等于"abcdef",a1同理
static void m1(String s1, int a1, int arr1[]) {
s1 = s1.substring(1);
a1 = 2;
// 虽然在m1调用处,传入的对象arr1是null,
// 但是m1内部并不知道参数列表中arr1[]是null,
// 因此对数组的赋值操作,仍能编译通过
arr1[0] = 4;
}
}
对于上述arr1对象,可通过在m1内return返回一个对象,达到数组初始化和赋值的目的。
public class Main{
public static void main(String[] args) {
String s1 = "abcdef";
int a1 = 18;
int arr1[] = null;
arr1 = m1(s1, a1, arr1);
System.out.println(arr1[0]);// arr1即为方法m1所赋值,控制台打印4
}
static int[] m1(String s1, int a1, int arr1[]) {
s1 = s1.substring(1);
a1 = 2;
arr1 = new int[2];//
arr1[0] = 4;
return arr1;//将方法内部对arr1的所有操作return给调用处
}
}
但是当方法的参数类型是一般的class类型时,方法内对参数列表中相应位置对象的改变,会将改变的内容传回该方法调用处。
如下代码:
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public class Main{
public static void modifyPoint(Point p1, Point p2) {
// 交换参数列表中p1和p2的引用
Point tmp = p1;
p1 = p2;
p2 = tmp;
p1.x=3;
p1.y=4;// 改变p1对象,相当于改变参数列表中的p2
p2.x=1;
p2.y=2;// 改变p2对象,相当于改变参数列表中的p1
// new操作为p2开辟了新的对象,而不影响参数列表中的原对象
p2 = new Point(100, 100);
p2.x=12;
p2.y=12;
}
public static void main(String[] args) {
Point p1 = new Point(0, 0);
Point p2 = new Point(0, 0);
modifyPoint(p1, p2);
System.out.print(p1.x+" "+p1.y+"——"+p2.x+","+p2.y +"\n");
// 输出1 2——3 4,在modifyPoint方法中,先交换,后赋值
}
}
由此可见,Java中方法传参的方式与C/C++类似,后者更灵活,不仅可以通过指针在外部方法内修改变量,还可以通过结构体来操作。
Java通过类的封装使得,在类的外部对私有变量的修改和传递更为安全(必须通过public方法),增加代码的可读性,便于理解和结构化编码。但Java这种传递参数的模式使得方法对非class类型变量的操作,不能马上反馈给调用者,需要return或者设置static成员变量的方式将修改同步,损失了一定的效率。而且代码各个模块之间对变量的修改无法相互知晓。
应用java编程模式可以有效地解决这一类参数问题。