0

Kindly advise what I am doing wrong here. I am getting the output like

[{"ItemId":"Item C"},{"ItemId":"Item C"},{"ItemId":"Item C"}]

Instead of I am expecting..

[{"ItemId":"Item A"},{"ItemId":"Item B"},{"ItemId":"Item C"}]


    public class ItemClass{
        public String ItemId;
    }


    List<ItemClass> lst = new List<ItemClass>();
    ItemClass ord = new ItemClass();

    ord.ItemId = 'Item A';
    lst.add(ord);

    ord.ItemId = 'Item B';
    lst.add(ord);

    ord.ItemId = 'Item C';
    lst.add(ord);

    System.debug(JSON.serialize(lst));

2 Answers 2

2

When you declare a variable, you are declaring that you would like to hold a "reference" (memory address) of an object in the "heap". The variable only holds a memory address that references the heap, not the object itself. You can declare multiple variables that refer to the same area of the heap.

ItemClass a = new ItemClass();
ItemClass b = a;

Note that b and a are the same object on the heap. You only get a new object in the heap when you use the new operator, or for certain factory functions and string concatenation. Most primitive types are immutable (cannot be changed), so most methods that work on primitives return a new object on the heap. Custom objects, however, are volatile by default, meaning they can be changed by code.

When you created the list of items, you actually just added the same reference to the list three times, rather than creating three distinct objects in the heap. It's not the objects that are duplicated, but rather the references to the same object that has been duplicated.

You can see this in the debug logs; adding the value to the list is adding the same memory address repeatedly:

10:58:28.1 (9577707)|STATEMENT_EXECUTE|[9]
10:58:28.1 (9587110)|HEAP_ALLOCATE|[9]|Bytes:6
10:58:28.1 (9616559)|VARIABLE_ASSIGNMENT|[9]|this.ItemId|"Item A"|0x61e029cf
10:58:28.1 (9629477)|STATEMENT_EXECUTE|[10]
10:58:28.1 (9817670)|SYSTEM_METHOD_ENTRY|[10]|List<ItemClass>.add(Object)
10:58:28.1 (9929730)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
10:58:28.1 (9974642)|SYSTEM_METHOD_EXIT|[10]|List<ItemClass>.add(Object)
10:58:28.1 (10013977)|STATEMENT_EXECUTE|[12]
10:58:28.1 (10026303)|HEAP_ALLOCATE|[12]|Bytes:6
10:58:28.1 (10062476)|VARIABLE_ASSIGNMENT|[12]|this.ItemId|"Item B"|0x61e029cf
10:58:28.1 (10073835)|STATEMENT_EXECUTE|[13]
10:58:28.1 (10142552)|SYSTEM_METHOD_ENTRY|[13]|List<ItemClass>.add(Object)
10:58:28.1 (10162068)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
10:58:28.1 (10177472)|SYSTEM_METHOD_EXIT|[13]|List<ItemClass>.add(Object)
10:58:28.1 (10185858)|STATEMENT_EXECUTE|[15]
10:58:28.1 (10191640)|HEAP_ALLOCATE|[15]|Bytes:6
10:58:28.1 (10208963)|VARIABLE_ASSIGNMENT|[15]|this.ItemId|"Item C"|0x61e029cf
10:58:28.1 (10221902)|STATEMENT_EXECUTE|[16]
10:58:28.1 (10254502)|SYSTEM_METHOD_ENTRY|[16]|List<ItemClass>.add(Object)
10:58:28.1 (10271297)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
10:58:28.1 (10282736)|SYSTEM_METHOD_EXIT|[16]|List<ItemClass>.add(Object)
10:58:28.1 (10291801)|STATEMENT_EXECUTE|[18]

In my example, 0x61e029cf is the object in the heap. You can see how you just added the same value each time.

In order to fix this, you need to actually use new every time.

List<ItemClass> lst = new List<ItemClass>();
ItemClass ord = new ItemClass();

ord.ItemId = 'Item A';
lst.add(ord);

ord = new ItemClass();
ord.ItemId = 'Item B';
lst.add(ord);

ord = new ItemClass();
ord.ItemId = 'Item C';
lst.add(ord);

System.debug(JSON.serialize(lst));
1
  • Thank you for explanation. Commented Feb 12, 2023 at 18:10
0

When you add an object to a list you are actually adding a reference to the object so all this is doing is adding the same object reference 3 times to a list and changing the same object 3 times one way to deal with this as follows.

public class ItemClass{
    public String ItemId;
}


List<ItemClass> lst = new List<ItemClass>();
ItemClass ord = new ItemClass();

ord.ItemId = 'Item A';
lst.add(ord);

ord = new ItemClass();
ord.ItemId = 'Item B';
lst.add(ord);

ord = new ItemClass();
ord.ItemId = 'Item C';
lst.add(ord);

System.debug(JSON.serialize(lst));

you should find it works

4
  • Yep, this boils down to OOP (Object-Oritented Programming) basics with a touch of Salesforce-specific behavior. I will note that collections only use references for non-primitive types (so this would not be necessary if you were storing an Integer, Boolean, String, etc...) Commented Feb 12, 2023 at 18:02
  • @DerekF You're technically incorrect, for reasons I don't fully understand but can demonstrate. Try: Long[] a = new Long[0]; a.add((Long)5); a.add((Long)5); and compare the heap usage to Long[] a = new Long[0]; Long b= 5; a.add(b); a.add(b);. You should see an extra 12 bytes of heap usage when not using the variable. Using a variable always returns a reference until you do something that overwrites the reference. Commented Feb 12, 2023 at 18:14
  • 1
    @sfdcfox Bah, figures that I didn't have the complete picture. If technically correct is the best kind of correct though, is being technically incorrect the least bad kind of incorrect? Commented Feb 12, 2023 at 18:53
  • 1
    @DerekF Definitely. It's one of those things that you could use to say, optimize heap usage, but if you need that trick, you've already got bigger problems to worry about, lol. Commented Feb 12, 2023 at 19:20

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.