In my generic class I need to restrict type parameter to Integer OR String. Is there a way to achieve this? I cannot use T extends SomeClass to limit types, because common parent is just Object...
update
public abstract class MyClass<T>{
private T value;
public T getValue(){
return value;
}
}
I'd like the value type to be a String or an Integer and I need to use the same method to get it (not getIntValue() + getStringValue() )
This doesn't seem to help...
If I were you, I would overload two methods:
public void withInteger(Integer param) { .. }
public void withString(String param) { .. }
Note that there's no reason to use something like T extends String, because both String and Integer are final and can't be subclassed.
Just made your class ctor private and pass through a factory method to create implementation; type restriction is not bounded to MyClass but via factory.
class MyClass<T> {
private T value;
MyClass(T value) { this.value = value; }
public T getValue() { return value; }
}
class MyClassFactory {
public final static MyClass<Integer> createInteger(Integer i) {
return new MyClass<Integer>(i);
}
}
Related
I'm attempting to create an enum whose constructor accepts an object whose base class is a generic class.
I seem to be unable to fetch the underlying generic type from within the enum however, Object gets returned instead of T.
Is there a way to do this?
abstract public class Field<T> {
abstract public T get();
}
public class IntegerField extends Field<Integer> {
public Integer get() {
return 5;
}
}
public class StringField extends Field<String> {
public String get() {
return "5";
}
}
public enum Fields {
INTEGER (new IntegerField()),
STRING (new StringField());
private final Field<?> field; // <<--- I can't have Field<T>, enum's can't be generic. :(
<T> Fields(Field<T> field) {
this.field = field;
}
public <T> T get() {
return field.get(); // <<--- Returns Object, not T
}
}
The issue is that enums can't be generically typed so even if you cast that get call ((T) field.get()) you won't have type safety because it will agree with any assignment (you could compile this successfully for instance: boolean b = Fields.INTEGER.get()).
Just use constants instead:
public final class Fields {
public static final Field<Integer> INTEGER = new IntegerField();
public static final Field<String> STRING = new StringField();
}
Why do you think an enum is preferable to this?
public final class Fields {
public static final Field<Integer> INTEGER = new IntegerField();
public static final Field<String> STRING = new StringField();
//private ctor
}
or if you prefer
public final class Fields {
public static Field<Integer> integerField() {
return new IntegerField();
}
public static Field<String> stringField() {
return new StringField();
}
//private ctor
}
Why would I want to call Fields.INTEGER.get() when I can just use Fields.INTEGER?
What are the pros/cons of using the abstract class constructor vs. an abstract method for passing final data to an abstract class?
Pass via constructor:
public abstract class MyAbstractClass<T> {
private final String type;
private final Function<String, T> factoryFn;
protected MyAbstractClass(String type, Function<String, T> factoryFn) {
this.type = type;
this.factoryFn = factoryFn;
}
public T doSomething(String value) { ... }
}
Pass via abstract method:
public abstract class MyAbstractClass<T> {
abstract String getType();
abstract T getFactoryFn(String value);
public T doSomething(String value) { ... }
}
I'm aware that the abstract methods can potentially be misused, because it doesn't enforce to always return the same value.
But apart from that, is it just a matter of personal preference, or are there any real (dis)advantages for using one over the other?
I hope I am understanding your question correctly..
Usually, when a property of a class is always held in a field, it is more concise to use an abstract constructor. For example, consider the two following scenarios....
// Scenario 1:
abstract class AClass {
final int field;
public AClass(int f) {
field = f;
}
public int getField() {
return field;
}
}
class Class1 extends AClass {
public Class1(int f) {
super(f);
}
// Class Unique Code...
}
class Class2 extends AClass {
public Class2(int f) {
super(f);
}
// Class Unique Code...
}
// Scenario 2:
abstract class AClass {
public abstract int getField();
}
class Class1 extends AClass {
final int field;
public Class1(int f) {
field = f;
}
#Override
public int getField() {
return field;
}
// Class Unique Code...
}
class Class2 extends AClass {
final int field;
public Class2(int f) {
field = f;
}
#Override
public int getField() {
return field;
}
// Class Unique Code...
}
Scenario 1 is shorter since the getter logic for field only needs to be specified once. Whereas in scenario 2, the getter logic must be overridden by both subclasses. I find scenario 2 to be redundant... why write the same code twice when you can use java inheritance to your advantage.
As a final note, I usually don't hold functions in fields unless totally necessary. Whenever you have a function in a field, it's usually a sign that an abstract function can be applied.
Here is your original code with my advice applied...
public abstract class MyAbstractClass<T> {
private final String type;
protected MyAbstractClass(String t) {
type = t;
}
protected abstract T applyFactoryFunction(String value);
public T doSomething(String value) { ... }
}
Hope this helped!
I have this compilation problem:
Here is the class in question:
package huru.entity;
import io.vertx.core.json.JsonObject;
import java.util.Date;
public class BaseEntity <T extends BaseModel> extends JsonObject {
private T model;
public BaseEntity(T m){
this.model = m;
}
public void setUpdateInfo(String user){
this.model.updatedBy = user;
this.model.updatedAt = new Date();
}
public JsonObject toJsonObject(){
return JsonObject.mapFrom(this.model);
}
public T getEntityType (){
return this.model.getClass(); // doesn't compile
}
}
I also tried using
public T getEntityType (){
return T; // doesn't compile
}
but that clearly doesn't work either. Anybody know how I can return the class instance of that generic type?
I also tried this:
public Class<T> getEntityType (){
return this.model.getClass();
}
and I get:
and then I tried this:
public Class<? extends T> getEntityType (){
return this.model.getClass();
}
and I have:
You appear to be confused. You're returning the class that represents T, not a T.
Let's replace T with String and show why what you're doing makes no sense:
private String model;
public String getEntityType() {
return model.getClass();
// Of course this does not work; model.getClass() is not a string!
}
public String getEntityType() {
return String;
// This doesn't even compile.
}
To try to explain, this:
public T getEntityType() {
....
}
requires you to return an actual instance of whatever T is. Not whatever type T is representing. Just like 'String' means you should return an actual instance of String, not the concept of String, the type.
Perhaps you meant to do this:
public T getEntityType() {
return model;
}
or more likely, given that you named this method 'getEntityType', what you mean is this:
public Class<? extends T> getEntityType() {
return model.getClass();
}
Yes, ? extends T, because model is a T, or any subtype of T.
What about the following code. I think it works.
public Class<? extends BaseModel> getEntityType (){
return model.getClass();
}
class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
Part of the problem is that getClass is defined in Object to give you a Class< ? > with a wildcard as the generic parameter. If you want to return Class< ? extends T > you will need to cast to that:
return (Class< ? extends T >) (model.getClass());
I would like to create a class that will take in different types. It should handle some basic operations like .equals() for all given types, but I'd like to create specific implementations for Strings and Booleans for example.
I'd like to use the same constructor but control what happens based on the type.
public class TestObject<T>{
private T value;
public TestObject{
}
public setValue(T value){
this.value=value;
}
public return Type??? getSpecificType(){
if (value instanceof Boolean){
return new TestObjectBoolean(this);
}
if (value instanceof String){
return new TestObjectString(this);
}
}
}
The desired usage below:
TestObject<String> test = new TestObject<String>();
test.setValue("Test");
boolean result = test.getSpecificType().stringSpecificMethod()
TestObject<Integer> test2 = new TestObject<Boolean>();
test.setValue(true);
boolean result2= test2.getSpecificType().booleanSpecificMethod();
I would like the below example to fail to compile:
TestObject<String> test3 = new TestObject<String>();
test.setValue("Test");
boolean result3= test3.getSpecificType().booleanSpecificMethod();
//should not compile because test2 should return a boolean specific class
//with the boolean specific methods
It may seem silly but I would like to avoid calling differently named constructors for different types like this:
TestObjectString test4 = new TestObjectString();
test.setValue("Test");
boolean result4= test4.stringSpecificMethod();
I am lost on how to implement this. Any advice or help on searching additional information on this would be appreciated.
Thank you.
I’m not sure I understand what you’re asking for, but I think you want to make the constructor private, and add public factory methods:
public class TestObject<T> {
private T value;
private final Supplier<? extends TestObject<T>> typeSpecificConstructor;
private TestObject(T initialValue,
Supplier<? extends TestObject<T>> constructor) {
this.value = initialValue;
this.typeSpecificConstructor = constructor;
}
protected TestObject(Supplier<? extends TestObject<T>> constructor) {
this.typeSpecificConstructor = constructor;
}
public boolean test(T valueToTest) {
throw new UnsupportedOperationException(
"Must be implemented by subclasses");
}
public static TestObject<Boolean> newInstance(boolean initialValue) {
return new TestObject<>(initialValue, TestObjectBoolean::new);
}
public static TestObject<String> newInstance(String initialValue) {
return new TestObject<>(initialValue, TestObjectString::new);
}
public TestObject<T> getSpecificType() {
return typeSpecificConstructor.get();
}
public T getValue() {
return value;
}
public void setValue(T newValue) {
this.value = newValue;
}
}
But methods particular to a subtype still won’t be accessible. There is simply no way for a variable whose type is a general superclass to make subclass methods available without casting.
I’m not sure what your intended purpose of getSpecificType() is, but you could probably do away with that method and make things simpler:
public abstract class TestObject<T> {
private T value;
public abstract boolean test(T valueToTest);
public static TestObject<Boolean> newInstance(boolean initialValue) {
TestObject<Boolean> instance = new TestObjectBoolean();
instance.setValue(initialValue);
return instance;
}
public static TestObject<String> newInstance(String initialValue) {
TestObject<String> instance = new TestObjectString();
instance.setValue(initialValue);
return instance;
}
public T getValue() {
return value;
}
public void setValue(T newValue) {
this.value = newValue;
}
}
Is there any way how to make class type parameter more narrow (add another bound to it) in concrete method?
Let's look at example
public class Value<T>
{
private final T value;
public Value(T value)
{
this.value = value;
}
public <V extends T> boolean eq(V value)
{
return Objects.equals(this.value, value);
}
// here, I want to create bound that T extends Comparable<T>
// error: type parameter cannot be followed by other bounds
public <V extends T & Comparable<T>> boolean gt(V value)
{
return ((V)this.value).compareTo(value) > 0;
}
// here, I want to create bound that T extends String
// error: interface expected here
public <V extends T & String> boolean match(V value)
{
return ((V)this.value).equalsIgnoreCase(value);
}
public static void main(final String[] args)
{
final Value<Integer> integerValue = new Value<>(10);
integerValue.eq(10); // should compile
integerValue.gt(5); // should compile
integerValue.match("hello"); // shouldn't compile because match operates only on String values
final Value<String> stringValue = new Value<>("Foo");
stringValue.eq("Foo"); // should compile
stringValue.gt("bar"); // should compile
stringValue.match("foo"); // should compile
}
}
In this example line
integerValue.match("hello");
doesn't compile, which is correct, but the class can't be compile too due to restriction that type parameter cannot be followed by other bounds
Is there any other way how to achieve this?
An instance method must be available to all instances of the class. You can't declare a method that only exists for some instances of the class, those with certain type parameters.
What you can do is make a generic static method that takes an instance of the class as an argument. Since the generic type parameter is now specific to the method, it can be restricted to what the method wants:
public static <T> boolean eq(Value<T> obj, T value)
{
return Objects.equals(obj.value, value);
}
public static <T extends Comparable<T>> boolean gt(Value<T> obj, T value)
{
return obj.value.compareTo(value) > 0;
}
public static <T extends String> boolean match(Value<T> obj, T value)
{
return obj.value.equalsIgnoreCase(value);
}
Using the & operator assumes that V directly extends T and String, so one of them has to be an interface as a class can not directly extend two other classes. It doesn't work either for Comparable<T> as compilator can not garantee type safety with that typo.
You just have to use a , :
// here, I want to create bound that T extends Comparable<T>
// error: type parameter cannot be followed by other bounds
public <V extends T, T extends Comparable<T>> boolean gt(V value)
{
return ((V)this.value).compareTo(value) > 0;
}
// here, I want to create bound that T extends String
// error: interface expected here
public <V extends T, T extends String> boolean match(V value)
{
return ((V)this.value).equalsIgnoreCase(value);
}
Type bounds aren't the solution you need. What you need are subclasses.
public class Value<T>
{
protected final T value;
public Value(T value)
{
this.value = value;
}
public boolean eq(T value)
{
return Objects.equals(this.value, value);
}
}
public class ComparableValue<T extends Comparable<T>> extends Value<T>
{
public ComparableValue(T value)
{
super(value);
}
public boolean gt(T value)
{
return this.value.compareTo(value) > 0;
}
}
public class StringValue extends ComparableValue<String>
{
public StringValue(String value)
{
super(value);
}
public boolean match(String value)
{
return this.value.equalsIgnoreCase(value);
}
}
Then main becomes
public static void main(final String[] args)
{
final ComparableValue<Integer> integerValue = new ComparableValue<>(10);
integerValue.eq(10); // will compile
integerValue.gt(5); // will compile
integerValue.match("hello"); // will not compile
final StringValue stringValue = new StringValue("Foo");
stringValue.eq("Foo"); // will compile
stringValue.gt("bar"); // will compile
stringValue.match("foo"); // will compile
}