Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Java custom types and subsets of types

Posted on 2014-07-22
5
168 Views
Last Modified: 2014-07-23
I have a bunch of unit types:
package units;

public enum Units {
  FAHRENHEIT,
  CELSIUS,
  KELVIN,
  FEET,
  INCHES,
  MILES,
  METERS;
}

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:

Units

    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?
0
Comment
Question by:deleyd
  • 3
  • 2
5 Comments
 
LVL 27

Assisted Solution

by:dpearson
dpearson earned 500 total points
ID: 40212196
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 {
	FEET, INCHES, MILES ;

	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 {
	CELSIUS, FAHRENHEIT, KELVIN ;
}

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?

Doug
0
 

Author Comment

by:deleyd
ID: 40212261
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,...)
0
 
LVL 27

Assisted Solution

by:dpearson
dpearson earned 500 total points
ID: 40212281
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) ;

Doug
0
 

Author Comment

by:deleyd
ID: 40212687
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?
0
 
LVL 27

Accepted Solution

by:
dpearson earned 500 total points
ID: 40212836
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:
http://tutorials.jenkov.com/java-reflection/constructors.html

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.

Doug
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
how to see all occupied ports on windows 10 laptop 15 75
spring jars download 1 35
eclipse buid path vs tomcat lib path 10 34
Java: anonymous class 4 29
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
Viewers will learn about the different types of variables in Java and how to declare them. Decide the type of variable desired: Put the keyword corresponding to the type of variable in front of the variable name: Use the equal sign to assign a v…

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question