This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
All references to an object
I'm looking for a way to get a list of class/instance members who have a reference to some variable, in Java.
For instance, for this case:
public class MyClass {
public LinkedList list;
}
public class MyOtherClass {
public LinkedList list;
}
public class Program {
public static void main(...) {
LinkedList list = new LinkedList();
MyClass c1 = new MyClass();
MyOtherClass c2 = new MyOtherClass();
c1.list = list;
c2.list = list;
}
}
At the end of the program we have 3 references for the LinkedList created on my first line of code in Program.main:
Program.main.list
MyClass.list
MyOtherClass.list
While the first one is a local variable (doesn't care for me), the others are instance fields. In this case, what I need it's some way to get, for 2. and 3., the reference to the objects (MyClass and MyOtherClass) and the field name that have the reference for the LinkedList created on line 1.
How can I do that?
"Pure" Java solution: not sure if it works for you, but if you can afford to wrap your object and access it only via wrapper, then you can try WeakHashMap:
public class Wrapper {
private final Object yourObject;
private final WeakHashMap<Object, Object> accessors = new WeakHashMap<Object, Object>();
public Wrapper(Object yourObject) {
this.yourObject = yourObject;
}
// add synchronized if you want thread-safety.
public Object getYourObject(Object accessor) {
accessors.put(accessor, accessor);
return yourObject;
}
// add synchronized if you want thread-safety.
public Object[] getAccessors() {
return accessors.keySet().toArray(new Object[accessors.keySet().size()]);
}
}
Related
I'm struggling with an assignment of mine and I can't figure out how to add another element to my list.
import java.util.ArrayList;
public class Ballot {
private ArrayList<Candidate> ballot;
private String officeName;
public Ballot(String officeName) {
this.officeName = officeName;
ArrayList<Candidate> ballot = new ArrayList<Candidate>();
}
public String getOfficeName() {
return officeName;
}
public void addCandidate(Candidate c) {
ballot.add(c);
}
public ArrayList<Candidate> getCandidates() {
return ballot;
}
public static void main(String[] args) {
Ballot b = new Ballot("Election");
b.addCandidate(new Candidate("Sarah", "President"));
System.out.println(b);
}
}
When I try to run the document, it throws a NullPointerException. What am I doing wrong?
The constructor initializes a local variable named ballot that hides the data member with the same name. Then, when you try to add to it, it fails with a NullPointerException, since it was never initialized. If you initialize it you should be OK:
public Ballot(String officeName) {
this.officeName = officeName;
ballot = new ArrayList<Candidate>(); // Here!
}
You're not initializing your list of candidates properly in the Ballot constructor. You need to do:
this.ballot = new ArrayList<Candidate>();
Right now you're just creating a local variable named ballot in the constructor which shadows the actual class field. Since it has never been initialized, you end up getting a NullPointerException when you eventually try to add an element to it.
Also, as a best practice, use interfaces instead of the concrete type. This makes it easy to change implementations later. So instead of defining the field as private ArrayList<Candidate> ballot;, define it as private List<Candidate> ballot;.
As simple that you are not using this object. You are never initiliazing your object
Correct way
public Ballot(String officeName) {
this.officeName = officeName;
this.ballot = new ArrayList<Candidate>();
}
You're overriding your class variable with a local variable of the same name. Either initialize the list directly
private List<Candidate> ballot = new Arraylist<>();
or initialize it in the constructor with
ballot = new ArrayList<>();
FYI: You shouldn't assign implementation classes for your local variables and return values if you can help it. "ballot" should just be the List interface as should the getter. That way if you ever want to change the implementation, you don't have to change everything. It could be an ArrayList, LinkedList, Stack, Vector, etc and it won't matter because they're all using the List interface.
This question already has answers here:
Why do we need copy constructor and when should we use copy constructor in java
(8 answers)
Closed 3 years ago.
I need to create several new objects from an ArrayList. Suppose my list is:
ArrayList<InvVoucher> list = .....;
int index = 0;
InvVoucher vch1 = list.get(index);
InvVoucher vch2 = list.get(index);
InvVoucher vch3 = list.get(index);
Here vch1, vch2 and vch3 are holding the same object reference. How can I make all of them independent? How can I get three different copy of InvVoucher?
One way would be to implement a copy constructor in IntVoucher as suggested in the comments.
public class IntVoucher {
public IntVoucher(IntVoucher original) {
this.field1 = new Field1(original.field1);
...
}
private Field1 field1;
...
}
That way you can do
IntVoucher vch1 = new IntVoucher(list.get(index));
Another possibility is overriding the clone method in IntVoucher and having it implement the java.lang.Cloneable interface.
public class IntVoucher implements Cloneable {
// note: change from protected to public if needed
protected IntVoucher clone() {
IntVoucher clone = new IntVoucher();
clone.field1 = new Field1(this.field1);
...
return clone;
}
private Field1 field1;
...
}
Read more on shallow / deep copying in Java. There are lots of complete examples if this isn't enough.
The code snippet below is part of some code I am reading for an assignment but I cant understand the role of the copy variable in the snippet or what it does. I know its an instance of the Sample class, but why it is then assigned an ArrayList is not clear to me.
public class Sample implements Var{
private List lst1;
private List lst2;
public Sample() {
super();
}
public Sample(List lst1) {
this();
this.lst1 = lst1;
}
public List getLst1() {
return lst1;
}
public void setLst1(List lst1) {
this.lst1 = lst1;
}
#Override
public Var copy(){
Sample copy = new Sample(lst1);
copy.lst2 = new ArrayList(lst2);
return copy;
}
#Override
public void randomize(){
}
}
In fact the error message is explicit to show that you can't iterate over the variable copy because you haven't implemented the Iterable interface which allows you to do it. If you insist to loop over it and to have functions allowing you to do so: just visit this link Java Generics - Implementing the Iterable Interface where you can for exemple (if this is what you want) iterate over the elements of the two lists of an instance lst1 and lst2
I'm writing a program now in Java which is kind of like a server. I got a MemberController, in MemberController it gets Members from the database OR from the cache (to speed up process). This is an example of how it looks:
public class MemberController {
private final TMap<Integer, Member> members;
public MemberController() {
this.members = new THashMap<>();
}
public Member getMemberByID(int id) {
if (members.containsKey(id)) {
return members.get(id);
}
// GET DATA FROM DB
members.put(ID, MEMBER);
return MEMBER;
}
Now, Member contains a BadgeController object, which contains a TMap for the badges. Example of Member:
public class Member {
// FIELDS OF MEMBER HERE
private BadgeController badgeController;
public Member(ResultSet set) {
// SET FIELDS
}
public void InitOtherData() {
badgeController = new BadgeController(id);
}
public BadgeController getBadgeController() {
return badgeController;
}
And BadgeController:
public class BadgeController {
private final int memberId;
private final TMap<String, Badge> badges;
public BadgeController(int memberId) {
this.memberId = memberId;
this.badges = new THashMap<>();
// LOAD FROM DB
}
public Badge getBadge(String code) {
return badges.get(code);
}
Now, I was wondering a few things (all actually refer to the same I guess):
If I get a Member from members, like members.get(1), and I edit the object, like this:
Member member = members.get(1);
member.setId(1);
Will this edit the id inside the TMap as well? So if I do members.get(1) again, it has the updated value?
If I have the member from above, and I change a value of the Badge, for example I do:
Member member = members.get(1);
member.getBadgeController().getBadge('500Members').setActive(true);
Will this result in true being printed?
System.out.println(members.get(1).getBadgeController().getBadge('500Members').getActive());
I hope my explaination is good enough. It's hard for me to explain it. I'm sorry.
Member member = members.get(1); does not copy the object but just makes a shortcut (reference). Changing member affects the item in your set as well.
To create an effective copy you have to make your object inherit from the Cloneable interface and call the clone() method on it to get a copy.
you need to DEEP copy object by:
implementing clone interface
create a copy constructor (simplest solution as clone)
examples:
// simple copy constructor
public SomerController(SomeController original) {
members = orginal.clone();
}
// more advanced copy constructor
public SomeController(SomeController original) {
Set<Map.Entry<String, String>> entries = orginal.members.entrySet();
members = new HashMap<String,Class>();
Iterator<Map.Entry<String, Class>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
String key = next.getKey();
// if class contains a collections ( maps, arrays )
// you need to provide a copy here
// ensure to copy whole tree of references
Class value next.getValue();
map.put(key,value);
}
}
Let's say I have a class called Object and a thread called ObjectCreator that manages the creation of an Object. For the sake of simplicity, Object has attributes: objectNumber and objectName.
If I were to create an instance of Object called instance, it would be held by ObjectCreator. Now let's say I needed another thread (let's call it ObjectChanger) to be able to see and manipulate instance; does it make sense to turn instance into a static Object?
I've managed to see results by making instance static so now I can do something like:
ObjectCreator.instance.getName();
Where getName() is a method of Object. From what I've read from answers to similar questions, static things are evil and there's always workarounds. One suggestion I've read is to pass instance to ObjectChanger as an argument for its constructor but what if instance wasn't created yet at the time I need to create an ObjectChanger?
Perhaps this question is more about OOP concepts than multi-threading or it may be a duplicate so forgive me but I'm quite lost here.
EDIT: To address frankie's and Jim's suggestions, here are some code snippets:
Object:
class Object
{
private String objectName = "Something";
private int objectNumber = 1;
public synchronized void changeNumber(int newNumber)
{
objectNumber = newNumber;
}
}
ObjectCreator:
class ObjectCreator extends Thread
{
static Object instance;
public ObjectCreator (Object something)
{
instance = something;
}
static void createObject()
{
...
}
static Object getObject()
{
return instance;
}
}
ObjectChanger:
public class ObjectChanger extends Thread
{
private Object currentInstance = null;
private int instanceNumber = null;
public void run()
{
currentInstance = ObjectCreator.getObject(); //If I were to make getObject() non-static, this line churns up an error
instanceNumber = currentInstance.getObjectNumber();
currentInstance.changeNumber(2); //valid?
}
}
If you want a thread to obtain access to an object not created within it, you must ensure that said thread has a path of references which it can follow, leading to the new object.
Consider the following code, with no threads involved.
class MyObject { /* ... */ }
interface MyObjectProvider {
MyObject getMyObject();
}
class Creator implements MyObjectProvider {
private MyObject obj;
/* ... */
#Override
public MyObject getMyObject() {
return obj;
}
/** Invoked at some point in time. */
void createMyObject() {
obj = new MyObject();
}
}
class Consumer {
private MyObjectProvider provider;
Consumer(MyObjectProvider mop) {
provider = mop;
}
void consume() {
// At some point in time...
MyObject o = provider.getMyObject();
}
}
Example of a program:
public static void main(String[] args) {
Creator creator = new Creator();
Consumer consumer = new Consumer(creator);
creator.createMyObject();
consumer.consume();
}
When you add threads to the mix, some code has to change, but the struture is the same.
The idea is to run the Creator in a thread, and the Consumer in another, as you've pointed out.
So, in short, these are the things you should be looking into:
Concurrency control: look into data races, synchronized, mutual exclusion, and their friends. Start here.
wait and notify, if the Consumer should wait for MyObject to be created. Look here.
When you have a nice grasp on these concepts, you may look into the volatile keyword (watch out for its pitfalls), and the java.util.concurrent package which provides better concurrency primitives, concurrent collections, and atomic variables.
You can put your objects in a list structure like Vector and store them in the ObjectCreator. Add a getter method to ObjectCreator which will accept an index of the object to be received.
This is just a skeleton showing the basic structure. Error handling is left as an exercise :-)
public class MyObject { ... }
...
public class MyObjectCreator {
private Map<String,MyObject> createdObjects = new HashMap<>();
public MyObject makeNewObject(int objNum, String objName)
{
MyObject o = new MyObject(objNum, objName);
this.createdObjects.put(objName,o);
}
public MyObject getObject(String objName)
{
return this.createdObjects.get(objName);
}
}
...
public class MyProgram {
public static void main(String[] args)
{
MyObjectCreator oc = new MyObjectCreator();
MyObject mo = oc.makeNewObject(10,"aNewObject");
...
MyObject o = oc.get("aNewObject");
...
If you only want to change the values of the fields of your class, you should just pass the object into your newly created thread. Then there is really no need to keep a static reference around in a holder class.
But as commented already, we need a bit more information to get to what you want to do with your object and thread.
Why cant you just make an getter in the ObjectCreator class that retrieves said Object?
ex: ObjectCreater.getMyObject()
EDIT:
I think you're looking for something like this if Im not mistaken:
public class ObjectCreator{
ArrayList<Object> children;
public ObjectCreator(){
children = new ArrayList<Object>();
}
//returns back index in children array (for accessing from other threads)
public int createObject( whatever params here ){
Object o = new Object( params );
children.add(o);
return children.size()-1;
}
}
since I dont know much about the problem you're trying to solve, Im not sure if it has to be thread safe, if you want these objects mapped, or accessed differently, but Im confused where all the confusion about static is coming...