Generics: How To Get Map Values ​​Without Casting

I have an abstract class named BaseCode

and 2 concrete classes named Location

and Department

:

public abstract class BaseCode {
   private Integer id;
   ...
   public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   ...
}

public class Location extends BaseCode {
   ...
}

public class Department extends BaseCode {
   ...
}

      

I have an abstract class named BaseCodeCache

and 2 concrete classes named LocationCache

and DepartmentCache

. LocationCache

and DepartmentCache

will use Singleton

.

public abstract class BaseCodeCache {
   ...
}

public class LocationCache extends BaseCodeCache {
   ...
}

public class DepartmentCache extends BaseCodeCache {
   ...
}

      


  • In BaseCodeCache

    , I want to have java.util.Map

    , whose value can be any type of BaseCode

    ie objects Location

    or Department

    objects.
    Q LocationCache

    I want to java.util.Map

    save objects Location

    .
    Q DepartmentCache

    I want to java.util.Map

    save objects Department

    .

To accomplish this, I put this code in BaseCodeCache

:

private Map<Integer, BaseCode> idMap = new HashMap<Integer, BaseCode>();

      


  1. I want to have a way to store the value in java.util.Map

    .

To accomplish this, I put this code in BaseCodeCache

:

public void add(BaseCode baseCode) {
   if (baseCode != null) {
      idMap.put(baseCode.getId(), baseCode);
   }
}

      

This is how I will use it for Location

:

Location location = new Location(); ...
LocationCache.getInstance().add(location);

      

This is how I will use it for Department

:

Department department = new Department(); ...
DepartmentCache.getInstance().add(department);

      


  1. I want to have a method to get all values ​​in java.util.Map

    as a java.util.List

    .
    In LocationCache

    this method should return List<Location>

    .
    In DepartmentCache

    this method should return List<Department>

    .

This is where I am stuck. I want to create this method in BaseCodeCache

, but when this method is called through LocationCache

, it returns List<Location>

and when this same method is called through DepartmentCache

, then it returns List<Department>

. Is it possible?

I put this code in BaseCodeCache

:

public List<BaseCode> getList() {
   return new ArrayList<BaseCode>(idMap.values());
}

      

But the above code returns List<BaseCode>

. When I call it like this:

List<Location> allLocations = LocationCache.getInstance().getList();

      

Then java won't let it compile and pass this error message:

Type mismatch: Cannot convert from List<BaseCode>

toList<Location>

I can fix this by getting List<BaseCode>

and then converting it to List<Location>

by looping, but it doesn't look right.

Can this be done?

+3


source to share


1 answer


Implement using generics like this:

public abstract class BaseCodeCache<T extends BaseCode> {
    private Map<Integer, T> idMap = new HashMap<>();

    public void add(T baseCode) {
        if (baseCode != null) {
            idMap.put(baseCode.getId(), baseCode);
        }
    }

    public List<T> getList() {
        return new ArrayList<>(idMap.values());
    }
}

public class LocationCache extends BaseCodeCache<Location> {}

public class DepartmentCache extends BaseCodeCache<Department> {}

      


This will allow you to do the following without compilation errors:



LocationCache locationCache = new LocationCache();
locationCache.add(new Location());

List<Location> locations = locationCache.getList();

      

Better yet, you get compilation errors if you try to add or get the wrong object type:

locationCache.add(new Department()); // won't compile
List<Department> departments = locationCache.getList(); // won't compile

      

+4


source







All Articles