Initiating instance variables in a class that extends a generic class - java

I have a generic class "SimpleList" (excerpt):
public abstract class SimpleList<T> {
protected List<T> list;
public SimpleList(List<T> list) {
this.list = list;
}
}
And another class "TrackList" that extends it (excerpt):
public class TrackList extends SimpleList {
public TrackList(List<XmlTrack> list) {
super(list);
}
}
In "TrackList" I specify that the list is to hold objects of type "XmlTrack". It seems though, like it's not possible to get an object from that list and access its methods. For example, this won't work:
list.get(0).someMethodSpecificToXmlTrack()
I don't understand why this doesn't work? Isn't the list in "SimpleList" set to only hold "XmlTrack"s?

You need to define it as
public class TrackList extends SimpleList<XmlTrack> {
public TrackList(List<XmlTrack> list) {
super(list);
}
}
Because SimpleList is generic, but you did not specify a type argument when you extended it.

May be you need
public class TrackList extends SimpleList<XmlTrack>

Related

Using self-referential generic types in Java

Consider the following Java method:
<T extends List<T>> List<T> getMyList() {
return Collections.emptyList();
}
I can assign its output to a variable with a raw type, like so:
List x = getMyList();
List<List> y = getMyList();
But, I can't think of any way to assign its output to a fully parameterized type. In particular, I can't think of a non-raw, concrete type T that would satisfy List<T> z = getMyList();
Can we create such a T ?
If not, why not?
For context, I created this question while trying to understand how Enums are implemented in Java.
Here's an example of a concrete type that both works and starts to hint at a possible use-case (registration of some sort). The type consists acts like both an instance of some type, and as a container for all instances of that type.
public class WeirdEnum extends AbstractList<WeirdEnum> {
private static List<WeirdEnum> underlyingList = new ArrayList<>();
#Override
public WeirdEnum get(int index) { return underlyingList.get(index); }
#Override
public int size() { return underlyingList.size(); }
static <T extends List<T>> List<T> getAList() {
return Collections.emptyList();
}
public WeirdEnum() {
underlyingList.add(this); // Sufficient for our example but not a good idea due to concurrency concerns.
}
static List<WeirdEnum> foo = WeirdEnum.getAList();
}
Not sure if I fully understand your question, but here's an example:
class Example<T> implements List<Example<T>> {
...
}
...
List<Example<String>> list = getMyList();
Every enum in Java extends from the base-enum-class Enum<T extends Enum<T>>, where T is the actual type of the implementing enum.
When writing SomeClass<T extends SomeClass<T>> you can enforce that the type-parameter is always the implementing class itself.
Let's say you have this interface:
public interface MyInterface<T extends MyInterface<T>> {
T getSelf();
}
And this implementing class:
public class MyClass implements MyInterface<MyClass> {
public MyClass getSelf() {
return this;
}
}
In MyClass it is not possible to use any other type-parameter than MyClass itself.

Why is this class not considered a supertype as a parameter?

