Creating an instance of a type param

A

Aryeh.Friedman

I am attempting to create a new instance of the class indicated in a
type param.

Here is little demo I wrote showing the problem (question below):

public class Foo
{
}

public class Ack extends Foo
{
}

public class GenericDemo<T>
{
public GenericDemo()
{
T t;

//t=new T(...); // compile error
t=(T) new Foo(); // not polymorphic to T

System.out.println(t.getClass()); // prints Foo not Ack
}
}

public class Main
{
public static int main(String [] args)
{
GenericDemo<Ack> demo=new GenericDemo<Ack>();

return 1;
}
}


Question: How do I create a new instance of T to be made in
GenericDemo<T>?
 
O

Oliver Wong

I am attempting to create a new instance of the class indicated in a
type param.

Here is little demo I wrote showing the problem (question below):

public class Foo
{
}

public class Ack extends Foo
{
}

public class GenericDemo<T>
{
public GenericDemo()
{
T t;

//t=new T(...); // compile error
t=(T) new Foo(); // not polymorphic to T

System.out.println(t.getClass()); // prints Foo not Ack
}
}

public class Main
{
public static int main(String [] args)
{
GenericDemo<Ack> demo=new GenericDemo<Ack>();

return 1;
}
}


Question: How do I create a new instance of T to be made in
GenericDemo<T>?

There are a few problems with your code, and it sounds like you're
misunderstanding something, which is why I'm not going to just give a direct
answer to your question, but instead probe you with a few questions of my
own to try to figure out what it is you REALLY are trying to do.

First of all, the line "t=(T) new Foo();" is a bit dangerous. T might
be, for example, a String, which is not assignment-compatible with Foo. T
might also (as in your example), be Ack. And a variable of type Ack cannot
be assigned a value of type Foo either!

As for your System.out.println() statement, the comment following it
implies that you think this is strange behaviour, but to me it makes sense:
The variable "t" does indeed contain an object of type "Foo"; you can tell,
because just one line above, you've assigned an object of type "Foo" to "t".

So what is it that you're trying to do with this code exactly?

- Oliver
 
A

Aryeh.Friedman

Note: I removed <T extends Foo> from the definition since I,
mistakingly thought it only confused the matter.

Basically what I need to do is create a new instance of Ack (or what
ever the type is). In the larger picture I hook toString in Foo to one
of it's subclasses for example in the command line version it should
call CmdLineFoo.toString() and GUIFoo.toString() for some generic GUI,
etc....

The sticking point is that all instances of Foo and/or it's subclasses
are created in GenericDemo<T>... basically when GenericDemo needs to
add something to say the output collection it needs to have the right
UI attached to it.

thus all main() should have to do is:

main(....)
{
GenericDemo<Ack> demo=new GenericDemo<Ack>();

// assume that a ArrayList<Ack> is returned
for(Ack ack:demo.getOutput())
System.out.println(ack); // Assume Ack
overides toString() and Foo does not
}
--Aryeh
 
A

Aryeh.Friedman

Note: I removed <T extends Foo> from the definition since I,
mistakingly thought it only confused the matter.

Basically what I need to do is create a new instance of Ack (or what
ever the type is). In the larger picture I hook toString in Foo to one
of it's subclasses for example in the command line version it should
call CmdLineFoo.toString() and GUIFoo.toString() for some generic GUI,
etc....

The sticking point is that all instances of Foo and/or it's subclasses
are created in GenericDemo<T>... basically when GenericDemo needs to
add something to say the output collection it needs to have the right
UI attached to it.

thus all main() should have to do is:

main(....)
{
GenericDemo<Ack> demo=new GenericDemo<Ack>();

// assume that a ArrayList<Ack> is returned
for(Ack ack:demo.getOutput())
System.out.println(ack); // Assume Ack
overides toString() and Foo does not
}
--Aryeh
 
O

Oliver Wong

Note: I removed <T extends Foo> from the definition since I,
mistakingly thought it only confused the matter.

So the code would look like:

<code>
public class GenericDemo<T extends Foo> {
public GenericDemo() {
T t = (T) new Foo();
System.out.println(t.getClass());
}
}
</code>

correct? Tbis is still problematic, because Ack extends Foo, so
"GenericDemo<Ack> demo=new GenericDemo<Ack>();" would be legal, which would
yield code that behaves like:

<code>
public class GenericDemo<Ack> {
public GenericDemo() {
Ack t = (Ack) new Foo();
System.out.println(t.getClass());
}
}
</code>

