I have two classes which pretty much implement the same operations for two different numeric types (except for the getHexadecimalValue() method):
public class IntegerType
{
private int value;
public IntegerType()
{
value = 0;
}
public void setValue(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
public String getHexadecimalValue()
{
int integerValue = (int) getValue();
String hexadecimal = ValueConversions.toHexadecimal(integerValue);
return hexadecimal;
}
}
and
public class FloatingPointType
{
private float value;
public FloatingPointType()
{
value = 0;
}
public void setValue(float value)
{
this.value = value;
}
public float getValue()
{
return value;
}
public String getHexadecimalValue()
{
float floatingValue = (float) getValue();
int intBits = Float.floatToRawIntBits(floatingValue);
return ValueConversions.toHexadecimal(intBits);
}
}
I'm wondering what the best way would be to reduce this redundancy by e.g. defining a superclass called NumberType like this:
public abstract class NumberType
{
protected Number value;
public NumberType()
{
setValue(0);
}
public void setValue(Number value)
{
this.value = value;
}
public Number getValue()
{
return value;
}
public abstract String getHexadecimalValue();
}
Now the problem is that any number can be passed to my inheriting classes but I only want to accept ints and floats respectively while still keeping redundancy to a minimum:
public class IntegerType extends NumberType
{
#Override
public String getHexadecimalValue()
{
// Crashes on runtime if the value doesn't happen to be of the expected type
int integerValue = (int) getValue();
String hexadecimal = ValueConversions.toHexadecimal(integerValue);
return hexadecimal;
}
}
Can this be done by still keeping proper type checking?
You can try this way.
public abstract class NumberType<T extends Number> {
protected T value;
public NumberType(T value) {
this.value = value;
}
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public abstract String getHexadecimalValue();
}
public class FloatingPointType extends NumberType<Float> {
public FloatingPointType() {
super(0f);
}
public String getHexadecimalValue() {
return ValueConversions.toHexadecimal(Float.floatToRawIntBits(value));
}
}
Note: Float and Integer, both class has static toHexString methods which you can directly use if you are comfortable to use them.
public static String toHexString(float f)
public static String toHexString(int i)
This can be done with overloading
for example:
public abstract class NumberType
{
private Number value;
public NumberType()
{
setValue(0);
}
public void setValue(float value)
{
this.value = value;
}
public void setValue(int value)
{
this.value = value;
}
public Number getValue()
{
return value;
}
public abstract String getHexadecimalValue();
}
You can also add then:
public int getIntValue()
{
return value.intValue();
}
public float getFloatValue()
{
return value.floatValue();
}
Ideally, setValue(Number value) must not allow entering any value but float in FloatingPointType and setValue(Number value) must not allow entering any value but int in IntegerType. You can check by using intValue() and floatValue() methods in class Number and throw exception if inappropriate value entered. Number class methods
It would be something like this in setValue(Number value) of IntegerType
if(value.intValue()!= value)
throw new IllegalArgumentException()
Related
My two Type classes called SearchType and ResultcodeType need a parent class in an elegant way. How to design these two classes and a parent class both inherit from in an clean and code saving way?
public enum SearchType {
BARCODE(0),
TEXT(1);
SearchType(int i)
{
this.type = i;
}
private int type;
public static SearchType getType(int value) {
for (SearchType searchType : SearchType.values()) {
if (searchType.type == value)
return searchType;
}
throw new IllegalArgumentException("SearchType not found.");
}
public int getNumericType() {
return type;
}
}
and
public enum ResultcodeType {
RESULTS(0),
NO_RESULTS(1),
PROBLEMS(2),
NO_VALUE(-1);
ResultcodeType(int i)
{
this.type = i;
}
private int type;
public static ResultcodeType getType(int value) {
for (ResultcodeType resultcodeType : ResultcodeType.values()) {
if (resultcodeType.type == value)
return resultcodeType;
}
throw new IllegalArgumentException("ResultcodeType not found.");
}
public int getNumericType() {
return type;
}
}
Where do I use SearchType / ResultCodeType?
Layout Data Binding
<ImageView
app:srcCompat="#{item.searchType == SearchType.BARCODE ? #drawable/ic_barcode : #drawable/ic_one_loupe}"
/>
Room database converter class (where there is redundancy again). But for now room can't handle generic types in it's TypeConverter. So this will stay as is.
#TypeConverter
public static SearchType SearchTypeFromInt(Integer value) {
return SearchType.getType(value);
}
#TypeConverter
public static ResultcodeType ResultcodeTypeFromInt(Integer value) {
return ResultcodeType.getType(value);
}
POJO (with room annotation)
#NonNull
#ColumnInfo(name = "resultcode", defaultValue="-1")
private ResultcodeType mResultcode;
Since enums cannot have base classes, I think this is the closest you're going to get:
public interface Typed {
int getNumericType();
static <E extends Enum<E> & Typed> E getType(E[] values, int type) {
for (E value : values)
if (value.getNumericType() == type)
return value;
throw new IllegalArgumentException(values[0].getClass().getSimpleName() +
" not found: " + type);
}
}
public enum SearchType implements Typed {
BARCODE(0),
TEXT(1);
private final int type;
private SearchType(int type) {
this.type = type;
}
#Override
public int getNumericType() {
return this.type;
}
public static SearchType getType(int type) {
return Typed.getType(values(), type);
}
}
public enum ResultcodeType implements Typed {
RESULTS(0),
NO_RESULTS(1),
PROBLEMS(2),
NO_VALUE(-1);
private final int type;
private ResultcodeType(int type) {
this.type = type;
}
#Override
public int getNumericType() {
return this.type;
}
public static ResultcodeType getType(int type) {
return Typed.getType(values(), type);
}
}
Your enums could implement an interface and add default method.
For example:
interface Typed {
Typed getType(int value)
public enum ResultcodeType implements Typed {
public Typed getType(int value) {
for (ResultcodeType resultcodeType :
ResultcodeType.values()) {
if (resultcodeType.type == value)
return resultcodeType;
}
throw new IllegalArgumentException("ResultcodeType not found.");
}
....
}
I also suggest the following approach using a map instead of searching. In fact, all you need is the mapping. You wouldn't even need to supply a value. Note that you can't reference a static value from within a constructor so you have to build the map externally.
enum SearchType {
BARCODE(0), TEXT(1), UNKNOWN(-1);
static Map<Integer, SearchType> map =
Map.of(0, SearchType.BARCODE, 1, SearchType.TEXT);
SearchType(int i) {
this.type = i;
}
private int type;
public static SearchType getType(int value) {
return SearchType.map.getOrDefault(value, SearchType.UNKNOWN);
}
public int getNumericType() {
return type;
}
}
public static void main(String[] args) {
System.out.println(SearchType.getType(0));
System.out.println(SearchType.getType(1));
System.out.println(SearchType.getType(99));
}
I am currently working in Processing 3, and am having troubles understanding the return of a HashMap. I have a map, Map<String, Chromosome> genes = new HashMap<String, Chromosome>() which uses my classes,
class Chromosome{
Genotype geneOne;
Genotype geneTwo;
Chromosome(){ ... }
Chromosome(Genotype gOne, Genotype gTwo){ ... }
void setGeneOne(Genotype gene){ ... }
void setGeneTwo(Genotype gene){ ... }
Genotype getDomGene(){ ... }
Genotype getRecGene(){ ... }
}
class Genotype{
Object value;
float weight;
public Genotype(int value, float weight){ ... }
public Genotype(int[] value, float weight){ ... }
public Genotype(String value, float weight){ ... }
public Genotype(float value, float weight){ ... }
public Object getValue(){ ... }
public float getWeight(){ ... }
public void setValue(int value){ ... }
public void setValue(int[] value){ ... }
public void setValue(String value){ ... }
public void setValue(float value){ ... }
}
What I'm thinking is that when I "get" a value from the map, I should be able to access its methods from there. I.E.
class Flower{
Map<String, Chromosome> genes;
Flower(){
genes = new HashMap<String, Chromosome>();
genes.put("color", new Chromosome(new Genotype(64, 1.0), new Genotype(25,0.5)));
Genotype test = genes.get("color").getDomGene(); //should return the first param passed to the new chromosome
}
}
I'm hoping to avoid having to declare the returned object every time I use it. From all of 20 minutes of googling, I can't seem to find anything about this working, so why does this not work, and what can be done to work around it?
You should just return genOne in getDomGene method.
Chromosome class.
package gen;
class Chromosome {
Genotype geneOne;
Genotype geneTwo;
Chromosome() {
System.out.println("Chromosome.Chromosome");
}
Chromosome(Genotype gOne, Genotype gTwo) {
System.out.println("Chromosome.Chromosome");
}
void setGeneOne(Genotype gene) {
System.out.println("Chromosome.setGeneOne");
}
void setGeneTwo(Genotype gene) {
System.out.println("Chromosome.setGeneTwo");
}
Genotype getDomGene() {
System.out.println("return genOne");
return geneOne;
}
Genotype getRecGene() {
System.out.println("return genTwo");
return geneTwo;
}
}
Genotype class
package gen;
class Genotype {
Object value;
float weight;
public Genotype(int value, float weight) {
System.out.println("Genotype.Genotype");
}
public Genotype(int[] value, float weight) {
System.out.println("Genotype.Genotype");
}
public Genotype(String value, float weight) {
System.out.println("Genotype.Genotype");
}
public Genotype(float value, float weight) {
System.out.println("Genotype.Genotype");
}
public Object getValue() {
System.out.println("Genotype.getValue");
return null;
}
public void setValue(String value) {
System.out.println("Genotype.setValue");
}
public void setValue(float value) {
System.out.println("Genotype.setValue");
}
public void setValue(int value) {
System.out.println("Genotype.setValue");
}
public void setValue(int[] value) {
System.out.println("Genotype.setValue");
}
public float getWeight() {
System.out.println("Genotype.getWeight");
return 0;
}
}
Flower class.
package gen;
import java.util.HashMap;
import java.util.Map;
class Flower {
Map<String, Chromosome> genes;
Flower() {
genes = new HashMap<>();
genes.put("color", new Chromosome(new Genotype(64, 1.0f), new
Genotype(25, 0.5f)));
Genotype test = genes.get("color")
.getDomGene(); //should return the first param passed to the new chromosome
}
public static void main(String[] args) {
new Flower();
}
}
It prints
Genotype.Genotype
Genotype.Genotype
Chromosome.Chromosome
return genOne
return genOne means that you have an access to the geneOne field of Chromosome class, that is its first parameter.
if you put class Flower in a different package? you can't see methods that are not "public". try putting all classes in the same package or make the method public
public Genotype getDomGene(){ ... }
public Genotype getRecGene(){ ... }
I have a class called monetary
public class Monetary
{
double value;
String type;
public Monetary()
{
value = 0;
type = "";
}
public double getValue()
{
return value;
}
public void setValue(double x)
{
x = this.value;
}
and i was testing get and set methods so i made a testing class as the following
public class test
{
public static void main(String [] args)
{
double test = 5000;
Monetary testM = new Monetary();
testM.setValue(5000);
System.out.println(testM.getValue());
}
}
The problem is that the result java prints is not 5000.0, but 0. I don't get why this is happening. Aren't these methods correct?
The problem is in the setValue method:
public void setValue(double x) {
x = this.value;
}
You're assigning the parameter the current value of the attribute, it should be backwards:
public void setValue(double x) {
this.value = x;
}
Note that even doing this, you will get an output like 5000.0000000.... In order to fix the result you can use String#format or System.out.printf:
System.out.println(String.format("%.2f", testM.getValue()));
or
System.out.printf("%.2f\n", testM.getValue());
In your code you are assigning the value to parameter x, it should be opposite.
public void setValue(double x){
this.value = x;
}
try this:
public void setValue(double x)
{
this.value = x;
}
public void setValue(double x){
this.value = x;
}
You are assigning the parameter you've passed x with the default value of the value. You must be doing the exact opposite of that. Assign the value with the value passed x.
Hence, instead of this this.value = 5000, this is happening x = 0.
You are assigning the parameter (double x) the value of int value which does nothing because you are return value, so what you want to do is
public class Monetary
{
double value;
String type;
public Monetary()
{
value = 0;
type = "";
}
public double getValue()
{
return value;
}
public void setValue(double x)
{
value = x;//change this
}
Suppose I have a Enum defined something like this:
public enum Sample{
// suppose AClass.getValue() returns an int
A(AClass.getValue()),
B(AClass.getValue()),
C(AClass.getValue());
private int _value;
private Sample(int _val){
this._value = _val;
}
public int getVal(){
return _value;
}
I can pull out values using Sample.A or Sample.A.getAVal() without issue.
Now suppose that AClass.getValue() could take a parameter to return a possibly different particular value, eg AClass.getValue(42).
It is possible to pass arguments to a public Enum method and retrive the Enum values? In other words, could I have an Enum definition like
public enum Sample{
// suppose AClass.getValue() returns an int
A(AClass.getAValue()),
B(AClass.getBValue()),
C(AClass.getCValue());
private int _value;
private Sample(int _val){
this._value = _val;
}
public int getVal(){
return _value;
}
public int getVal(int a){
// somehow pull out AClass.getAValue(a)
}
using Sample.A.getValue(42)?
You can do it, but only by making an abstract method in the enum, and overriding it in each value:
public enum Sample {
A(AClass.getAValue()) {
#Override public int getVal(int x) {
return AClass.getAValue(x);
}
},
B(BClass.getAValue()) {
#Override public int getVal(int x) {
return BClass.getBValue(x);
}
},
C(CClass.getAValue()) {
#Override public int getVal(int x) {
return CClass.getCValue(x);
}
};
private int _value;
private Sample(int _val){
this._value = _val;
}
public int getVal(){
return _value;
}
public abstract int getVal(int x);
}
Of course if you could create an instance of some other base type which has a getValue(int x) method, then you could put the code into the enum class itself instead of into the nested ones.
As stated in Java Specification
there is only one instance of each enum constant
So no, you can't have different values of a specific enum constant.
But you could put an array or a map inside your enum, so Sample.A.getValue(42) would return Sample.A.myMap.get(42) :
public enum Sample{
A(),
B(),
C();
Map<Integer, Integer> myMap = new HashMap<Integer, Integer>();
public int getVal(int i){
return myMap.get(i);
}
public int setVal(int i, int v){
return myMap.put(i, v);
}
}
public class App {
public static void main(String[] args) {
Fruit.setCounter(5);
System.out.println(Fruit.Apple.getCmd());
Fruit.setCounter(6);
System.out.println(Fruit.Apple.getCmd());
}
}
public enum Fruit {
Apple {
public String getCmd() {
return counter + " apples";
}
},
Banana {
public String getCmd() {
return counter + " bananas";
}
};
private static int counter = 0;
public abstract String getCmd();
public static void setCounter(int c) {
counter = c;
}
}
Output:
5 apples
6 apples
I have three different types of parameters: int, float and long. I want to use an object to represent each of them. So i have one abstract class:
abstract public class AbstractProtocolParamObj<T extends Number>
{
public enum ProtocolParamConstraintTypeEnum
{
None,
OnOff,
Values,
ValueRange,
ValueRangeIncrement
}
protected String name;
protected ProtocolParamConstraintTypeEnum constraintValueType;
protected Vector<AbstractProtocolParamObj<T>> dependentParams;
protected Vector<AbstractProtocolParamObj<T>> constraintParams;
protected T value;
protected AbstractProtocolParamObj(String name,
ProtocolParamConstraintTypeEnum constraintValueType,
T value)
{
this.name = name;
this.constraintValueType = constraintValueType;
this.value = value;
}
public final String getName()
{
return name;
}
public final ProtocolParamConstraintTypeEnum getConstraintValueType()
{
return constraintValueType;
}
public void addDependentParam(AbstractProtocolParamObj<T> param)
{
if(dependentParams == null)
{
dependentParams = new Vector<AbstractProtocolParamObj<T>>();
}
dependentParams.add(param);
}
public void addConstraintParam(AbstractProtocolParamObj<T> param)
{
if(constraintParams == null)
{
constraintParams = new Vector<AbstractProtocolParamObj<T>>();
}
constraintParams.add(param);
}
public Vector<AbstractProtocolParamObj<T>> getDependentParams()
{
return dependentParams;
}
public Vector<AbstractProtocolParamObj<T>> getConstraintParams()
{
return constraintParams;
}
public T getValue()
{
return value;
}
public void setValue(T val)
{
value = val;
}
abstract public ReturnStatusEnum validate(T tempVal);
}
Then I will have one class for float parameters, one class for int and one for long. Like this:
public class ProtocolFloatParamObj extends AbstractProtocolParamObj
{
private float[] constraintVals;
private float maxVal;
private float minVal;
private float increment;
public ProtocolFloatParamObj(String name,
float value,
float[] constraintVals,
ProtocolParamConstraintTypeEnum constraintType
)
{
super(name, constraintType, value);
this.constraintVals = constraintVals;
}
public ProtocolFloatParamObj(String name,
float value,
float maxVal,
float minVal,
ProtocolParamConstraintTypeEnum constraintType
)
{
super(name, constraintType, value);
this.maxVal = maxVal;
this.minVal = minVal;
}
public ProtocolFloatParamObj(String name,
float value,
float maxVal,
float minVal,
float increment,
ProtocolParamConstraintTypeEnum constraintType
)
{
this(name, value, maxVal, minVal, constraintType);
this.increment = increment;
}
#Override
public ReturnStatusEnum validate(Number val)
{
ReturnStatusEnum status = ReturnStatusEnum.SUCCESS;
float tempVal = val.floatValue();
switch(constraintValueType)
{
case None:
{
break;
}
case OnOff:
{
break;
}
case Values:
{
break;
}
case ValueRange:
{
break;
}
case ValueRangeIncrement:
{
break;
}
}
return status;
}
}
Above code has no compile error but do has warnings which complain the generic type should be parameterized in subclass at the following lines:
public class ProtocolFloatParamObj extends AbstractProtocolParamObj
super(name, constraintType, value);
But if i change
public class ProtocolFloatParamObj extends AbstractProtocolParamObj
to
public class ProtocolFloatParamObj <T extends Number> extends AbstractProtocolParamObj<T>
and change the constructor value parameter from float to T. then everything looks good without compile error and warning.
The issue is because the ProtocolFloatParamObj constructor has a T parameter, its user/caller needs to define the T and it's easy to get warning or compile error.
For example in another class, I try to create a Vector contains some of those parameter objs but I cannot eliminate warnings or I cannot add to the objs vector:
public Vector<AbstractProtocolParamObj<T>> getAxialParamObjs()
{
Vector<AbstractProtocolParamObj<T>> objs = new Vector<AbstractProtocolParamObj<T>>();
ProtocolFloatParamObj<T> scanSpeed = new ProtocolFloatParamObj("scanSpeed",
new Float(Float.parseFloat(m_axialDefaultConfig.getProperty("scanSpeed"))),
new float[]{0.5f, 0.8f, 1.0f, 1.5f, 2.0f},
ProtocolParamConstraintTypeEnum.Values
);
objs.add(scanSpeed);
......
return objs;
}
It seems this is not a good idea or i need read more about java generic.
Do you have a better idea and do you have any advanced java generic tutorial links?
Try the following:
public class ProtocolFloatParamObj extends AbstractProtocolParamObj<Float>
Which should assign Float as the type parameter T of the super class.
Why not doing it like:
public class ProtocolFloatParamObj extends AbstractProtocolParamObj<Float>{
....
}
Change
AbstractProtocolParamObj<T> to AbstractProtocolParamObj<Float>
and change
ProtocolFloatParamObj <T extends Number> to only ProtocolFloatParamObj
resulting in
public class ProtocolFloatParamObj extends AbstractProtocolParamObj<Float>