covariant return or generic - java

I want to have a method in an interface that returns a class whose type is not defined in the package. The implementing class will then return a specific type. I can see at least 3 methods how I can do this, shown below as fn1, fn2 and fn3. In all cases there is some form of unchecked cast. Is any of these methods preferred? or is there something better? (assume that the interface I1 and the method dostuff are in some other jar package and do not have access to the Test or the Integer class)
public class Myclass {
public interface I1
{
Object fn1();
<T> T fn2();
<T> T fn3();
}
public class Test implements I1
{
#Override
public Integer fn1() {
return new Integer(1);
}
#Override
public <T> T fn2() {
return (T) new Integer(2); //requires cast to T
}
#Override
public Integer fn3() { //automatic unchecked conversion to T in return value
return new Integer(3);
}
}
public static void main(String[] args) {
Myclass c = new Myclass();
I1 t = c.new Test();
Integer i = (Integer) t.fn1(); //cast required here since I1.fn1() returns Object
Integer j = t.fn2();
Integer k = t.fn3();
dostuff(t);
}
static void dostuff(I1 p)
{
Object i = p.fn1();
Object j = p.fn2();
Object k = p.fn3();
}
}

Can't you use generics with the Interface? Like
public interface I1<T> {
T fn1();
// etc
}
Then there's no casting required when you refer to T.
That's what I prefer, at least. You can then also of course specify what you want T to be using
<T extends myInterface>

I would do it this way
public interface I1<T> {
T fn1();
}
public class Test implements I1<Integer> {
#Override
public Integer fn1() {
return new Integer(1);
}
}
public static void main(String[] args) {
Myclass c = new Myclass();
I1<Integer> t = c.new Test();
Integer i = t.fn1(); <-- no cast
}

Related

JAVA generics constructor issue

I'm studying JAVA generics nowadays and find out some weird situation.
class A{
public void mInA(){
System.out.println("mInA");
}
}
interface I{
public void mInInterfaceI();
}
class B extends A implements I{
public void mInInterfaceI(){
System.out.println("mInterfaceI");
}
}
class MyList <TP1, TP2>{
MyList(TP1 data1){
this.data1 = data1;
}
TP1 data1;
TP2 data2;
MyList<TP1, TP2> next;
}
public class GenericPrepare {
public static void main(String[] args){
B obj = new B();
MyList<A,B> anchor = new MyList<>(obj);//Curious
anchor.data2 = new B();
anchor.next = null;
}
}
My constructor is designed to put TP1 as input. So I must input 'A' type reference as argument in above remark.
But when i input 'B' type reference as argument, JAVA is not complaining about it.
I have no idea what's going on here.
The MyList<A,B> constructor expects an A object as parameter, but because B extends A, B is actually assignable to A -> your code works.

How to Use a method in super class differently for subclasses ((without enum or any attributes))?

The problem is that I want a super class of A and three subclasses , B,C,D.
and there's a method that only the super class A has , and none of the subclasses have that method and the method has different results in each sub class.
I also can't Override any methods.
how do I code this without using enum or giving any attributes to any class?
for example :
public class {
public String method1(){
//what each class type should do
}
}
public class B extends{
}
public static void main(String[] args) {
A[] elements = {new A(),new B()};
for (int i = 0; i < elements.length; i++) {
System.out.println(elements[i].method1());
}
}
results eg:
A1
B1
Method overriding is the best solution i think.
But if you want to have one function in class A, you can use istanceof to verify the class
if(object instnaceof A) doSomething ..
class A {
public String method1() {
if(this instanceof B) {
return "Class B";
//do something for class B
} else if (this instanceof C) {
return "Class C";
//do something for class C
}
return "";
}
}
class B extends A { }
class C extends A { }
public class Main {
public static void main(String[] args) {
A[] elements = {new A(),new B()};
for (int i = 0; i < elements.length; i++)
System.out.println(elements[i].method1());
}
}
You can use Generics like this, but better use overriding
public class A {
public <T extends A> String method1(T classInstance) {
return method(classInstance);
}
private String method(A classInstance) {
return classInstance.toString();
}
private String method(B classInstance) {
return classInstance.toString();
}
}
public class B extends A{
}
public class Application {
public static void main(String[] args) {
A[] elements = {new A (), new B ()};
for (int i = 0; i < elements.length; i++)
{
System.out.println (elements[i].method1(elements[i]));
}
}
}

Unchecked call and Unchecked assignment java factory generics