But this is an error, because you have a Foo object, not an Ack object, so
the casting should fail.
Basically what I need to do is create a new instance of Ack (or what
ever the type is). In the larger picture I hook toString in Foo to one
of it's subclasses for example in the command line version it should
call CmdLineFoo.toString() and GUIFoo.toString() for some generic GUI,
etc....

The sticking point is that all instances of Foo and/or it's subclasses
are created in GenericDemo<T>... basically when GenericDemo needs to
add something to say the output collection it needs to have the right
UI attached to it.

thus all main() should have to do is:

main(....)
{
GenericDemo<Ack> demo=new GenericDemo<Ack>();

// assume that a ArrayList<Ack> is returned
for(Ack ack:demo.getOutput())
System.out.println(ack); // Assume Ack
overides toString() and Foo does not
}

This vaguely sounds like the Abstract Factory pattern. Have you taken a
look at that to see if it solves your problem more elegantly?
http://en.wikipedia.org/wiki/Abstract_factory_pattern

- Oliver
 
A

Aryeh.Friedman

Oliver said:
So the code would look like:

<code>
public class GenericDemo<T extends Foo> {
public GenericDemo() {
T t = (T) new Foo();
System.out.println(t.getClass());
}
}
</code>

correct? Tbis is still problematic, because Ack extends Foo, so
"GenericDemo<Ack> demo=new GenericDemo<Ack>();" would be legal, which would
yield code that behaves like:

<code>
public class GenericDemo<Ack> {
public GenericDemo() {
Ack t = (Ack) new Foo();
System.out.println(t.getClass());
}
}
</code>

Yes, but I would much prefer t=new T() but as I mentioned that produces
a compilor error.
But this is an error, because you have a Foo object, not an Ack object, so
the casting should fail.

If I was able to do t=new T() problem solved ;-)
This vaguely sounds like the Abstract Factory pattern. Have you taken a
look at that to see if it solves your problem more elegantly?
http://en.wikipedia.org/wiki/Abstract_factory_pattern

I agree but how do you get the desired subtype? (namely don't you need
prototyped versions of each possible subtype and then you just return
the required one?)

--Aryeh
 
A

Aryeh.Friedman

Note: I removed <T extends Foo> from the definition since I,
mistakingly thought it only confused the matter.

Basically what I need to do is create a new instance of Ack (or what
ever the type is). In the larger picture I hook toString in Foo to one
of it's subclasses for example in the command line version it should
call CmdLineFoo.toString() and GUIFoo.toString() for some generic GUI,
etc....

The sticking point is that all instances of Foo and/or it's subclasses
are created in GenericDemo<T>... basically when GenericDemo needs to
add something to say the output collection it needs to have the right
UI attached to it.

thus all main() should have to do is:

main(....)
{
GenericDemo<Ack> demo=new GenericDemo<Ack>();

// assume that a ArrayList<Ack> is returned
for(Ack ack:demo.getOutput())
System.out.println(ack); // Assume Ack
overides
// toString() and
Foo does not
}
--Aryeh
 
O

Oliver Wong

Yes, but I would much prefer t=new T() but as I mentioned that produces
a compilor error.


If I was able to do t=new T() problem solved ;-)

Alternatively, you could pass a factory to GenericDemo, and the factory
could create your objects for you. But then, what is it exactly that
GenericDemo does? If all it does is creates objects, then GenericDemo itself
should be made into a factory.
I agree but how do you get the desired subtype? (namely don't you need
prototyped versions of each possible subtype and then you just return
the required one?)

I don't understand the question. In fact, I don't really understand the
application described earlier in the thread. What makes a subtype desired?
What do you mean by prototyped? Are you implying you already need an
instance of a subtype to clone() it? 'Cause you don't, you just generate
instances of the subtypes via the factory.

- Oliver
 
A

Aryeh.Friedman

Oliver said:
Alternatively, you could pass a factory to GenericDemo, and the factory
could create your objects for you. But then, what is it exactly that
GenericDemo does? If all it does is creates objects, then GenericDemo itself
should be made into a factory.

Maybe we are talking across each other... basically I have some class
that as a result of a rather costly, O(n^2), calculation will create n
or fewer elements of some type... Since almost all the logic (except
the user interface) for this is in the base class ("Foo") and I just
want to create decorators for different UI standards (i.e. toString()
when called from a CmdLineFoo spits out a user readable version but
from anything else just returns this.getClass()@this.hashCode()
[default Object method])

Some details on the application might make it a little clearer:

