Java difference between two methods (generics) - java

Consider the class hierarchy
public class A {
public void say() {
System.out.println("I am A");
}
}
and
public class B extends A {
public void say() {
System.out.println("I am B");
}
}
In a third class I have two different methods
private static void print(A input) {
}
private static <T extends A> void print2(T input) {
}
What is the "difference" between them?
I can both call them with an instance of A and all subclasses of A:
public class Test {
private static void print(A input) {
input.say();
}
private static <T extends A> void print2(T input) {
}
public static void main(String[] args) {
B b = new B();
print(b);
print2(b);
}
}
Thank you for your help!
P.S.: The difference between
private static void print(java.util.List<A> input) {
}
private static <T extends A> void print2(java.util.List<T> input) {
}
is clear!

Well from a practical reason there is not so much difference there.
You could call the second method by
<B>test2(new B());
It would fail then when you try to use is with an A
<B>test2(new A()); //Compile error
Although this does not make a big use for it.
However:
The generic declaration does make sence when you e.g. add the return-types.
public void <T extends A> T test2(T var) {
//do something
return var;
}
that you could call with:
B b = new B();
B b2 = test2(b);
while calling a similar method without generics would require a cast.

Related

Java - How to call method class with interface without know class name

I'm new in java, I want to call method class from implemented Class with interface without know class name "ClassA", which only know Object c and I have 2 file.
File (1) CobaInterface.java
package cobainterface;
public class CobaInterface {
public static void main(String[] args) {
ImplementedClass implementedClass = new ImplementedClass();
ClassA clsA = new ClassA();
implementedClass.myMethodFromClassA(clsA);
}
}
class ClassA{
public Integer getTwo(){
return 2;
}
}
interface MyInterface {
public void myMethod();
//here interface
public void myMethodFromClassA(Object c);
}
File (2) : ImpementedClass.java
package cobainterface;
public class ImplementedClass extends CobaInterface {
public void myMethodFromClassA(Object c) {
//System.out.println(c.getTwo()); <- wrong when call method c.getTwo()
}
}
How about if I want to call method getTwo() from ClassA without know Class Name, which only know Object c from file (2) as describe in code above. Thanks for advance.
You should use generic types so the implementation knows what the object will be,
interface MyInterface<T> {
public void myMethod();
//here interface
public void myMethodFromClassA(T c);
}
The impl becomes,
package cobainterface;
public class ImplementedClass Implements MyInterface<ClassA> {
public void myMethodFromClassA(ClassA c) {
//System.out.println(c.getTwo()); <- wrong when call method c.getTwo()
}
}
All together,
class Scratch {
public static void main(String[] args) {
ImplementedClass implementedClass = new ImplementedClass();
ClassA clsA = new ClassA();
implementedClass.myMethodFromClassA(clsA);
}
}
class ImplementedClass implements MyInterface<ClassA> {
#Override
public void myMethod() {
}
#Override
public void myMethodFromClassA(ClassA c) {
System.out.println(c.getTwo());
}
}
class ClassA {
public Integer getTwo() {
return 2;
}
}
interface MyInterface<T> {
void myMethod();
void myMethodFromClassA(T c);
}
You could also do a cast
System.out.println((MyClass)c.getTwo());
but you will lose all benefit of type saftey.

Implement a common function accepting argument of two different classes?