Given the following example, why am I able to override the return type List<? extends IConfigUser> as List<ConfigUser> in getUserList() but cannot do the same for the parameter of setUserList()?
Isn't ConfigUser considered a supertype of IConfigUser in this case?
public class Test {
public interface IConfigUser {
}
public interface IConfig {
public List<? extends IConfigUser> getUserList();
public void setUserList(List<? extends IConfigUser> list);
}
public class ConfigUser implements IConfigUser {
}
// The type Test.Config must implement the inherited abstract method
// Test.IConfig.setUserList(List<? extends Test.IConfigUser>)
public class Config implements IConfig {
#Override
public List<ConfigUser> getUserList() {
return null;
}
// The method setUserList(List<ConfigUser> list) of type Test.Config
// must override or implement a supertype method
#Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
You can achieve your goal by adding a generic type parameter to IConfig:
public class Test {
public interface IConfigUser {
}
public interface IConfig<T extends IConfigUser> {
public List<T> getUserList();
public void setUserList(List<T> list);
}
public class ConfigUser implements IConfigUser {
}
public class Config implements IConfig<ConfigUser> {
#Override
public List<ConfigUser> getUserList() {
return null;
}
#Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
You can return a more specific type in an override, but you can't require that you accept a more specific type. Get rid of the generics, and you can override a method returning Object with a method returning String, but you can't override a method accepting an Object parameter with a method accepting a String parameter.
All of this is so that callers are compatible. Consider:
IConfig config = new Config();
List<SomeOtherConfigUser> list = new ArrayList<SomeOtherConfigUser>();
list.add(new SomeOtherConfigUser());
config.setUserList(list);
Oops - your Config.setUserList is expecting every element to be a ConfigUser, not a SomeOtherConfigUser.
You can return ("specialize") the return type of getUserList() due to covariance, i.e. if you call that method on a IConfig reference all you know is that you'll get a List<? extends IConfigUser> and a List<ConfigUser> is a List<? extends IConfigUser> so the requirements are satisfied.
If you call that on a Config reference the information is more concrete but the basic requirements are still met.
With setUserList(...) the situation is different: it allows you to pass any "subclass" of List<? extends IConfigUser> which can be a List<ConfigUser> but it also can be something else, e.g. a List<SomeConfigUser>.
Btw, since you don't know the concrete generic parameter of list in setUserList(List<ConfigUser> list) the compiler will also only allow you to read from that list, never add to it - for the same reason as above: you don't know what you get and whether adding a ConfigUser is allowed because the list could only allow SomeConfigUser instances to be added.

Call generic type instance method

I have implemented Generic DAO for all my bean classes. I am facing a problem in setting the entries in to the cache.
DAO.class
public abstract class DAO<T extends Serializable> extends Cache
{
save(Collection<T> list)
{
// batch process will store the list to db
for(T t : list)
{
cache(t.getKey(), t);
}
}
}
Bean's DAO classes
public class BeanDAO1 extends DAO<Bean1>
{
public static set(Collection<Bean1> list)
{
super.save(list);
}
}
public class BeanDAO2 extends DAO<Bean2>
{
public static set(Collection<Bean2> list)
{
super.save(list);
}
}
Now the problem is, both Bean classes have same getter method getKey(). But in DAO class, as it is type referenced, i couldn't access the method.
Is it something i am doing wrong or I should do some other thing?
In your save method you access the method getKey() on objects of type T. For that you must constrain that type variable to be a subtype of a type that has this method. As it is, the only thing the compiler know that your T is a subtype of Serializable (which doesn't have this method).
That means you should have a supertype for all your beans:
public interface Bean extends Serializable {
public ? getKey(); // I do not know what type your keys are
}
Your bean classes should implement this interface. Then you can do the following:
public abstract class DAO<T extends Bean> extends Cache {
public save(Collection<T> list) {
for(T t : list) {
cache(t.getKey(), t);
}
}
}
Your type declaration T extends Serializable is too broad. You must define a class implementing or an interface extending Serializable that has an abstract method getKey() and let T extend this new type.
The cleanest solution as #Ray suggested is having a common interface for Entity classes such as:
public abstract class DAO<T extends AbstractEntity> extends Cache
{
save(Collection<T> list)
{
// batch process will store the list to db
for(T t : list)
{
cache(t.getKey(), t);
}
}
}
And the interface:
public interface AbstractEntity
{
}
EDIT:
And having Bean1 and Bean2 implement the interface as such:
public class Bean1 implements AbstractEntity
{
}
public class Bean2 implements AbstractEntity
{
}
The marker interface Serializable doesn't define getKey() method.However,your type T can declare multiple upper bounds.Let your Bean1 and Bean2 extend a common super class or inteface which has a getKey() method
interface Bean{
Object getKey();
}
class Bean1 implements Bean,Serializable {
public String getKey(){
///
}
}
class Bean2 implements Bean,Serializable{
public String getKey(){
///
}
}
public abstract class DAO<T extends Bean & Serializable> extends Cache
{
save(Collection<T> list)
{
// batch process will store the list to db
for(T t : list)
{
cache(t.getKey(), t);
}
}
}
public class BeanDAO1 extends DAO<Bean1>
{
public static set(Collection<Bean1> list)
{
super.save(list);
}
}
public class BeanDAO2 extends DAO<Bean2>
{
public static set(Collection<Bean2> list)
{
super.save(list);
}
}

Get actual enum class of the Parameterized class T extends Enum<?>

I have a class:
public class MultipleSorting<T extends Enum<?>> {
private T criteriaType;
public Class<T> getCriteriaClass() {
Field field = ReflectionUtils.getField(getClass(),"criteriaType");
ReflectionUtils.makeAccessible(field);
return (Class<T>)field.getType();
}
}
This class is get instantiated as:
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?,?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController() {
super();
multipleSorting = new MultipleSorting<U>();
}
}
The actual value of U is passed from the child class of MultiSortPageableController which is:
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T,ArticleSortField> {
}
The ArticleSortField is an Enum.
I was expecting the method getCriteriaClass of MultipleSorting would return ArticleSortField from a method of MultiSortPageableController. But it is returning java.lang.Enum.
I am unable to figure it out why it is not returning the actual enum and how can I make it so. Any pointer would be very helpful to me. I need to get ArticleSortField.
Purpose:
I two requirement:
To get the actual class of enum type (say ArticleSortField.class)
To list enum value. If I have the enum class, then I could invoke class..getEnumConstants().
Java compiler removes information about generics, therefore when you use reflection you get no information about the declared type, other than Enum. This process is called type erasure.
How about passing the type down, via the constructor, like this:
public class MultipleSorting<T extends Enum<?>> {
private Class<T> criteriaType;
MultipleSorting(Class<T> criteriaType) {
this.criteriaType = criteriaType;
}
public Class<T> getCriteriaClass() {
return criteriaType;
}
}
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?, ?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController(Class<U> criteriaType) {
super();
multipleSorting = new MultipleSorting<U>(criteriaType);
}
}
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T, ArticleSortField> {
public AbstractArticleSearchController() {
super(ArticleSortField.class);
}
}

Generics: generic class based on generic class

I'm trying to create a generic service that is based on a class with a generics based collection
public class GenericClass<T> {
List<T> results;
public List<T> getResults() {
return results;
}
}
Im just not sure how to create a service that is based on this GenericClass and has a concrete implementation of T. I would expect something like
public class ServiceManagerImpl<GenericClass<T>> implements ServiceManager<GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
But the compiler doesn't like this. Any ideas how to do this?
Marc
You are close... just pass the T through:
public class ServiceManagerImpl<T> implements ServiceManager<GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
I can suggest the following implementation that doesn't break the rules of JLS:
// ServiceManager.java
public interface ServiceManager<E, T extends GenericClass<E>> {
}
// ServiceManagerImpl.java
public class ServiceManagerImpl<E, T extends GenericClass<E>> implements ServiceManager<E, T> {
public T getMyClass() {
return null;
}
}
The content between <> is called Type Parameters, and GenericClass<T> is not a valid Type Parameter in declaration.
Quote from java generic guide
A generic class is defined with the following format:
class name<T1, T2, ..., Tn> { /* ... */ }
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.
so, you need to use GenericClass<T> in implementation, not in declaration.
// declaration
public class ServiceManagerImpl<YourGenericType> implements ServiceManager<YourGenericType> {
public YourGenericType getMyClass() {
...
}
}
// implementation
ServiceManager<GenericClass<Object>> sm = new ServiceManagerImpl<GenericClass<Object>>();
public class ServiceManagerImpl<T extends GenericClass<T>> implements ServiceManager<T extends GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
I am not sure my answer is legal , but it seems meet your requirement:
public class ServiceManagerImpl<T extends GenericClass> implements ServiceManager<T>
{
#Override
public T getMyclass() {
//do your work here;
}
}
Although it may have a unchecked warning when I declare this class , but this really does!
ServiceManager<GenericClass<Integer>> manager = new ServiceManagerImpl<GenericClass<Integer>>();//passed
You should try likes this;
public class ServiceManagerImpl<GenericClass<Object>> implements ServiceManager<GenericClass<Object>> {
public GenericClass<Object> getMyClass() {
...
}
}
You can replace Object with Integer or String or any data types as you likes.

Categories

Resources