0

Here's the indicted code :

import java.util.Iterator;

public class MyClass<T> implements Iterable<T> {

    private int n;
    private Object array[];

    public myClass( int size ){
        array = new Object[size];
        n=0;

    }

    @Override
    public Iterator<T> iterator(){
        return new MyClassIterator<T>(n,array); //Here's my error!
    }



    }
    class MyClassIterator<T> implements Iterator<T>{

    private int n;
    private T[] array;

    MyClassIterator( int n, T[] array ){

        this.n = n;
        this.array = array;

    }

    @Override 
    public T next(){
        return array[n++];
    }

    @Override
    public boolean hasNext(){

        return n==array.length;
    }

}

This code give me the error :

error: incompatible types: Object[] cannot be converted to T[] return new myClassIterator(n,array); where T is a type-variable: T extends Object declared in class myClass Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output 1 error

But after removing the <T> in the creation of the myClassIterator object in iterator() the error disappears and the code works without problems, now I'm asking why specify the generic type give me this error?

The "correct" code that works would be this :

@Override
public Iterator<T> iterator(){

    return new myClassIterator(n,array);     

}
OhleC
  • 2,821
  • 16
  • 29
  • Well, it depends on how `MyIterator` is defined. – Louis Wasserman Oct 24 '18 at 19:03
  • 1
    You seem to made a typo, `` should be after `myCollection ` instead of after `class` – Ferrybig Oct 24 '18 at 19:04
  • *Sorry for the typo, edited. ** I also written a general implementation of myIterator, the problem is that I can't understand why in this case I should not define the generic type when i create the Iterator object. – Rodion Raskol'nikov Oct 24 '18 at 19:07
  • Where exactly do you have an error? – tsolakp Oct 24 '18 at 19:13
  • I have an error when I use the second version of this chunk of code, when in iterator() there's "return new myIterator( . . . ); ". Instead, with "return new myIterator( . . . ); " there aren't error and the code works, but I'm still wondering why, thanks you for the concern. – Rodion Raskol'nikov Oct 24 '18 at 19:13
  • Please include in your question what and where the error is. – rgettman Oct 24 '18 at 19:16
  • If you are getting an error you need to tell us what it is. – takendarkk Oct 24 '18 at 19:17
  • Please provide a [mcve]. – shmosel Oct 24 '18 at 19:20
  • @RodionRaskolnikov You should follow the Java Naming Conventions: class names are always in PascalCase, variables and methods always in camelCase. Constants (variables marked `static final`) are always UPPER_SNAKE_CASE. – MC Emperor Oct 24 '18 at 19:21
  • What is your compiler error? I don't have any issues doing `return new myIterator();` or even `return new myIterator<>();` in your posted code. – Roddy of the Frozen Peas Oct 24 '18 at 19:25
  • I edited the whole question inserting the code that gives me problem and the error generated. – Rodion Raskol'nikov Oct 24 '18 at 19:32
  • Your structure is all wrong. The outer class doesn't need `n`, and the inner class doesn't need `array` or `T`. – shmosel Oct 24 '18 at 19:37
  • I know that n is not needed, is just a piece of code that I invented atm to clarify the situation, the point is about that in the iterator body when i create the MyClassIterator, why specifying the parameter I get an error? I really appreciate you for the tips but this is a meaningless piece of code except for the iterator()'s part. Thank you a lot again for the interest! – Rodion Raskol'nikov Oct 24 '18 at 19:42

2 Answers2

1

You said:
But after removing the `in the creation of the myClassIterator object in iterator() the error disappears and the code works without problems

By removing the type parameter <T> you're using the raw type of MyClassIterator. The error disappears because

For backward compatibility, assigning a parameterized type to its raw type is allowed.

Using raw types, you essentially get pre-generics behavior

In such a case iterator() would return an MyClassIterator which returns elements of type Object.

This works because

if you assign a raw type to a parameterized type, you get a warning:

Thus you get a warning but not a compile-time error.

But why specify the generic type give me this error?

public Iterator<T> iterator() {
  return new MyClassIterator<T>(n, array); // Here's my error!
}

Here you're trying to pass in an array with component type Object to the constructor MyClassIterator(int n, T[] array). This constructor accepts an array of type T. Are the Objects instances of type T? This could be but doesn't have to. But to call this constructor it has to be.

How to fill this gap?
The field array needs to be declared with the component type T.

private T[] array;

But then array = new Object[size]; will not work because

You cannot create arrays of parameterized types.

How to solve this?
Either by passing the Class<T> into the constructor like @ohlec suggests.

Another option is to follow the example of Stream.toArray(IntFunction<T[]> generator):

public MyClass(int size, IntFunction<T[]> generator) {
  array = generator.apply(size);
  n = 0;
}

To create a MyClass<String> instance with n = 5 we call the constructor like that:

MyClass<String> strings = new MyClass<>(5, String[]::new);

In this case we're passing implicit the type argument String into the constructor.

LuCio
  • 5,055
  • 2
  • 18
  • 34
0

The constructor of MyClassIterator<T> is declared as taking an array of T, but you're passing an array of Object. Since you've parameterized your outer class with T as well, it really looks like you want the array field to be an array of Ts

private T array[]

However, you then can only initialize the array if you pass the class to the constructor like so:

public myClass( int size, Class<T> clazz ){
    array = (T[]) Array.newInstance(clazz, size);
}
OhleC
  • 2,821
  • 16
  • 29
  • Ok, thanks for the answer but I have another question : why if I remove the in the creation of the Iterator object it works? The constructor of MyClassIterator still wants a T[] array and I'm passing an Object array. Thanks you! – Rodion Raskol'nikov Oct 24 '18 at 19:47
  • Because then you explicitly ask for the raw (unparameterized) type. The `T` in the `MyClassIterator` instance then has no value. – OhleC Oct 24 '18 at 20:35
  • I think I undestood, infact when I pass an Object array in the constructor when it should be of T type the compiler says that there are equality constraint that I'm not respecting, the MyClass have a version of T while MyClassIterator automatically values T ( that should be the same ) as an Object. It's everything right? Sorry for my bad english and thank you again. – Rodion Raskol'nikov Oct 24 '18 at 20:42
  • Maybe the confusion is that `T` in `MyClass` and `T` in `MyClassIterator` are different - they're two distinct type parameters of two different classes that happen to have the same name. The value that `T` in `MyClass` has is only determined when you instantiate a `MyClass` (from outside presumably). The value of `T` in the iterator is determined by what you put in the constructor call. If you call the constructor with `T`, then you say that both classes should be parameterized with the same type. If you don't put anything, you say the type of the iterator should be left raw. – OhleC Oct 24 '18 at 20:50
  • 1
    "However, you then can only initialize the array if you pass the class to the constructor like so:" but since the object pointed to by `array` is never exposed to the outside of the class (never exposed outside the scope of `T`), nothing bad will happen if they just create an `Object[]` (the erasure of the type of `array`) and cast it to `T[]`: `array = (T[]) new Object[size];`. That way, they don't need to pass a class in. – newacct Oct 25 '18 at 01:18