tyuijhgs
tyuijhgs

Reputation: 3

Java Generic Class which Implements a Generic Interface

Initially I wanted to create a generic way of deep copying objects which implement a 'X' interface. However, I did not want to write a copy list function for every class which implemented 'X'. Instead I created a generic Class which bounds it's generic with interface 'X'.

The problem lies that if class 'A' implements 'X' and contains sub-classes which (do)/(do not) implement 'X'. How do you stop sub-classes from inheriting from the 'A' implementation of 'X' and force their own implementation, without having to implement 'X for every sub-class.

I am pretty sure that this is impossible to do in java, due to inheritance, and generics.

Here is the implementation thus far, but I need a type cast which brings unsafe operations for sub-classes not inheriting interface 'X'.

import java.util.*;


public class HelloWorld {

    public static void main(String[] args) {
    // Prints "Hello, World" to the terminal window.
    System.out.println("Hello, World");

    List<Foo> l = new ArrayList<Foo>();
    List<Bar> b = new ArrayList<Bar>();
    List<Nar> n = new ArrayList<Nar>();

    GenericCopyClass<Foo> g = new GenericCopyClass<Foo>();
    GenericCopyClass<Bar> gb = new GenericCopyClass<Bar>();
    GenericCopyClass<Nar> gn = new GenericCopyClass<Nar>();


    l.add(new Foo());
    l.add(new Foo());
    l.add(new Foo());


    b.add(new Bar());
    b.add(new Bar());
    b.add(new Bar());

    n.add(new Nar());
    n.add(new Nar());
    n.add(new Nar());


    //prints FOO
    List<Foo> foo = g.copyList(l);

    //prints BAR
    List<Bar> bar = gb.copyList(b);

    //prints FOO
    List<Nar> nar = gn.copyList(n);

    /* Is there a clean way to prevent a typecast of Foo to Nar using generics*/

    }

}

class Foo implements WantToClone{
    public Foo(){}
    private Foo(int i){
    System.out.println("Foo");
    }
    public Foo instance(){
    return new Foo(1);
    }
}

class Bar extends Foo{
    public Bar(){} 

    private Bar(int i){
    System.out.println("Bar");
    }
    public Bar instance(){
    return new Bar(1);
    }
}

class Nar extends Foo{
    public Nar(){} 

}

interface WantToClone<E extends WantToClone<E>>{
    public E instance();
}


class GenericCopyClass<S extends WantToClone>{

    public GenericCopyClass(){}

    public List<S> copyList(List<S> original){
        List<S> temp = new ArrayList<S>();

        for(S item : original){
            temp.add((S)item.instance());   
        }
        return original;
    }

}

The output is as follows:

Hello, World
Foo
Foo
Foo
Bar
Bar
Bar
Foo
Foo
Foo

*edit 1

Problems:

implicit type cast:

temp.add((S)item.instance());

interface does not explicitly specify the class instance:

interface WantToClone<E extends WantToClone<E>>

Upvotes: 0

Views: 2874

Answers (1)

tsolakp
tsolakp

Reputation: 5948

I would go with parametrized abstract class that will contain all common method and let sub classes implement only instance method:

    public abstract class AbstractFoo< F extends AbstractFoo<F> > 
    implements WantToClone<F>{

        public AbstractFoo(){}

        //add common methods here
    }

    public class Foo extends AbstractFoo<Foo>{
        public Foo(){}

        private Foo(int i){
            System.out.println("Foo");
        }

        public Foo instance(){
            return new Foo(1);
        }
    }

    public class Bar extends AbstractFoo<Bar>{
        public Bar(){} 

        private Bar(int i){
            System.out.println("Bar");
        }

        public Bar instance(){
            return new Bar(1);
        }
    }

    public class Nar extends AbstractFoo<Nar>{
        public Nar(){}

        @Override
        public Nar instance() {
            return new Nar();
        } 

    }

    public interface WantToClone< E extends WantToClone<E> >{
        public E instance();
    }


    public class GenericCopyClass< S extends WantToClone<S> >{

        public GenericCopyClass(){}

        public List<S> copyList(List<S> original){
            List<S> temp = new ArrayList<S>();

            for(S item : original){
                temp.add( item.instance() );   
            }
            return original;
        }    
    }

Upvotes: 1

Related Questions