请问这个程序要怎么理解?

img

首先运行结果嘛,直接放到IDEA里运行就OK了。让我们先看一下运行结果再来逐步分析代码在运行的时候都干了啥:

img


可以看到,代码最后的输出结果是:Ccount is 101 Time is 0
OK,现在我们顺着代码执行的顺序,来分析一下在执行这段代码的时候,代码都干了啥,怎么干的:
先看所有的源码:

public class Test
{
    public static void main(String[] args)
    {
        Count myCount = new Count();
        int times=0;
        for (int i=0;i<100;i++)
            increment(myCount,times);
        System.out.println("Ccount is "+myCount.count);
        System.out.println("Time is "+ times);
    }
    public static void increment(Count c,int times)
    {
        c.count++;
        times++;
    }
}
class Count
{
    public int count;
    Count(int c)
    {
        count = c;
    }
    Count()
    {
        count = 1;
    }
}

ok,首先,代码执行的时候肯定要执行main方法,然后,开始逐一执行main内的代码,首先main内的代码第一行
Count myCount = new Count();
是实例化了一个Count对象是吧?实例化对象就要找构造器对吧?我们来看Count类

class Count
{
    public int count;
    Count(int c)
    {
        count = c;
    }
    Count()
    {
        count = 1;
    }
}

可以看到,里面有一个有参构造器和一个无参构造器。由于我们在实例化对象的时候括号内没有提供参数,所以虚拟机会调用无参构造器。在执行完构造器代码的时候,这个对象myCount所含有的一个实例字段 count 就被设置成了1。这样,在第一次调用构造器后,myCount.count就等于1了。鉴于此种情况,我们可以在count前面加上this.用以指示隐式参数。同时提高代码的可读性。
OK,构造器分析完了。在执行完构造器后,myCount.count就等于1了,接下来继续执行main的下一部分
int times=0;
for (int i=0;i<100;i++)
increment(myCount,times);
这部分呢,我们把times设置成了0,然后执行for,for会循环100次,每次循环都会调用increment这个方法。这个方法有两个参数
Count c,int times
而执行内容是
c.count++;
times++;
可以看到,是一个修改对象的实例字段的方法,在重复执行100次后,myCount.count就被加了100。100+1=101,所以最后打印出来的myCount.count就是101
那你可能会问,为什么最后打印出来的time值还是0呢?我们看,由于increment被声明为void,导致它不会返回任何值。由于这里的times只是一个参数而并非一个对象的示例字段,这就导致了方法执行完后times就会被抛弃了。times的值也不会反馈给main中的times的值。因为在不同的代码块中相同名字的变量是没有联系的,而这个increment又被声明为void,所以main中的times变量是不会收到increment方法中的times参数的牵连的。自然循环了100遍之后main中的times变量还是0。 如果你在increment方法添上System.out.println(times);这一行,你会发现,100次循环中每次打印的times的值都是1

img


为啥捏?前面说过了。这个times只是increment方法的一个参数。由于increment方法被声明为void,这就导致它自身内部的参数不会流传出去。而myCount.count之所以受到increment方法的影响,是因为人家是实例字段而并非一个方法的参数。方法参数由一个方法储存,实例字段由一个对象储存。方法参数要想反馈给一个变量储存就必须有return语句反馈给外部调用者,再赋值给一个变量或者直接在方法内部赋值给一个外部变量。实例字段则不需要这样。每次更改实例字段都会被对象储存下来。由于increment方法被声明为void,那么它就不能含有return,又因为方法内没有使用外部变量,因而内部参数times就流传不出去。每一次执行参数都会被抛弃一次。所以导致每次打印times都是1。因而main中的变量times就不会受到方法中参数times的影响,最后导致打印times还是0
OK,差不多就这些内容。觉得有帮助请采纳,如果发现哪里说的不对的地方,恳请批评指正,谢谢

Java 方法调用时,传递给方法的是实际的值,对于基本类型而言就是变量实际的值,对于引用类型而言是这个变量地址的值。

因此方法内部代码执行时改变方法基本类型参数的值不会影响到外部,改变引用类型方法参数的属性会影响到这个这个引用类型的实例。

题主看看能不能理解,如果不能理解我再画一个图。

直接上代码。

public class Test {

    public static void main(String[] args) {
        // 调用无参数构造方法,将 Count 成员变量 count 设置为 1
        Count myCount = new Count();
        int times = 0;
        for (int i = 0; i < 100; i++) {
            // 循环 100 次调用方法
            increment(myCount, times);
        }
        // 循环了 100 次,因此 count 值加了 100遍,值为 101
        System.out.println("count is " + myCount.count);
        // 循环了 100次,但改变的都是 increment 方法参数的值,并不是 main 方法 times 的值,因此 times 值为 0
        System.out.println("time is " + times);
    }
    
    public static void increment(Count c, int times) {
        // 将 Count 类型的 c 对象的成员变量 count 加 1
        c.count++;
        // 将方法参数 times 的值加 1
        times++;
    }

}

101 0
引用数据类型 Count是可以被方法中修改的 times是基本数据类型,传递过去是不可变的