Java template class that takes an array; any way to enforce that?
I'm writing a template class which should take an array as its type.
public cl开发者_开发百科ass Foo<T> {...}
How best can I enforce that "T" is an array type? (int[], Bar[], ...) Preferably compile time if possible, obviously, but otherwise what is the best way at debug run time to throw an exception or something if T is not an array?
I am going to agree and extend David Blevin's answer. You can put MyClass inside a factory class and make the constructors of MyClass private. This way only code within the factory class can directly instantiate a MyClass. It is up to you to make sure they do the right thing. You can either make the factory clas parameterized (as below) or make the make method itself parameterized.
// T is the component type of the array
public class MyClassFactory < T >
{
// we can't directly enforce TARRAY=T[], but TARRAY=T[]
public final class MyClass < TARRAY >
{
private MyClass ( ... arguments ) throws ... exceptions { ... code }
// no non private constructors
.... more code
}
// this is the only way to construct a MyClass
// so we indirectly enforced TARRAY=T[]
public MyClass<T[]> make ( ... arguments ) throws ... exceptions
{
return new MyClass <T[]>( ... arguments ) ;
}
}
It is not possible to do it exactly how you have asked and have the generic type specify an array or primitive.
The syntax allows for things like:
public class Foo <az09$_ extends MyClassOrInterface & Serializable & Closeable> {...}
Where az09$_ is any valid identifier that may also be parameterized with an identically formatted generic type.
But az09$_ is restricted to being a java identifier, so you cannot do public class Foo<T[]> {...}
any more than you can do public class Foo[] {...}
.
Typically you would do what you are after in your usage of T, i.e:
public class Foo<T> {
public T[] processIt(T... ts) {
// do something
return ts;
}
}
If you actually want to check if the type is an array, it can be done at runtime with the following code, though this is a bit of a hack and not exactly efficient:
public static boolean isArrayType (Object o) {
return o.getClass().isArray();
}
Ultimately it depends on exactly what you're trying to do.
@emory is on the right track for a clean way to do this without runtime checks. Personally I'd be concerned with readability of the type name - here's a very compact example using inner classes and I think the resulting type name at the end is very readable.
public static class Bar {}
public static class Foo<T> {
public static class Array<TA> {
private Array() {}
}
public Array<T[]> make() {
return new Array();
}
}
Foo.Array<Bar[]> fooray = new Foo<Bar>().make();
精彩评论