有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java return hashmap更改指针而不是返回值

虽然我已经编程多年了,但我对Java还是新手。我遇到了一个哈希映射问题,我不知道如何解决。我认为我搜索这个网站很好,但我一定没有使用正确的术语,因为我不认为我是第一个遇到这个问题的人。我必须相信有一个简单的解决方案,我只是没有看到(森林换树木)

我有一个程序,它使用HashMaps在类之间来回传递大量变量。之所以这样做,是因为我们正在连接各种系统,其中包含我们试图在程序中处理的非协调数据

我发现,在做了大量的梳理之后(我没有太多的开始),当HashMap由类中的方法“返回”时,值不会返回给调用类的过程。而是返回一个指向“called”类过程中HashMap的指针。在“调用”类的方法中对HashMap的“副本”的后续修改会反映在被调用类的HashMap中,即使被调用类的HashMap被标记为private(并且这些类在不同的包中!)

同样,对“被调用类的HashMap”的任何修改也会反映在调用类的HashMap中

困惑?我也是,所以我把它归结为一小段代码来复制我发现的东西。(它可能会缩短得更多,但我正试图保留我使用的一些级别。)

  1. 麦因。java-默认包:

    import mainLogic.MainLogic;
    
    public class TMain {
        private static MainLogic  ml = new MainLogic();
    
        public static  void  main(String[] args) { 
            ml.performMainLogic();
        }   
    }
    
  2. 主要逻辑。java——“调用类”

    package mainLogic;
    import java.util.HashMap;
    import subLogic.SubLogic;
    
       public class MainLogic {
    
           private HashMap<String,String> slValues;
    
       public MainLogic() {
         // do constructor stuff here
       }
    
       public void performMainLogic(){
           SubLogic sl = new SubLogic();
    
           sl.performSubLogic();
    
           // returns pointer rather than values?
           slValues = sl.getSLHashUser();
           showSLValues("MainLogic - after calling sl.getSLHashUSer");
           sl.showSLHashUser("MainLogic - calling sl.showSLHashUserafter calling sl.getSLHashUser");
    
           // affects both slValues AND slHash in the SubLogic Class!!!!!
           slValues.put(SubLogic.USER_FLD1,"NEWVALUE");
           showSLValues("MainLogic - slValues after put");
           sl.showSLHashUser("MainLogic - calling SubLogic showSLHashUser after slValues put");
    
           // modifies slHash in SubLogic Class  AND slValues here!!!!!
           sl.doSubLogic2();
           showSLValues("MainLogic - slValues after doSubLogic2");
           sl.showSLHashUser("MainLogic - calling SubLogic showSLHashUser after doSubLogic2");
    
        }       
    
        public void showSLValues(String title) {
            System.out.println(title);
            System.out.println(" slValues");
            System.out.println("  Field 1 :\t" + slValues.get(SubLogic.USER_FLD1)  );
            System.out.println("  Field 2 :\t" + slValues.get(SubLogic.USER_FLD2)  );
            System.out.println("");
        }
    }
    
  3. 子逻辑-被调用的类

    package subLogic;
    import java.util.HashMap;
    
    public class SubLogic {
    
        private HashMap<String,String> slHashUser = new HashMap<String, String>();
    
        // field names slHashUser
        static public final String USER_FLD1  = "ONE";
        static public final String USER_FLD2  = "TWO";
    
        public SubLogic() {
            slHashUser.put(USER_FLD1,  "SubLogic1");
            slHashUser.put(USER_FLD2,  "SubLogic2");
            showSLHashUser("SubLogic - Constructor");
        }
    
        public void performSubLogic(){
            slHashUser.put(USER_FLD1,  "PSubLogic1");
            slHashUser.put(USER_FLD2,  "PSubLogic2");
            showSLHashUser("SubLogic - performSubLogic");
        }
    
        public void doSubLogic2(){
            slHashUser.put(USER_FLD1,  "modified");
            showSLHashUser("SubLogic - doSubLogic");
        }
    
        public HashMap<String,String> getSLHashUser() {
            showSLHashUser("SubLogic - getSubLogic");
            return slHashUser;
        }
    
        public void showSLHashUser(String title) {
            System.out.println(title);
            System.out.println(" slHash Values");
            System.out.println("  Field 1 :\t" + slHashUser.get(USER_FLD1)  );
            System.out.println("  Field 2 :\t" + slHashUser.get(USER_FLD2)  );
            System.out.println("");
       }
    }
    

我的第一个想法是,我需要在生产线的MainLogic中做一些不同的事情:

    slValues = sl.getSLHashUser();

但我不确定真正的问题是否出在SubLogic的getSLHashuser方法中,我尝试在该方法中执行返回:

    return slHashUser;

因为java应该是关于“按值传递”和“按引用传递”(在老派的“C”意义上)的,所以我没有想到这一点

您的帮助将不胜感激,即使这是一个指向正确文档的指针,我一定忽略了


共 (2) 个答案

  1. # 1 楼答案

    当方法返回对可变对象的引用时,该方法的调用方可以通过调用该引用的方法来改变该对象,从而改变调用该方法的对象的状态

    要防止此类修改,您可以返回HashMap的副本:

    public HashMap<String,String> getSLHashUser() {
        showSLHashUser("SubLogic - getSubLogic");
        return new HashMap<String,String>(slHashUser);
    }
    

    这样,更改返回的HashMap不会影响slHashUser成员的内容

  2. # 2 楼答案

    "Confused?"

    不,这是Java中可变对象的工作方式

    Since java is supposed to be all about "passing by value" and "pass by reference" (in the old school "C" sense), I just wasn't expecting this.

    Java方法参数和结果是按值传递的

    然而,有一个微妙之处,许多新手错过了。当您传递或返回一个对象时,传递和复制的是对象引用。。。而不是对象本身的状态

    但如果你记住了这一点,你所观察到的是可以解释的,也是自然的

    如果您的应用程序要求在返回HashMap时进行复制,则需要显式地进行复制。幸运的是,HashMap有一个“拷贝构造函数”,它生成一个新的HashMap,它是现有映射状态的浅拷贝