Access the pointer to an ArrayList? - java

I have an ArrayList in Java. Now, I want to access the pointer to the said list. This is so that I can make a variable out of the pointer and make operations using it. Any advise on how to do this?
What I want to do exactly is similar to making "list" below always point to the value of "someOtherList".
import java.util.ArrayList;
import java.util.List;
public class ListContainingObject {
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public static void main(String args[]){
ListContainingObject listContainingObject= new ListContainingObject();
System.out.println(listContainingObject.getList());
List someOtherList = new ArrayList();
listContainingObject.setList(someOtherList);
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
someOtherList.add("1");
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
//I want the two below to have the same value
someOtherList = new ArrayList();
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
}
}
The seemingly appropriate workaround would be to call the setters again explicitly like below.
public class ListContainingObject {
public void resetList(List toReset) {
this.list = new ArrayList();
toReset = this.list;
}
}
listContainingObject.resetList(someOtherList);
But this would lead to another problem wherein I want solcowiab.getList() and listContainingObject.getList() below to always be the same, assuming that I don't have the source code for SomeOtherListContainingObjectWhichIsABlackBox.
import java.util.ArrayList;
import java.util.List;
public class ListContainingObject {
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public static void main(String args[]) {
ListContainingObject listContainingObject = new ListContainingObject();
SomeOtherListContainingObjectWhichIsABlackBox solcowiab = new SomeOtherListContainingObjectWhichIsABlackBox();
List aNewList = new ArrayList();
aNewList.add("1");
solcowiab.setList(aNewList);
listContainingObject.setList(solcowiab.getList());
System.out.println(listContainingObject.getList());
System.out.println(solcowiab.getList());
//The two below will have the same value but
//at some point "list" did not point to "someOtherList"
solcowiab.aMethodThatSupposedlyWontCallSetList();
listContainingObject.setList(solcowiab.getList());
System.out.println(listContainingObject.getList());
System.out.println(solcowiab.getList());
}
}
class SomeOtherListContainingObjectWhichIsABlackBox {
private List someOtherList;
public List getList() {
return someOtherList;
}
public void setList(List list) {
this.someOtherList = list;
}
public void aMethodThatSupposedlyWontCallSetList() {
//this one won't be observed by ListContainingObject
setList(new ArrayList());
getList().add("2");
//do some other stuff
//only this assignment will be controlled by ListContainingObject's main method
setList(new ArrayList());
}
}

You can't because the line someOtherList = new ArrayList(); is assigning a whole new "section of memory" to someOtherList, meaning it will point to a different place in memory than listContainingObject.getList().
Now it is true that the listContainingObject has only a reference to your created list, but this reference is not semantically linked to someOtherList. So if someOtherList changes, your object won't know about it.
If you want to clear the lists without destroying the link, use someOtherList.clear() instead.
EDIT: You may be able to get away with resetting the list another way:
public class ListContainingObject {
public void resetList(List toReset) {
this.list = new ArrayList();
toReset = this.list;
}
}
listContainingObject.resetList(someOtherList);
This is, however, a pretty dirty hack. But without somehow manually changing both variables to reference the new structure in memory, I know of no way to get one to automatically update the other.

Probably, you are trying to update the contents of the "list" field.
Please find an solution here:
import java.util.ArrayList;
import java.util.List;
public class ListContainingObject {
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public static void main(String args[]){
ListContainingObject listContainingObject= new ListContainingObject();
System.out.println(listContainingObject.getList());
List someOtherList = new ArrayList();
listContainingObject.setList(someOtherList);
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
someOtherList = listContainingObject.getList();
someOtherList.add("1");
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
//I want the two below to have the same value
//someOtherList = new ArrayList();
someOtherList.clear();
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
}
}
Thus, someOtherList is referring to the "list" field which is the same.
You have to again setList to the new address as once someOtherList is referring to different. So, as required "list" should be updated also and must be followed elsewhere.
Suppose you have a method, which modifies this list you can achieve this by below.
public void someMethod(){
List someOtherList = getList();
someOtherList = new ArrayList();
//some code
setList(someOtherList);
}
For similar post check: Confused, whether java uses call by value or call by reference when an object reference is passed?

