Java方法及传递参数到方法中
在 Java 中,方法定义对象行为或在类级别实现不同的功能(对于静态方法)。如果变量(值类型或引用)表示 Java 编程的静态部分,则方法表示动态部分,因为方法等效于执行和处理某些变量的代码块。
如何定义方法
用于定义方法的一般语法是
[access_modifier] [non-access modifier] return_type method_name (type parameter1, type parameter2, …, type parameterN) [访问修饰符] [非访问修改符] 返回值 方法名称 (类型参数 1, 类型参数 2, ..., 类型参数N)
其中:
[access_modifier] [ 定义该方法的可见性;可能的值包括:
[default] = 当你不写任何东西;
[public] 方法在其他类中可见;
[private] 方法在其他类中不可见;
[protected] = 方法仅在子类中可见。
[non-access modifier] [定义其他属性的方法,如:
[static] (该方法在类级别定义 = 它不是对象方法),
[final] (该方法不能在子类中重写),
[abstract] (该方法不能实例化,因为包含抽象方法 = 虚拟纯方法)
[return_type] [任何基元或参考类型;如果该方法不返回值,则返回类型为 [void];如果定义返回类型,则该方法必须以 返回值/变量语句结束,其中值/变量类型是定义的返回类型:
public class Test { public static void main(String[] args) { int vb1 = 10; int vb2 = 20; //调用doSum 方法 int sum = doSum(vb1, vb2); System.out.println("The sum is "+sum); } public static int doSum(int a, int b) { int result = a + b; return result; } }
[method_name] [ 必须尊重变量使用的相同命名约定;Java 建议使用 camelCase 命名约定(第一个单词以小写字母开头);此外,名称应该是动词名词对,如getName,doSum;
[参数] = 表示方法的输入值(原始值或引用值);关于参数,你必须知道这一点:
- 方法声明中变量称为形式参数
parameters
简称形参
;调用 方法时,输入值称为实际参数arguments
简称实参
; - 方法输入的参数是该方法的局部变量;
- 我们可以使用
var-arg 方法
定义可变数量的输入参数 ;
参数的重要规则
- 方法参数始终按其值传递;方法参数始终是参数的副本(可能是最重要的规则);
- 基元参数表示调用参数的值副本;
- 引用参数表示调用引用参数的值副本(引用值不是对象,而是对象地址)
如何传递参数并返回多个值
在我们描述这个概念之前,请记住一个重要的Java规则:
方法的实参argument总是按其值传递;方法形参parameters始终是实参的副本
。
有 2 种类型的参数:值类型和 对象引用。它们之间的区别在于合乎逻辑的,因为引用就像具有重要特征的数字变量:它们的值表示存储在 Heap 中的对象的地址。
在C++,则是不同的,因为我们有参数通过它们的值和它们的地址传递(当我们使用指针时)。此外,在 C# 中:我们有参数通过其值或指针(不安全)传递,或者使用 [ref] 作为输入参数属性。
因为 在 Java 中,方法的实际参数argument
始终由其值传递,这意味着方法局部变量的值与调用参数的值相同。当我们想要编写返回多个值的方法时,这可能表示一个问题(对于一个值,可以使用方法返回类型)。
例如,让我们编写一个用于交换 2 个基元变量的值的方法。如果我们这样写:
public class Main { public static void main(String[] args) { int vb1 = 10; int vb2 = 20; doInterchange(vb1, vb2); System.out.println("vb1 = "+vb1+", vb2 = "+vb2); } public static void doInterchange(int a, int b) { int temp = a; a = b; b = temp; } }
那么输出将会是:
vb1 = 10, vb2 = 20
尽管 [doInterchange)] 方法正在实现正确的算法,但结果并不是预期的,因为根据以前的规则,该方法正在交换其自身局部变量 [a] 和 [b] 的值。
因此,我们必须编写一个更好的方法,它将交换2个主要变量的值。让我们尝试通过将 2 个整数装箱到其相应的对象中的引用,像这样:
public class Main { public static void main(String[] args) { int vb1 = 10; int vb2 = 20; doInterchange2(vb1, vb2); //the values are boxed by default System.out.println("vb1 = "+vb1+", vb2 = "+vb2); } public static void doInterchange2(Integer ra, Integer rb) { int temp = ra; //default unboxing ra = rb; rb = temp; //boxing } }
但是, 令人惊讶的是, 输出还是一样
vb1 = 10, vb2 = 20
在这种情况下,原因更微妙,因为默认boxing机制正在创建一个具有基元变量值的新对象。
另请注意,Integer对象是不可变的。
正确解决方案是使用我们自己的类的引用,例如:
class MyValue { public int value; public MyValue(int input) { value = input; } } public class Main { public static void main(String[] args) { int vb1 = 10; int vb2 = 20; MyValue value1 = new MyValue(vb1); MyValue value2 = new MyValue(vb2); doInterchange3(value1, value2); vb1 = value1.value; vb2 = value2.value; System.out.println("vb1 = "+vb1+", vb2 = "+vb2); } public static void doInterchange3(MyValue aValue, MyValue bValue) { int temp = aValue.value; aValue.value = bValue.value; bValue.value = temp; } }
结果:
vb1 = 20, vb2 = 10
因为来自主堆栈和 doInterchange3 堆栈的引用引用在堆中引用相同的对象。
因为,在Java中,方法参数总是由它们的值(也是引用)传递的。[不要]错误地认为这行得通:
public static void doInterchange4(MyValue aValue, MyValue bValue) { //interchange references VALUES and NOT objects values MyValue temp = aValue; aValue = bValue; bValue = temp; }
请记住,aValue参考值是 *value1 * 参考值的副本。
另一个解决方案是使用数组作为基元值的包装器,如下:
public class Main { public static void main(String[] args) { int vb1 = 10; int vb2 = 20; int[] anArray = {vb1,vb2}; doInterchange5(anArray); vb1 = anArray[0]; vb2 = anArray[1]; System.out.println("vb1 = "+vb1+", vb2 = "+vb2); } public static void doInterchange5(int[] values) { int temp = values[0]; values[0] = values[1]; values[1] = temp; } }
方法的一些规则
方法输入参数parameters由基元和/或引用表示;
定义方法时,声明的变量称为参数parameters;
调用方法时,输入值称为参数arguments;
方法输入参数是方法的局部变量;
方法实际参数arguments始终按其值传递;方法形式参数parameters始终是实际参数arguments的副本(可能是最重要的规则);
基元参数表示调用实参argument的值副本;
引用参数表示调用引用参数的值副本(引用值不是对象,而是对象的地址);
当输入参数与局部变量或实例变量具有相同的名称时,将发生阴影(由于这是逻辑错误,因此很难调试);例如,变量使用 this.表示法来区分输入参数和对象属性;对于类静态变量,则使用类名来区分;
方法可以具有变量数参数(var-args 方法);
var-arg 方法只能有一个 var-arg 参数;
var-arg 必须是最后一个参数(如果该方法具有其他参数);