passing Object Instances as generics to a method - java

I have a scenario similar to the below example.
I have two different objects and have already created instances from them. I need to pass these instances as generic to a method parameters.
I tried passing the method parameters as Class obj but it didnt work
Class A
{
A()
{
List<String>collection = new ArrayList<>();
}
}
Class B
{
B()
{
List<String>collection = new ArrayList<>();
}
}
Class Main()
{
A a = new A();
B b = new B();
methodTest(a);
methodTest(b);
void methodTest(Class<T> genericObj)
{
genericObj.collection.add("1");
// I need to pass both the instance A and instance B to
genericObj
}
}
Need some suggestions.

You don't pass generics to methods, since generic is a Type, not an object.
What you do is, you pass an object; with generic being declared in your class.
E.g.
public class Test <T extends ClasThatHasCollection> {
void methodTest(T genericObj) {
genericObj.collection.add("1");
}
}
However in your case, generics seem like an overkill!
Just have a parent class P that has .collection instance variable; and have both classes A and B extend P; and pass object type P into methodTest:
public class P {
public Collection collection;
// ....
}
public class A extends P {
}
void methodTest(P genericObj) {
P.collection.add("1");
}

The simplest way would be to create a base class and have A and B inherit from it.
In the method you use the base class as the type.
This is valid since both A and B extend it.
For example:
class Base {
List<String> collection;
Base() {
collection = new ArrayList<>();
}
}
class A extends Base{
A(){
super()
}
}
class B extend Base{
B(){
super()
}
}
void methodTest(Base genericObj)
{
genericObj.collection.add("1");
}
Another possibility is to use an interface. This would be useful if the collections are not the same type and are therefore not defined in the base object.
Using an interface:
interface MyInterface{
public ArrayList<> getCollection();
}
class A implements MyInterface {
List<String> collection;
A(){
collection = new ArrayList<>();
}
public ArrayList<> getCollection(){
return collection;
}
}
class B implements MyInterface{
List<String> collection;
B(){
collection = new ArrayList<>();
}
public ArrayList<> getCollection(){
return collection;
}
}
void methodTest(MyInterface genericObj)
{
genericObj.getCollection().add("1");
}

Related

Java factory inheritance with generic interface implementation

I would like to have a factory that inherits another one with both factories implementing same generic interface with different type that inherits one another:
class FactoryA implements FactoryI<A> {
// common code
...
A get() {
return new A();
}
}
class FactoryB extends FactoryA implements FactoryI<B> {
B get() {
return new B();
}
}
class B extends A {
}
FactoryI<T> {
T get()
}
But this gives me following compilation error:
'FactoryI' cannot be inherited with different type arguments: 'A' and 'B'
My first version did not have FactoryB inheriting from FactoryA and this was working fine.
But it turns out that there is now common code between both factories that I want to reuse.
What is the best way to achieve this?
You need to make FactoryA generic as well. This way a subclass can return a different subclass of A
class FactoryA<T extends A> implements FactoryI<T> {
// common code
public T get() {
return (T) new A();
}
}
class FactoryB extends FactoryA<B> {
public B get() {
return new B();
}
}
class A {
}
class B extends A {
}
interface FactoryI<T> {
T get();
}

How to get T type in parent class after extends?

How to get T type after extends?
The code below.
class A<T>{
void method(){
// how to get T type ?
}
}
class B extends A<String> {
}
class C extends B {
}
class D<T> extends A<List<T>>{
}
class E extends D<String>{
}
class Main{
public static void main(String[] args){
C c = new C();
c.method();// I want to get T type here is String.
E e = new E();
e.method();// I want to get T type here is List<String> but I can only get String.
}
}
If I create a B, I can use getGenericSupperclass to get T, but when I create a C, I can't.
You should either pass an object of the generic type with the constructor of your A or create an abstract method that returns an object.
Then, your method uses the object to get the class.
Passing an object with the constructor:
class A<T>{
private T dummy;
public A(T dummy){
this.dummy = dummy;
}
void method(){
System.out.println("Our type T is a " + dummy.getClass().getName());
}
}
Using an abstract method:
abstract class A<T>{
public abstract T getDummy();
void method(){
System.out.println("Our type T is a " + getDummy().getClass().getName());
}
}
Instead of an instance of T the various solutions could also pass the class of T.
For instance:
abstract class A<T>{
public abstract Class<T> getGenericClass();
void method(){
System.out.println("Our type T is a " + getGenericClass().getName());
}
}
Personally, I prefer this solution.
Of course, al derived classes should be adapted.
For instance:
class B extends A<String> {
#Override
public Class<String> getGenericClass(){
return String.class;
}
}
You can not.
This problem is caused by something called Type Erasure, which means that Java doesn't store any information about class' generics at runtime, and therefore there is no way to acquire them.
One possibility to work-around this is adding a constructor to A which takes a parameter of type Class and passing the class explicitly by the extending class:
class B extends A<String> {
public B() {
super(B.class)
}
}

How to use Constructors/Casting with Generic Types

