Argonath
Argonath

Reputation: 63

Initializing generics in Java

Suppose I have a class called NodeList with two fields, called value (type Object) and index (type int). NodeList implements an interface called Copiable, with a single method called copyNotSyncronized().

I want the NodeList version of copyNotSincronyzed() to recognize if this.value implements Copiable and, if that happens:

  1. Use copyNotSincronyzed() on this.value and...
  2. ...build a new NodeList object that have this.value.copyNotSincronyzed() as field value.

I tried to write the code and drown in red underlining. After that I know two things: my Eclipse really hate me and I still have to undestand how to use generics in Java.

What mistakes did I do?

public class NodeList implements Copiable {

    int index;
    Object value;

public NodeList(Object value, int index){
[...]
}

NodeList copyNotSincronyzed(){
  NodeList copied;
  if(  onArray.findPositionsOfElement(this.value.getClass().getInterfaces() , this.getClass().getInterfaces()[0])[0] !=-1   )
     // aka if this.value implements the same interface of this class (aka Copiable)
     {
// Following line features three errors: 
   // Incorrect number of arguments for type Class<T>; it cannot be parameterized with arguments <T, Copiable>
   // T cannot be resolved to a type
   // Syntax error on token "implements", , expected
     Class<T implements Copiable> copiedObject = this.value;


     copiedObject=copiedObject.copyNotSincronyzed();
     copied = new NodeList( copiedObject , this.index );
     }
   else copied = new NodeList(this.value, this.index);

   }  

}

Upvotes: 0

Views: 133

Answers (3)

Mark Jeronimus
Mark Jeronimus

Reputation: 9543

Java has an interface Clonable that lets you clone unlinked (unsynchronized) objects through a method Object clone(). There is a lot of controversy around this and the bottomline is that it's discouraged.

A widely accepted way of creating copies of objects is by using a copy-constructor. This will not work for general Object since you don't know the run-time class in advance. In this case Clonable-like structure may still prove useful.

Because Clonable is legacy, it doesn't have generics. Let's make Copyable as a replacement for Clonable (and rename clone() as copyNotSyncronyzed())

public interface Copyable<T> {
    T copyNotSyncronyzed();
}

public class NodeList implements Copyable<NodeList> {
    private int     index; // make final too unless you plan to change it at some point
    private Object  value; // make final too unless you plan to change it at some point

    public NodeList(final Object value, final int index) {
        this.value = value;
        this.index = index;
    }

    @Override
    public NodeList copyNotSyncronyzed() {
        if (value instanceof Copyable) {
            Object copiedObject = ((Copyable<?>)this.value).copyNotSyncronyzed();

            return new NodeList(copiedObject, this.index);
        } else
            return new NodeList(this.value, this.index);
    }
}

The last question is if you are really happy with this structure, as it copies linked value instances if they are not Copyable. This can potentially create dangerous situations since code calling copyNotSyncronyzed() may expect it to be comppletely unrelated to the original.

For example, if value is an int[]. You create a copy using copyNotSyncronyzed(), then you change some values in the array, and lo and behold, the values in the array of the original object are changed too.

Upvotes: 0

RealSkeptic
RealSkeptic

Reputation: 34628

An interface is a type, like a class. Therefore, when another class implements it, any object of that class can be used polymorphically as that interface.

Which means that you can check if that object implements that interface simply by using x instanceof Y. It's an operator that tells you whether x "is a" Y, and Y can be either a class or an interface.

Once you established that your object implements the type, you can cast it into the type of the interface using parentheses.

For the code itself I refer you to the answer given by Vitaliy.

Upvotes: 0

Vitaliy
Vitaliy

Reputation: 8206

this.value is of type Object. And you are trying to put it into a type Class<T implements Copiable>. The compiler does not know how to do that so you are getting a compilation error.

In order to make this check you should use the instanceof operator, combine with a cast, like this:

if (this.value instanceof Copiable){ // check that the instance implements an interface
    Copiable asCopiable = (Copiable)this.value; // safely cast to the appropriate type
}

Note that your problem does not have anything to do with generics.

Upvotes: 2

Related Questions