How to add a generic object to list in java?
Currently, I have two classes doing the same function and would like to integrate them together
public class MyClass1 {
private List<Object1> myList = new ArrayList<>();
public void addList(Object1 o) {
myList.add(o);
}
}
public class MyClass2 {
private List<Object2> myList = new ArrayList<>();
public void addList(Object2 o) {
myList.add(o);
}
}
something like
public class MyClass {
private List<Object> myList = new ArrayList<>();
public void addList(Object o) {
myList.add(o);
}
}
You could make your own class generic:
public class MyClass<T> {
private List<T> myList = new ArrayList<>();
public void addList(T o) {
myList.add(o);
}
}
You can make both classes Object1 and Object2 implement the same interface 'ObjInterface'
public class MyClass {
private List<ObjInterface> myList = new ArrayList<>();
public void addList(ObjInterface o) {
myList.add(o);
}
}
If you want the class to contain only Object1 or only Object2 and never anything else, you can combine the other two answers:
interface ObjInterface {
// may be empty
}
public class MyClass<T extends ObjInterface> {
private List<T> myList = new ArrayList<>();
public void addList(T o) {
myList.add(o);
}
}
MyClass<Object1> object1only = new MyClass<>();
MyClass<Object2> object2only = new MyClass<>();
and add implements ObjInterface to the definitions of Object1 and Object2.
If you add methods common to both classes to ObjInterface, you can call those methods on the T objects in MyClass, since they're guaranteed to be a subclass of ObjInterface.
Related
I want to implement a generic functionality which would enable that our domain classes are being proxied for the case that its values to be xml compliant (escaping special characters in strings). The domain classes/objects are being generated, so that they can not be changed by me. What I tried to do was following code for the generation of proxies:
public class StringValuesFormatterForXml implements InvocationHandler {
public static interface IA {
String getMa1();
List<? extends IB> getBs();
}
public static class A implements IA {
#Override
public String getMa1() {
return "Ma1";
}
#Override
public List<? extends IB> getBs() {
return Arrays.asList(new B(), new B());
}
}
public static interface IB {
String getMb1();
String getMb2();
}
public static class B implements IB {
#Override
public String getMb1() {
return "Mb1";
}
#Override
public String getMb2() {
return "Mb2";
}
}
Object destObj;
private final Map<String, Method> methods = new HashMap<>();
#SuppressWarnings("unchecked")
public static IA createProxyA(IA destObj) {
return (IA) Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] {
IA.class
}, new StringValuesFormatterForXml(destObj));
}
#SuppressWarnings("unchecked")
public static Object createProxy(Object destObj, Class<?> clazz) {
return Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] {
clazz
}, new StringValuesFormatterForXml(destObj));
}
public StringValuesFormatterForXml(Object destObj) {
this.destObj = destObj;
for (Method method : destObj.getClass().getMethods()) {
this.methods.put(method.getName(), method);
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getReturnType().isAssignableFrom(List.class)) {
List<Object> elems = (List<Object>) method.invoke(destObj, args);
List<Object> proxyElems = new ArrayList<Object>();
for (Object obj : elems) {
Object proxyObj = createProxy(obj, obj.getClass());
proxyElems.add(proxyObj);
}
return proxyElems;
}
return method.invoke(destObj, args); // Here I will format the output for xml
}
public static void main(String[] args) {
A orig = new A();
IA proxy1 = createProxyA(orig);
A proxy2 = (A) createProxy(orig, orig.getClass());
}
}
Code in createProxy(orig, orig.getClass()) throws following error java.lang.IllegalArgumentException: StringValuesFormatterForXml$A is not an interface but the code createProxyA(orig) does not. So it seems that I would need to have a separate creator method for every interface which I use. In our domain model there are many classes and I do not want to create for every class separate creator.
Are there any other ways/frameworks which are better suited for my case of proxying objects.
Your createProxy method does work, you just have to pass the class of the interface as second parameter:
A orig = new A();
IA proxy1 = (IA) createProxy(orig, IA.class);
In addition I would recomment you to use the createProxy function as a generic function in order to avoid the obkect cast:
#SuppressWarnings("unchecked")
public static <T> T createProxyB(T destObj, Class<T> clazz) {
return (T) Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] { clazz },
new StringValuesFormatterForXml(destObj));
}
In this case you can call the function like this:
A orig = new A();
IA proxy1 = createProxyB(orig, IA.class);
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");
}
I want to pass the getter of a bean as a function. When the function is called the getter should be invoked. Example:
public class MyConverter {
public MyConverter(Function f) {
this.f = f;
}
public void process(DTO dto) {
// I just want to call the function with the dto, and the DTO::getList should be called
List<?> list = f.call(dto);
}
}
public class DTO {
private List<String> list;
public List<String> getList() { return list; }
}
Is that possible with java 8?
If the constructor of MyConverter must take a function, and process must take an object, this is probably the best way:
class MyConverter<T> {
// V takes a thing (in our case a DTO)
// V returns a list of Strings
private Function<T, List<String>> f;
public MyConverter(Function<T, List<String>> f) {
this.f = f;
}
public void process(T processable) {
List<String> list = f.apply(processable);
}
}
MyConverter<DTO> converter = new MyConverter<>(DTO::getList);
DTO dto = new DTO();
converter.process(dto);
I'm trying to define an abstract class that takes in a List of things and does stuff. Something like:
abstract public class AbstractClass {
private final List<?> list;
public AbstractClass(List<?> list) {
this.list = list;
}
public List<?> getList() { return list; }
abstract void addToList(List<?> list);
}
public class Class1 extends AbstractClass {
public Class1(List<Integer> list) {
super(list);
}
#Override
void addToList(List<Integer> list) {
// do stuff
}
}
public class Class2 extends AbstractClass {
public Class2(List<String> list) {
super(list);
}
#Override
void addToList(List<String> list) {
// do stuff
}
}
List<Integer> a = new List<Integer>();
Class1 c1 = new Class1(a);
List<Integer> b = c1.getList();
c1.addToList(a);
List<String> c = new List<String>();
Class2 c2 = new Class2(c);
List<Integer> d = c2.getList();
c2.addToList(c);
Having addToList with specific types in the subclasses is generating errors, but I don't know if that's a matter of syntax (with my poor knowledge of generics) or what I'm trying to do itself (is it possible to overload an abstract method like that)?
You should make AbstractClass a typed class instead of using the ? wildcard.
abstract public class AbstractClass<T> {
private final List<T> list;
public AbstractClass(List<T> list) {
this.list = list;
}
public List<T> getList() { return list; }
abstract void addToList(List<T> list);
}
In this case, you would have
public class Class1 extends AbstractClass<Integer> { ... }
public class Class2 extends AbstractClass<String> { ... }
I have these classes:
class Parent {
public Parent() {
}
}
class ChildA extends Parent {
public ChildA() {
super();
}
}
class ChildB extends Parent {
public ChildB() {
super();
}
}
public ListClas(List(Parent) list) {
this.list=list;
}
}
And I want to run ListClas constructor as below.
List<ChildA> list_childA = new ArrayList<ChildA>();
List<ChildB> list_childB = new ArrayList<ChildB>();
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
But the compiler throws an error. How do I do this correctly using polymorphism?
If you want a function that accepts List containing subclasses of a superclass you should use syntax.
public ListClas(List<? extends Parent> list){
this.list=list;
}
It will accept both of them.
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);
If you change to List<? extends Parent> list (also change ListClas.list field definition) in your ListClas then it will compile and work.
All of them: List<Parent>, List<ChildA> and List<ChildB> are different concrete parameterized type.
You can read more about this here: https://stackoverflow.com/a/20940807/516167
I think you want your ListClas to look something like this:
class ListClas<T>
{
private List<T> list;
public ListClas(List<T> list)
{
this.list = list;
}
}
Then to create them:
ListClas<ChildA> listClasA = new ListClas<ChildA>(list_childA);
ListClas<ChildB> listClasB = new ListClas<ChildB>(list_childB);
The T is a generic type designation. It allows you to use the same class for multiple runtime types. So you can do the above instead of having to write this:
class AListClas
{
private List<ChildA> list;
public AListClas(List<ChildA> list)
{
this.list = list;
}
}
class BListClas
{
private List<ChildB> list;
public BListClas(List<ChildB> list)
{
this.list = list;
}
}
If you don't need quite as much flexibility you could write your ListClas like this:
class ListClas
{
private List<? extends Parent> list;
public ListClas(List<? extends Parent> list)
{
this.list = list;
}
}
and use it like this:
ListClas listClasA = new ListClas(list_childA);
ListClas listClasB = new ListClas(list_childB);