I have a parent class, Parent, with two child classes, A and B. I have another class, Wrapper<Type1,Type2>, that contains an interface, Function<Type1,Type2>, which is supposed to transform an A into a B or a B into an A.
If I define
new Wrapper<A,B>(new Function<A,B>(){public B transform(A a){return new B(a);}});
outside of the Wrapper class, then this works fine.
I run into the problem that I can't instantiate a generic type when I want to define a default Function for the default constructor public Wrapper() within the Wrapper<Type1,Type2> class itself.
Eclipse recommends casting from Type1 to Type2, but the problem is that A can't cast to B because they are sibling classes. I do have constructors for Parent(Parent), A(B), and B(A), so it would be great if I could implement a generic constructor somehow. How can I work around this?
public class Parent {
protected int value = 0;
public void setValue(int x){ value = x; }
public int getValue(){ return value; }
public Parent(){}
public Parent(A a){setValue(a.getValue());}
public Parent(B b){setValue(b.getValue());}
public Parent(Parent p){setValue(p.getValue());}
}
public class A extends Parent{
public A(){ setValue(1); }
public A(B b){ setValue( b.getValue()); }
}
public class B extends Parent{
public B(){ setValue(2); }
public B(A a){ setValue(a.getValue()); }
}
public interface Function <Type1 extends Parent, Type2 extends Parent> {
public Type2 transform(Type1 t);
}
public class Wrapper<Type1 extends Parent, Type2 extends Parent> {
Function<Type1,Type2> function;
public Wrapper(Function<Type1,Type2> x){ function = x; }
public Wrapper(){
function = new Function<Type1,Type2>(){
public Type2 transform(Type1 t){
///I want to use constructor Type2(t), given that they both extend Parent
//return new Type2( t);
return (Type2) t; ///causes an error because can't cast from A to B
}
};
}
public Type2 transform(Type1 t){
return function.transform(t);
}
}
public class Main {
public static void main(String[] args){
///Start with custom function. This part works.
Wrapper<A,B> wrapper = new Wrapper<A,B>(
new Function<A,B>(){
public B transform(A a){
///Want to use constructor B(a)
///Can't cast A to B
return new B(a);
}
}
);
A a = new A();
B b = wrapper.transform(a);
///This part works
System.out.println(b.getValue());
///Next try the default Function
wrapper = new Wrapper<A,B>();
b = wrapper.transform(a); ///This part causes the error, as wrapper attempts to cast from A to B
System.out.println(b.getValue());
}
}
Edit:
My question is unique in scope and implementation from the suggested duplicate. E.g., the structure of my code is a simple parent with two sibling child classes. The structure in the possible duplicate is more intricate, involving multiple generations and child classes that are disheveled in a confusing way. I'm not sure what that code is attempting to do, and the answer didn't help me understand my own question in the slightest as it seemed particular to the distinct structure of the other question.
There's no way to make a "generic" constructor. The solution closes to your current implementation is to instantiate objects in your function. As this is anyway the responsibility of the caller (in your design), then it's easy:
Wrapper<A, B> wrapper = new Wrapper<A, B>((a) -> new B(a));
But where the default Wrapper() constructor is being called, you can make the caller send Class objects for type1 and type2:
public Wrapper(Class<Type1> type1Class, Class<Type2> type2Class) {
this.function = (object1) -> {
try {
return type2Class.getConstructor(type1Class).newInstance(object1);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
With both of the above, your main method will look like the following:
public static void main(String... args) {
Wrapper<A, B> wrapper = new Wrapper<A, B>((a) -> new B(a));
A a = new A();
B b = wrapper.transform(a);
System.out.println(b.getValue());
wrapper = new Wrapper<A, B>(A.class, B.class);
b = wrapper.transform(a);
System.out.println(b.getValue());
}
And this runs without any type cast errors.
The java1.7 version of the above lambda expressions:
Wrapper<A, B> wrapper = new Wrapper<A, B>(new Function<A, B>() {
#Override
public B transform(A a) {
return new B(a);
}
});
And:
this.function = new Function<Type1, Type2>() {
#Override
public Type2 transform(Type1 object1) {
try {
return type2Class.getConstructor(type1Class).newInstance(object1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
Since it's not possible to create an instance using a generic type parameter we must work around it. I'll restrict the answer to Java 7 as I read from the comments you're working with. Here is my suggestion:
public interface Transform<P extends Parent> {
P with(int value);
}
public static void main(String[] args) {
Transform<B> transformToB = new Transform<B>() {
#Override
public B with(int value) {
return new B(value);
}
};
A a = new A();
B b = transformToB.with(a.getValue());
System.out.println(b.getValue());
}
How it works?
We have an interface Transform<P extends Parent> defining the method with. This method has one parameter. This is the only one field of the classes you defined. Using this value the method has to return an instance of some P which extends Parent. Looking at the implementation of transformToB it creates a B instance by calling the (by me added) constructor B(int value).
Why another constructor?
Declaring constructors like B(A a) or A(B b) results in a circular dependency between these classes. A and B aren't loosely coupled. Declaring a constructor which takes only a value we instantiate the state without having to know where this value comes from.
Also declaring constructors like Parent(A a) and Parent(B b) introduces dependencies to Parent on it's subclasses. Following this approach Parent would need to provide a constructor for each subclass.
Possible extension:
If value is just an example for many other fields, we do not want to define a constructor like A(int value1, int value2, String value3, ...) having many parameters. Instead of we could use the default constructor A() and do the transformation like this:
interface Transform<From extends Parent, To extends Parent> {
To from(From f);
}
public static void main(String[] args) {
Transform<A, B> transformToB = new Transform<A, B>() {
#Override
public B from(A a) {
B b = new B();
b.setValue(a.getValue());
b.setValue2(a.getValue2());
b.setValue3(a.getValue3());
return b;
}
};
A a = new A();
B b = transformToB.from(a);
System.out.println(b.getValue());
}
This last approach is also applicable if A and B have different fields. In case B has a field String value4 we could add an additional line to transformToB like b.setValue4(a.getValue3()+"#"+a.getValue2());.

Return data type the same as class name via superclass?

I have an abstract class which has one abstract method. I want this method to return the same data type as the class which is overriding the method without having to cast the result of create or having to make a new method declaration on each subclass. I want it to all be declared seemlessly from the parent class.
I want the method to return a object whose data type is the same as the class it was called on.
EDIT: I removed print as people are getting confused with what I am asking
abstract class A
{
public abstract ... create();
}
class B extends A
{
#override
public ... create()
{
return new B...;
}
}
class C extends A
{
#override
public ... create()
{
return new C...;
}
}
Such that
B x1 = new B();
B x2 = x1.create();
// Since create was called on a B object
// a B object is returned, NOT AN "A" object
C y1 = new C();
C y2 = y1.create();
// create makes a C object this time,
// because it's called on a C object
// Problem: create() returns A object, even when
// called from class B or C.
// I want create() to return a B object if called from a B object.
What would be a good way of going about this? Thanks.
I no longer think this is the right answer. It's an answer, but is over-complicated. See my other answer.
There is no notion of a "self" type in Java's generics. The best you can do is to use self-bounded generics:
abstract class A<T extends A<T>>
{
public abstract T create();
}
Then, in your subclasses:
class B extends A<B>
{
#override
public B create()
{
return new B...;
}
}
Actually, there is an easier way to do it than with my other answer: just use a covariant return type in the subclass:
abstract class A {
public abstract A create();
}
class B extends A {
#Override public B create() {
return new B...
}
}
This is more pleasant if you are dealing with instances of A, since you don't have to make it generic (or, shudder, raw).
It also gives just as much of a guarantee that it returns a "self" type, i.e. no guarantee at all.
this.getClass() to get the class object, or, this.getClass().getSimpleName() to get a string of class name.
I have to question the design approach.
I'd be going for
abstract class A {
abstract Supplier<? extends A> create();
}
with
class B extends A {
public Supplier<B> create() {
return B::new;
}
}
(and C accordingly).
Then, there is
A b = new B();
A anotherB = b.create().get(); // will create a B
A c = new C();
A anotherC = c.create().get(); // will create a C
You don't need to make your create method abstract. If all the subclasses have a no-argument constructor, then you can just write this (in class A)
public A create() {
try {
return getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}
This checks the class of the object that you called the method on; and creates a new object of the same class, using its no-argument constructor.
Update
OP's comment suggests that they don't want to have to cast the returned value. If this is a requirement, then the casting can be avoided by changing the method signature as follows.
public <T extends A> T create() {
try {
return getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}

Giving List the same type as the class which contains it

Let's assume I have a class A that can be extended. Within that Class A I have a List List<A>. So this class will contain a list with elements A. Now If I subclass this class B extends A, I want class B to have the same member List<B>, ie the same list but this type containing items of type B. Is this possible using generics ? I can see something like A <T extends A>, while declaring List<T>, but I don't like as the information about the class type are already there. Is there another better solution ? Example below:
public class A {
List<A> list = new ArrayList<A>();
}
public class B extends A {
}
I want list to have the generic type of B in class B.
If you want to put the behaviour in the super class, then you're going to have to tell the super class what type of class the subclass is. This can be done by adding a generic type to the super.
public class A<E> {
protected List<E> items;
public A() {
this.items = new ArrayList<E>();
}
}
public class B extends A<B> {
public static void main(String[] args) {
B b = new B();
b.items.add(b);
}
}
You can use extends keyword in generic.
For example:
public class A {
protected List<? extends A> list;
public A() {
list = new ArrayList<A>();
}
public <T extends A> List<T> getList() {
return (List<T>) list;
}
public void setList(List<A> list) {
this.list = list;
}
}
public class B extends A {
public B() {
list = new ArrayList<B>();
}
public static void main(String[] args) {
A a = new A();
a.getList().add(new A());
B b = new B();
b.getList().add(new B());
}
}

Categories