Java custom types and subsets of types

I have a bunch of unit types:
package units;

public enum Units {

Open in new window

and unit categories:
public enum TemperatureUnits = { FAHRENHEIT, CELSIUS, KELVIN }

Open in new window

public enum LengthUnits = {  FEET, INCHES, MILES, METERS }

Open in new window

Problem is as you can see all of my values are defined twice, and I'm sure that's going to lead to endless confusion.

I've also considered using a hierarchy of classes:


    TemperatureUnits extends Units
    LengthUnits extends Units

        Fahrenheit extends TemperatureUnits
        Celsius extends TemperatureUnits
        Kelvin extends TemperatureUnits

        Inches extends LengthUnits
        Feet extends LengthUnits
        Miles extends LengthUnits
        Meters extends LengthUnits

Then I can do:
double value = myMeasurement.getValueAs(new Meters());

Open in new window

but it seems silly to create a class instance new Meters() when all I really need is the class type.

I'd like to be able to specify what range of units a method can accept:
    public double getValueAs(LengthUnits u) {
    public double getValueAs(TemperatureUnits u) {
    public double manipulate(Units u) {

Open in new window

Any suggestions?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Although you can't extend an enum to create a hierarchy you can implement an interface.

So how about this structure:

public interface Units {

public enum LengthUnits implements Units {

	public double convertToMeters(double value) {
                // Yes this math is a bit off...
		switch (this) {
			case FEET: return value / 3.0 ;
			case INCHES: return value / 36.0 ;
			case MILES: return value * 8000.0 / 5.0 ;
			default: throw new IllegalStateException("Unknown value in enum") ;

public enum TemperatureUnits implements Units {

Open in new window

Then you can write code like this:

            Units example = LengthUnits.FEET ;
            LengthUnits other = LengthUnits.INCHES ;

                // Convert 100 inches to meters
                double meters = LengthUnits.INCHES.convertToMeters(100)  ;

together with your methods taking Units or LengthUnits etc.

You can also define methods in the Units interface, which would need to be implemented by the enums - just like for a class - if you'd like to be able to call a method on a Units object.

Any good?

deleydAuthor Commented:
Hmm, interesting.

How could I use this to pass a parameter to a method specifying what unit type I would like the return value to be in? The method would be in a different class.

Some methods can accept any unit, while other methods want a specific subtype of unit (as in Length, Temperature,...)
The examples you posted earlier could all be written now.
If they're in different classes it would look like this:

public class A { public double getValueAs(LengthUnits u) ; }
public class B { public double getValueAs(TemperatureUnits u) ; }
public class C { public double manipulate(Units u) ; }

Here are some example calls:

A a = new A() :
a.getValueAs(LengthUnits.INCHES) ;

// Or we can use a variable if we prefer:
LengthUnits unitsForThisCalc = LengthUnits.MILES ;
a.getValueAs(unitsForThisCalc) ;

// This won't compile - it only takes LengthUnits
a.getValuesAs(TemperatureUnits.CELSIUS) ;

// But these are all fine, since they accept any Units
C c = new C() ;
c.manipulate(TempatureUnits.CELSIUS) ;
c.manipulate(LengthUnits.FEET) ;

deleydAuthor Commented:
Thank you I think I see it now, I'll give it a try.

Somewhat related, is it true with Generics there's no way to create a Generic type T and pass parameters to the constructor? As in:
class MyClass<T>

public T myMethod() {
    int p1 = 5;
    String p2 = "Hello";

    T t = new T(p1,p2);  //not possible...
    return (t);

Open in new window

I've seen ways of creating type T passing no parameters to the constructor, but I don't think it's possible to create type T with parameters. Is that correct that it can't be done?
Yeah I don't think that's possible.
I'd be surprised if you can even call the default constructor (the one with no parameters).

I think the root issue is that in Java, the generic information is all discarded at runtime.
So there's no "T" left to instantiate at runtime (it's only available at compile time - but clearly the runtime would need it as well to call a constructor on the right class).

You should however be able to get the desired behavior through reflection.  You'd need to pass in both "T" and the class of T as a String.  Then you can call the constructor for that class, passing parameters etc.  The code's a bit ugly and verbose but should work fine.  Here's a sample tutorial on how to do this:

You'd end up instantiating the class with something like

MyClass<Integer, Integer.class.toString()) <-- second parameter passes in the name of the class so you can instantiate it at runtime.  The first parameter you'd use for type checking like normal.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.