cleaner alternative for cast

G

Giovanni Azua

hi,

I have a situation with a generic class and parameter and the only way I
found to solve it was kind of ugly. The class definition looks like this:

// A is parameterized with a T parameter and
// receives a Class<T> as parameter in its constructor
//
public class A<T>
{
public A(Class<T> aClass)
{
// ...
}
}

// class B extends from A and provides a Queue as parameter, to
// avoid leaving the Queue in its raw form, B is also parameterized
// with the E(lement) type of the Queue
//
public class B<E>
extends A<Queue<E>>
{
public B()
{
super(???); // <<<<<<<== My problem is here
}
}

Substituting ??? with the following does not compile:

- Queue.class => does not fit a
Class<Queue<E>>
- (Class<Queue<E>>) Queue.class => cast does not work, no type
contravariance
- Queue<E>.class => does not compile

Parameterizing class A with A<Queue> rather than A<Queue<E>> will work but
it is not elegant.

So I found this solution but it is very ugly, replacing ??? by:
- (Class<Queue<E>>) new
PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

That's it, I needed to instantiate a concrete implementation of Queue,
through reflection get to the Queue interface, and cast it to the
Class<Queue<E>> I needed.

Any better way?

TIA,
regards,
Giovanni
 
J

Joshua Cranmer

Giovanni said:
hi,

I have a situation with a generic class and parameter and the only way I
found to solve it was kind of ugly. The class definition looks like this:

Ah yes, I believe you've discovered
So I found this solution but it is very ugly, replacing ??? by:
- (Class<Queue<E>>) new
PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

The method I think would be preferable would be to have A produce a
protected static method to "solve" these conundrums:

@SuppressWarnings("unchecked")
protected static <K> Class<K> reparameterize(Class<?> clazz) {
return (Class<K>)clazz;
}

And then call with something like this:

super(A.<Queue<E>>reparameterize(Queue.class));

Rare types suck.
 
J

Jerry Gerrone

So I found this solution but it is very ugly, replacing ??? by:
- (Class<Queue<E>>) new
PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

Didn't (Class<Queue<E>>)Queue.class work? (modulo a compiler warning
about an unchecked cast)

The above is definitely klunky and moreover, brittle. The Queue
interface might not always be at index zero in that array, or on all
Java runtime implementations.
 
S

soul.mirror1

So I found this solution but it is very ugly, replacing ??? by:
- (Class<Queue<E>>) new
PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

Didn't (Class<Queue<E>>)Queue.class work? (modulo a compiler warning
about an unchecked cast)

The above is definitely klunky and moreover, brittle. The Queue
interface might not always be at index zero in that array, or on all
Java runtime implementations.

Jerry Gerrone, I hold up a mirror to your soul!

Though you have contributed many useful and on-topic posts to a number
of newsgroups, you have also shown an unfortunate tendency to get into
arguments.

Actually, that's putting it mildly. Your refusal to let any perceived
slight pass unchallenged has had unbelievable and astonishing results.
It seems that few can resist the temptation to try to get the last
word in an argument with you, while you absolutely will NEVER let THEM
get the last word. Combined with your tendency to respond tit for tat
to every single post that is the least bit hostile, and the presence
in most newsgroups of short-tempered people, people that are simply
blunt and uncompromising, and assorted nuts and flakes, this results
in frequent and severe flamewars.

Indeed, during your usenet career you appear to have destroyed several
newsgroups, subjecting many more to volcanic flamewars the likes of
which have rarely been seen and that have left scars and trauma
lasting for years afterward. Whole hierarchies informally divide
their history into "Before Neo" and "After Neo", or date everything
relative to "the Coming of Twisted", and the people that have
killfiled you are legion. Indeed, their combined numbers, wealth, and
incomes are comparable to the population, resources, and GDP of a mid-
size country. It's possible only spammers are in more killfiles or
have more aliases.

Speaking of which, your dozen or more google groups accounts add to
the misery and prolong the flamewars by making it difficult for anyone
to killfile you. Between the knee-jerk reactions you seem to provoke
and the inability of even the wiser such persons to block you from
their view, explosions are inevitable. You are a powder keg and any
random thing might light the fuse.

