explain my problem:
I have a super abstract class called First and then I have a lot of class that inherit from it.
I want to build a method that I "say" to it "create a ArrayList of one of the types that inherit from First class", but I'm not to able to find solution.
For example:
public abstract class First{
public First(){
}
}
public class FirstOne extends First{
...........
}
//It's a pseudo-code
public class MyProgramClass{
public creatingMethod(TypeThatInheritFromFirstClass x ){
return ArrayList<TypeThatInheritFromFirstClass>;
}
}
I insert creatingMethod in program class,but it can be anywhere(I prefer in First class like static method, but it's an example)
Thank for your time
You could use a type token:
public class SomeGenerics {
public static void main(String[] args) {
List<SubFirst1> list1 = creatingMethod(SubFirst1.class);
List<SubFirst2> list2 = creatingMethod(SubFirst2.class);
}
public static <T extends First> List<T> creatingMethod(Class<T> type) {
return new ArrayList<>();
}
}
class First {}
class SubFirst1 extends First {}
class SubFirst2 extends First {}
EDIT as per the comment:
As you already have the type token, you can use it for creating instances of that type. A little restriction is, that you must know what constructor to use. If they - for example - all have a parameterless constructor, you can create instances like that:
public static <T extends First> List<T> creatingMethod(Class<T> type) throws ReflectiveOperationException {
List<T> result = new ArrayList<>();
result.add(type.newInstance());
return result;
}
If you have a constructor with parameters (again: all sub classes must have the same parameterized constructor), you must go a more difficult way. Example with a string parameter:
public static <T extends First> List<T> creatingMethod(Class<T> type, String param) throws ReflectiveOperationException {
List<T> result = new ArrayList<>();
Constructor<T> constructor = type.getDeclaredConstructor(String.class);
result.add(constructor.newInstance(param));
return result;
}
Related
I'm new to Java and I'm trying to learn about generics. I tried to implement a simple version of binarySearch() method that is also found in the Collections class. I looked up the method signature and it's something like this:
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
// definition
}
I was wondering if the method above still accepts the same data types if you were to change the method definition to this:
public static <T extends Comparable<? super T>> int binarySearch(List<T> list, T key) {
// definition
}
If not, what are the differences between the two? Thank you!
Consider these classes:
class A extends Comparable<A> { /* ... */ }
class B extends A { /* ... */ }
Now define a key and a list with these types:
A key = new B();
List<B> list = List.of(key);
You can invoke the first form with these arguments, but not the second.
For example:
static class NonComparable {
}
static class MyComparable implements Comparable<NonComparable> {
#Override
public int compareTo(NonComparable o) {
return 0; // irrelevant for the example
}
}
And then declare the parameters:
List<MyComparable> list = Arrays.asList(new MyComparable());
NonComparable nonComparable = new NonComparable();
binarySearch(list, nonComparable);
One of your method definitions allows an invocation, the other does not.
Is it possible to reflectively instantiate a generic type in Java? Using the technique described here I get an error because class tokens cannot be generic. Take the example below. I want to instantiate some subclass of Creator that implements Creator. The actual class name is passed in as a command line argument. The idea is to be able to specify an implementation of Creator at runtime. Is there another way to accomplish what I'm trying to do here?
public interface Creator<T> {
T create();
}
public class StringCreator implements Creator<String> {
public String create() { return new String(); }
}
public class FancyStringCreator implements Creator<String> {
public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
/*ERROR*/Class<? extends Creator<String>> creatorClass = someClass.asSubclass(Creator.class);
Constructor<? extends Creator<String>> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}
Edit: I like Marcus' approach as being the most simple and pragmatic without circumventing the whole generics thing. I can use it in my situation because I can specify that the class passed must be a subclass of StringCreator. But as Ericson pointed out the generic information is still there at the type level, just not at the runtime level so it is still possible to reflectively examine whether a given class implements the correct generic type.
The generic information is lost in runtime. There is no runtime equivalent of a Creator<String>.class. You could create a type between Creator and StringCreator which fixes the generic type:
public interface Creator<T> {
T create();
}
public interface StringCreator extends Creator<String> { }
public class StringCreatorImpl implements StringCreator {
public String create() { return new String(); }
}
public class FancyStringCreator implements StringCreator {
public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Class<? extends StringCreator> creatorClass = someClass.asSubclass(StringCreator.class);
Constructor<? extends StringCreator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}
But of course you lose a bit of flexibility, because you cannot use the following creator class:
public class AnotherCreator implements Creator<String> {
public String create() { return ""; }
}
This will do what you are trying to do while providing type safety. There's no way to avoid an unchecked warning, but the type checking done here justifies its suppression.
public static void main(String[] args)
throws Exception
{
Class<? extends Creator<String>> clz = load(argv[0], String.class);
Constructor<? extends Creator<String>> ctor = clz.getConstructor();
Creator<String> creator = ctor.newInstance();
System.out.println(creator.create());
}
public static <T> Class<? extends Creator<T>> load(String fqcn, Class<T> type)
throws ClassNotFoundException
{
Class<?> any = Class.forName(fqcn);
for (Class<?> clz = any; clz != null; clz = clz.getSuperclass()) {
for (Object ifc : clz.getGenericInterfaces()) {
if (ifc instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) ifc;
if (Creator.class.equals(pType.getRawType())) {
if (!pType.getActualTypeArguments()[0].equals(type))
throw new ClassCastException("Class implements " + pType);
/* We've done the necessary checks to show that this is safe. */
#SuppressWarnings("unchecked")
Class<? extends Creator<T>> creator = (Class<? extends Creator<T>>) any;
return creator;
}
}
}
}
throw new ClassCastException(fqcn + " does not implement Creator<String>");
}
The main restriction you have to adhere to is that a class in the hierarchy must specify the type parameter. For example class MyCreator implements Creator<String>. You can't use it with class GenericCreator<T> implements Creator<T>.
It doesn't currently handle the valid case where you create a new interface interface StringCreatorIfc extends Creator<String>, and have a class implement that. It could be enhanced to do that, but I'll leave that as an exercise for those inclined.
You don't need that line. Nor do you need the constructor as you're just using the default one. Just instantiate the class directly:
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Creator<String> creator = (Creator<String>) someClass.newInstance();
}
If you insist, you'll only be able to get halfway there:
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Class<? extends Creator> creatorClass = someClass.asSubclass(Creator.class);
Constructor<? extends Creator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
Creator<String> creator = (Creator<String>) creatorCtor.newInstance((Object[]) null);
}
Not quite sure why you're using generics here.
The instantiation of the object using reflection would suggest a general use but presumably you're going to call create at some point and assign the result to a String, otherwise why use the generics to control the return type.
But if you wrote the following implementation of Creator:
public class IntegerCreator implements Creator<Integer>
{
public Integer create()
{
...
}
}
And passed it in as a argument you'd get a ClassCastException when calling create and assigning the result.
I have searched other questions/answers, an I'm still confused about this JAVA ISSUE.
If I want to subclass a type that takes generic parameters, how would I do so while using generic parameters for the subclass too without it getting shadowed?
For example:
public class A <T> extends ArrayList<T> {}
So if i instantiate my custom class, with say, Integers as the parameter, does it take that value as parameter for <T> for the ArrayList part of it too? If not, then how would I specify the type for the ArrayList?
And I know sub classing containers may not be the best idea in many situations, but in this case I have decided it would be appropriate.
yes that would be how one goes about it.
public static void main(String[] args) {
B<Integer> b = new B<Integer>();
b.a = 1;
b.b = "one";
b.add(1);
b.add(2);
}
public static class A<T> extends ArrayList<T> {
public T a;
}
public static class B<T> extends A<T> {
public T b;
}
if you like you could even have them have different types, as long as you supply the super-class with it's type as well:
public static void main(String[] args) {
B<Integer, String> b = new B<Integer, String>();
b.a = 1;
b.b = "one";
b.add(1);
b.add(2);
}
public static class A<T> extends ArrayList<T> {
public T a;
}
public static class B<U, T> extends A<U> {
public T b;
}
I'm currently facing an issue with base and subclasses.
While having a single object as parameter (method single) the compiler doesn't complain.
But if it comes to lists the compiler forces me to declare the list as <? extends Base>
After that I'm no longer allowed to add objects of the base type to that list.
How can I use both types (Base and Subclass) in one list?
public class Generics {
class Base { }
class Sub extends Base{ }
interface I {
public void list( List<Sub> list );
public void single( Sub p);
}
class C implements I {
public void list( List<Sub> list) { }
public void single( Sub p) { }
}
void test() {
C c = new C();
c.single( new Sub() );
c.list( new ArrayList<Base>() ); // The method list(List<Generics.Sub>) in the type Generics.C is not applicable for the arguments (ArrayList<Generics.Base>)
}
public static void main( String[] args) {
Generics g = new Generics();
g.test();
}
}
Change:
public void list(List<Sub> list);
to:
public void list(List<? extends Base> list);
Using just List<Base> will give you compiler errors like this one:
public static void main(String[] args) {
List<Sub> subs = new ArrayList<Sub>();
doSomethingWith(subs); // The method doSomethingWith(List<Base>) in the type Main is not applicable for the arguments (List<Sub>)
}
private static void doSomethingWith(List<Base> bases) {
// Do something with bases
}
If all you're going to pass is List<Base> to doSomethingWith, then this point is moot, since this won't give you a compiler error. If you want to pass lists that are of a specific type (such as List<Sub> above), then you need to change doSomethingWith to:
private static void doSomethingWith(List<? extends Base> bases) {
This fixes the problem. You could also do it at the caller lever (but it's a bit messier):
List<Sub> subs = new ArrayList<Sub>();
doSomethingWith(new ArrayList<Base>(subs));
One issue with the wildcard (?) approach is that you can't add new items to the list. To do that, you need something like:
private static <B extends Base> void doSomethingWith(List<B> bases) {
And then add only B instances to bases.
Just declare all your lists as
List<Base> list;
Then you can add both Base objects and objects of any subclass.
Below are the 2 ways to do it....
public void inTake(List<? extends Base> list){
}
Or
public T extends Base void inTake(List<T> list){
}
How does one get a parameterized Class object to be used as a method argument?
class A<T>
{
public A(Class<T> c)
{
}
void main()
{
A<String> a1 = new A<String>(String.class); // OK
A<List<String>> a2 = new A<List<String>>(List<String>.class); // error
A<List<String>> a3 = new A<List<String>>(Class<List<String>>); // error
}
}
Why do I want to do that, you may ask? I have a parameterized class whose type is another parameterized class, and whose constructor requires that other class type as an argument. I understand that runtime classes have no information on their type parameters, but that shouldn't prevent me from doing this at compile time. It seems that I should be able to specify a type such as List<String>.class. Is there another syntax to do this?
Here is my real usage case:
public class Bunch<B>
{
Class<B> type;
public Bunch(Class<B> type)
{
this.type = type;
}
public static class MyBunch<M> extends Bunch<List<M>>
{
Class<M> individualType;
// This constructor has redundant information.
public MyBunch(Class<M> individualType, Class<List<M>> listType)
{
super(listType);
this.individualType = individualType;
}
// I would prefer this constructor.
public MyBunch(Class<M> individualType)
{
super( /* What do I put here? */ );
this.individualType = individualType;
}
}
}
Is this possible?
How about just cast?
super((Class<List<M>>)List.class);
Class literals are not going to have the type parameters that you want.
Remember you will NOT get a List as a class in runtime, and the right approach would probably be using TypeToken as BalusC told you. Without TypeToken, you can't cast to List, but you can create something like this:
public static class MyBunch2<List_M extends List<M>, M> extends Bunch<List_M>
{
Class<M> individualType;
#SuppressWarnings("unchecked")
public MyBunch2(Class<M> individualType)
{
super((Class<List_M>) List.class);
this.individualType = individualType;
}
}
Since List_M extends List<M> this is not as typesafe as you may wish, but maybe is nice enough. Creating an instance will be as ugly as writing
MyBunch2<List<String>, String> a = new MyBunch2<List<String>, String>(String.class);
but you can improve it with a factory method
public static <M2> MyBunch2<List<M2>, M2> of(Class<M2> individualType){
return new MyBunch2<List<M2>, M2>(individualType);
}
and then write
MyBunch2<List<String>, String> b = MyBunch2.of(String.class);
If you are using eclipse, code assist will help you writing the ugly class MyBunch2, String>
Of course, in runtime, this.type will be java.util.List, not java.util.List
To get it right, go for TypeToken.
---Continuation---
You can even make another class
public static class MyBunch3<M> extends MyBunch2<List<M>, M>
{
public MyBunch3(Class<M> individualType) {
super(individualType);
}
}
And then create instances as
MyBunch3<String> c = new MyBunch3<String>(String.class);
There must be a way to do that in just one class...but I can't figure it out