Assume I have some class that prepares a list of "chunks" of difference
between two files (simelor to diff(1) but using a slightly improved LCS
algorithm)... The super class Chunk knows everything there is know
about chunks (i.e. there size, where they are in the file(s), and what
edits they require)....

Now I want to make two different (maybe more in the future) UI's for
this app
one is a command line version that will produce output identical to
diff(1) (I want to make it so this can be done as a call to some method
in the diff class [version control and a few other apps would do it
this way]).

I have defined the following:

public class DiffChunk
{
// impliment UI independant code... DOES NOT overide toString()!!!!
}

public class DiffChunkText extends DiffChunk
{
// overides toString() ONLY!!!!
}

So in the differnence finding class I have something like this:

public class FileDiff<T extends DiffChunk>
{
public FileDiff(String file1, String file2)
{
// parse and generate LCS for both files

T chunk=new T(...); // Complor error
T chunk=(T) new DiffChunk(...); // Problem for reasons
discussed alrady

while(operations are left in the LCS)
if op != NOP // the lines are the SAME
chunk.add(op)
else {
chunks.add(chunk);
T chunk=new T(...); // see comment above

T chunk=(T) new DiffChunk(...);
}
}
}

public class CmdLine
{
public void main(String [] args)
{
for(DiffChunkPrint chunk:new FileDiff(arg[0],arg[1])
System.out.println(chunk);
}
}

public class GUI {
public void main(String [] args)
{
for(DiffChunkPrint chunk:new FileDiff(arg[0],arg[1])
Draw(chunk);
}
}
I don't understand the question. In fact, I don't really understand the
application described earlier in the thread. What makes a subtype desired?
What do you mean by prototyped? Are you implying you already need an
instance of a subtype to clone() it? 'Cause you don't, you just generate
instances of the subtypes via the factory.

I hope the above makes it clearer

--Aryeh
 
I

Ian Pilcher

Yes, but I would much prefer t=new T() but as I mentioned that produces
a compilor error.

I won't pretend to understand this entire thread, but I suspect that
you're running into type erasure issues. When working with generics,
it's easy to forget that they're compile-time only.

With that in mind, how would the runtime execute "T t = new T()"?

The usual workaround is to pass a Class object to the constructor/
method in question, so you would end up with something like:

T t = cls.newInstance();

Does this help?
 
R

Roedy Green

Basically what I need to do is create a new instance of Ack (or what
ever the type is).

It that case you would have naively tried

new T();

instead of new Foo();

Foo means Foo!

But you would soon discover that would not work either because of this
ruddy type erasure. Generics all disappear at runtime leaving only
the base types. So to dynamically create a new T where the flavour is
passed in as a parameter you need code of the form:

foo = x.newInstance();

where x is the class you want a new object of.

This has been hashed over in a very long previous thread. you might
find it by searching for generics and newInstance.

See my explanation at
http://mindprod.com/jgloss/generics.html#FACTORIES

Check out http://mindprod.com/jgloss/generics.html#UNDERTHEHOOD
and follow the link to Angelika Langer's Generics FAQ. which explains
the problem in more detail
 
O

Oliver Wong

Now I want to make two different (maybe more in the future) UI's for
this app
one is a command line version that will produce output identical to
diff(1) (I want to make it so this can be done as a call to some method
in the diff class [version control and a few other apps would do it
this way]).

I have defined the following:

public class DiffChunk
{
// impliment UI independant code... DOES NOT overide toString()!!!!
}

public class DiffChunkText extends DiffChunk
{
// overides toString() ONLY!!!!
}

Okay, is there a reason why you can't have the code for UI rendering,
and the code for toString() in the same class, thus eliminating the need for
generics altogether?

Or why the code for "rendering" (whether in a UI or a console) can't be
in a seperate class, which just accepts a "data" class which it queries to
know to actually display for the user?

- Oliver
 
J

John C. Bollinger

Oliver said:
[...]
So the code would look like:

<code>
public class GenericDemo<T extends Foo> {
public GenericDemo() {
T t = (T) new Foo();
System.out.println(t.getClass());
}
}
</code>
[...]

If I was able to do t=new T() problem solved ;-)

But this cannot possibly work because the compiler cannot be sure that
all possible classes T have a nullary constructor. Or, more accurately,
it *can* be sure that there are hypothetical classes T that do NOT have
such a constructor. And then there are the more esoteric considerations
such as type parameter erasure. Anyway, give it up. You're not going
to get what you expressly want here, and it's reasonable that you won't.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top