Suppose the situation in which we must have list of WeakReference and "Strong Reference".But there are not StrongReference class in Java.My solution is
Keep list of objects
List<? extends Object> list =new ArrayList();
and any time when we get element from list, check:
if(list.get(i) instanceof WeakReference){
MyClass myObject = ((MyClass)((WeakReference) list.get(i)).get());
if(myObject != null){
myObject.doSomething();
}
}else{
MyClass myObject = ((MyClass)list.get(i));
myObject.doSomething();
}
Is there better solution to keep strong and weak references together in one collection?.
I'd be tempted to abstract the concept of "strong or weak reference":
public interface DualRef<T> {
T get();
}
Then implement two subclasses, one for weak references:
public class WeakDualRef<T> implements DualRef<T> {
private final WeakReference<T> mRef;
public WeakDualRef(T object) {
mRef = new WeakReference<T>(object);
}
public WeakDualRef(WeakReference<T> ref) {
mRef = ref;
}
T get() {
return mRef.get();
}
}
and another for strong references:
public class StrongDualRef<T> implements DualRef<T> {
private final T mRef;
public StrongDualRef(T object) {
mRef = object;
}
public T get() {
return mRef;
}
}
Then you can implement your code as:
List<DualRef<MyObject>> list = new ArrayList<DualRef<MyObject>>();
// add mixed instances of WeakDualRef<MyObject> or StringDualRef<MyObject> . . .
MyClass myObject = list.get(i).get();
myObject.doSomething();
All this has the advantage of preserving type safety through proper use of generics.
Mixing types is not a good conception.
List< WeakReference > weakRefs = new ArrayList<>();
List< MyClass > myClasses = new ArrayList<>();
With two loops to do two different thing.
Why mixing two different kind of object, they don't share any behavior.
I would write it something like this
Object o = list.get(i);
if (o instanceof WeakReference) o = ((WeakReference) o).get();
if (o instanceof MyClass) ((MyClass) o).doSomething();
Related
first of all my code below just delivers an abstract view of my classes so that you can easily understand what my question is about :) -so also no equals, hashcode.
I have an ABC extended from Observable which has a List of AbstractObservers
Then I have some classes B and C inherit from AbstractObservers. AbstractObservers implements Observer.
The focus is now at the Recover class.
With the method recover() I try to return a List with the concrete type (B or C) instead of AbstractObservers.
I am not satisfies with my solution, I think it could be better, easier?
Have you any idea how I could solve that problem better? The Abstract classes must stay due to Hibernate.
Thank you in advance
public abstract class ABCObservable extends Observable {
List<AbstractObserver> abstractObserverList = new LinkedList<>();
public List<AbstractObserver> getAbstractObserverList() {
return abstractObserverList;
}
#Override
public synchronized void addObserver(Observer o) {
super.addObserver(o);
abstractObserverList.add((AbstractObserver) o);
}
}
AbstractObserver
public abstract class AbstractObserver implements Observer {
#Override
public void update(Observable o, Object arg) {
}
}
B
public class B extends AbstractObserver {
}
C
public class C extends AbstractObserver {
}
Recover
public class Recover {
public List<? extends AbstractObserver> recover(ABCObservable abcObservable) {
List<AbstractObserver> returnList = new LinkedList<>(); //does that delivers a List with AbstractObserver or B or C?
if (abcObservable.getAbstractObserverList().get(0) instanceof B) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
} else if (abcObservable.getAbstractObserverList().get(0) instanceof C) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
}
return returnList; // returns a List with B or C elements
}
}
In Java, you can't convert a list to a new type, what you can do, however, is create a new one and add the values to it. If you use a generic method, you should be able to accomplish this. I haven't test this code, but theoretically it should work:
public <T> List<T> recover(T abcObservable) {
List<AbstractObserver> list = abcObservable.getAbstractObserverList();
List<T> returnList = new LinkedList<>();
returnList = new LinkedList<>();
for(AbstractObserver a : list) {
if(a instanceof T) {
returnList.add(a);
}
}
return returnList;
}
Instead of using a defined class, this snippet uses T, you can find out more about how Java Generic Methods work on this Java Tutorial by Oracle.
EDIT: I think I'm confused about what you are asking for, this doesn't answer your question, if I understand it correctly.
I have an inteface 'MyCollection' with just two methods : addAll and containsAll which take as a parameter a generic collection. How can I effectively implement these methods in my class so that they would work on any type of collection.
This is what I've done so far :
The interface:
interface MyCollection<T extends Collection> {
boolean containsAll(T c);
boolean addAll(T c);
}
My class where I implement the methods:
public class MyPersonalCollection<E extends Collection> implements MyCollection {
private E myCollection;
public MyPersonalCollection(E myCollection) {
this.myCollection = myCollection;
}
public boolean containsAll(Collection c) {
return myCollection != null && myCollection.containsAll(c);
}
public boolean addAll(Collection c) {
return myCollection != null && myCollection.addAll(c);
}
}
And the tests:
#Test
public void testIfNewCollectionCanBeAdded() {
ArrayList<String> input = new ArrayList<>();
MyPersonalCollection<ArrayList<String>> myCollection = new MyPersonalCollection<>(input);
input.add("first");
input.add("secon");
input.add("third");
assertTrue(myCollection.addAll(input));
}
#Test
public void testIfMyCollectionContainsAnotherCollection() {
LinkedList<String> list = new LinkedList<>();
MyPersonalCollection<LinkedList<String>> myCollection = new MyPersonalCollection<>(list);
list.add("bacon");
list.add("tuna");
list.add("steak");
assertTrue(myCollection.addAll(list));
}
I also get a warning : Unchecked call to 'containsAll(Collection) as a member of raw type 'Java.Util.Collection" in my class when I call the methods containsAll() and addAll().
So how can I tackle this problem ? Many thanks in advance !
Both E and T extend Collection, but you want to treat a Collection as T in MyCollection in this line:
return myCollection != null && myCollection.containsAll(c);
Which can be wrong because every Collection is not from type T.
Anyway if you are sure that this type casting is safe, simply ignore it and use
#SuppressWarnings("unchecked")
to suppress that warning.
The problem is that you have to define 2 generic:
C for the kind of collection
E for the content of the collection
I fixed your code, now there is no warnings
interface MyCollection<C> {
boolean containsAll(C c);
boolean addAll(C c);
}
public class MyPersonalCollection<E, C extends Collection<E>>
implements MyCollection<C> {
private C collection;
public MyPersonalCollection(C myCollection) {
this.collection = myCollection;
}
public boolean containsAll(C c) {
return collection != null && collection.containsAll(c);
}
public boolean addAll(C c) {
return collection != null && collection.addAll(c);
}
}
You can use your class in the test like this:
MyPersonalCollection<String, LinkedList<String>> myCollection =
new MyPersonalCollection<String, LinkedList<String>>(list);
private LinkedList register;
public Register(Object obj){
register = new LinkedList<obj>();
}
So basically, can I define the type of objects that the LinkedList should contain through this method? (For Java)
Perhaps obj.getClass?
Generics can be confusing. I think you want this:
public class Register<T> {
private LinkedList<T> register = new LinkedList<T>();
public static <T> Register<T> create(T object) {
return new Register<T>();
}
}
Essentially no, generics are compile time only and need to be declared somewhere.
class Register<T> {
LinkedList<T> register;
Register(T obj) {
register = new LinkedList<T>();
}
You could, for example, use a factory method.
static <U> Register<U> of(U obj) {
Register<U> result = new Register<U>(obj);
return result;
}
}
Register<String> a = new Register<String>("abc");
Register<Double> b = Register.of(1.0d);
See also Lesson: Generics.
I had 2 classes, B and C, who needed to keep track of their instances, so each of them has an ArrayList of their respective types to which instances were added in the constructor.
Since this seemed like common behaviour, I tried to find some sort of standard Java interface or class that expresses this behaviour, something like an InstanceManager interface. I didn't find any
I ended up trying to write an abstract class for it and I got stuck because I don't know how to specify the specific type of the subclasses.
For example:
public abstract class C { public static ArrayList<C> list; }
public class A extends C { }
public class B extends C { }
In this case, B.list or A.list would be lists of C objects, but I would actually want them to be lists of B and A objects, respectively.
Is there any way I could make that happen easily?
I am thinking something along the lines of
public abstract class C { public static ArrayList<thisclass> list; }
but that would obviously not work.
I realise that I could probably use generics to handle this, but it feels redundant and I can't help wishing that there is a way to somehow infer the child class type in this situation.
Also, is there any standard Java interface for handling instance management or unique instance id generation?
EDIT:
I have come to understand that static variables are not inherited, and the subclasses' static variables actually refer to the same thing. As such, is there any way I can define instance managing behaviour without resorting to redundancy, having to write the same things in all subclasses?
It's already been pointed out that a Map is appropriate here; however there are a few other concerns:
Multithreading.
Garbage collection.
#1 is fairly easy to factor in but worthwhile to point out.
#2 is important because you want to think carefully about whether or not keeping a list of all instances should prevent them from being garbage collected. If not, you need to become familiar with the WeakReference class.
Here is an example of the more complicated case.
public final class InstanceManager<T> {
private final Map<Class<?>, List<Reference<T>>> refMap = (
new HashMap<Class<?>, List<Reference<T>>>()
);
public synchronized <U extends T> U manage(U instance) {
Class<?> cls = instance.getClass();
List<Reference<T>> refList = refMap.get(cls);
if(refList == null) {
refList = new LinkedList<Reference<T>>();
refMap.put(cls, refList);
}
refList.add(new WeakReference<T>(instance));
return instance;
}
public synchronized <U extends T> List<U> getAll(Class<U> cls) {
List<U> returnList = new LinkedList<U>();
List<Reference<T>> refList = refMap.get(cls);
if(refList != null) {
Iterator<Reference<T>> it = refList.iterator();
while(it.hasNext()) {
T instance = it.next().get();
if(instance == null) {
it.remove();
} else {
returnList.add(cls.cast(instance));
}
}
}
return returnList;
}
}
As an example of usage,
InstanceManager<Object> im = new InstanceManager<Object>();
Object o1 = im.manage(new Object());
Object o2 = im.manage(new Object());
String s1 = im.manage("a");
String s2 = im.manage(new String("b"));
System.out.println("Object count: " + im.getAll(Object.class).size());
System.out.println("String count: " + im.getAll(String.class).size());
o2 = s1 = s2 = null;
System.gc();
Thread.sleep(1000);
System.out.println("Object count: " + im.getAll(Object.class).size());
System.out.println("String count: " + im.getAll(String.class).size());
The output here is
Object count: 2
String count: 2
Object count: 1
String count: 1
because this InstanceManager allows its referents to be garbage collected. If that's not the desired behavior (you aren't keeping references to the instances elsewhere) then of course you need to release them manually.
But either way this allows you to do something like
public abstract class C {
private static final InstanceManager<C> manager = new InstanceManager<C>();
protected C() {
manager.manage(this);
}
}
where all instances of C and its subclasses are automatically managed and categorized by actual type.
Using generics, you can do something like:
abstract class C<T> {
public List<T> list;
}
class A extends C<A> {
}
class B extends C<B> {
}
Keep a class name to list of instances mapping, determine the type at runtime to insert instances to the appropriate list:
Map<String,List<?>> instances;
....
instances.get(instance.getClass().getName()).add(instance);
I have a Java Set<MyClass> on which I've overridden equals and hashCode to use the String name; variable.
public class MyClass{
final String name;
public boolean equals(Object o){...}
public int hashCode(){return name.hashCode();}
}
Is there anyway I can get my Object out of the HashSet using something like
MyClass o = set.get("nameofmyobject");
Is there a way to do this in Java, or a datastructure? or do I need to change up all of my Sets to Maps?
No. You need to change to a Map. None of the methods of Set return an element.
Addendum A
If you don't care about speed you can always search manually:
MyClass find(String name, Set<MyClass> set)
{
MyClass wrapper = new MyClass(name);
for (MyClass e : set) {
if (wrapper.equals(e)) {
return e;
}
}
return null;
}
Addendum B
If you use a TreeSet you can use floor:
MyClass find(String name, TreeSet<MyClass> set)
{
MyClass wrapper = new MyClass(name);
MyClass candidate = set.floor(wrapper);
if (candidate != null && wrapper.equals(candidate)) {
return candidate;
} else {
return null;
}
}
Have a look at this question. The answer is no. Sets are not for getting elements, but to look for equality. Use a Map or List insteed.
As Tim said you can't. And if so you would have to call it like set.get(myClassInstance); and not set.get(some member of the stored instance)
Use
Map<String, MyClass> myMap = new HashMap<String, MyClass>();