How to use Java generics method? - java

I am moving from C++ to Java. Now I am trying a generics method. But the compiler always complains below error
The method getValue() is undefined for the type T HelloTemplate.java /helloTemplate/src/helloTemplate
The error was pointing to t.getValue() line
As I understand, T is class MyValue, which has the method getValue
What is wrong? How Can I fixed this. I am using Java1.8
public class MyValue {
public int getValue() {
return 0;
}
}
public class HelloTemplate {
static <T> int getValue(T t) {
return t.getValue();
}
public static void main(String[] args) {
MyValue mv = new MyValue();
System.out.println(getValue(mv));
}
}

The compiler doesn't know that you are going to pass to getValue() an instance of a class that has a getValue() method, which is why t.getValue() doesn't pass compilation.
It will only know about it if you add a type bound to the generic type parameter T:
static <T extends MyValue> int getValue(T t) {
return t.getValue();
}
Of course, in such a simple example you can simply remove the generic type parameter and write:
static int getValue(MyValue t) {
return t.getValue();
}

Just you need casting before calling the method. return ((MyValue) t).getValue();
, so that compiler can know that it's calling the MyValue's method.
static <T> int getValue(T t) {
return ((MyValue) t).getValue();
}
in case of multiple classes, you can check for instances using instanceofoperator, and the call the method.. like below
static <T> int getValue(T t) {
//check for instances
if (t instanceof MyValue) {
return ((MyValue) t).getValue();
}
//check for your other instance
return 0; // whatever for your else case.

Related

How to cast integer to some generic type?

I have a class MyClass and its super-class MySuperClass.
MySuperClass is from a standard library, so its codes cannot be changed.
As per the user requirement, the method name myMethod() of MyClass cannot be changed as well.
Unluckily, the same name MyClass is already in MySuperClass, and those codes are not what I want. I used #Override to override those codes (Thanks for the help from Matteo NNZ who suggested me for this fix in the case of having various generic types).
However, I need to cast keyInt to type K such that I can call the mySubMethod(). Below is my code:
MyClass
public class MyClass<K,V> extends MySuperClass {
// the name "myMethod" are not allowed to be modified
public boolean myMethod(K key) { // if key is NOT integer, Main.java will call this method
mySubMethod(key);
return false;
}
#Override // This is a fix; To Override myMethod(int index) of MySuperClass.
public boolean myMethod(int keyInt) { // if key is integer, Main.java will call this method
K key = (K) keyInt; // <-- I have error here
mySubMethod(key);
return false;
}
public boolean mySubMethod(K key) {
System.out.println("I want to call this");
return false;
}
}
MySuperClass
public class MySuperClass { // codes of MySuperClass are not allowed to be modified
public boolean myMethod(int index) {
System.out.print("Shouldn't be called.");
return false;
}
}
To call MyClass, in Main.java I will create new instances for either MyClass<Integer, String> or MyClass<String, String>. But currently I got error message "Cannot cast from int to K".
I tried to fix the error by using if(key instanceof Integer){ /** blahblahblah */}, but it doesn't work since KeyInt is already an integer when the method is called. How can I fix this?
Do you want this result?
public class MyClass<K,V> extends MySuperClass {
// the name "myMethod" are not allowed to be modified
public boolean myMethod(K key) { // if key is NOT integer, Main.java will call this method
mySubMethod(key);
return false;
}
#Override // This is a fix; To Override myMethod(int index) of MySuperClass.
public boolean myMethod(int keyInt) { // if key is integer, Main.java will call this method
// K key = (K) keyInt; // <-- I have error here
mySubMethod(keyInt);
return false;
}
public <T> boolean mySubMethod(T key) {
System.out.println("I want to call this");
return false;
}
}

Java- Returning different classes based on generic type

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;
}
}

Why this Java lambda expression parameter has an error?

This is an aritmetic expression evaluator that uses the interpreter GOF pattern, BinaryOp is a non terminal expression.
public class BinaryOP<T> implements Expression<T> {
private Expression<T> e1;
private Expression<T> e2;
private BiFunction<Expression<T>, Expression<T>, T> f;
public BinaryOp(Expression<T> e1, Expression<T> e2,
BiFunction<Expression<T>, Expression<T>, T> f){
this.e1 = e1; this.e2 = e2; this.f = f;
}
#Override
public <T> T interpret(IContext context){
return (T)f.apply(e1, e2);
}
}
And variable is the terminal expression.
public class Variable<T> implements Expression<T> {
private T v;
public Variable(T v){
this.v = v;
}
#Override
public <T> T interpret(IContext context){
return (T)context.recognize(v);
}
}
When defining the BiFunction sum I get an error when using the lambda, an error on its parameters, if a and b are of type expression and the result returns an integer ¿Why is this error?.
public class AritmeticInterpreter
{
public static void main(String[] args) {
IContext<Integer> ctxArimetic = value -> value;
BiFunction<Expression<Integer>, Expression<Integer>, Integer> sum
//Error = incompatible types: incompatible parameter types in lambda expression
= (a, b, result) -> {
return (Integer)a.interpret(ctxArimetic) + (Integer)b.interpret(ctxArimetic);
};
}
}
What is causing this error, has to be the return type another expression?
if I change the interpret method return type to expression, I wouldn't be able to sum two expressions a and b like this:
(a, b) -> a + b
because they are not Integers.
and well, this no part of the title but, ¿can I get rid of casting interpret on method? I know that java compiler erases the generic type but, ¿is there a way?
Update:
Here is the Expression interface.
public interface Expression<T> {
public <T> T interpret(IContext context);
}
Acording to JB Nizet comment and this example I found that I just have to use a and b as arguments in the lambda.
Here is the correct code.
public static void main(String[] args) {
IContext<Integer> ctxArimetic = value -> value;
BiFunction<Expression<Integer>, Expression<Integer>, Integer> sum
= (a, b) -> {
return a.interpret(ctxArimetic) + b.interpret(ctxArimetic);
};
}
and for the last question.
on BinaryOP class i make this change:
#Override
public T interpret(IContext<T> context){
return f.apply(e1, e2);
}
and on the Expression Interface:
public interface Expression<T> {
public T interpret(IContext<T> context);
}
This error was because I parametrized the interpret method, and this allows the method to return any object. I remember that the compiler output the error "T#2 is different from type T#1" T#2 was the generic parameter <T> on interpret method and T#1 was the generic type on the class BinaryOp<T>.
I didn't Know how to use lambdas and generics correctly.
Update: Fix some errors, I changed
public T interpret(IContext context);
To
public T interpret(IContext<T> context);

