In the following program, I have class Cow
, class Dragon
derived from class , Cow
and class IceDragon
derived from class Dragon
.
There is also the class HeiferGenerator
, responsible for creating an array containing instances of Cow
, Dragon
and IceDragon
.
However, in the class HeifeferGenerator
, I get the warning " Raw use of parameterized class 'Class' " on the line:
private static final Class[] dragonTypes = {Dragon.class, IceDragon.class};
What can I do to correct this warning?
// Cow class
public class Cow {
// Declaring attributes name and image
private final String name;
private String image;
// Constructor to create a new Cow object with parameter name
public Cow (String name) {
this.name = name;
this.image = null;
}
// Accessor to return the name of the cow
public String getName() {
return this.name;
}
// Accessor to return the image used to display the cow after the message
public String getImage() {
return this.image;
}
// Mutator to set the image used to display the cow after the message
public void setImage(String _image) {
this.image = _image;
}
}
enter code here
// Dragon class derived from the Cow class
public class Dragon extends Cow {
// Constructor to create a new Dragon object with parameters name and image
public Dragon (String name, String image) {
super(name);
setImage(image);
}
// Function to return true for the default Dragon type
public boolean canBreatheFire() {
return true;
}
}
// IceDragon class derived from the Dragon class
public class IceDragon extends Dragon {
// Constructor to create a new IceDragon object with parameters name and image
public IceDragon (String name, String image) {
super(name, image);
}
// Function to return false for the IceDragon type
public boolean canBreatheFire() {
return false;
}
}
import java.lang.reflect.Constructor;
public class HeiferGenerator
{
public static Cow[] getCows()
{
if (cows == null)
{
cows = new Cow[cowNames.length + dragonNames.length];
// Add the "regular" cows
for (int index = 0; index < cowNames.length; index++)
{
cows[index] = new Cow(cowNames[index]);
cows[index].setImage(quoteLines + cowImages[index]);
}
// Add the dragons
for (int offset = cowNames.length, index = 0; index < dragonNames.length; index++)
{
try
{
@SuppressWarnings("unchecked")
Constructor<Dragon> constructor = dragonTypes[index].getConstructor(String.class, String.class);
cows[offset + index] = constructor.newInstance(dragonNames[index], quoteLines + dragonImage);
}
catch (Exception ignored) { }
}
}
return cows;
}
// Hard-coded values for some of the cows
private static final String[] cowNames = { "heifer", "kitteh" };
private static final String quoteLines = " \\\n" +
" \\\n" +
" \\\n";
private static final String[] cowImages = { " ^__^\n" +
" (oo)\\_______\n" +
" (__)\\ )\\/\\\n" +
" ||----w |\n" +
" || ||\n",
" (\"`-' '-/\") .___..--' ' \"`-._\n" +
" ` *_ * ) `-. ( ) .`-.__. `)\n" +
" (_Y_.) ' ._ ) `._` ; `` -. .-'\n" +
" _.. `--'_..-_/ /--' _ .' ,4\n" +
" ( i l ),-'' ( l i),' ( ( ! .-'\n"
};
private static final String[] dragonNames = { "dragon", "ice-dragon" };
private static final Class[] dragonTypes = {Dragon.class, Dragon.class};
private static final String dragonImage = " |\\___/| /\\ //|\\\\\n" +
" /0 0 \\__ / \\// | \\ \\\n" +
" / / \\/_ / // | \\ \\\n" +
" \\_^_\\'/ \\/_ // | \\ \\\n" +
" //_^_/ \\/_ // | \\ \\\n" +
" ( //) | \\ // | \\ \\\n" +
" ( / /) _|_ / ) // | \\ _\\\n" +
" ( // /) '/,_ _ _/ ( ; -. | _ _\\.-~ .-~~~^-.\n" +
" (( / / )) ,-{ _ `.|.-~-. .~ `.\n" +
"(( // / )) '/\\ / ~-. _.-~ .-~^-. \\\n" +
"(( /// )) `. { } / \\ \\\n" +
" (( / )) .----~-.\\ \\-' .~ \\ `. __\n" +
" ///.----..> \\ _ -~ `. ^-` \\\n" +
" ///-._ _ _ _ _ _ _}^ - - - - ~ `-----'\n";
private static Cow[] cows = null;
}
The caveat is that there could accidentally be cows between the dragon types! What a mess... I wouldn't want my cows mixed with dragons (even though dragons are claimed to be cow subtypes)
The use of generics with arrays is a very tricky thing, most people prefer to use some class from the java collections API and convert to an array later.
I give you another option... The always reliable enumerations. While basic enums just have a list of integer words starting at zero, you can bind them to as many things as you like by adding a constructor. In our case it would be like this:
As you can see,
?
he indicates any class, which sounds good but isn't specific enough, so we say anything that extends Dragon so that we don't miss a thing.To get all the values as an array we have the nice method
values()
, so replacing in the code we would putbut this would not give us an array of classes, but an array of dragon types... Fortunately for that we put an ever-handy getter , so in the list of constructors we will put
and magic magic magic! Now it is no longer a builder of only Dragons... but of dragons and their subtypes.
Advantage
As you will see, the advantages of this approach are that:
Extra
Since my solution looks like two lines and your program is the same with very few cows and dragons, we can change the code to support having a lot more cows and dragons as follows:
We extract the image generation process using an interface and its respective implementations
for cow pictures
and for images of dragons
We put faker in it to generate the names and pass the logic to stream.
As you may have seen, I set it to randomly spawn up to 100 cows and up to 100 dragons, but you can modify the numbers up to the maximum value of long (and that may be too much... for your computer... not for the number of cows and dragons that one might want in their fantasy world)