一、方法的所属性
方法由传统的函数发展而来,方法与传统的函数显著不同:在结构化编程中,函数是一等公民,这个程序由一个个函数组成;在面向对象编程语言里,类才是一等公民,整个系统由一个个类组成。因此在Java语言里,方法不能独立存在,方法必须属于类或对象。
方法的所属性:
(1)方法类似于函数。但与函数不同的是,方法不能存在,方法必须定义在类里面。
(2)方法一定要有执行者,必须通过类或对象来调用方法。从逻辑上来看,该方法属于类本身,应该用类来调用
如果该方法有static修饰,该方法属于类本身,应该用类调用;
如果该方法无static修饰,该方法属于对象本身,应该用对象调用
【规则】如果调用同一个类中方法,可以省略调用者,此时系统会默认添加调用者。如果方法是无static方法,添加this作为默认调用者;如果方法是static方法,添加类作为调用者。
1 class Method_attribute 2 { 3 //定义一个普通方法 4 public void nonStaticMethod() 5 { 6 System.out.println("这是一个普通方法"); 7 } 8 9 //定义一个static方法 10 public static void StaticMethod() 11 { 12 System.out.println("这是一个类方法"); 13 } 14 15 //在同一个类中一个方法调用另外一个方法 16 public void test() 17 { 18 19 this.nonStaticMethod(); 20 this.StaticMethod(); 21 StaticMethod();//省略的是主调类 22 } 23 public static void main(String[] args) 24 { 25 var p=new Method_attribute(); 26 //此时test()方法中的两个this代表对象p 27 p.test(); 28 } 29 } 30 ---------- 运行Java捕获输出窗 ---------- 31 这是一个普通方法 32 这是一个类方法 33 这是一个类方法 34 35 输出完成 (耗时 0 秒) - 正常终止
二、方法参数的传递机制
Java里方法是不能独立存在的,调用方法时必须使用类或对象作为主调者。如果声明方法时,包含了形参声明,则调用方法时必须给这些形参指定参数值,调用参数时传给形参参数值也称为实参。
Java里面参数传递方式只有一种:值传递。所谓值传递,就是将实际参数的副本(复制品)传入方法内,而参数本身不会受到影响。
class ParamTransferTest { public static void swap(int a,int b) { //实现变量a和b的值交换 //定义一个临时变量来保存a的值 var temp=a; a=b; b=temp; System.out.println("swap方法里,a的值为:"+a+",b的值为:"+b); } public static void main(String[] args) { int a=6; int b=9; swap(a,b); System.out.println("交换结束后,a的值为:"+a+",b的值为:"+b); } } ---------- 运行Java捕获输出窗 ---------- swap方法里,a的值为:9,b的值为:6 交换结束后,a的值为:6,b的值为:9 输出完成 (耗时 0 秒) - 正常终止
Java程序从main()方法开始执行,main()方法开始定义了a、b两个局部变量,如图所示:
程序从main()函数开始执行,当程序进入swap()方法时,系统分配了两个栈区,将mian()方法中的变量a、b的副本传入swap()方法,而不是a、b本身。
程序在swap()方法中,进行变量a、b交换的值,交换结束后,内存中的存储情况:
两个示意图可以发现,mian()方法栈区中a、b值并未发生改变,程序只改变swap()栈区中的变量a、b。这就是值传递的实质:当系统开始执行方法时,系统为形参初始化,就是把实参变量的值赋给方法的形参变量,方法里操作的并不是实参变量。
再看一个例子:
1 class DataWrap 2 { 3 int a; 4 int b; 5 } 6 7 public class ReferenceTransferTest 8 { 9 public static void swap(DataWrap dw) 10 { 11 //下面实现的dw的两个成员的变量值的交换 12 var temp=dw.a; 13 dw.a=dw.b; 14 dw.b=temp; 15 System.out.println("swap()方法里,a成员变量的值是:" + dw.a + ",b成员变量的值是:"+dw.b); 16 } 17 18 public static void main(String[] args) 19 { 20 var dw=new DataWrap(); 21 dw.a=6; 22 dw.b=9; 23 swap(dw); 24 System.out.println("swap()方法里,a成员变量的值是:"+dw.a+",b成员变量的值是:"+dw.b); 25 } 26 } 27 ---------- 运行Java捕获输出窗 ---------- 28 swap()方法里,a成员变量的值是:9,b成员变量的值是:6 29 swap()方法里,a成员变量的值是:9,b成员变量的值是:6 30 31 输出完成 (耗时 0 秒) - 正常终止
上面结果swap()方法里和mian()方法里的两个变量a、b都发生了改变。这很容易产生错觉:调用swap()方法时,传入的时dw本身,而不是它的复制品。
下面分析一下程序执行的过程:
(1)程序从mian()方法开始执行:
var dw=new DataWrap();
dw.a=6;
dw.b=9;
这里创建了一个DataWrap对象,并赋给引用变量dw。堆内存保存该对象本身,栈内存保存的该对象的引用变量。
(2)执行swap(dw);
接下来main()方法开始调用swap()方法,mian(0方法并未结束,系统会为main()和swap()开辟两个栈区,用于存放mian()和swap()方法里的局部变量。调用swap(0方法时,dw作为实参传入swap()方法,同样采用值传递:把main()方法里的dw变量赋值给swap()方法里的dw形参,从而完成swap()方法的dw形参初始化。下图显示main()方法中实参dw传入swap()方法后的存储示意图:
系统只复制了dw变量,但未复制DataWrap对象。
不管程序在swap()方法中还是在mian()方法的操作dw变量时,实际操作的都是堆内存中的DataWrap对象,他们引用的是同一个变量。因此在swap()方法中交换了dw所引用的a、b两个成员变量后,可看到在main()方法中dw引用变量引用的a、b变量的值也发生了改变。
实际上,我们在创建swap()方法时,将
public static void swap(DataWrap dw);中的dw换个符号表示理解起来就更容易,不易混淆。
三、形参个数可变的方法
Java允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参。如果在定义方法时,在最后一个形参的类型后增加三点(...),则表示该形参可以接受多个参数值,多个参数被当作数组传入。
1 class VarArgs 2 { 3 public void test(int a,String... names) 4 { 5 System.out.println("a参数:"+a); 6 System.out.println("names数组的长度:"+names.length); 7 for(int i=0;i<names.length;i++) 8 { 9 System.out.println(names[i]); 10 } 11 } 12 public static void main(String... args) 13 { 14 VarArgs va=new VarArgs(); 15 va.test(2,"efdf","fdfs","fjgd"); 16 va.test(34,new String[]{"孙悟空","猪八戒"}); 17 } 18 } 19 class VarArgs 20 { 21 public void test(int a,String... names) 22 { 23 System.out.println("a参数:"+a); 24 System.out.println("names数组的长度:"+names.length); 25 for(int i=0;i<names.length;i++) 26 { 27 System.out.println(names[i]); 28 } 29 } 30 public static void main(String... args) 31 { 32 VarArgs va=new VarArgs(); 33 va.test(2,"efdf","fdfs","fjgd"); 34 va.test(34,new String[]{"孙悟空","猪八戒"}); 35 } 36 } 37 ---------- 运行Java捕获输出窗 ---------- 38 a参数:2 39 names数组的长度:3 40 efdf 41 fdfs 42 fjgd 43 a参数:34 44 names数组的长度:2 45 孙悟空 46 猪八戒 47 48 输出完成 (耗时 0 秒) - 正常终止
va.test(2,"efdf","fdfs","fjgd"); va.test(34,new String[]{"孙悟空","猪八戒"});
这两种多形参传入方法都可以,但是第一种方法更加简洁。
类型[] 形参名
类型...写法的好处是:
调用方法时更加方便,即可直接传入多个元素,系统会自动将它们封装为数组
也可直接传入数组
确定:类型... 这种写法只能作为形参列表的最后一个形参
【暗示】一个方法只能由一个形参个数可变的形参
再看一个例子:
1 class VarIntTest 2 { 3 public int add(int... num) 4 { 5 int result=0; 6 for (int i=0;i<num.length;i++) 7 { 8 result+=num[i]; 9 } 10 return result; 11 } 12 public static void main(String[] args) 13 { 14 var p=new VarIntTest(); 15 System.out.println(p.add(1,2,3,4)); 16 } 17 } 18 ---------- 运行Java捕获输出窗 ---------- 19 10 20 21 输出完成 (耗时 0 秒) - 正常终止
原文地址:https://www.cnblogs.com/weststar/p/12341091.html