Consider the following scenario:
public abstract class A {}
public class B extends A {}
public interface Provider<T extends A> {
List<String> list(T param);
}
public class ProviderB implements Provider<B> {
#Override
public List<String> list(B param) {
return Collections.singletonList("ProviderB");
}
}
public class Factory {
public static Provider get(int x) {
if (x == 1)
return new ProviderB();
throw new RuntimeException("Not supported");
}
}
public class Main {
public static void main(String[] args) {
Provider provider = Factory.get(1);
A a = new B();
List<String> result = provider.list(a);
}
}
In Main at List<String> result = provider.list(a); , I'm getting:
Unchecked call to list(T) ..
Unchecked assignment java.util.List .. Reason 'provider' has raw type.
I do know some basic stuff about type erasure in generics. How would you solve the warnings ?
EDIT:
Actually main will look like this:
public static void main(Map<Integer, ? extends A> types) {
for (Map.Entry<Integer, ? extends A> entryType : types.entrySet()) {
Provider provider = Factory.get(entryType.getKey());
List<String> result = provider.list(entryType.getValue());
}
}

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 { ... }

Generic Functional Interface that accepts and returns same type

I'm looking for a functional interface that satisfies the following two requirements:
Should accept and return the same type
The type should be inferred while calling the method on the FunctionalInterface
If the requirement had just been the first, I can create a simple FunctionalInterface as follows:
#FunctionalInterface
public interface MonoFunction<T> {
T apply (T arg);
}
But, this would require the type to be specified while using the interface. But, I want the type to be inferred. Something like the below pseudo-code:
class A {
int a;
}
class B {
int b;
}
public static void main (String[] args) {
A a;
B b;
MonoFunction foo = (obj) -> {
system.out.println (obj)
return obj;
};
a = foo.apply (new A());
b = foo.apply (new B());
}
How do I achieve something like this?
You could use the UnaryOperator<T> but you have to define beforehand what type you're expecting.
UnaryOperator<A> foo = a -> {
system.out.println(a);
return a;
};
Otherwise, just cast your result into the variable type :
a = (A) foo.apply (new A());
b = (B) foo.apply (new B());
Use a generic factory method returning the function:
static <T> UnaryOperator<T> getFooFunction() {
return obj -> {
System.out.println(obj);
return obj;
};
}
public static void main (String[] args) {
A a;
B b;
UnaryOperator<A> fooA = getFooFunction();
a = fooA.apply(new A());
UnaryOperator<B> fooB = getFooFunction();
b = fooB.apply(new B());
System.out.println(fooA==(Object)fooB);
}
Note that getFooFunction() does not only return the same function semantically, given the current implementation (HotSpot/OpenJDK), it will even be the same object, as you can test easily via fooA==(Object)fooB, so there is no reason to sacrifice the Generic’s type safety.
It’s the same thing that happens when you use UnaryOperator.identity().
The other answers already discuss how to use UnaryOperator<T>. While that approach provides the type safety of Java generics, you still have to specify the type upon creating the UnaryOperator. While I would recommend the UnaryOperator approach in most situations, you specifically asked (in the comments) how one might avoid specifying the type <T>, even if you had to give up type safety.
You can make a MonoFunction implementation as follows (unsafe and usually not recommended):
public class MonoFunction {
private UnaryOperator<Object> func;
#SuppressWarnings("unchecked")
public <T> MonoFunction(UnaryOperator<T> func) {
this.func = (UnaryOperator<Object>) func;
}
#SuppressWarnings("unchecked")
public <T> T apply(T obj) {
return (T) func.apply(obj);
}
}
Note that this is not a #FunctionalInterface, so you'll have to put your lambda expression inside a new MonoFunction(...) call, as follows:
public class MonoFunctionTest {
public static void main(String[] args) {
A a;
B b;
MonoFunction foo = new MonoFunction((obj) -> {
System.out.println(obj);
return obj;
});
a = foo.apply(new A()); // toString in A
b = foo.apply(new B()); // toString in B
MonoFunction bad = new MonoFunction((A obj) -> {
System.out.println(obj);
return obj;
});
a = bad.apply(a); // toString in A
b = bad.apply(b); // ClassCastException: B cannot be cast to A
}
}
class A {
public String toString() { return "toString in A"; }
}
class B {
public String toString() { return "toString in B"; }
}
I stress again that this is unsafe, and it is relatively easy to get a ClassCastException as demonstrated.
This is possible using a generic method within a functional interface:
#FunctionalInterface
interface Identity {
< T > T apply( T input );
}
Unfortunately an interface defined like this cannot be implemented using a lambda function. Instead it must be done the old way using a class, and most concisely with an anonymous class:
Identity id = new Identity() {
public < T > T apply( T anyInput ){
// do something
return anyInput;
}
};
This then works for any input:
class A {
int a = 1;
}
String outputString = id.apply( "one" );
int outputInteger = id.apply( 1 );
A outputClass = id.apply( new A() );

Categories

Resources