方法调用时方法覆盖的变量传递值 - Java

时间:2016-10-13 04:52:14

标签: java

我是学生,目前正在学习java。 据我所知,java从上到下读取代码,但我的程序行为令我感到困惑。 这不是我的完整程序,我创建了一个更简单的程序来强调我不理解的部分。

我有两个项目:

Problem.java - 我的主要项目。

Procedures.java - 包含许多公共void方法,我只是创建它来重用一组代码。示例:GetAllDigits() - 这是为了获取String的每个数字/字符并存储在ArrayList中。

正如您在将变量account传递给GeAllDigits()后所看到的那样,我立即将值解析为String AllDigits(这是为了保存第一个结果。我这样做是因为我知道我将再次调用该方法,并将有另一个结果)。然后我将第二个结果存储在变量ThreeDigits中。

所以我的预期输出应该

所有数字:[2,0,1,0,0,5]

三位数:[2,0,1]

但我得到了:

所有数字:[2,0,1]

三位数:[2,0,1]

String account = "201005";
ArrayList<String> AllDigits = new ArrayList<>();
ArrayList<String>  ThreeDigits = new  ArrayList<>();
String num = new String();

Public Problem()
{   int length = account.length();
    Procedures proc = new Procedures();
    proc.GetAllDigits(account);
    AllDigits = proc.digits;

    for(int x=0;x < (length-3);x++)
    {
        num += AllDigits.get(x);
    }
    proc.GetAllDigits(num);
    ThreeDigits = proc.digits;

    System.out.println("All Digits: " + AllDigits.toString());
    System.out.println("Three Digits: " + ThreeDigits.toString());
}

public static void main(String[] args) {
    new Problem();
}

这就是Procedures.java的样子:

public ArryList<String> digits = new ArrayList<>();

public void OddEvenDigits(String number)
{...
}

public void GetAllDigits(String acc){
    digits.clear();
    for(int i =0; i < acc.length(); i++)
     {
       int j = Character.digit(acc.charAt(i), 10);
       digits.add(Integer.toString(j));
     }
}

对于这个关于这个简单问题的长篇文章感到抱歉。任何答案都将非常感谢,如果有任何网站/书籍,你可以推荐我学习,这将是非常棒的!

5 个答案:

答案 0 :(得分:1)

您收到了All Digits: [2, 0, 1] Three Digits: [2, 0, 1],因为您从同一个GetAllDigits对象中调用了proc
在java中,一个对象可以有多个引用,因此每次从同一个GetAllDigits对象调用proc时,此更改都会反映在所有引用中{{1} }和Alldigits相同为了获取所需的值,请从新的Threedigits对象中调用GetAllDigits

答案 1 :(得分:0)

如果您可以在某些IDE中学习调试或在程序中更改后打印所有值以了解您编写的代码的行为,那么您将更容易。 要回答你的问题,

All Digits: [2, 0, 1]

这是因为您使用length-3的这一行:

for(int x=0;x < (length-3);x++)

通过编写另一个类似的println来验证它:

Procedures proc = new Procedures();
proc.GetAllDigits(account); //Call1 GetAllDigits("201005")
AllDigits = proc.digits;

//This should print  [2, 0, 1, 0, 0, 5]
System.out.println("All Digits: " + AllDigits.toString());

// (length-3) reduces the string to be traced by 3
for(int x=0;x < **(length-3)**;x++)
{
    num += AllDigits.get(x);
}

//Value of num = "201"
proc.GetAllDigits(num); //Call2 GetAllDigits("201"). Here ArrayList digits gets cleared
ThreeDigits = proc.digits;

System.out.println("All Digits: " + AllDigits.toString());
System.out.println("Three Digits: " + ThreeDigits.toString());

如果您想保留值,建议您更改代码:

public ArryList<String> GetAllDigits(String acc){
    public ArryList<String> digits = new ArrayList<>();
    //digits.clear();

    for(int i =0; i < acc.length(); i++)
     {
       int j = Character.digit(acc.charAt(i), 10);
       digits.add(Integer.toString(j));
     }

     return digits;
}

在Program()中试试这个:

Public Problem()
{   int length = account.length();
    Procedures proc = new Procedures();
    AllDigits = proc.GetAllDigits(account);
    //AllDigits = proc.digits;

    for(int x=0;x < (length-3);x++)
    {
        num += AllDigits.get(x);
    }
    ThreeDigits = proc.GetAllDigits(num);

    System.out.println("All Digits: " + AllDigits.toString());
    System.out.println("Three Digits: " + ThreeDigits.toString());
}

建议您学习以下概念以进一步了解: - 调试代码 - static功能 - Java中的命名约定。 希望这可以帮助。快乐的编码!

答案 2 :(得分:0)

出现问题是因为您使用了相同的Procedures实例。 当您的代码到达

行时

proc.GetAllDigits(NUM);

它改变了proc.digits的值

用于设置AllDigits和ThreeDigits的值。

尝试创建一个新的Procedures实例 即程序procs = new Procedures(); procs.GetAllDigits(NUM);

答案 3 :(得分:0)

在致电AllDigits.toString()之前尝试打印proc.getAllDigits(num)。在Inside Procedure中,您有一个名为digits的成员,这是一个数组列表,每次调用getAllDigits()时都会被清除并设置为新数字。因此,当您打印出AllDigits和ThreeDigits时,它们都只是打印出proc.digits中的值,这些值最近更新为[2,0,1]

看看这个post有关在java中复制值的内容,但是讨论了对象的引用,这将有助于您理解这个问题。

答案 4 :(得分:0)

您的代码中存在许多问题。通常,解决这些问题的最简单方法是将代码缩减到您能想到的最简单的示例,并让它逐个工作,直到您能够确定导致问题的原因为止。

使用无状态方法替换全局变量的使用

在这种情况下,您在多个位置引用相同的全局变量digits(在proc实例中),因此当其值发生变化时,它会随处变化。

解决方案是使Procedures.getAllDigits 静态无状态。不要依赖共享的实例变量。它应该每次创建一个新的List,并返回该值。这样,getAllDigits的逻辑就不依赖于该方法之外的任何东西。请参阅下面的简单示例。

命名约定

此外,您在整个代码中都在蔑视Java命名约定。方法名称和变量名称应在lowerCamelCase中。类名应在UpperCamelCase中。相信我,当我说它在可读性方面有很大的不同,因此使你的代码更容易理解。

其他需要注意的事项

  1. 在循环时构建字符串时,请使用StringBuilder
  2. 无需将逻辑从main方法移动到对象构造函数(例如new Problem())。构造函数应该只负责创建对象的实例,而不是存储应用程序的逻辑。
  3. import java.util.ArrayList;
    import java.util.List;
    
    public class Problem {
    
        public static void main(String[] args) {
            String account = "201005";
    
            List<String> allDigits = Procedures.getAllDigits(account);
    
            StringBuilder builder = new StringBuilder();
    
            for(int x = 0; x < account.length() - 3; x++) {
                builder.append(allDigits.get(x));
            }
    
            List<String> threeDigits = Procedures.getAllDigits(builder.toString());
    
            System.out.println("All Digits: " + allDigits.toString());
            System.out.println("Three Digits: " + threeDigits.toString());
        }
    
        private static class Procedures {
            private static List<String> getAllDigits(String acc) {
                List<String> digits = new ArrayList<>();
    
                for(int i =0; i < acc.length(); i++) {
                    int j = Character.digit(acc.charAt(i), 10);
                    digits.add(Integer.toString(j));
                }
    
                return digits;
            }
        }
    }