first the someotherlist is pointing to an object in heap
someotherlist ----> Object
then you are making two references to point to the same object in the heap
someotherlist ----
|
Object
|
list -------------
now when you assign the reference someotherlist to a new object in the heap
someotherlist ------> new Object
the object refered by list will not be changed
list -----------> oldobject
you have to call the setters again to make list point to the new object refered by someotherlist
Object (now eligible for garbage collection as referred by none)
someotherobject ------
|
new Object
|
list ------
Note:
you can only refer objects not object references.. what you can do is set up a method for setting the object to someotherlist and assign the same reference to the list also... like
class Test {
List<E> list;
List<E> someOtherList;
setterMethod(ArrayList<E> a) {
someOtherList = a;
list = someOtherList;
}
Edit:
class One {
List<E> list;
public void setList(List<E> newList) {
this.list = newList;
}
//getters and setters and other methods
}
class Two {
One one;
List<E> someOtherList;
public void setSomeOtherList(List<E> newList) {
this.someOtherList = newList;
this.one.setList(newList);
}
//getters and setters and other methods
}

Related

Why does static hashmap created for every instances?

I have a course class having one Hashmap. I'm trying to add values to the map with different objects. Map is common for all the objects so I marked it as Static still it shows weird behavior.
I have the following code -
class Course
{
static HashMap<Integer,List<String>> map;
Course()
{
map = new HashMap<>();
}
public boolean add(int id,String Course)
{
if(!map.containsKey(id))
{
map.put(id,new ArrayList<>());
}
try
{
List<String> temp = map.get(id);
temp.add(Course);
return true;
} catch (Exception e)
{
return false;
}
}
public void get()
{
System.out.println(map);
}
public static void main(String[] args)
{
Course c = new Course();
c.add(1, "abs");
c.add(2,"xyx");
c.add(1,"new");
c.add(3,"tye");
c.get();
Course c2 = new Course();
c2.add(1,"GP");
c2.add(2, "PT");
c2.get();
}
}
I have defined Hashmap as static because it is common for all the objects. But still, the new Hashmap is created for every instance.
Output
{1=[abs, new], 2=[xyx], 3=[tye]}
{1=[GP], 2=[PT]}
Because you initialize it in the constructor.
Don't. Just initialize it on the field:
static HashMap<Integer,List<String>> map = new HashMap<>();
(And remove the constructor).
And consider making the field final if you never intend to reassign it. This ensures that 1) you don't actually reassign it; 2) you actually do assign it once.

Java - Access Object's Array List through HashMap (Key is object)

I am trying to loop through a HashMap, then for each key I want to access the object (Shipment) that is associated to the key and access my array list for further analysis purposes. Each object/key in HashMap has the same array list (metricList). I cannot seem to access it, though I have checked the private/public thing. Can someone point me in the right direction?
I think I need to maybe get the class of my object and then use the method "getList"... I tried with no luck.
This is a sample of the code (removed irrelevant parts) if it helps:
This is my object:
public class Shipment{
//Members of shipment
private final String shipment;
public Date creationDate;
public int creationTiming;
public int processingTiming;
public ArrayList<Integer> metricList;
public void createArrayList() {
// create list
metricList = new ArrayList<Integer>();
// add metric to list
metricList.add(creationTiming);
metricList.add(processingTiming);
}
public ArrayList<Integer> getList() {
return metricList;
}
}
This is the class where I create a hashMap and run through different analysis:
public class AnalysisMain {
public static Map<String, Shipment> shipMap = new HashMap();
public static void main(String[] args) {
try {
... // Different calls to analysis
}
catch {}
}
}
This is where the issue occurs (it does not recognize that I already have a "metricList", asking if I want to create local variable)
public class Metric_Analysis{
public static void analyze() throws Exception{
ResultSet rs;
try {
rs = getSQL("SELECT * FROM TEST_METRICS");
}
catch(Exception e) {
//Pass the error
throw new java.lang.Exception("DB Error: " + e.getMessage());
}
Iterator<Map.Entry<String, Shipment>> iterator = shipMap.entrySet().iterator();
while(iterator.hasNext()){
Iterator<String> metricIterator = metricList.iterator();
//Above is the Array List I want to access and loop through
//I will then perform certain checked against other values on a table...
while (metricIterator.hasNext()) {
//I will perform certain things here
}
}
}
}
You need to get the List out of your Shipment.
You can access the object from the iterator with: iterator.next();
This will also set the pointer to the next Entry in your List/Map.
Change your code:
Iterator<Map.Entry<String, Shipment>> iterator = shipMap.entrySet().iterator();
while(iterator.hasNext()){
// Get the Entry from your Map and get the value from the Entry
Entry<String, Shipment> entry = iterator.next();
List<Integer> metricList = entry.getValue().getList();
Iterator<String> metricIterator = metricList.iterator();
//Above is the Array List I want to access and loop through
//I will then perform certain checked against other values on a table...
while (metricIterator.hasNext()) {
//I will perform certain things here
}
}