Particularly hard-hit have been comp.lang.java.programmer,
comp.text.tex, and rec.games.roguelike.angband, all of which have at
times been littered with the smouldering wreckage of threads you
blasted, and even a time or two been temporarily reduced to cratered
wastelands by the sheer ferocity of your detonations. You've left a
trail of bombed-out threads all over usenet, but these three
newsgroups have been especially cursed by repeat visitations by the
aptly-named Twisted One, and even by having you actually hang out as a
regular for a while now and again, your every post a bomb waiting to
go off at the slightest provocation, the group a minefield until you
bless it -- all too temporarily -- with your departure.

But this is the post that really takes the cake: (WARNING -- May be
radioactive. Avoid long-duration exposure to this post!)

http://groups.google.com/group/comp.lang.java.programmer/msg/a1eb0b90a65a6533?dmode=source

The thread in question started with a spam, the classification of
which had already become the subject of a fairly acrimonious debate in
which you were participating. Then you dropped what appears to have
been the usenet equivalent of the hydrogen bomb: to a vi-user, you
said "I think you should probably get with the times. Console-mode
archaisms from the 70s simply cannot and will not ever decently
support unicode, anyway ... Gobs of software got written during the
80s and 90s, and more has been written so far this millennium; I
suggest that you find and use some."

This phrase is a work of evil genius. It must have taken a dedicated
team of researchers working around the clock for the past several
years to devise it and craft it so precisely for its deadly purpose.
Theories about the possibility of a usenet chain reaction must have
been devised, revised, and eventually televised to you, and at the end
of the process a precisely shaped charge was delivered into your hands
which, when detonated, would send every geek within a light-year into
a flaming frenzy.

And then for some odd reason you chose comp.lang.java.programmer as
your proving ground, where that carefully constructed phrase ignited
the editor rwar to end all editor rwars.

The newsgroup now gets a third the traffic it did before that terrible
day in September of 2007. (How appropriate -- September.) And the
nuclear fireball has expanded to engulf alt.off-topic, which has been
completely obliterated. To this very day nothing can be found there
but flames -- even the spammers steer clear of it. And flames there
are. The thread you nuked has burned for seventeen whole months now
and shows no signs of stopping; it contains more than ten thousand
news posts, and every last one of them is a complete and utter waste
of bandwidth. Thousands of hours must have been poured, by you and
several other people, into dousing it with bucketloads of gasoline day
after day, week after week, month after month. It probably has a whole
rack of servers at google employed full-time just indexing all of the
random shit that gets dumped into it. It's the ultimate entropy
machine, sucking in work and time and effort and generating nothing
but heat. Perhaps it will grow to eventually consume the entire
universe, as some physicists once feared the detonation of the H-bomb
might.

And it's to a significant degree your fault.

The devil of it is, it doesn't look like you actually mean any harm at
all, though perhaps instead you're just the most successful troll
ever.

If ever there was a poster child for that proverbial road to hell that
is paved with good intentions, it is you, and if ever there has been a
hell on earth, it is that monstrous thread. Like the beast of
revelation, or the hydra of Greek mythology, the more heads are cut
off the more it grows, and it consumes everything in its path.
Banished for now to a backwater newsgroup, it is ever threatening to
burst its chains and go rampaging all over usenet, which event would
probably herald the end of days. What the government regulators, tax
planners, spammers, meowers, alt.tasteless trolls, hipcrime,
cancelbunnies, and google groups all failed to do, you might
accomplish: the death of usenet, film at 11.

Even if you don't manage to start armageddon, and even if it was
inadvertent, it's still the case that you nuked a perfectly good
newsgroup back to the stone age and left the survivors traumatized and
quivering in terror at every newbie that shows up for fear it's yet
another of your seemingly unlimited supply of google groups accounts.

If you have an excuse for your behavior, please speak now, and give
your apology before the witnesses gathered here.

If you do not, then know that your soul is forever tainted!
 
M

Mike Schilling

