4.2 方法所属性、方法参数传递机制、形参个数可变的方法

一、方法的所属性

  方法由传统的函数发展而来,方法与传统的函数显著不同:在结构化编程中,函数是一等公民,这个程序由一个个函数组成;在面向对象编程语言里,类才是一等公民,整个系统由一个个类组成。因此在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 秒) - 正常终止

猜你喜欢

转载自www.cnblogs.com/weststar/p/12341091.html
4.2