I have two classes A and B and they both have a common field in them, and I want to create a function in which if I pass Class A object then I want to set that common field value to the passed value and if I pass Class B object then I want to set that common field value to the passed value. Can anyone please tell me how can I do this, I am new to Java Generic Classes.
Otherwise I would have to make two different functions OR I would have to make an if and else which would decide that passed object belongs to which class ??
Class A
public class A{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class B
public class B{
int footer;
public void setFooter(int fo) {
footer = fo;
}
}
Class D
public class D{
public void change_footer(T generic_param, int value) {
generic_param.setFooter(value);
}
}
Class HelloWorld
public class HelloWorld{
public static void main(String []args){
Here I want to call
A a = new A();
new D().change_footer(a, 5);
B b = new B();
new D().change_footer(b, 5)
}
}
Thank You
And if I got all of the question wrong, and nor A nor B are generic, AND the type of field is fixed.
then you mean something like:
class D {
/*public <T extends Super> would be muuuch nicer here as well!*/
public /*static*/ <T> void change_footer(T obj, int data) {
//otherwise, you could just cast to Super...and set dat field.
if (obj instanceof A) {
((A) obj).setField(data);
} else if (obj instanceof B) {
((B) obj).setField(data);
} // else ... ?
}
}
Original answer:
Easy peasy (the "straight forward" implementation produces the desired results.):
class A<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
class B<T> extends A {//empty
}
class Test {
public static void main(String... args) {
B<Object> testB1 = new B<>(); //
testB1.setField(new Object());
System.out.println(testB1.getField());
B<String> testB2 = new B<>();
testB2.setField("blah blah");
System.out.println(testB2.getField());
B<Integer> testB3 = new B<>();
testB3.setField(42);
System.out.println(testB3.getField());
}
}
System.out:
java.lang.Object#6d06d69c
blah blah
42
It get's (little) more complicated, when you want to instantiate Ts ...but still possible/other question. :)
Edit to your comment:
If there's only one common field, then why not:
/*abstract */class Super<T> {
T daField;
public void setField(T pField) {
daField = pField;
}
public T getField() {
return daField;
}
}
? ...and:
class A<T> extends Super { ... }
class B<T> extends Super { ... }

Role of Type Inference over Type Erasure - Wildcard bounding can be possible if Type Inference works well over Type Erasure?

Working on a specific need. Most of online tutorial talks about applying wildcard implementation with Collections. In below example, extends works OK but when I apply super with wildcard bounding getting error. I wish to restrict a method with it super type like said in the below example. Is there any limitation with super that I supposed to know.
class SuperClass3 {
public void display() {
System.out.println("This is display3 method");
}
}
class SuperClass2 extends SuperClass3 {
public void display() {
System.out.println("This is display2 method");
}
}
class SuperClass1 extends SuperClass2 {
public void display() {
System.out.println("This is display1 method");
}
}
Extends works well (with Type bounding NOT with wildcard bounding)...
public <T extends SuperClass2> void displayOutput(T obj) {
obj.display();
}
Try to do the same with Super not working. Throw compile error on method signature.
public <T super SuperClass2> void displayOutputWithSuper(T obj) {
//obj.display();
}
Complete Example ...
package com.tutorial.generic.bounds.wildcard;
import java.util.List;
public class UpperBoundWildcardExample {
class SuperClass3 {
public void display() {
System.out.println("This is display3 method");
}
}
class SuperClass2 extends SuperClass3 {
public void display() {
System.out.println("This is display2 method");
}
}
class SuperClass1 extends SuperClass2 {
public void display() {
System.out.println("This is display1 method");
}
}
public <T extends SuperClass2> void displayOutput(T obj) {
obj.display();
}
public void addData(List<? extends SuperClass2> data) {
}
public <T super SuperClass1> void displayOutputWithSuper(T obj) {
obj.toString();
}
/*
* This wont work
*
* public void addData(<? extends SuperClass2> data){
*
* }
*/
public static void main(String[] args) {
UpperBoundWildcardExample obj = new UpperBoundWildcardExample();
// Oops!!! Error
// obj.displayOutput(obj.new SuperClass3());
// It suppports SuperClass2 & which extends SuperClass2
obj.displayOutput(obj.new SuperClass2());
obj.displayOutput(obj.new SuperClass1());
}
}
#Shaan
This might be helpful
Bounding generics with 'super' keyword
let's say that you have this generic method declaration:
<T super Integer> void add(T number) // hypothetical! currently illegal in Java
And you have these variable declarations:
Integer anInteger
Number aNumber
Object anObject
String aString
Your intention with (if it's legal) is that it should allow add(anInteger), and add(aNumber), and of course add(anObject), but NOT add(aString). Well, String is an Object, so add(aString) would still compile anyway.

Interesting behavior of method binding with generics

I am learning Generics, and while learning come across a sample code which, according to me should print'ok'
However i am getting following excetpion.
Exception in thread "main" java.lang.ClassCastException: Test$B cannot be
cast to java.util.Collection
Can some one help me on this behavior.
public class Test {
#SuppressWarnings("unchecked")
public static <U extends B> U get() {
return (U) new B();
}
public static void main(String[] args) {
A<B> a = new A<>(get());
}
static class A<T> {
A(Collection<? extends T> lst) {
System.out.println("Bad constructor");
}
A(T e) {
System.out.println("ok");
}
}
static class B {
}
}

Avoid cast in a generics hierarchy

I have some difficulty to simplify more the problem. Sorry if they are too many code here.
I try to improve the architecture of the code above because I hate warning and cast and I feel something wrong.
Now, the code.
I have a util class with these two parametrized methods (same signature as OpenJPA's CriteriaBuilder...)
public class MyUtil {
public void equal(List<?> l, Object value) {
// do something (see CriteriaBuilder.equal method)
}
public <Y extends Comparable<? super Y>> void greaterThan(List<? extends Y> l, Y value) {
// do something (see CriteriaBuilder.greaterThan method)
}
}
Then, I want to be able to abstract them to call it via an interface.
public interface IOperation<T> {
// maybe make this method generic ? but how ?
public abstract void doOp(List<T> l, T value);
}
public abstract class AbstractOperation<T> implements IOperation<T> {
protected MyUtil myUtil;
}
public class EqualOp extends AbstractOperation<Object> {
#Override
public void doOp(List<Object> path, Object value) {
myUtil.equal(path, value);
}
}
public class GreaterThanOp<T extends Comparable<? super T>> extends AbstractOperation<T> {
#Override
public void doOp(List<T> path, T value) {
myUtil.greaterThan(path, value);
}
}
I create a factory
public class OperationFactory {
private static OperationFactory instance;
public static OperationFactory getInstance() {...}
public IOperation<?> get(String op) {
if ("=".equals(op)) {
return new EqualOp();
} else if (">".equals(op)) {
return new GreaterThanOp<Comparable<? super Object>>();
}
throw new InvalidParameterException();
}
}
Then I use it :
public class Client {
public void needOp(String op) {
IOperation<String> operation = (IOperation<String>) OperationFactory.getInstance().get(op); // How to avoid this cast ?
List<String> l = null;
operation.doOp(l, "a string");
}
}
My question is : is it possible to avoid this cast in the Client class ? How ? Is there a way to have a better architecture ?
Thanks for reading
I'm assuming you can require your type to be Comparable.
Parameterize EqualOp like GreaterThanOp:
public class EqualOp<T extends Comparable<T>> extends AbstractOperation<T> {
#Override public void doOp(List<T> path, T value) ...
And define get() like this:
public <T extends Comparable<T>> IOperation<T> get(String op) {
if ("=".equals(op)) {
return new EqualOp<T>();
} else if (">".equals(op)) {
return new GreaterThanOp<T>();
}
...

Categories

Resources