Jerry said:
So I found this solution but it is very ugly, replacing ??? by:
- (Class<Queue<E>>) new
PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

Didn't (Class<Queue<E>>)Queue.class work? (modulo a compiler warning
about an unchecked cast)

The above is definitely klunky and moreover, brittle. The Queue
interface might not always be at index zero in that array, or on all
Java runtime implementations.

In fact, given the way PriorityQueue is declared in JDK 1.5, which is

public class PriorityQueue<E> extends AbstractQueue<E> implements
Serializable

there will only be one class in the array, and it will be
Serializable. getInterfaces() doesn't return interfaces implemented
by superclasses.
 
G

Giovanni Azua

Hi Lew,

Thank you for your reply, but I quite didn't understand the reasoning behind
your statement below:

Lew said:
You can't provide the super constructor with more information than you
give the child constructor.

I have had this situation many times where a subclass fixes part of the
information required for constructing its supertype class. In fact, it is
very useful in the so called partial implementations [Object Oriented
Software Construction, Bertrand Meyer, page 503] i.e. Abstract classes that
more less generically (could be depending on some parameters) achieve a
great deal of reusable code for their subclasses.

You find this same pattern in JDK itself e.g.

AbstractDocument
<http://java.sun.com/javase/6/docs/a...nt(javax.swing.text.AbstractDocument.Content)>
^
|
PlainDocument
<http://java.sun.com/javase/6/docs/api/javax/swing/text/PlainDocument.html#PlainDocument()>


Abstract document has no default constructors but e.g.
AbstractDocument(AbstractDocument.Content data)

PlainDocument class offers a default data model to be GapContent so it
offers its clients a default empty constructor while its super class
doesn't. If you look the JDK index for AbstractXXX classes I bet you will
find more cases like this.

Best regards,
Giovanni
 
G

Giovanni Azua

Hi Joshua,

Many thanks! your proposed solution works beautifully :) I spend a while
looking for a cleaner workaround like this :)

btw I was using JDK 1.6.0_11, now I am downloading the 12 update to see if
anything changes.

Would you mind if I used your snippet in my open source project? :) The
context for this was while providing example code for a componentized
version of the Adapter Pattern. I was trying to demonstrate how to adapt a
List implementation to be a Queue, not really useful in Java 5 but just to
demonstrate the use of the Adapter implementation:

QueueAdapter (corresponds to B):
<http://perfectjpattern.svn.sourcefo...uctural/adapter/QueueAdapter.java?view=markup>

Example:
<http://perfectjpattern.svn.sourcefo...e/structural/adapter/Example.java?view=markup>

Again many thanks!
Best regards,
Giovanni
 
G

Giovanni Azua

Hi Mike,

Please find my comments below:

Mike Schilling said:
In fact, given the way PriorityQueue is declared in JDK 1.5, which is

public class PriorityQueue<E> extends AbstractQueue<E> implements
Serializable

there will only be one class in the array, and it will be Serializable.
getInterfaces() doesn't return interfaces implemented by superclasses.
This statement is not correct. The snippet in the OP is:
new PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

Translated to plain english it will get the Class of the PriorityQueue, then
get its superclass AbstractQueue and then ask for the list of implemented
interfaces which is only one Queue. This is tested and works.

I guess you misunderstood with:
new PriorityQueue().getClass().getInterfaces()[0]

This one yes it does get the interfaces implemented by PriorityQueue which
is java.io.Serializable

Best regards,
Giovanni
 
G

Giovanni Azua

Hi Jerry,

Yes that's what I said in the OP. I was precisely trying to move away from
that solution but it was the only one I could find that worked.

Best regards,
Giovanni

So I found this solution but it is very ugly, replacing ??? by:
- (Class<Queue<E>>) new
PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

Didn't (Class<Queue<E>>)Queue.class work? (modulo a compiler warning
about an unchecked cast)

The above is definitely klunky and moreover, brittle. The Queue
interface might not always be at index zero in that array, or on all
Java runtime implementations.
 
T

Tom Anderson

Any better way?

You may need to use stronger kung fu:

http://gafter.blogspot.com/2006/12/super-type-tokens.html

