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);
Related
private <Y> void meth(
MyObj ds, MultiValueMap<String, List> mvm, Class<Y> data) {
if(data.isAssignableFrom(Employee.class)) {
for (Employee rd : (List<Employee>) mvm.get(0).get(1)) {
for (String cName : (List<String>) mvm.get(0).get(0)) {
ds.setCellValue((String)rd.getDataElement(cName));
}
}
}
if(data.isAssignableFrom(Department.class)) {
for (Department rd : (List<Department>) mvm.get(0).get(1)) {
for (String cName : (List<String>) mvm.get(0).get(0)) {
ds.setCellValue((String)rd.getDataElement(cName));
}
}
}
//some more similar if conditions as above
}
In above, I have like similar 10 if conditions, how to avoid duplicate code in above? Do I need to use any Java 8 Function classes as parameters to avoid duplicate code (or) have to use any extra generics code?
So it looks like that what you need is inheritance and not generics.
In your if condition you always cast and call the same method on the Object.
So what you can do is e.g. define an interface looking something like this:
public interface MyInterface {
String getDataElement(String name);
}
And implement it in your Employee, Department and other classes you have.
If the method always does the same you can use default or an abstract class to not always write the same:
public interface MyInterface {
default String getDataElement(String name) {
//do your thing
return value;
}
}
public abstract class MyAbstractClass {
public String getDataElement(String name) {
//do your thing
return value;
}
}
Now you can change your meth method to this:
private void meth(MyObj ds, MultiValueMap<String, List> mvm) {
List<MyInterface> list = (List<MyInterface>) mvm.get(0).get(1));
for (MyInterface rd : list) {
List<String> cNames = (List<String>) mvm.get(0).get(0);
for (String cName : cNames) {
ds.setCellValue((String) rd.getDataElement(cName));
}
}
}
While generic methods can be applied, they won't solve the actual scenario you're trying to solve for (an earlier edit of this answer was an attempt before I thought through it more).
Taking a step back, this looks like the problem statement ("what" you're solving for, not "how"):
Iterate all lists present in a map – in your posted code, this would be: MultiValueMap<String, List> mvm
Accomodate different object types – you posted Employee and Department as examples
Whatever the list contains (Employee, Department, etc), you want to call getDataElement()
As the other answer by Ausgefuchster describes, this can be solved with interfaces. I voted that answer up, but wanted to provide more
more detail and examples.
Step 1: define an interface
Regardless of concrete class, your map contains lists of things which have getDataElement(), so make an interface which captures that:
interface HasDataElement {
String getDataElement();
}
Step 2: classes implement the interface
For this answer, I made up a few simple classes – A, B, and C – which implement the interface, but otherwise only return a string when getDataElement() is called. In your code, you would modify Employee, Department, etc. to implement your new interface.
class A implements HasDataElement {
#Override
public String getDataElement() {
return "A";
}
}
class B implements HasDataElement {
#Override
public String getDataElement() {
return "B";
}
}
class C implements HasDataElement {
#Override
public String getDataElement() {
return "C";
}
}
Step 3: handle the map
I'm using built-in types, so Map<String, List> instead of your posted code which uses MultiValueMap<String, List>. I think this difference is not significant, but pointing it out anyway.
The method signature below specifies that the map isn't just <String, List>, but further specifies that the list itself must contain things which extend the HasDataElement interface: List<? extends HasDataElement>.
Inside the method, the same List<? extends HasDataElement> type shows up in the first loop.
Once inside, the concrete class of item isn't relevant – we know it conforms to the HasDataElement interface, so we can call item.getDataElement().
private static void processAllDataElements(Map<String, List<? extends HasDataElement>> map) {
for (List<? extends HasDataElement> list : map.values()) {
for (HasDataElement item : list) {
System.out.println(item.getDataElement());
}
}
}
Example usage
Here's a simple example, along with output, that creates a few different lists of the various classes A, B, and C. It then creates a map and adds all three lists.
List<A> listOfA = List.of(new A[]{new A()});
List<B> listOfB = List.of(new B[]{new B(), new B()});
List<C> listOfC = List.of(new C[]{new C(), new C(), new C()});
Map<String, List<? extends HasDataElement>> map = new HashMap<>();
map.put("A", listOfA);
map.put("B", listOfB);
map.put("C", listOfC);
processAllDataElements(map);
A
B
B
C
C
C
Perhaps the hidden question is which structure to use for keys that have a sort of hierarchy (therefore my attempt in using classes and inner classes, so that a test on specific subsets is possible). I'm looking for a structure where I can add a new key to the appropriate place and having automaticallly this key in the appropriate keySet. Here my actual try:
Now I work with keys as static final String and a corresponding keySet.
I often need to test if a certain key is contained in the set of keys (public static final String) declared in some other class.
Therefore I extend all classes with keys from a class Keys1 which has a method keySet() that gives the set of keys. That works fine.
public class Keys1
{
private TreeSet<String> m_keySet = new TreeSet<String>();
public Keys1()
{
initKeySet();
}
private void initKeySet()
{
Field[] felder = this.getClass().getFields();
for (Field f : felder)
{
if (Modifier.isFinal(f.getModifiers()))
{
try
{
if (f.get(f) instanceof String)
{
m_keySet.add(f.get(f).toString());
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
public TreeSet<String> keySet()
{
return m_keySet;
}
}
Now I try in vain to code a similar functionality in a class Keys2 where the keySet should also contain keys that are declared in inner classes of type Keys2.
public class Keys2 extends Keys1
{
#Override
protected void initKeySet()
{
super.initKeySet();
Class<?>[] innerClasses = this.getClass().getDeclaredClasses();
for (Class<?> innerClass : innerClasses )
{
if (innerClass.getClass().isInstance(Keys1.class))
{
Keys1 newKeys;
try
{
newKeys = (Keys1) innerClass.newInstance(); // Doesn't work
keySet().addAll(newKeys.keySet());
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
}
}
}
If I'm not mistaken at first you need to get declared constructor of inner class. Than invoke it with an instance of outer class as an argument.
Since you said, you are looking for public static final String fields only, you are doing unnecessary work. You are not filtering the fields to access static fields only, further, you are querying the field and checking the result’s type instead of checking the field’s type in the first place.
Also, you don’t need an object instance to retrieve a static field. If you write the code in a way that it operates on a Class, it can be used to process inner classes just as discovered, without instantiating them.
Since this procedure doesn’t need an object instance, there is also no reason to repeat that operation for every instance nor to store the result in an instance field. You only need to remember the result on a per-class basis and, thankfully, there is a class named ClassValue which provides this for free.
Putting it together, you can implement it as
public class Keys1 {
static final ClassValue<TreeSet<String>> KEYS = new ClassValue<TreeSet<String>>() {
#Override protected TreeSet<String> computeValue(Class<?> type) {
final int desired=Modifier.PUBLIC|Modifier.STATIC|Modifier.FINAL;
Field[] fields=type.getDeclaredFields();
TreeSet<String> set = new TreeSet<>();
for(Field f: fields) {
if((f.getModifiers()&desired)==desired && f.getType()==String.class) try {
set.add((String)f.get(null));
} catch(IllegalAccessException ex) {
throw new AssertionError(ex);
}
}
for(Class<?> inner: type.getDeclaredClasses()) {
set.addAll(get(inner));
}
type = type.getSuperclass();
if(type != null && type != Object.class) set.addAll(get(type));
return set;
}
};
public TreeSet<String> keySet() {
return KEYS.get(getClass());
}
}
The ClassValue takes care of the caching. When you call get, it checks whether there is already a computed value for the specified class, otherwise, it calls computeValue. The computeValue method in this solution utilizes this itself for processing the super class fields, so if you call it for different subclasses, they will share the result for the common base class instead of repeating the work.
The subclass doesn’t need to do anything here, the inherited keySet() method is sufficient, as it uses getClass(), which returns the actual class.
As shown in this ideone demo.
When you are running in a Java version before Java 7, you may use the following ersatz, which you should replace with the real thing as soon as you migrate to a newer Java version.
/**
* TODO: replace with {#code java.lang.ClassValue<T>} when migrating to >=7.
*/
abstract class ClassValue<T> {
private final ConcurrentHashMap<Class<?>,T> cache=new ConcurrentHashMap<Class<?>,T>();
protected abstract T computeValue(Class<?> type);
public final T get(Class<?> key) {
T previous = cache.get(key);
if(previous != null) return previous;
T computed = computeValue(key);
previous = cache.putIfAbsent(key, computed);
return previous!=null? previous: computed;
}
}
The only change needed by the solution itself, is replacing the diamond operator use
new TreeSet<>() with the explicitly typed new TreeSet<String>(). Then, it should work in Java 6.
Make your inner class static or as already briarheart mentioned create nested instance through the instance of outer class (see Instantiating inner class).
Consider using enums instead of String constants.
You can use something like:
public enum A {
A1,
A2;
public static enum B {
B1,
B2
}
public static enum C {
C1,
C2
}
static Set<Enum> allValues() {
Set<Enum> allValues = new HashSet<>();
allValues.addAll(Arrays.asList(A.values()));
allValues.addAll(Arrays.asList(A.B.values()));
allValues.addAll(Arrays.asList(A.C.values()));
return allValues;
}
}
This solution may be improved depending on your needs.
For example you can implement interface with the method
boolean contains(Enum e);
for each enum to check inclusion of arbitrary value in any enum
and its nested enums.
I have an abstract class A and two subclasses B and C.
In some other class I have a list of instances of A's ie: List. The list of A's could of course contain elements that could be instances of B or C.
If the instance is B, I want to add it to table A which resides in Class D.
If the instance is C, I want to add it to table B which also resides in Class D.
Is this possible without using instanceof?
Yes, put a method in A which you override in B and C containing the table name.
You have a list L : List<A> which contains B extends A and C extends A. While you fetch elements E from L you like to add E to D.A if E instanceof B or add E to D.B if E instanceof C.
Use the Visitor Pattern by providing an abstract method A.visit(D). B.visit(D) would implement it by calling D.addMeToTableA(this) while C.visit(D) would implement it by calling D.addMeToTableB(this).
Here could be a solution:
public abstract class A {
public abstract void addTo(D d);
}
public class B extends A {
#Override
public void addTo(D d) {
d.addB(this);
}
}
public class C extends A {
#Override
public void addTo(D d) {
d.addC(this);
}
}
A simple D class:
public class D {
public void addB(B b) {
// ...
}
public void addC(C c) {
// ...
}
}
Then:
List<A> list = new ArrayList<A>();
list.add(new B());
list.add(new C());
D d = new D();
for (A a : list) {
a.addTo(d);
}
A possible approach is to let B and C return some discriminator to let the class that moves stuff from the list into D's tables know to which table they should be added, but you'll eventually get to a point where you need a switch or something like that.
Example:
public enum TypeOfA { TYPE_1, TYPE_2 }
public abstract class A {
// your other stuff
public abstract TypeOfA getType();
}
public class B extends A {
public TypeOfA getType() {
return TypeOfA.TYPE_1;
}
}
public class Sorter {
public void putInTables() {
for (final A a: this.listOfAs()) {
this.getTableFor(a).add(a);
}
}
private Table getTableFor(final A a) {
switch(a.getType()) {
case TypeOfA.TYPE_1: return tableA;
case TypeOfA.TYPE_2: return tableB;
}
}
}
With this solution, you could add more sub-classes of A that share the same type of "discriminator" with B or C, so your sorter class will put their instances in the same tables.
Apart from that, you keep the actual decission in the Sorter's logic, and if TYPE_1 and TYPE_2 have some semantic meaning, B and C don't actually have to know why they expose it.
"How to do different things with subclasses based on subclass type", or in other words: polymorphism. Off course is possible, its one of the main principles of OO software. And you don't need to use instanceOf, .getClass or others forms of meta-programing for solving a basic OO problem.
You can have an abstract method in A like:
public String belongsToTable() {}
in A you implement in one way in B you implement in another way.
Off course its probably a bad name and off course returning a string is probably a bad idea, its only an example based in your A,B,C problem. Software development its about naming and semantic, the next time please use meaningful names if you really want good advice and no a generic advice that you can find in a basic OO book.
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();
I'm having a bit of a problem grasping something - I might be going about this completely wrong.
I am trying to create a class which extends ArrayList but has several methods which increase the functionality (at least for the program I am developing.)
One of the methods is a findById(int id), which searches each ArrayList object for a particular id match. So far it's working, but it won't let me do for (Item i : this) { i.getId(); }
I don't understand why?
Full code:
public class CustomArrayList<Item> extends ArrayList<Item> {
// declare singleton instance
protected static CustomArrayList instance;
// private constructor
private CustomArrayList(){
// do nothing
}
// get instance of class - singleton
public static CustomArrayList getInstance(){
if (instance == null){
instance = new CustomArrayList();
}
return instance;
}
public Item findById(int id){
Item item = null;
for (Item i : this) {
if (i.getId() == id) {
// something
}
}
return item;
}
public void printList(){
String print = "";
for (Item i : this) {
print += i.toString() + "\n";
}
System.out.println(print);
}
}
Change
public class CustomArrayList<Item> extends ArrayList<Item> {
to
public class CustomArrayList extends ArrayList<Item> {
I suspect Item is the name of the class that you want to store in the list. By adding <Item> after CustomArrayList you're introducing a type parameter which shadows this class.
With the <Item> parameter, your code is equal to
public class CustomArrayList<T> extends ArrayList<T> {
// ...
for (T i : this) { i.getId(); }
// ...
}
which obviously won't always work, as T may refer to any type.
What is getId()? Presumably it's a method in some class, but we don't know which class.
If you've actually got a class called Item with a getId() method, which this is meant to be a list of, you simply need to stop your class from being generic. So instead of this:
public class CustomArrayList<Item> extends ArrayList<Item> {
you want:
public class CustomArrayList extends ArrayList<Item> {
Currently within your class, Item doesn't refer to a class called Item, it refers to a type parameter called Item.
Now personally:
I wouldn't avoid creating singletons unless you really have to
If you have to, I'd avoid creating them in the way you have (which isn't thread-safe)
I wouldn't extend ArrayList<> unless I really had to, preferring composition over inheritance