This is how I add a line to my chart at the moment. This is the abstract class for an arbitrry funciton I want to display:
public abstract class ArbitraryFunction implements
ValueProvider<ArbitraryFunctionData, Double> {
private String field;
public abstract Double f(Double x);
/**
* Constructor
*/
public ArbitraryFunction(String field) {
this.field = field;
}
#Override
public Double getValue(ArbitraryFunctionData object) {
return object.get(field);
}
#Override
public void setValue(ArbitraryFunctionData object, Double value) {
object.put(field, value);
}
#Override
public String getPath() {
return field;
}
}
This is how the chart is created:
ArbitraryFunction f1 = new ArbitraryFunction("f1") {
#Override
public Double f(Double x) {
return Math.sin(x);
}
};
functionMap.put(f1.getPath(), f1);
// collects the data of the functions and adds them to the store
for (Double x = 0.0; x <= 2 * Math.PI; x = x + 0.1) {
ArbitraryFunctionData d = new ArbitraryFunctionData();
d.setName("" + x);
for (Map.Entry<String, ArbitraryFunction> entry : functionMap.entrySet()) {
ArbitraryFunction tmp = entry.getValue();
d.put(tmp.getPath(), tmp.f(x));
}
store.add(d);
}
chart.setStore(store);
verticalAxis.setPosition(Position.LEFT);
verticalAxis.addField(f1);
verticalAxis.setSteps(2);
verticalAxis.setMinorTickSteps(5);
chart.addAxis(verticalAxis);
This works so far as intended. The graph shows my lines as it should do it and the vertical axis is correct too. But I have problems drawing the horizontal axis since I don't know what I need to give horizontalAxis.addField( ??? ). I've tried a few things, but nothing worked.
Does anyone know how I need to set up the horizontal axis?
What do you want the horizontal axis value to be? Is it another NumericAxis - does each data point have a x value that it should be drawn on? Each d in your loop has a String name and some value - perhaps you want a CategoryAxis<ArbitraryFunctionData, String> that just draws those name values?
Looks like I misunderstood earlier - your Function objects are just used in setup, not in changing how you plot data
I'm still not sure what you are after, but it sounds like you mostly want to plot some lines. Each data point (ArbitraryFunctionData?) seems to have Y values for each function being used, and a title, but no X values, so there is no way to plot each point as (X,Y) with two numeric axes, just as (name, Y) using a CategoryAxis and a NumericAxis. This would end up more or less like this sample: http://www.sencha.com/examples/#ExamplePlace:linechart - strings along the bottom, and numbers along the side.
Here's take one, build mostly off of the idea/structure you already have:
public class FunctionPlotter implements EntryPoint {
public static class ArbitraryFunctionData {
private double xValue;
private Map<String, Double> yValues = new HashMap<String, Double>();
public double get(String key) {
return yValues.get(key);
}
public void put(String key, double yValue) {
yValues.put(key, yValue);
}
public double getXValue() {
return xValue;
}
public void setxValue(double xValue) {
this.xValue = xValue;
}
}
public interface AFDProperties extends PropertyAccess<ArbitraryFunctionData> {
//xvalue is unique, key off of that
#Path("xValue")
ModelKeyProvider<ArbitraryFunctionData> key();
//automatic ValueProvider generation for the get/setXValue methods
ValueProvider<ArbitraryFunctionData, Double> xValue();
}
/**
* This is really doing two different jobs at once - wasn't quite was I was trying to suggest in
* that other question. See the second version of this for clarification...
*/
public static abstract class ArbitraryFunction implements ValueProvider<ArbitraryFunctionData, Double> {
private final String field;
public ArbitraryFunction(String field) {
this.field = field;
}
public abstract Double f(Double x);
#Override
public Double getValue(ArbitraryFunctionData object) {
return object.get(field);
}
#Override
public void setValue(ArbitraryFunctionData object, Double value) {
object.put(field, value);
}
#Override
public String getPath() {
return field;
}
}
#Override
public void onModuleLoad() {
Viewport vp = new Viewport();
Set<ArbitraryFunction> functions = new HashSet<ArbitraryFunction>();
ArbitraryFunction f1 = new ArbitraryFunction("f1") {
#Override
public Double f(Double x) {
return Math.sin(x);
}
};
functions.add(f1);
AFDProperties props = GWT.create(AFDProperties.class);
ListStore<ArbitraryFunctionData> store = new ListStore<ArbitraryFunctionData>(props.key());
// collects the data of the functions and adds them to the store
for (Double x = 0.0; x <= 2 * Math.PI; x = x + 0.1) {
// Create one data object, and set the X value, since that is the same for all Y values
ArbitraryFunctionData d = new ArbitraryFunctionData();
d.setxValue(x);
// For each function, set the corresponding Y value
for (ArbitraryFunction func : functions) {
d.put(func.getPath(), func.f(x));
}
store.add(d);
}
Chart<ArbitraryFunctionData> chart = new Chart<ArbitraryFunctionData>();
chart.setStore(store);
//Y-axis
NumericAxis<ArbitraryFunctionData> verticalAxis = new NumericAxis<ArbitraryFunctionData>();
verticalAxis.setPosition(Position.LEFT);
verticalAxis.addField(f1);//needs to know this field to properly set the range of values
//f2, f3, etc
verticalAxis.setSteps(2);
verticalAxis.setMinorTickSteps(5);
chart.addAxis(verticalAxis);
// X-Axis, this time reading from the xValue, not the series of ValueProviders
NumericAxis<ArbitraryFunctionData> horizAxis = new NumericAxis<ArbitraryFunctionData>();
horizAxis.setPosition(Position.BOTTOM);
horizAxis.addField(props.xValue());//same value for all
horizAxis.setSteps(2);
horizAxis.setMinorTickSteps(5);
chart.addAxis(horizAxis);
for (ArbitraryFunction func : functions) {
LineSeries<ArbitraryFunctionData> line = new LineSeries<ArbitraryFunctionData>();
// configure x axis
line.setXAxisPosition(Position.BOTTOM);//where is it
line.setXField(props.xValue());//what value do i use
// configure y axis
line.setYAxisPosition(Position.LEFT);//where is it
line.setYField(func);//what value do i use
//probably want to customized per func
line.setStroke(RGB.GRAY);
line.setStrokeWidth(2);
chart.addSeries(line);
}
vp.setWidget(chart);
RootPanel.get().add(vp);
}
}
And here's take two, this time with much simpler data and actually making the Function its own ValueProvider, and keeping the data dirt simple - just a double! Note that the ValueProvider is the function, and we never call getValue ourselves, we let the axis/series do it for us! Added a second function here to demonstrate that it does actually work.
public class FunctionPlotter implements EntryPoint {
/**
* Where did everything go? We're just making a ValueProvider now that can handle
* each number as a value, and working out the details from there
*
* For fun, added per-function coloring too
*/
public abstract static class Function implements ValueProvider<Double, Double> {
private final String name;
private final Color color;
public Function(String name, Color color) {
this.name = name;
this.color = color;
}
#Override
public abstract Double getValue(Double object);
#Override
public String getPath() {
return name;
}
#Override
public void setValue(Double object, Double value) {
//no-op
}
public Color getColor() {
return color;
}
}
#Override
public void onModuleLoad() {
Viewport vp = new Viewport();
Set<Function> functions = new HashSet<Function>();
Function f1 = new Function("f1", RGB.RED) {
#Override
public Double getValue(Double x) {
return Math.sin(x);
}
};
functions.add(f1);
Function f2 = new Function("f2", RGB.BLACK) {
#Override
public Double getValue(Double x) {
return Math.cos(x);
}
};
functions.add(f2);
//Turns out Stores can hold any objects - should probably factor out this key provider for reuse...
ListStore<Double> store = new ListStore<Double>(new ModelKeyProvider<Double>() {
#Override
public String getKey(Double item) {
return item.toString();
}
});
// collects the data of the functions and adds them to the store
for (Double x = 0.0; x <= 2 * Math.PI; x = x + 0.1) {
store.add(x);
}
Chart<Double> chart = new Chart<Double>();
chart.setStore(store);
//Y-axis
NumericAxis<Double> verticalAxis = new NumericAxis<Double>();
verticalAxis.setPosition(Position.LEFT);
for (Function func : functions) {
verticalAxis.addField(func);//needs to know this field to properly set the range of values
}
verticalAxis.setSteps(2);
verticalAxis.setMinorTickSteps(5);
chart.addAxis(verticalAxis);
// X-Axis, this time reading from the xValue, not the series of ValueProviders
NumericAxis<Double> horizAxis = new NumericAxis<Double>();
horizAxis.setPosition(Position.BOTTOM);
horizAxis.addField(new IdentityValueProvider<Double>());//magic value provider that returns the same string
horizAxis.setSteps(2);
horizAxis.setMinorTickSteps(5);
chart.addAxis(horizAxis);
for (Function func : functions) {
LineSeries<Double> line = new LineSeries<Double>();
// configure x axis
line.setXAxisPosition(Position.BOTTOM);//where is it
line.setXField(new IdentityValueProvider<Double>());//what value do i use
// configure y axis
line.setYAxisPosition(Position.LEFT);//where is it
line.setYField(func);//what value do i use
//probably want to customized per func
line.setStroke(func.getColor());
line.setStrokeWidth(2);
chart.addSeries(line);
}
vp.setWidget(chart);
RootPanel.get().add(vp);
}
}
Related
Question Summary
Is there any way of updating the probabilities within an existing instance of the class EnumeratedIntegerDistribution without creating an entirely new instance?
Background
I'm trying to implement a simplified Q-learning style demonstration using an android phone. I need to update the probabilities for each item with each loop through the learning process. Currently I am unable to find any method accessible from my instance of enumeratedIntegerDistribution that will let me reset|update|modify these probabilities. Therefore, the only way I can see to do this is to create a new instance of EnumeratedIntegerDistribution within each loop. Keeping in mind that each of these loops is only 20ms long, it is my understanding that this would be terribly memory inefficient compared to creating one instance and updating the values within the existing instance. Is there no standard set-style methods to update these probabilities? If not, is there a recommended workaround (i.e. using a different class, making my own class, overriding something to make it accessible, etc.?)
A follow up would be whether or not this question is a moot effort. Would the compiled code actually be any more/less efficient by trying to avoid this new instance every loop? (I'm not knowledgeable enough to know how compilers would handle such things).
Code
A minimal example below:
package com.example.mypackage.learning;
import android.app.Activity;
import android.os.Bundle;
import org.apache.commons.math3.distribution.EnumeratedIntegerDistribution;
public class Qlearning extends Activity {
private int selectedAction;
private int[] actions = {0, 1, 2};
private double[] weights = {1.0, 1.0, 1.0};
private double[] qValues = {1.0, 1.0, 1.0};
private double qValuesSum;
EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);
private final double alpha = 0.001;
int action;
double reward;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
while(true){
action = determineAction();
reward = determineReward();
learn(action, reward);
}
}
public void learn(int action, double reward) {
qValues[selectedAction] = (alpha * reward) + ((1.0 - alpha) * qValues[selectedAction]);
qValuesSum = 0;
for (int i = 0; i < qValues.length; i++){
qValuesSum += Math.exp(qValues[i]);
}
weights[selectedAction] = Math.exp(qValues[selectedAction]) / qValuesSum;
// *** This seems inefficient ***
EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);
}
}
Please don't focus on the absence of the determineAction() or determineReward() methods, as this is simply a minimal example. You could easily just sub in fixed values there (e.g. 1, and 1.5) if you wanted a working example.
Also, I'm well aware of the infinite while loop that would be troublesome for a GUI, but again, just trying to reduce the code I have to show here to get the point across.
Edit:
In response to a comment I'm posting what I had for a similar class below. Note I haven't used this in over a year and things may be broken. Just posting for reference:
public class ActionDistribution{
private double reward = 0;
private double[] weights = {0.34, 0.34, 0.34};
private double[] qValues = {0.1, 0.1, 0.1};
private double learningRate = 0.1;
private double temperature = 1.0;
private int selectedAction;
public ActionDistribution(){}
public ActionDistribution(double[] weights, double[] qValues, double learningRate, double temperature){
this.weights = weights;
this.qValues = qValues;
this.learningRate = learningRate;
this.temperature = temperature;
}
public int actionSelect(){
double sumOfWeights = 0;
for (double weight: weights){
sumOfWeights = sumOfWeights + weight;
}
double randNum = Math.random() * sumOfWeights;
double selector = 0;
int iterator = -1;
while (selector < randNum){
try {
iterator++;
selector = selector + weights[iterator];
}catch (ArrayIndexOutOfBoundsException e){
Log.e("abcvlib", "weight index bound exceeded. randNum was greater than the sum of all weights. This can happen if the sum of all weights is less than 1.");
}
}
// Assigning this as a read-only value to pass between threads.
this.selectedAction = iterator;
// represents the action to be selected
return iterator;
}
public double[] getWeights(){
return weights;
}
public double[] getqValues(){
return qValues;
}
public double getQValue(int action){
return qValues[action];
}
public double getTemperature(){
return temperature;
}
public int getSelectedAction() {
return selectedAction;
}
public void setWeights(double[] weights) {
this.weights = weights;
}
public void setQValue(int action, double qValue) {
this.qValues[action] = qValue;
}
public void updateValues(double reward, int action){
double qValuePrev = getQValue(action);
// update qValues due to current reward
setQValue(action,(learningRate * reward) + ((1.0 - learningRate) * qValuePrev));
// update weights from new qValues
double qValuesSum = 0;
for (double qValue : getqValues()) {
qValuesSum += Math.exp(temperature * qValue);
}
// update weights
for (int i = 0; i < getWeights().length; i++){
getWeights()[i] = Math.exp(temperature * getqValues()[i]) / qValuesSum;
}
}
public double getReward() {
return reward;
}
public void setReward(double reward) {
this.reward = reward;
}
}
Unfortunately it is not possible to update the existing EnumeratedIntegerDistribution. I have had similar issue in the past and I ended up re-creating the instance everytime I need to update the chances.
I won't worry too much about the memory allocations as those will be short-lived objects. These are micro-optimisations you should not worry about.
In my project I did implement a cleaner way with interfaces to create instances of these EnumeratedDistribution class.
This is not the direct answer but might guide you in the right direction.
public class DistributedProbabilityGeneratorBuilder<T extends DistributedProbabilityGeneratorBuilder.ProbableItem> {
private static final DistributedProbabilityGenerator EMPTY = () -> {
throw new UnsupportedOperationException("Not supported");
};
private final Map<Integer, T> distribution = new HashMap<>();
private DistributedProbabilityGeneratorBuilder() {
}
public static <T extends ProbableItem> DistributedProbabilityGeneratorBuilder<T> newBuilder() {
return new DistributedProbabilityGeneratorBuilder<>();
}
public DistributedProbabilityGenerator build() {
return build(ProbableItem::getChances);
}
/**
* Returns a new instance of probability generator at every call.
* #param chanceChangeFunction - Function to modify existing chances
*/
public DistributedProbabilityGenerator build(Function<T, Double> chanceChangeFunction) {
if (distribution.isEmpty()) {
return EMPTY;
} else {
return new NonEmptyProbabilityGenerator(createPairList(chanceChangeFunction));
}
}
private List<Pair<Integer, Double>> createPairList(Function<T, Double> chanceChangeFunction) {
return distribution.entrySet().stream()
.map(entry -> Pair.create(entry.getKey(), chanceChangeFunction.apply(entry.getValue())))
.collect(Collectors.toList());
}
public DistributedProbabilityGeneratorBuilder<T> add(int id, T item) {
if (distribution.containsKey(id)) {
throw new IllegalArgumentException("Id " + id + " already present.");
}
this.distribution.put(id, item);
return this;
}
public interface ProbableItem {
double getChances();
}
public interface DistributedProbabilityGenerator {
int generateId();
}
public static class NonEmptyProbabilityGenerator implements DistributedProbabilityGenerator {
private final EnumeratedDistribution<Integer> enumeratedDistribution;
NonEmptyProbabilityGenerator(List<Pair<Integer, Double>> pairs) {
this.enumeratedDistribution = new EnumeratedDistribution<>(pairs);
}
#Override
public int generateId() {
return enumeratedDistribution.sample();
}
}
public static ProbableItem ofDouble(double chances) {
return () -> chances;
}
}
Note - I am using EnumeratedDistribution<Integer>. You can easily change it to be EnumuratedIntegerDistribution.
The way I use the above class is as follows.
DistributedProbabilityGenerator distributedProbabilityGenerator = DistributedProbabilityGeneratorBuilder.newBuilder()
.add(0, ofDouble(10))
.add(1, ofDouble(45))
.add(2, ofDouble(45))
.build();
int generatedObjectId = distributedProbabilityGenerator.generateId();
Again, this is not a direct answer to your question but more of a pointer towards how you can use these classes in a better way.
I develop a java application to generate a 3D object as a .obj file. I would like to visualize this object in a viewer3D of my application before exporting it but I only have a java object containing a list of faces and vertices of my 3D object. From my list of faces and vertices I would like to create a javafx type Shape or MeshView.
In fact, I'm trying to convert my java object into a javafx 3D object.
I have implement a Face Object :
public class Face {
private int id, idVertice1, idVertice2, idVertice3;
public Face(int idVertice1, int idVertice2, int idVertice3) {
this.idVertice1 = idVertice1;
this.idVertice2 = idVertice2;
this.idVertice3 = idVertice3;
}
public int getIdVertice1() {
return idVertice1;
}
public int getIdVertice2() {
return idVertice2;
}
public int getIdVertice3() {
return idVertice3;
}
}
I have too an Vertices class :
public class Vertices {
private double x, y, z;
public Vertices(double line, double height, double column) {
x = column;
y = height;
z = line;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
And her is my Mesh class :
public class Mesh {
private TreeMap<Double, TreeMap<Double, Vertices>> setOfVertices;
private LinkedList<Face> setOfFaces;
public Mesh() {
setOfFaces = new LinkedList();
setOfVertices = new TreeMap<Double, TreeMap<Double, Vertices>>();
}
public TreeMap getSetOfVertices() {
return setOfVertices;
}
public LinkedList<Face> getSetOfFaces() {
return setOfFaces;
}
How convert this Mesh object to a JavaFX mesh object into my viewer 3D (my viewer 3D is a subScene) :
Is this possible?
I was looking for some good patterns to have possibility to express distance in different units. I found Martin Fowler article about quantities and I programmed something like:
Here is Distance class ( I think it is not necessery to make it abstract ):
public class Distance {
double mValue;
DistanceUnit mUnit;
public Distance(double value, DistanceUnit unit){
this.mValue = value;
this.mUnit = unit;
}
public Distance toUnit(DistanceUnit unit){
double factor = this.mUnit.getMetresFactor()/unit.getMetresFactor();
double newValue = this.mValue * factor;
Distance distance = new Distance(newValue, unit);
return distance;
}
#Override
public String toString(){
return String.valueOf(mValue);
}
}
It looks very simple. Conversion toUnit is based on DistanceUnit method getMetresFactor. Each Unit class implements DistanceUnit interface and has method getMetresFactor() like:
public interface DistanceUnit {
double getMetresFactor();
}
public class Inch implements DistanceUnit {
#Override
public double getMetresFactor() {
return 0.0254;
}
}
public class Kilometer implements DistanceUnit {
#Override
public double getMetresFactor() {
return 1000.0;
}
}
And the usage is for example:
Distance inches = new Distance(300.0, new Inch());
Distance kilometres = inches.toUnit(new Kilometres());
So it returns the correct value.
Is it good way to store distance in this way? Maybe you know some weaknesses of this approach. Maybe is a good idea to use here a FactoryMethod pattern to construct distance based on unit shortcut like "m" for meter. I think about the amount of classes if I would have a lot of units... Is it good idea to have factory which return factor of meters based on unit name? There will be no classes for units then?
Hm, i would use enum instead of DistanceUnit classes, because there is no different instances of them.
You can set a value to enum like here
and then call enum.getValue() instead of unit.getMetresFactor().
Also it is a little bit confusing, is the mValue value in meters or in DistanceUnit's, if in meters, you must have
double factor = unit.getMetresFactor();
there
Ok and now with any convertion function support:
import java.util.HashMap;
import java.util.Map;
public abstract class MeasureConverter {
public abstract double valueToBasic(double value);
public abstract double basictoValue(double basic);
/**
*
*/
public static Map<String, MeasureConverter> converters;
public static Map<String, MeasureConverter> getConverters() {
if (converters == null) {
converters = new HashMap<String, MeasureConverter>();
converters.put("kilo", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value * 1000;
}
#Override
public double basictoValue(double basic) {
return basic / 0.001;
}
});
// taking the basic temperature value in kelvines
converters.put("kelvine", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value;
}
#Override
public double basictoValue(double basic) {
return basic;
}
});
converters.put("celsius", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value + 273.15;
}
#Override
public double basictoValue(double basic) {
return basic - 273.15;
}
});
converters.put("faren", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value * 1.8 - 459.67 ; // or whatever is there?
}
#Override
public double basictoValue(double basic) {
return (basic + 459.67 ) / 1.8;// or whatever is there?
}
});
}
return converters;
}
}
And then :
import java.util.Objects;
public class MeasurePattern {
double value;
String name;
public MeasurePattern(double value, String name) {
this.value = value;
this.name = name;
}
#Override
public String toString() {
return "MeasurePattern{" + "value=" + value + ", name=" + name + '}';
}
#Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32));
hash = 29 * hash + Objects.hashCode(this.name);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MeasurePattern other = (MeasurePattern) obj;
if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
public MeasurePattern convertTo(String converter) {
MeasureConverter mycon = MeasureConverter.getConverters().get(name);
MeasureConverter hiscon = MeasureConverter.getConverters().get(converter);
double basic = mycon.valueToBasic(value);
double hisValue = hiscon.basictoValue(basic);
return new MeasurePattern(hisValue, converter);
}
public static void main(String[] args) {
//trying temperatures;
MeasurePattern temp = new MeasurePattern(10, "celsius");
MeasurePattern kelvine = temp.convertTo("kelvine");
MeasurePattern faren = kelvine.convertTo("faren");
MeasurePattern cels = faren.convertTo("celsius");
System.out.println("kelvine = " + kelvine);
System.out.println("faren = " + faren);
System.out.println("cels = " + cels);
}
}
Output:
kelvine = MeasurePattern{value=283.15, name=kelvine}
faren = MeasurePattern{value=412.67777777777775, name=faren}
cels = MeasurePattern{value=9.999999999999943, name=celsius}
You can implement it analog to java.util.concurrent.TimeUnit as an enum. E.g.
public enum DistanceUnit {
KILOMETER {
#Override
protected double conversionFactor(DistanceUnit toDistanceUnit) {
switch (toDistanceUnit) {
case KILOMETER:
return 1;
case MILE:
return 0.621371;
default:
throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
}
}
},
MILE {
#Override
protected double conversionFactor(DistanceUnit toDistanceUnit) {
switch (toDistanceUnit) {
case KILOMETER:
return 1.60934;
case MILE:
return 1;
default:
throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
}
}
};
public double toDistance(double value, DistanceUnit targetDistance) {
return value * conversionFactor(targetDistance);
}
protected abstract double conversionFactor(DistanceUnit toDistanceUnit);
}
change your Distance class to
public class Distance {
double mValue;
DistanceUnit mUnit;
public Distance(double value, DistanceUnit unit){
this.mValue = value;
this.mUnit = unit;
}
public Distance toUnit(DistanceUnit unit){
double newValue = mUnit.toDistance(mValue, unit);
Distance distance = new Distance(newValue, unit);
return distance;
}
#Override
public String toString(){
return String.valueOf(mValue);
}
}
and the client code will look very clear
public class Main {
public static void main(String[] args) {
Distance kilometers = new Distance(265.35, DistanceUnit.KILOMETER);
Distance miles = kilometers.toUnit(DistanceUnit.MILE);
System.out.println(miles);
}
}
will output
164.88079485000003
Java convention does not use a m(ember) prefix (but say a this. qualification), and convention is taken quite seriously in java (as opposed to C++ for instance).
toString misses the unit.
JScience offers more, the capability to calculate in different units, m/s², and so on. Your class is a nice abstraction. But in a wider context, you probably will want to have math operations, powers of units (-2 for s above).
Take a look at your own usage ideas first:
(Just garbage:)
U speedUnit = U.of(Distance::km, Time::h.up(-1));
double timeInS = U.mile(40).div(speedunit(30)).in(U.m);
I think you should use the "Strategy" pattern.
An interface:
public interface DistanceUnit {
double getDistance(int metres);
}
The Inch class:
public class Inch implements DistanceUnit {
#Override
public double getDistance(int metres) {
return meters*39; //do conversion here
}
}
The Kilometers class:
public class Kilometres implements DistanceUnit {
#Override
public double getDistance(int metres) {
return meters/1000; //do conversion here
}
}
Then:
List<DistanceUnit> distanceList = new ArrayList<>();
distanceList.add(new Inch());
distanceList.add(new Kilometres());
for (DistanceUnit item : distanceList) {
System.out.println(item.getDistance(1000));
}
If I understand you, I think it is a simple and clean solution.
You can follow this model for conversion between others units.
I am trying to understand extending inner classes in Java. I have read around but nothing I found quite answers my question. So here goes...
I have...
public class Pie{
protected Slice[] slices;
// Pie constructor
public Pie(int n){
sliceGenerator(n)
}
private void sliceGenerator(int n){
slices = new Slice[n];
final float sweepAngle = 360.0f/(float)n;
float startAngle = 0;
for (int i=0;i<n;i++){
slices[i] = new Slice(startAngle);
startAngle += sweepAngle;
}
}
#Override
public String toString(){
for (Slice s:slices){
s.toString();
}
}
// Inner class...
public class Slice{
public Slice(float startAngle){
//set some private fields based on startAngle and generic pie
}
#Override
public String toString(){
return **string based on private fields**
}
}
}
Then I extend this...
public class ApplePie extends Pie{
protected Slice[] slices;
// Apple Pie constructor
public ApplePie(int n){
super(n);
}
// Inner class...
public class Slice extends Pie.Slice{
public Slice(float startAngle){
super(startAngle);
//set some **additional** private fields based on startAngle **specific to apple pie** appleness or something
}
#Override
public String toString(){
return **string based on apple pie specific private fields**
}
}
}
Now, when I make an Apple pie and call its toString method, like so...
ApplePie ap = new ApplePie(8);
System.out.println(ap.toString());
I do not get information about the apple pie slices, but information about the pie slices. It ignores my toString override, or more likely ignores my apple pie Slice. How can I arrange it such that apple pie slices refer to ApplePie?
Any help much appreciated! Sorry for pie references - it is the actual class I am working with...
I've changed your code to meet your requirements.
Your super class Pie is about to create a new instance of Slice, but the child class ApplePie's Slice does not override the Slice method of its super class'.
I added the functions below to enable the child class to create its own Slice.
protected void newSliceArray(int n) {
slices = new Slice[n];
}
protected Slice newSlice(float startAngle) {
return new Slice(startAngle);
}
Pie.java:
public class Pie {
private int a = 1;
protected Slice[] slices;
// Pie constructor
public Pie(int n) {
sliceGenerator(n);
}
private void sliceGenerator(int n) {
newSliceArray(n);
final float sweepAngle = 360.0f / n;
float startAngle = 0;
for (int i = 0; i < n; i++) {
slices[i] = newSlice(startAngle);
startAngle += sweepAngle;
}
}
protected void newSliceArray(int n) {
slices = new Slice[n];
}
protected Slice newSlice(float startAngle) {
return new Slice(startAngle);
}
#Override
public String toString() {
String t = "";
for (Slice s : slices) {
t += s.toString();
}
return t;
}
// Inner class...
public class Slice {
public Slice(float startAngle) {
// set some private fields based on startAngle and generic pie
}
#Override
public String toString() {
return "" + a;
}
}
}
ApplePie.java:
public class ApplePie extends Pie {
private int b = 2;
// protected Slice[] slices;
// Apple Pie constructor
public ApplePie(int n) {
super(n);
}
protected void newSliceArray(int n) {
slices = new Slice[n];
}
protected Slice newSlice(float startAngle) {
return new Slice(startAngle);
}
// Inner class...
public class Slice extends Pie.Slice {
public Slice(float startAngle) {
super(startAngle);
// set some **additional** private fields based on startAngle **specific to apple pie**
// appleness or something
}
#Override
public String toString() {
return b + "";
}
}
}
Test:
public static void main(String[] args) {
ApplePie ap = new ApplePie(8);
System.out.println(ap.toString());
}
The code will print 22222222
In your superclass, you are creating and storing Pie.Slice objects:
private void sliceGenerator(int n){
slices = new Slice[n];
final float sweepAngle = 360.0f/(float)n;
float startAngle = 0;
for (int i=0;i<n;i++){
slices[i] = new Slice(startAngle);
startAngle += sweepAngle;
}
}
These are the same objects being used by Pie.toString (which ApplePie doesn't override by the way).
Extending Pie with ApplePie and extending Pie.Slice with ApplePie.Slice doesn't change this. The new Slice(startAngle) in the above code does not magically switch to instantiating something different.
Aside from that, your Pie.toString() isn't returning anything - it shouldn't even compile:
#Override
public String toString(){
for (Slice s:slices){
s.toString();
}
}
I'm guessing you want to return a String representing all the slices. This would be a quick solution for example:
#Override
public String toString() {
return Arrays.toString(slices);
}
(Arrays.toString is just a utility method to get a String representing of an array.)
The answer lies within your program. When you instantiate Slice class, it gives call to the super class and invokes sliceGenerator. This method internally creates instances of Pie.Slice and not ApplePie.Slice. To get around this, make sliceGenerator method protected and override it in Apple.Slice class. Create the instances of Apple.Slice and it should work.
Is it possible to get a Field through Java reflection if I have the field itself? It's a primitive float (public, no problem). I don't want to use its name as a String.
Example:
public class TVset {
public float voltageA;
public float voltageB;
public float voltageC;
public TVset(...) {...} // constructor
public void function() {...} // it changes voltages
}
class Voltmeter{
Object theObject;
Field theField;
Voltmeter(Object obj) {
theObject = obj;
Class theFieldClass = obj.getClass();
Class theContainerClass = theFieldClass.getDeclaringClass();
Field theField = ??? // <-- here I don't want to use a String
}
float getVoltage() {
return theField.getFloat(theObject);
}
}
TVset tv1 = new TVset(...);
TVset tv2 = new TVset(...);
Voltmeter meter = new Voltmeter(tv1.voltageB);
meter.getVoltage();
tv1.function();
meter.getVoltage(); <- should reflect the changed voltage
tv1.function();
meter.getVoltage(); <- should reflect the changed voltage
...
The effect is similar to passing the float by reference, but without wrapping it into a wrapper class.
I need to measure different voltages on different TV sets, just by changing the line:
Voltmeter meter = new Voltmeter(tv1.voltageB);
to something else, like:
Voltmeter meter = new Voltmeter(tv2.voltageA);
Is it possible to do it with reflection?
Thx
To use reflection you have to use a String. Instead of using a float you can use an object to wrap mutable float or a simple float[1];
BTW I wouldn't use float unless you have a really good reason, double suffers far less rounding error.
public class TVset {
public double[] voltageA = { 0.0 };
public double[] voltageB = { 0.0 };
public double[] voltageC = { 0.0 };
}
class Voltmeter{
final double[] theField;
Voltmeter(double[] theField) {
this.theField = theField;
}
double getVoltage() {
return theField[0];
}
}
// works just fine.
Voltmeter meter = new Voltmeter(tv1.voltageB);
EDIT: Using an abstract accessor. This is the fastest way to do this. AFAIK,the difference is less than 10 nano-seconds.
public abstract class Voltmeter{ // or use an interface
public abstract double get();
public abstract void set(double voltage);
}
public class TVset {
private double _voltageA = 0.0;
private double _voltageB = 0.0;
private double _voltageC = 0.0;
public final Voltmeter voltageA = new Voltmeter() {
public double get() { return _voltageA; }
public void set(double voltage) { _voltageA = voltage; }
}
public final Voltmeter voltageB = new Voltmeter() {
public double get() { return _voltageB; }
public void set(double voltage) { _voltageB = voltage; }
}
public final Voltmeter voltageC = new Voltmeter() {
public double get() { return _voltageC; }
public void set(double voltage) { _voltageC = voltage; }
}
}
Personally, if speed is critical, I would just use the fields directly by name. You won't get simpler or faster than that.
Just for completeness I've included the delegate way of solving this. I would also not recommend having your floats with public access.
public class stackoverflow_5383947 {
public static class Tvset {
public float voltageA;
public float voltageB;
public float voltageC;
public Tvset() {
}
public void function() {
voltageA++;
}
};
public static class Voltmeter {
private VoltageDelegate _delegate;
public Voltmeter(VoltageDelegate delegate) {
_delegate = delegate;
}
float getVoltage() {
return _delegate.getVoltage();
}
};
public static interface VoltageDelegate {
public float getVoltage();
}
public static void main(String[] args) {
final Tvset tv1 = new Tvset();
Voltmeter meter = new Voltmeter(new VoltageDelegate() {
public float getVoltage() {
return tv1.voltageA;
}
});
System.out.println(meter.getVoltage());
tv1.function();
System.out.println(meter.getVoltage());
tv1.function();
System.out.println(meter.getVoltage());
}
}
If you control the TVSet but need to use reflection for some reason, a good way to avoid errors is to write the method/field names that you need as String Constants in the TVSet class.
However if your concern is performance, reflection is not the way to go because accessing a field or method through reflection can be much slower than accessing through getters or directly.
Here a variant where you can give your float value instead of a string.
class Voltmeter{
Object container;
Field theField;
Voltmeter(Object obj, float currentValue) {
container = obj;
Class<?> containerClass = obj.getClass();
Field[] fields = containerClass.getFields();
for(Field f : fields) {
if (f.getType() == float.class &&
f.getFloat(container) == currentValue) {
this.theField = f;
break;
}
}
}
float getVoltage() {
return theField.getFloat(container);
}
}
Then call it like this:
Voltmeter meter = new Voltmeter(tv1, tv1.voltageB);
It works only if the voltages in the moment of Voltmeter creation are different (and not NaN), as it takes the first Field with the right value. And it is not really more efficient, I think.
I wouldn't really recommend this.