class Attribute<T>{
private T attr;
public Attribute(T attr){
this.attr = attr;
}
}
Class Matrix<T>{
private String name;
List<Attribute<T>> list;
public Matrix(String name, T t){
this.name = name;
list = new ArrayList<>();
list.add(new Attribute<T>(t));
}
}
interface Extractor<T> {
public List<Matrix<T>> extract();
}
InfoExtractor implements Extractor<String>{
public List<Matrix<String>> extract(){
List<Matrix<String>> matrixList = new ArrayList<>();
// The problem is here!!!!
matrixList.add(new Matrix<String>("abc"));
}
}
Document<T>{
Map<String, List<Matrix<T>>> matrixMap;
public void process(){
...
Extractor<T> extractor = (Extractor<T>) new StringExtractor(sent);
List<Matrix<T>> matrix = extractor.extract(...);
}
My question is, is there a way to avoid defining Matrix as a generic type ? The reason I want to avoid is that the "List<Attribute<T>> " is used in multiple other classes, either as private member variables, or method return types. Due to Attribute, it seems I have to define some other related classes as generic types too, which causes my problem.
In this case, is there a way to not define Matrix as generic, but keep the "list" variable as a generic type?
Your problem lies not in the generic implementation, but in its usage:
class InfoExtractor implements Extractor{
// The problem is actually here
public <T> List<Matrix<T>> extract(){
List<Matrix<T>> matrixList = new ArrayList<>(); //and here
// "The problem is here!!!!"
matrixList.add(new Matrix<String>("abc"));
}
}
The <T> indicates that you are binding a new generic type relative to the method invocation. In short, a new T type just for this method's execution. You also make a List<Matrix<T>> but then attempt to add a new Matrix<String> back. If you know the list is going to be of the type Matrix<String>, then you can specify that in InfoExtractor:
//If you cannot generify the interface for some reason
interface Extractor {
public List<? extends Matrix<?>> extract(); //explained at bottom
}
//IDEALLY, then implement Extractor<String> instead
interface Extractor<T> {
public List<Matrix<T>> extract();
}
class InfoExtractor implements Extractor { //or Extractor<String>
public List<Matrix<String>> extract() {
List<Matrix<String>> matrixList = new ArrayList<>();
matrixList.add(new Matrix<>("abc"));
return matrixList;
}
}
Of course, you can see the method signature for Extractor changed. Due to using a nested generic on the return type, things will get a bit messy for type matching at compile-time. The <?> for the Matrix is fairly self-explanatory, we're returning multiple and possibly unknown types inside of the Matrix.
By specifying ? extends Matrix on Extractor, we're specifying the proper variance. Concrete generics are invariant, thus a List<Toyota> isn't a List<Car>, even if Toyota is a subclass of Car. If we want the Matrix to be covariant, then we need the bounding on Matrix as well unfortunately. This means in effect, ignoring Liskov's substitution principal, we'd essentially be referencing the concrete subclasses for the extractors (InfoExtractor ex vs Extractor ex), especially from a usability standpoint (as the concrete classes can return proper type safety whereas the interface cannot).
This of course, is handled much more sanely/cleanly when you specify the <T> for the matrices in the list as a class-level generic type.
It depends on what you would like to do.
If you intend to use Matrix to hold a single type of attribute, that is T then the best approach seems to be the one you posted as you get to have compile time type checking.
If you remove the generic type T from Matrix then you cannot know the type of each attribute. You can completely remove T from Matrix declaration and use the wildcard for the Attribute variable. While this would allow you to store attributes of different T types in the same Matrix object, it will remove the compile type checking. In other words, the classes using the Matrix would have to know what class to expect and perhaps cast each attribute to the class expected.
Class Matrix{
private String name;
List<Attribute<?>> list;
public Matrix(String name, T t){
this.name = name;
list = new ArrayList<>();
list.add(new Attribute<>(t));
}
}
Adding a Class variable and saving the Class object inside the attribute, could help you retain some information in runtime to identify the class of the objects inside the attribute.
class Attribute<T>{
private T attr;
private final Class<T> clazz;
public Attribute(T attr, Class<T> clazz){
this.attr = attr;
this.clazz=clazz;
}
public Attribute(T attr){
this.attr = attr;
Objects.requireNonNull(attr);
this.clazz= (Class<T>) attr.getClass();
}
}
Using this approach the original constructor can be used only for non null values, otherwise the class object should be provided by the programmer.
Related
In a library for charts I found the following class:
public class SeriesBuilder<T> {
private T[] data;
private SeriesBuilder() {
}
public static SeriesBuilder<?> get() {
return new SeriesBuilder();
}
public SeriesBuilder<T> withData(T... data) {
this.data = data;
return this;
}
public Series<T> build() {
Series<T> series = new Series<T>();
series.setData(data);
return series;
}
}
Using code:
SeriesBuilder.get()
.withData(<<<<<???>>>>)
.build()
I'm not able to find out how to use the class because of the <?> Type. I can't find an argument that fullfills the signature. How to use this?
I'm not able to find out how to use the class because of the <?> Type. I can't find an argument that fullfills the signature. How to use this?
You pretty much can't use it. There is no way to obtain a SeriesBuilder instance except via SeriesBuilder.get(), and the type parameter of an instance that you obtain that way is unknown -- in fact, what get actually instantiates is the raw type. You should be able to produce a series of nulls if you wish.
There cannot even be any subclasses of SeriesBuilder (that might be more usable), because its only constructor is private.
Without putting too fine a point on it, this SeriesBuilder is pretty much an abomination. There is an argument to be made for preferring factory methods (such as SeriesBuilder.get()) over constructors, but that implementation is terrible. In addition to the type parameter issues, it does not initialize the resulting object to a valid state. That has to be done separately via withData(), so what is the point of get() supposed to be?
I'm inclined to think that whoever wrote that was looking for something that would have been better expressed via this variation on withData():
public static <T> SeriesBuilder<T> withData(T ... data) {
SeriesBuilder<T> builder = new SeriesBuilder<>();
builder.data = data;
return builder;
}
You might use that as
SomeType item1 = /* value */;
SomeType item2 = /* value */;
SomeType item3 = /* value */;
Series<SomeType> series =
SeriesBuilder.withData(item1, item2, item3)
.build();
Say I've got two interfaces:
public interface IObjectOne<T>
{
List<T> digest(final List<T> myList);
}
public interface IObjectTwo<T>
{
List<T> create();
}
And an object which manages concrete implementations of these two interfaces, which must work over the same type.
public class Entity<T>
{
private IObjectOne<T> objectOne;
private IObjectTwo<T> objectTwo;
... setters
public IObjectOne<T> getObjectOne() {
return objectOne;
}
public IObjectTwo<T> getObjectTwo() {
return objectTwo;
}
}
These Entitys are stored in a Map, and I retrive one of them by a key:
final Entity<?> entity = entities.get(key);
Why cannot I do that?
entity.getObjectOne().digest(entity.getObjectTwo().create());
To do this, you need to do your operation in a method with a type variable:
<T> void doSomething(Entity<T> entity) {
entity.getObjectOne().digest(entity.getObjectTwo().create());
}
You can invoke this even for an Entity<?>, because that wildcard has some type, you just don't know it.
final Entity<?> entity = entities.get(key);
doSomething(entity);
Here:
final Entity<?> entity = entities.get(key);
you are saying: you absolutely do not care about the exact type of an entity. Reminder: wildcard means "I don't know" about the exact type.
And one consequence of using the wildcard for generics, as described here:
If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
In other words: by using the wildcard like this, the compiler is unable to correlate the generic types.
How are you creating the Map<String, Entity<YOUR_TYPE>>
You should parameterize your Entity<> since it is generic.
Map<String, Entity<YOUR_TYPE>> entities = new HashMap<>();
final Entity<YourType> entity = entities.get(key);
I have a generic class in java defined as:
public static class KeyCountMap<T>
{
private Map<T, MutableInt> map = new LinkedHashMap<T, MutableInt>();
// ... rest of the properties...
public KeyCountMap()
{ }
#SuppressWarnings({ "unchecked", "rawtypes" })
public KeyCountMap(Class<? extends Map> mapType) throws InstantiationException, IllegalAccessException
{
map = mapType.newInstance();
}
//... rest of the methods...
}
I have defined same class in .NET as:
public static class KeyCountMap<T>
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
{
obj = new T(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
}
And then a method is defined to sort map of type KeyCountMap<T> by value in the descending order . The method is defined as:
public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> _map)
{
List<KeyValuePair<T, MutableInt>> _list = new List<KeyValuePair<T, MutableInt>>(_map.EntrySet());
// whereas _map.EntrySet() return of type HashSet<KeyValuePair<T, MutableInt>>
_list = _list.OrderByDescending(_x => _x.Value).ToList();
KeyCountMap<T> _result = new KeyCountMap<T>();
foreach (KeyValuePair<T, MutableInt> _entry in _list)
{
_result.Put(_entry.Key, _entry.Value);
}
return _result;
}
How can I get corrected the class defined in .NET ?
I assume you know Java erases any generic type information after compiling (there's metadata for variables, but actual objects are void of generic type information). Moreover, your code is not type safe:
#SuppressWarnings({ "unchecked", "rawtypes" })
You're using this because you're creating a non-parameterized instance of Map.
In .NET, you don't get around the type system like this, because generic type information is kept and used at runtime.
Let's see your C# code:
public static class KeyCountMap<T>
A static class in C# is a class that cannot be instanced, it's used for its static members alone. I think you don't want this. Perhaps KeyCountMap is a static nested class in Java, as opposed to an inner class.
In C#, you don't have inner classes. Nested classes don't share data with an instance of the containing class, it's as if the name of the containing class is part of the namespace for the nested class. So, you don't need, and actually don't want, the static keyword here.
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
In .NET, Dictionary is a class. To keep the intent, you should use IDictionary, the corresponding interface, as the type for the map field.
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
Why the void return type, isn't this a constructor?
In C#, constructors can't be generic. You probably want a Type.
Your C# code just doesn't make sense, so here's what you could do:
public KeyCountMap(Type dictionaryType)
{
if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
{
throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", nameof(dictionaryType));
}
map = (IDictionary<T, MutableInt>)Activator.CreateInstance(dictionaryType);
}
}
We're checking the type before creating an instance. If we didn't, we would create an instance, the cast would fail and the assignment wouldn't even happen, so the new instance would just be garbage.
It may be that the actual instance will be a proxy; if so, you may not want to check the type before creating an instance.
You can't just copy-paste Java as C# (or vice-versa) and expect to make just a few changes until it works, for some definition of works, e.g. it compiles. The languages are not that similar, and chances are that too many subtle things are wrong.
This approach might be fun at first, but you'll stumble so often it will soon stop being any fun at all. You should learn the basics and understand the way things are done in the target language before you start translating code line-by-line. Many times, you may find that something you had to do in one environment already exists in the other or vice-versa, or that something may take more or less steps to do in the other, etc.
In this particular case, Java made Class be a generic class, while .NET kept Type a non-generic class. In .NET only interfaces and delegates may state generic type covariance or contravariance. This is rather restrictive anyway, if Type was generic, the intended uses could be either covariant or contravariant. But remember that in Java, a generic Class<T> at runtime is as good as Class, it only has any value at compile time and you can tell the compiler you know better anyway, just like you did.
There are two problems. First, you need to tell the compiler that T has a parameterless constructor, so you can call new T(). You can do that by providing the new() argument to the class definition.
You also have to tell the compiler that T is actually the dictionary you are trying to assign, so we have to extend the class a little more:
public class KeyCountMap<K>
{
private Dictionary<K, MutableInt> map = new Dictionary<K, MutableInt>();
// ... rest of properties...
Note that K is the key type of the dictionary, which you didn't specify yet.
Second, the T in your method can be another T than in your class. Omitting that will do the trick:
public void Map()
{
var obj = new Dictionary<K, MutableInt>(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
Maybe this is what you want?
public class KeyCountMap<T>
where T : new()
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public KeyCountMap(T obj)
{
obj = new T();
map = (Dictionary<T, MutableInt>)(object)obj;
}
}
I'm working with the following jaxb class hierarchy:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(...)
public class RecordModifyType extends RecordBaseType
{
...
public List<FieldModifyType> getField() { ... }
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(...)
public class RecordAddType extends RecordBaseType
{
...
public List<FieldAddType> getField() { ... }
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(...)
public class FieldModifyType extends FieldBaseType
{
...
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(...)
public class FieldAddType extends FieldBaseType
{
...
}
I stumbled upon a method in some other class with the following signature (please note the raw types):
private void createFields(FTPPartner user,
String addressMasterDataID,
String connectionMasterDataID,
CRTypeEnum crType,
List addrFields,
List connFields)
This method is called from different parts of the class sometimes with List<FieldAddType> as arguments and other times with List<FieldModifyType>.
Now I'm trying to get rid of the raw types in its signature.
Following the get-put principle, I decided to change the signature to
private void createFields(FTPPartner user,
String addressMasterDataID,
String connectionMasterDataID,
CRTypeEnum crType,
List<? super FieldBaseType> addrFields,
List<? super FieldBaseType> connFields)
{
...
FieldBaseType someField = new buildField(...);
addrFields.add(someField);
...
}
... since the createFields implementation is only putting stuff in these collections.
The problem is that since RecordModifyType#getFields() returns List<FieldModifyType> and RecordAddType#getFields() returns List<FieldAddType>,
I now can not invoke the method, since it only allows for super types of FieldBaseType, not subtypes:
RecordAddType addrRecord = getRecordAddType(...);
RecordAddType connRecord = getRecordAddType(...);
List<FieldAddType> addrFields = addrRecord.getFields();
List<FieldAddType> connFields = connRecord.getFields();
createFields(user,
addressMasterDataID,
connectionMasterDataID,
crType
addFields, // This won't compile
connFields); // This won't compile
marshalRecord(addrRecord);
marshalRecord(connRecord);
Using raw types is working as expected - there are no compile errors and marshalling works.
So my question is - is there a way to preserve the behaviour but get rid of the raw types?
If I understand your problem correctly, the compiler is complaining because it doesn't know that the type ? super FieldBaseType for the call is the the same type for each parameter. Also, because both concrete types are subclasses of FieldBaseType, that's how the type needs to be bound IMHO.
Try typing the method:
private <T extends FieldBaseType> void createFields(FTPPartner user,
String addressMasterDataID,
String connectionMasterDataID,
CRTypeEnum crType,
List<T> addrFields,
List<T> connFields) {
// during the call, the compiler knows that addrFields and connFields
// hold the same type as each other
}
Now the type is inferred at the call point.
I have a class with a collection of Wildcard Types that is a singleton, something like:
public ObliviousClass{
private static final ObliviousClass INSTANCE = new ObliviousClass();
private Map<Key, Type<?>> map = new HashMap<Key, Type<?>>();
public void putType(Key key, Type<?> type){
map.put(type);
}
// returns the singleton
public static ObliviousClass getInstance(){
return INSTANCE;
}
}
I'd like to be able to add different Parameterized types to this collection in client code:
void clientMethod(){
ObliviousClass oc = ObliviousClass.getInstance();
Type<Integer> intType = ...
Type<String> stringType = ...
oc.putType(new Key(0), intType);
oc.putType(new Key(1), stringType);
}
Up to this point, as I understand it, everything is ok. But a client also needs to be able to get a Type<?> provided the Key. So a method something like the following would be added to ObliviousClass:
public Type<?> getType(Key key){
return map.get(key);
}
But in my handy copy of Effective Java, I read:
Do not use wildcard types as return types.
I understand the issue, as the client would have to cast the returned Type<?>. But I really do not want to make ObliviousClass a generic type, ObliviousClass<T>, because then my client code above would not work...
Is there a better design for what I am trying to do?
-My current solution is to provide a static method for the client; something along the lines of:
public static <T> void getType(ObliviousClass instance, Key key, Type<T> dest){
dest = (Type<T>)instance.getType(key);
}
I searched around, but wasn't able to find an answer that totally cleared my confusion.
Here's a type-safe way to store multiple instances of a given type in a map. The key is that you need to provide a Class instance when retrieving values in order to perform runtime type-checking, because static type information has been erased.
class ObliviousClass {
private final Map<Key, Object> map = new HashMap<Key, Object>();
public Object put(Key key, Object value)
{
return map.put(key, value);
}
public <T> T get(Key key, Class<? extends T> type)
{
return type.cast(map.get(key));
}
}
Usage would look like this:
oc.put(k1, 42);
oc.put(k2, "Hello!");
...
Integer i = oc.get(k1, Integer.class);
String s = oc.get(k2, String.class);
Integer x = oc.get(k2, Integer.class); /* Throws ClassCastException */
Simply type your class:
public ObliviousClass <T> {
private Map<Key, Type<T>> map = new HashMap<Key, Type<T>>();
public void putType(Key key, Type<T> type){
map.put(type);
}
public Type<T> getType(Key key){
map.get(key);
}
}
FYI, at this point you have the delegation pattern in play.
Your example client code would need to declare two instances of ObliviousClass: ObliviousClass<String> and ObliviousClass<Integer>.
Edit:
If you must have a mixed bag of Types, you can impose a type on your method, but you'll get a compiler warning for an unsafe cast:
public class ObliviousClass {
private final Map<Key, Type<?>> map = new HashMap<Key, Type<?>>();
public void putType(Key key, Type<?> value) {
map.put(key, value);
}
#SuppressWarnings("unchecked")
public <T> Type<T> getType1(Key key, Class<T> typeClass) {
return (Type<T>)map.get(key);
}
#SuppressWarnings("unchecked")
public <T> Type<T> getType2(Key key) {
return (Type<T>) map.get(key);
}
}
Clients can type the calls to these methods like this:
Type<Integer> x = obliviousClass.getType1(key, Integer.class);
Type<Integer> y = obliviousClass.<Integer>getType2(key);
Take your pick as to which one you prefer and use that.
For those landing on this question these many years later, this is not how Java generics are designed to be used. (I was going to comment but had more to details.)
The generic pattern manages a single parent class per type ID rather than multiple different classes. If we consider the simpler List<T>, a list of strings OR integers (as List<String> or List<Integer>) is how generics are defined. One class per type. This way, there is a consistent type when the values are referenced. Storing unrelated types would be the same as List<Object>. Only the programmer can know when multiple types are stored and how to retrieve them with casting.
It would be ok to store subclasses to a parent class, but when accessed from the collection without casting, the parent class contact is all that is known. For instance, a generic collection defined with an interface like Map<String, Runnable>. However, only the run() method is visible even if other public methods are added to implementations (unless the programmer explicitly casts). To access additional methods, casting is necessary.
This is a limitation in Java. A language could be defined to know the L-Value type - even Java. But it wasn't. When new features are added, there are many backward compatible considerations [Sun and] Oracle take into account. Code compiled with generics was designed to run on older JVMs with type erasure. Java uses type erasure at compile time once it has determined that the generics are consistently reference. The bytecode uses Object as if the instance was (sort of) defined as List. If the choice was made to abandon backward compatibility, like Java 9 and 11, then multiple types might have been workable.
Your ObliviousClass, by design, doesn't know the parameterized type of the item it holds. So to be type safe, you should avoid such design :-\
But if you want to keep it, first things is that you will have to cast. There is no way out of this. But the way you do it is very error prone. For example:
oc.put(k1, intType);
oc.put(k2, strType);
Type<Integer> tint = oc.get(k1, Integer.class)
Type<String> tstr = oc.get(k1, String.class) // typo in k2: compile fine
And worst, due to type erasure, it will fail at runtime only once you actually use tstr, not when you get it from ObliviousClass.
So you can improve safety by tracking the parameterized type in some other way. For example, you could associate the key to the type, not losing it:
#Value // lombok
class Key<T> {
private int index;
}
class Type<T> {}
class ObliviousClass {
// side note: static final can be public safely
public static final ObliviousClass instance = new ObliviousClass();
private List<Type<?>> map = new ArrayList<>();
public <T> Key<T> appendType(Type<T> type){
// here, I found it nicer that obliviousClass generates and return the key
// otherwise use: "public <T> void appendType(key<T> key, Type<T> type)"
// that binds parametrized type of both key and type arguments
map.add(type);
return new Key<>(map.size() - 1);
}
public <T> Type<T> get(Key<T> key){
return (Type<T>) map.get(key.index);
}
}
Then you can use it such as:
Type<Integer> intType = new Type<>();
Type<String> strType = new Type<>();
Key<Integer> k1 = ObliviousClass.instance.appendType(intType);
Key<String> k2 = ObliviousClass.instance.appendType(strType);
Type<Integer> t1 = ObliviousClass.instance.get(k1);
Type<String> t2 = ObliviousClass.instance.get(k2);
Type<String> t3 = ObliviousClass.instance.get(k1); // won't compile