Execute a specific parametrized class method

I have this (simplified) java interface
public interface MyInterface<T> {
public String run( T arg );
}
and some classes that implement that interface, i.e.
public final class SomeImplementation1 implements MyInterface<String> {
#Override
public String run( String arg) {
// do something with arg and return a string
}
}
and
public final class SomeImplementation2 implements MyInterface<CustomClass> {
#Override
public String run( CustomClass arg) {
// do something with arg and return a string
}
}
Now, I have a global resource manager for all of those implementations, which instantiates all of them in a List for latter usage. What I would like to achieve is something like this, which obviously gives me an error
public final class MyInterfaceManager {
private List<MyInterface<?>> elements = new List<MyInterface<?>>();
public MyInterfaceManager() {
elements.put( new SomeImplementation1() );
elements.put( new SomeImplementation2() );
// more implementations added
}
// this is what I would like to achieve
public <T> void run( T arg ) {
for( MyInterface<?> element: elements ) {
String res = element.run( arg ); // ERROR
}
}
}
because "arg cannot be converted to capture#1 of ? by method invocation conversion".
A possible solution could be to perform an instanceof test inside the loop, and cast the element to its real type, along with the argument as well, like that
public <T> void run( T arg ) {
for( MyInterface<T> element: elements ) {
if (element instanceof SomeImplementation2) {
String res = ((SomeImplementation2)element).run( (CustomClass)arg );
} else if // other tests here ...
}
}
But i don't like it, it's not elegant at all, and it forces me to do lots of instanceof and casts.
So, I'm wondering if there is a better way to achieve this.
Thanks for your help :)
You are running into type erasure. You need to add another method to the interface that returns the Class instance that relates to the type parameter <T>, this will allow you to do runtime checks on that Class.
I would accomplish this thus:
public interface MyInterface<T> {
String run( T arg );
Class<T> type();
}
So the interface returns its type. N.B. all interface members are public by default - no need for the extra public.
public final class SomeImplementation1 implements MyInterface<String> {
#Override
public String run(final String arg) {
return arg;
}
#Override
public Class<String> type() {
return String.class;
}
}
#SuppressWarnings({"unchecked"})
public static <T> String run(final T arg) {
for (final MyInterface<?> element : elements) {
if (element.type().isAssignableFrom(arg.getClass())) {
return ((MyInterface<T>) element).run(arg);
}
}
throw new IllegalArgumentException("No element found.");
}
The logic is that for each MyInterface you check whether the argument provided is safely castable to that MyInterface's type(). If it is then you can cast the whole MyInterface to the arg's type. This is unchecked as the compiler cannot verify this as compile time, but as you are manually doing a check this warning can be ignored.
public static void main(String[] args) throws Exception {
elements = new LinkedList<>();
elements.add(new SomeImplementation1());
System.out.println(run("test"));
System.out.println(run(1));
}
Output:
test
Exception in thread "main" java.lang.IllegalArgumentException: No element found.
at com.XXX.App.run(App.java:33)
at com.XXX.App.main(App.java:55)
As expected.

java generic type inference based on generic argument

what I'm trying to do is send a generic method(filter) inside generic object(ItemDelegate) to another generic method(getItem). The problem is that the second method(getItem) can not infer the correct type.
// Generic object
public class ItemDelegate<T> {
public <T> T filter() {
return null;
}
}
// Generic method (receiver):
public static <T> T getItem(ItemDelegate<T> delegate) {
T item = delegate.filter();
//... do something
return item;
}
// Usage in code:
getItem(new ItemDelegate<String>() {
public String filter() {
return "Hi!";
}
}
this code generates a compile error in getItem:
type parameters of T cannot be determined; no unique maximal instance exists for type variable T with upper bounds T,java.lang.Object
Can this even be done in java or is there a better way.
Thanks.
This works for me:
// Generic object
public class ItemDelegate<T> {
public T filter() {
return null;
}
// Generic method (receiver):
public static <R> R getItem(ItemDelegate<R> delegate) {
R item = delegate.filter();
// ... do something
return item;
}
public static void main(String[] args) {
// Usage in code:
getItem(new ItemDelegate<String>() {
#Override
public String filter() {
return "Hi!";
}
});
}
}
It is not clear to me what you want - do you want to make filter generic on a different parameter than that of the generic class ItemDelegate<T>? Then I guess you should use a different parameter name as a minimum:
public class ItemDelegate<T> {
public <U> U filter() {
return null;
}
}
or if you need the same parameter, don't redeclare it:
public class ItemDelegate<T> {
public T filter() {
return null;
}
}
Another problem is, you don't actually override filter in your anonymous class here
getItem(new ItemDelegate<String>() {
public String filter(ResultSet x) throws SQLException {
return "Hi!";
}
}
since this filter has a parameter and throws an exception.
These two issues together mean that the compiler can't infer T for ItemDelegate.filter.

Categories

Resources