Allow only one thread at the time to use an object

I have the following class:
public class MyClass{
private List<Integer> ints = new LinkedList<Integer>();
public List<Integer> getInts(){
return ints;
}
public synchronized void doAction(){
//Do some with the list
}
}
I need to allow only one thread at the time having acces to the List. I would do that as follows:
public class MyClass{
private List<Integer> ints = new LinkedList<Integer>();
private static final Semaphore s = new Semaphore(1);
public List<Integer> getInts(){
s.acquire();
return ints;
}
public void release(){
s.release();
}
public synchronized void doAction(){
s.acquire();
//Do some with the list
s.release();
}
}
But the implementaion is obviously not reliable, because if the client request the List through the getter for adding some elements into it and forget to call release() we'll get into troubles if try to invoke the doAction method.
What is the solution for the problem?
Don't allow the client to get the reference. Put all the methods that work on the list to MyClass and synchronize them.
You can allow the users to get a snapshot copy of the list however.
You could use a synchronized list:
private List<Integer> ints = Collections.synchronizedList(new LinkedList<Integer>());

custom arraylist with notification for delete and add

I want to detect when adding some items to the array list or when removing some item from it. Actually I have some code like below:
public class myClass {
MyCustomArrayList<MyObject> al;
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
private void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
private void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}
I know that array list has not the ability for having listener or some kind of notifications or events and if I want to detect add should have a custom array list. something like below class:
class MyArrayList<T> {
private ArrayList<T> list;
public MyList(){
list = new ArrayList<>();
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
}
(I get it from here)
So the question is that: how can I inform the object of MyArrayList (al) that call DoByEachAdd and DoByEachRemove methods when the remove and add method fired. Does some body have any ideas?
First, follow naming convention. Second, the three class names you used for the same class, MyList, MyArrayList and MyCustomArrayList will confuse people. As for your question, you would have to have an instance field inside MyArrayList of type myClass (unless you want to refactor DoByEachAdd and DoByEachRemove to be static). This can be done by adding it as a constructor parameter, e.g.
// inside MyArrayList
private ArrayList<T> list;
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
Also, I question your approach. Other classes with instances of MyArrayList can only use the add and remove methods of ArrayList. If you want to save a lot of bother and have all methods visible, either declare list as public final or make MyArrayList a subclass of ArrayList, e.g.
public class MyArrayList<T> extends ArrayList<T> {
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
#Override
public boolean add(T t) {
boolean returnThis = super.add(t);
// do some stuff
instance.DoByEachAdd();
return returnThis;
}
#Override
public boolean remove(T t) {
boolean returnThis = super.remove(t);
// do some stuff
instance.DoByEachRemove();
return returnThis;
}
}
If you insist on being able to return a T from remove, declare another method:
public T removeT(T t) {
remove(t);
// do some stuff
return someT;
}
you need to give access to your myClass to MyArrayList
class MyArrayList<T> {
private ArrayList<T> list;
private myClass theClass;
public MyList(myClass theClass){
list = new ArrayList<>();
this.theClass = theClass;
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
theClass.DoByEachAdd();
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
theClass.DoByEachRemove
}
and in your myClass give the object to your list
public class myClass {
MyCustomArrayList<MyObject> al;
public myClass(){
al = new MyCustomArrayList<MyObject>(this);
}
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
public void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
public void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}

Java synchronization: Synchronization method and synchronization block

I have a mulitThread Java application. In one method, there is a need to synchronize a ArrayList. Since arrayList is not a thread safe, so I have to use synchonization. The problem is that object which is type of ArrayList is not a member variable of the object. Prototype of the method is as follows:
public void simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
//...Codes manipulate the list
}
Due to mulitthreading, shall I use
A)
public void synchronized simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
//...Codes manipulate the list
}
Or
B)
public void simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
Synchronized(list){
//...Codes manipulate the list
}
}
From the performance test, neither works.
But I donot know why?
Here comes whole source codes:
package com.juhani.prototype.sync;
import java.util.ArrayList;
public class ArrayListWrapper {
public ArrayList<Integer> aList = new ArrayList<Integer>();
public ArrayListWrapper(){
Integer one = new Integer(1);
Integer two = new Integer(2);
Integer three = new Integer(3);
aList.add(one);
aList.add(two);
aList.add(three);
}
}
package com.juhani.prototype.sync;
import java.util.ArrayList;
public class TestClass {
public int count_test=0;
public synchronized void test(ArrayListWrapper listWrapper){
ArrayList<Integer> list = listWrapper.aList;
int temp = list.get(1)+1;
list.set(1,temp);
}
public void testBlock(ArrayListWrapper listWrapper){
ArrayList<Integer> list = listWrapper.aList;
synchronized(list){
int temp = list.get(1)+1;
list.set(1,temp);
}
}
}
package com.juhani.prototype.sync;
public class WorkerSyncObj extends Thread {
ArrayListWrapper listWrapper = null;
TestClass tc = null;
int number;
public WorkerSyncObj(int aNumber){
number = aNumber;
}
public void setListWrapper(ArrayListWrapper aListWrapper){
listWrapper = aListWrapper;
}
public void setTestClass(TestClass aTc){
tc = aTc;
}
public void run(){
int i = 1000;
for(int j=0;j<i;j++){
tc.testBlock(listWrapper);
System.out.println("Thread "+number+" is runing at loop "+j+" . index 1 value is:"+listWrapper.aList.get(1));
}
}
}
package com.juhani.prototype.sync.main;
import com.juhani.prototype.sync.ArrayListWrapper;
import com.juhani.prototype.sync.TestClass;
import com.juhani.prototype.sync.WorkerSyncObj;
public class TestMain {
public static void main(String[] args){
ArrayListWrapper list = new ArrayListWrapper();
TestClass tc = new TestClass();
WorkerSyncObj work1 = new WorkerSyncObj(1);
work1.setListWrapper(list);
work1.setTestClass(tc);
WorkerSyncObj work2 = new WorkerSyncObj(2);
work2.setListWrapper(list);
work2.setTestClass(tc);
WorkerSyncObj work3 = new WorkerSyncObj(3);
work3.setListWrapper(list);
work3.setTestClass(tc);
work1.start();
work2.start();
work3.start();
}
}
In the first case you lock on the this object while in the second on the list object. This might be a problem if you call the method from different objects but the list is the same. This is can be the reason of the exception in the first case.
Alternatively you could try some built-in concurrent types like Collections.synchronizedList or CopyOnWriteArrayList.
In java, every object instance has an intrinsic lock (as well as corresponding class itself). Synchronzied keywork is actually use the intrinsic lock for exclusive access, i.e.
syncrhonized method(...) {...}
is equal to
method(...) {
this.intrinsicLock.lock();
...;
this.intrinsicLock.unlock() }
And
synchronized( obj_ref ) { ... }
is equal to
obj_ref.intrinsicLock.lock();
{...}
obj_ref.instrinsicLock.unlock();
So, syncrhonized the method is not right for the protection of list (the parameter). There are two problems if you use the synchronized( list):
1. The granularity of exclusive access seems a little gross
2. Every list access wherever in the whole program need to use "synchronized( list )" too. This is a protocol (for the exclusive acess).
That's the reason why Java library provide quite some concurrent data structures.

Categories

Resources