I have the following class Type:
class Type{
String type;
public Type(String type){
this.type = type;
}
}
I have few types initialised here:
Type cor = new Type("cor");
Type name = new Type("name")
and Now I want to have a class called Record,
class Record{
String name;
Type[] types;
public Record(String name, Type[] types){
this.name = name;
this.types = types;
}
}
Well I got stuck here. What I want to do is when initialise an instance of the class Record, like this:
Record rec = new Record("Position", ...);
it should be something like this, I will give an example of the position record here:
Record Position = [cor x, cor y, name z];
So is using Type[] a good choice here? I find it hard to both record the type and the variable name such as x, y;
Or should I use a HashMap?
It's hard to answer the question without more information about what you are trying to model. Your 'position' example is fairly confusing as it implies that a single record has several 'variables' of different types. However I'm assuming that a record can have several types. It's unclear whether the types can change and whether there are a fixed set of types.
Ideally the set of types are static and you could use an enumeration of types:
enum RecordType {
COR, NAME, ...;
}
class Record {
public Record(String name, EnumSet<RecordType> types) {
...
}
}
Then creating a new record would look like:
Record record = new Record("My record", EnumSet.of(RecordType.NAME));
If the set of types aren't static then you will need to define a class. In that case I would recommend you use Set<RecordType> rather than RecordType[] as the constructor argument. This makes it clear that it is a set of types (i.e. no duplicates) and avoids all the error checking you'll need to do with an array.
If a single record can have several values for different types then you will need to have a Map<RecordType,String> member variable. In that case I would recommend against trying to define the values in the constructor. Instead have a addTypeValue method for adding values to the map.
Related
I have a Java class that has a few members. I want to write a custom cast for it. I was wondering how is it possible to do so?
Let's assume the class is as follows:
class Person {
private int age;
private float weight;
// getters and setters and etc
}
I would like the int cast to return the member age of an object, and the float cast to return the weight of an object.
For instance:
public class Main {
public static void main(String[] args) {
// create an object
Person P = new Person();
P.setAge(21);
P.setWeight(88.0);
// case 1: casting object to an existing data type
int personAge = (int) P; // would return the age
float personWeight = (float) P; // would return the weight
// case 2: casting an existing data type to an object
Person P2 = (Person) personAge; // this would create an instance of the object whose age is assigned and weight is not assigned
}
}
I was wondering if it is possible to do the opposite. In particular, casting int to Person would return an instance of Person that its age is assigned and similarly for float.
I know this question may not have an answer. But because I did not find any useful results in my search, I decided to ask it.
P.S. I understand that for a String, the toString method would take care of case 1.
You can't overload the cast operator. Java doesn't support it and probably never will.
To convert a single value to an instance of the desired class, we use static factory methods.
public static Person fromAge(int age) {
return new Person(age);
}
They often return a partially constructed object. In the snippet above, a newly constructed person has only age set: other fields will have their default values.
To do the opposite, we use getters.
public int getAge() {
return age;
}
However, since toString is already there, it makes sense to add other data types as well.
toInt makes no sense when it's applied to me (as an instance of the Person class). It could be my height, my weight, my age, a number of times I went to a bathroom today, etc. I can't represent myself by one int number, neither can a large majority of classes.
On the other hand, toString can do this job pretty well: I can give you (read return) a summary of my hobbies, my biometric information, even my picture. Or I can leave it to the default implementation, which still would satisfactorily represent an object.
You wouldn't use a cast for this just write methods in your Person class to get those values.
public int getAge()
{
return age;
}
etc.
So I've only done this once and I'm unsure whether the approach I did is the appropriate way.
But my approach was a method called typeConverter, which i would give an object as parameter, then you could take that parameter and look what object type it is and then create a new Person, with your value.
Although this approach could cause problems, when your class would have two integer fields. But I think you could find a solution for this, by giving it another parameter that defines, which field you'd want to convert it to.
I'm really sorry for my poor english, but I hope you get the principle.
I'm porting my Minecraft block protections plugin from Bukkit to Sponge so I can add mods with SpongeForge. Bukkit uses a Material enum to identify all the valid block types in the game. All my protections are specified in the config.yml file like this:
CHEST:
Price: 0.75
InteractMember: R
...
With an enum it was very easy to take the keyname in the config file, CHEST, and get the actual enum value with Bukkit.getMaterial(String name). Unfortunately, Sponge refuses to use enums anywhere in their code, so their list of block types is a class containing nothing but static final int constants, which I cannot iterate through or retrieve by name. I tried reflection..
HashMap<String,Integer> blockTypes = new HashMap<String,Integer>();
for(Field field, BlockTypes.class.getFields())
blockMap.put(field.getName(), field.getInt(null));
But I can only get the int values for the constants. I need the constants themselves to use in the code, and I can't find any way to do that without making my own enum wrapper for the static constants:
public enum Blocks {
ACACIA_FENCE(BlockTypes.ACACIA_FENCE),
ACACIA_STEPS(BlockTypes.ACACIA_STEPS),
...
YELLOW_FLOWER(BlockTypes.YELLOW_FLOWER);
private final BlockTypes type;
Blocks(BlockTypes type) {
this.type = type;
}
public BlockTypes getType() { return type; }
public static BlockTypes getByName(String name) {
// retrieve enum by name
}
}
Am I really stuck doing this or is there another way I'm missing?
Sponge doesn't use enums for a reason: since you can add other mods, constants would have to be dynamically added (which isn't possible), and assuming blocks in the vanilla game are the only blocks isn't valid. Support for other mods is one of the main goals of the sponge API.
If your goal is to get a list of all valid BlockTypes in the game, you should use the GameRegistry:
// Getting a list of all types
Collection<BlockType> types = Sponge.getRegistry().getAllOf(BlockType.class)
for (BlockType type : types) {
System.out.println(type.getName());
}
// Getting a single type by name
Optional<BlockType> type = Sponge.getRegistry().getType(BlockType.class, "minecraft:chest");
if (!type.isPresent()) {
// show some error, as the given type doesn't exist
} else {
return type.get();
}
You should be able to use BlockType as a key in a map, or alternatively the String id. You shouldn't need to make an enum for it (and can't do it automatically).
Worth noting that you're using reflection wrong in your example as well, but I don't think it's too important to explain how it needs to be used right now as that's the wrong approach.
I have a large collection of classes. These classes have similar properity names but with different values. For example, I have Spearmen, and Swordsman. These two classes have the same properity names but with different values for them. Now. Suppose I have another class. Entity. How can I call the class's constructor and specifiy which type of unit the entity should be, Without going through a chain of if statements to decicide whether the object is more specifically a type Swordsman or a type Spearmen or an ... Through all my classes.
I can make a simple runnable example but i'm not sure if it is necessary as I have explained myself above
What i can recommend you to do is to create an base class, lets call it hero
public class Hero
{
public HeroType Type { get; set; }
public int Power { get; set;}
public Hero(HeroType type, int power){
this.Type = type;
this.Power = power;
}
....
}
and then create an enum of hero types:
enum HeroType{
Spearmen,
Swordsman,
...
}
Every time you create a new hero you just need to specify his type like so
Hero swordsman = new Hero(HeroType.Swordsman,50)
this way you son't need to create multiple classes and you can save all your objects in the same collection because they all from the same base type.
And if you need a special Hero that has more properties you can create a new class that inherit from the Hero base class.
If you want to find out the class name of an object you could try:
String className = variable.getClass().getSimpleName();
java reflection API will give you methods to accomplish what you need. Object.getClass()....
I am having a data structure (LinkedHashMap) but the problem is that the (second) value should be of variable type since I can put there type String or type int or any primitive type so my question is:
Is there a way to define a variable type for it that can get any value type?
This is what I'm having:
private LinkedHashMap<String, String> keyVal;
I want something like this:
private LinkedHashMap<String, anyValue> keyVal;
private LinkedHashMap<String, Object> keyVal;
You can use Object for that. But do remember that while trying to get data back from this map(sometime later), you may face difficulty in casting the Object to your required data type, as you may not know, what data type is actually present.
Hence, its advisable to avoid such implementations.
You cannot have a generic type be a primitive type. If you want to be able to store anything in your map, you can have the "value" generic type for the map be Object:
private LinkedHashMap<String, Object> keyVal;
You can still store what looks like primitives types due to autoboxing, i.e.
keyVal.put("one", 1);
will place an Integer, even though you specified an int.
No, the closest you can have is Object as a second argument.
Now, I would advise to rethink what you need to accomplish, since this is actually going against what generics were created for.
If you have a bound type and want to maintain some flexibility, then you could use something like <String, ? extends SomeType>.
Mixing several types of Objects in the same data-structure is not advisable in Java (if this is good or bad, is beside the point), but type safety goes a long way in preventing weird errors along the line.
Try to think about how you would deal with this when you actually need to retrieve the objects... will you assume they're Strings? What are you going to do with them?
You say you want to have a Map< String, Primitive type>.
A specified by the JLS, primitives are NumericType or boolean, NumericType are IntegralType or FloatingPointType.
If your need is not primitive but only NumericType, you may use java.lang.Number:
Map< String, Number >
Another way is to define a class Any which hold all the possible attributes:
enum Type {
NULL,
INTEGER,
SHORT,
FLOAT,
...
}
class Any {
private int iValue;
private short sValue;
private float fValue;
...
private Type active = Type.NULL;
public void setInt( int value ) {
iValue = value;
active = Type.INTEGER;
}
public void setFloat( float value ) {
fValue = value;
active = Type.FLOAT;
}
...
public int getInt() {
if( type != Type.INTEGER ) {
throw new ClassCastException( type.name() + " is not an integer" );
}
return iValue;
}
...
}
It's up to you to put some check and throw exception if getInt() is called on a float holder. Everything is possible, transtyping like C language for example.
EDIT
You want String too, and String isn't a primitive.
You have to add the following below private short sValue; into the Any class:
private String sValue;
and the followinf below SHORT, into the Type enum:
STRING,
But, like others says, the best way is to avoid these weak type (fourre-tout in french).
You can use
private LinkedHashMap<String, Object> keyVal;
to leave the second type argument as general as possible.
It allows you to store any object as a value, because every class extends Object.
This leads you to the problem that you don't know what type of things are inside your map - you only know that they are of type Object what means you don't know anything.
So to use these objects again you would have to cast them back to their original type what may cause a runtime exception: ClassCastException.
Generics are about defining data structures for different types with the same code, but if you want to use a generic class you have to parameterize it with its type arguments. This ensures that the type is known at runtime and is the great advantage of generics (avoid ClassCastException).
However, you can still specify a more general type that allows multiple types.
For example, if you define it the following way you can store any object that implements Serializable.
private LinkedHashMap<String, ? extends Serializable> keyVal;
As you can see, this allows you to restrict the permitted types to a common property (i.e., to be a subclass of a more general type). That way, you use the map's values as objects of the more general class, because it's everything you know (and want to know) about the objetcs.
It's better to have a look at:
Generics lesson on Oracle.com.
Care when should use wild cards (?) and you should use Generics.
Using Object in type of LinkedHashMap<String, Object> keyVal; is not recommended.
Like some people said, you could use Object for generic variable type, especially while using generic method or not knowing what data type user would come, like this simple one:
import java.util.Scanner;
public class GenericMethod {
public static void main(String[] args) {
System.out.println("Type something that's yours: ");
Scanner sc = new Scanner(System.in);
Object thing;
thing = sc.next();
isMine(thing);
}
// Generic Method
public static <T> void isMine(T x) {
System.out.println(x + " is mine.");
}
}
I am writing a program to simulate cities from a game called Civilization 4. In order to do this I have several Enums to represent types of terrain, resources, improvements etc for each plot owned by said city.
The problem is I want to program to be compatible with Fan made mods which may add things to the Game that need to be accepted into my independant utility. So I thought of creating a Enum style class to hold the new types defined by the loaded mods (as Enums cannot be changed at runtime) which is created during runtime when the user enters in a mod to be loaded (which is a txt file that is parsed to read the new additions)
So is there a way to simulate Enums that are created and added to at runtime? I take it static member variables cannot be used as they are done before runtime...
You can make a enum implement an interface.
This way you can have your defined values in the enum, but new values can be any class which implements the interface.
An alternative is that you generate or load the enum at runtime using a byte code generator or the Compiler API. I wrote a library to make it easier to take a String and compile&load it.
http://vanillajava.blogspot.co.uk/2010_11_01_archive.html
Well, enums in Java are simply classes where the language guarantees that the set of known objects is known and limited at compile-time. If you want to add new enum literals at runtime, you end up with regular classes.
The beauty of enums is that you can write human readable names in code that are compiled as numbers behind the scenes, because computers like numbers better. Take for example this enum:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Behind the scenes WINTER might be 0 (zero), SPRING is 1 etc.
To replicate this behaviour in runtime code you could create a list of strings, like this:
List<String> seasons;
seasons = new ArrayList<String>();
seasons.add("Winter");
seasons.add("Spring");
...
That way you can reference the items as numbers, such as seasons[1] would equal "Spring".
This answer is just one of many ways to approach this question.
By default, enum types have only a set number of values. The values in an enum type are actually declared as static final, and there's no way to add more on runtime.
That being said, there are other patterns you can use to implement what you want. Let's take a look at using an interface and a registration system. We'll start with the Terrain interface:
public interface Terrain {
int getId();
String getName();
int getSightBonus();
}
Now an enum, DefaultTerrain:
public enum DefaultTerrain implements Terrain {
PLAINS(0, "Plains", 1),
HILLS(1, "Hills", -1),
MOUNTAINS(2, "Mountains", -2);
private int id;
private String name;
private int sightBonus;
private DefaultTerrain(int id, String name, int sightBonus) {
this.id = id;
this.name = name;
this.sightBonus = sightBonus;
}
public int getId() {return id;}
public String getName() {return name;}
public int getSightBonus() {return sightBonus;}
}
And a registration class, which can be either a static utility class or a singleton.
public class TerrainManager {
private static Map<Integer, Terrain> terrainsById = new HashMap<>();
static {
for (DefaultTerrain terrain : DefaultTerrain.values())
register(terrain);
}
public static void register(Terrain terrain) {
Integer id = terrain.getId();
if (terrainsById.contains(terrain.getId()))
throw new IllegalArgumentException("Terrain with id already exists: " + id);
terrainsById.put(id, terrain);
}
public static Terrain getTerrainById(int id) {
return terrainsById.get(id);
}
public static Set<Terrain> getAllTerrains() {
return new HashSet<Terrain>(terrainsById.values());
}
}
This last class is where the magic happens. Presumably the modders will have some kind of identifier in the game's world definition to say "use this tile," right? In this case, I've called it an integer, id, but really it could be any type, just modify the Map accordingly. In the map-loading code, just use the ID in the world definition to look up the Terrain. When a modder adds a new Terrain, they just need to implement Terrain and register it with TerrainManager.
The static initializer makes sure that your DefaultTerrain objects are added before anything else is added. If you use a singleton, this could be put into the class constructor instead.
Use this pattern for your different enum types that you want users to add to. You could also use it for pretty much any other type as well besides enum.
You will need CGLIB, http://cglib.sourceforge.net/