Here, that would look like:

public class A<T>
{
public A(TypeReference<T> aType)
{
// but ...
}
}

public class B<E> extends A<Queue<E>>
{
public B()
{
super(new TypeReference<Queue<E>>() {});
}
}

However, a TypeReference isn't necessarily a replacement for a Class - for
instance, it doesn't do cast(), unless you can write some kind of freaky
reflective implementation of it yourself.

tom
 
M

Mike Schilling

Giovanni said:
Hi Mike,

Please find my comments below:

Mike Schilling said:
In fact, given the way PriorityQueue is declared in JDK 1.5, which
is

public class PriorityQueue<E> extends AbstractQueue<E> implements
Serializable

there will only be one class in the array, and it will be
Serializable. getInterfaces() doesn't return interfaces implemented
by superclasses.
This statement is not correct. The snippet in the OP is:
new PriorityQueue().getClass().getSuperclass().getInterfaces()[0]

OK, I missed the "getSuperclass()" . Still, depending on the fact
that Queue is the first interface declared to be implemented by
AbstractQueue is not robust.
 
L

Lew

Giovanni said:
Thank you for your reply, but I quite didn't understand the reasoning behind
your statement below:

Lew said:
You can't provide the super constructor with more information than you
give the child constructor.

I have had this situation many times where a subclass fixes part of the
information required for constructing its supertype class. In fact, it is
very useful in the so called partial implementations [Object Oriented
Software Construction, Bertrand Meyer, page 503] i.e. Abstract classes that
more less generically (could be depending on some parameters) achieve a
great deal of reusable code for their subclasses.

You find this same pattern in JDK itself e.g.

AbstractDocument
<http://java.sun.com/javase/6/docs/a...nt(javax.swing.text.AbstractDocument.Content)>
^
|
PlainDocument
<http://java.sun.com/javase/6/docs/api/javax/swing/text/PlainDocument.html#PlainDocument()>

Abstract document has no default constructors but e.g.
AbstractDocument(AbstractDocument.Content data)

PlainDocument class offers a default data model to be GapContent so it
offers its clients a default empty constructor while its super class
doesn't. If you look the JDK index for AbstractXXX classes I bet you will
find more cases like this.

Your example illustrates the point I made: You can't provide the super
constructor with more information than you give the child constructor.

When you call the no-arg PlainDocument constructor, it must pass its own
default to super(AbstractDocument.Content). The author of PlainDocument
provided that information to the child constructor.

From the source:
public PlainDocument() {
this(new GapContent());
}

AbstractDocument needs information known only to the child class.
PlainDocument cannot call the parent constructor and expect the parent class
to know which AbstractDocument.Content to use if the child constructor doesn't
know.

--
Lew
 
B

blue indigo

...

Plonk, "soul.mirror".

+-------------------+ .:\:\:/:/:.
| PLEASE DO NOT | :.:\:\:/:/:.:
| FEED THE TROLLS | :=.' - - '.=:
| | '=(\ 9 9 /)='
| Thank you, | ( (_) )
| Management | /`-vvv-'\
+-------------------+ / \
| | @@@ / /|,,,,,|\ \
| | @@@ /_// /^\ \\_\
@x@@x@ | | |/ WW( ( ) )WW
\||||/ | | \| __\,,\ /,,/__
\||/ | | | (______Y______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
==================================================================
 
L

Lew

blue said:
+-------------------+ .:\:\:/:/:.
| PLEASE DO NOT | :.:\:\:/:/:.:
| FEED THE TROLLS | :=.' - - '.=:
| | '=(\ 9 9 /)='
| Thank you, | ( (_) )
| Management | /`-vvv-'\
+-------------------+ / \
| | @@@ / /|,,,,,|\ \
| | @@@ /_// /^\ \\_\
@x@@x@ | | |/ WW( ( ) )WW
\||||/ | | \| __\,,\ /,,/__
\||/ | | | (______Y______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
==================================================================

Seems to me that "plonk" is the antithesis of feeding a troll, but thanks for
the excellent and clearly much-needed advice.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top