Java : Genrics - Two similar codes, one doesn't work - java

The below code doesn't work :
class Stats<T extends Number>
{
T[] nums;
Stats(T[] o)
{
nums = o;
}
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
boolean sameAvg(Stats<T> ob)
{
if(average() == ob.average())
return true;
return false;
}
}
class BoundsDemo
{
public static void main(String args[])
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Stats<Integer> iob = new Stats<Integer>(inums);
double v = iob.average();
System.out.println("iob average is " + v);
Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Double> dob = new Stats<Double>(dnums);
double w = dob.average();
System.out.println("dob average is " + w);
if(iob.sameAvg(dob))
System.out.println("Averages are the same.");
else
System.out.println("Averages differ.");
}
}
But, the following works:
class Gen04<T extends Number>
{
T num;
void set(T a)
{
num = a;
}
T get()
{
return num;
}
boolean equals(Gen04<T> ob)
{
if(num.doubleValue() == ob.get().doubleValue())
return true;
else
return false;
}
}
class GenericCompare
{
public static void main(String args[])
{
Gen04<Integer> obI1 = new Gen04<Integer>();
obI1.set(new Integer(5));
Gen04<Double> obI2 = new Gen04<Double>();
obI2.set(new Double(5.0));
System.out.println("obI1 and obI2 are equal = "+obI1.equals(obI2));
}
}
What is the difference ? In both the programs, I am trying to call a method with parameter type different from the parameter type of the invoking object

In the first snippet, in iob.sameAvg(dob) you attempt to pass a Stats<Double> instance to a method of Stats<Integer>, which expects a Stats<Integer> argument. Since Stats<Double> is not a sub-class of Stats<Integer>, the compiler doesn't accept it.
In the second snippet you call obI1.equals(obI2). equals is a method of Object class that accepts an Object argument, so you can pass any Object instance to it.
EDIT : I see were you got confused. Your second snippet has an equals(Gen04<T> ob) method that overloads Object's equals, but that method is not being called. Instead, the compiler chooses the equals(Object other) method of Object class. If you rename your equals method and call the renamed method from your main, the second snippet would produce the same error.

Related

Passing two variables to one method to get two results

I am trying to pass two variables along to a method and have the method give me back two independent results.
int numX = 5;
int numY = 3;
System.out.println(displayTwiceTheNumber(numX, numY));
}
public static int displayTwiceTheNumber(int numX, int numY) {
int numW, numZ;
numW, numZ = 2 * (numX, numY);
return numW numZ;
}
Java takes it that at numW, numZ = 2 * (numX, numY); that I am trying to redefine numX and numY. How do I phrase the last block to take two variables and give two results?
A single int function can only return 1 int at a time.
If you want to return 2 values, consider calling the function twice or creating a custom object to be used.
You need to change the return type of the function. Currently, the return type is int, so you have to return one integer.
To return two integer, you should consider returning an array or a list or something similar.
public static int[] displayTwiceTheNumber(int numX, int numY){
//your code that do something
int[] ret = {numW, numZ};
return ret;
}
Or knowing that this function would change the value of numW and numZ, you could declare those as global variable. Now, when you call this function, those variable will be changed. Then, you can use numW and numZ subsequently.
public int numW;
public int numZ;
public static void displayTwiceTheNumber(int numX, int numY){
//your code that do something and modifies numW and numZ
}
public static void anotherfunction(){
//after calling displayTwiceTheNumber, numW and numZ would have the appropriate value
//you can now just use numW and numZ directly
}
Overview: Use a tuple. In this example I use an tuple to return more than one result. Tuple means to return more than one result type. In this example I return a tuple of two integer types. My class TupleCustom contains one method function1 which receives two parameters of type integer: x and y. I create a tuple of type integer and return the tuple as a variable. Internally, the precomiler converts the tuple json than back to a tuple with variable Item1, Item2...ItemN in the unit test method.
public class TupleCustom
{
public async Task<Tuple<int, int>> Function1(int x, int y)
{
Tuple<int, int> retTuple = new Tuple<int, int>(x, y);
await Task.Yield();
return retTuple;
}
}
public class TestSuite
{
private readonly ITestOutputHelper output;
public TestSuite(ITestOutputHelper output)
{
this.output = output;
}
[Fact]
public async Task TestTuple()
{
TupleCustom custom = new TupleCustom();
Tuple<int, int> mytuple = await custom.Function1(1,2);
output.WriteLine($" Item1={mytuple.Item1} Item2={mytuple.Item2} ");
}
When I have this problem I create a private utility class for handling the return values. By doing it this way, you can pass various types in the argument list. Aspects of the class can be tailored to your requirements.
public static void main(String [] args) {
int numX = 5;
double numY = 3.0;
Nums n = displayTwiceTheNumber(numX, numY);
System.out.println(n.numX);
System.out.println(n.numY);
}
public static Nums displayTwiceTheNumber(int numX, double numY) {
int numW;
double numZ;
// do something with arguments.
// in this case just double them and return.
return new Nums(2*numX, 2*numY);
}
private static class Nums {
int numX;
double numY;
public Nums(int nx, double ny) {
this.numX = nx;
this.numY = ny;
}
public String toString() {
return "(" + numX + ", " + numY +")";
}
}
Prints
10
6.0

OOP in Java: problem with constructor and methods

I am new to Java and I am trying to write a class with constructors and methods that adds and divides two numbers, and also compares if one object is larger or equal than the other. But I am getting an error: The method plus(int) in the type Compare is not applicable for the arguments (Compare). what's wrong?
Here's the code:
public class Compare {
// fields
private int number;
private int plus;
private double div;
// constructor
public Compare (int n) {
number = n;
}
public int plus (int x) {
return this.number + x;
}
public int div (int x) {
return this.number / x;
}
public boolean isLargerThan (int x) {
return this.number > x;
}
public boolean isEqualTo (int x) {
return this.number == x;
}
public static void main(String[] args) {
Compare n1 = new Compare(9);
Compare n2 = new Compare(4);
Compare sum = n1.plus(n2);
Compare div = n1.div(n2);
boolean check1 = sum.isLargerThan(n1);
boolean check2 = div.isLargerThan(n2);
boolean check3 = div.isEqualto(sum);
}
}
The requirement is to create sum and div objects using Compare constructor that will be equal to n1 plus n2, with plus method or division as applicable.
It may be that here you want a new Compare, containing the sum.
public Compare plus (int x) {
return new Compare(number + x);
}
public Compare plus (Compare x) {
return new Compare(number + x.number);
}
This also is implied by expecting a Compare object, not an int as shown.
With that Compare would become immutable, which is very good, as you then can share objects in different variables without problems (changing one variable's value changing other variables' values).
#Override
public String toString() {
return Integer.toString(number);
}
public int intValue() {
return number;
}
The issue here is for the "plus", "div", "isLargerThan" and "isEqualTo" methods in "Compare" class the argument/return type is of type "int". But in "main" function you are passing the object and expecting object of type "Compare".
To fix it either change the argument/return type to "Compare" for those methods in "Compare" class or pass the "int" value as parameter and get "int" value in "main" function.
The plus and div methods take an int and return an int and you are trying to receive their output in a Compare object. Also, isLargerThan takes an int and not a Compare.
Problem is here :
Compare sum = n1.plus(n2);
Compare div = n1.div(n2);
methods : plus and div return int value not an objet of Class Compare.
public int plus (int x) {
return this.number + x;
}
public int div (int x) {
return this.number / x;
}
Add getter method in Compare Class.
public int getNumber(){
return number;
}
Use below code and try to run:
public static void main(String[] args) {
Compare sum = new Compare(9);
Compare divObj = new Compare(4);
sum.plus(n2);
divObj.div(n2);
boolean check1 = sum.isLargerThan(sum.getNumber());
boolean check2 = divObj.isLargerThan(divObj.getNumber());
boolean check3 = divObj.isEqualto(sum.getNiumber());
}

How to simulate Java generic wildcards in C#

The following Java code compares the average of two arrays, one of Integers and one of Doubles.
class Generic_Class<T extends Number>
{
T[] nums; // array of Number or subclass
Generic_Class(T[] o)
{
nums = o;
}
// Return type double in all cases.
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
// boolean sameAvg(Generic_Class<T> ob)
// Using Generic_Class<T> i get the error:
// incompatible types: Generic_Class<Double> cannot be converted to Generic_Class<Integer>
// Using wilcards I get no error
boolean sameAvg(Generic_Class<?> ob)
{
if(average() == ob.average())
return true;
return false;
}
}
The main method is like this:
public static void main(String args[])
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Double dnums[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
Generic_Class<Integer> iob = new Generic_Class<Integer>(inums);
Generic_Class<Double> dob = new Generic_Class<Double>(dnums);
System.out.println("iob average is " + iob.average());
System.out.println("dob average is " + dob.average());
if (iob.sameAvg(dob))
System.out.println("Averages of iob and dob are the same.");
else
System.out.println("Averages of iob and dob differ.");
}
The result is:
iob average is 3.0
dob average is 3.0
Averages of iob and dob are the same.
I've tried to do the same in C# but, since I have no wildcards, I can't accomplish the same task.
How can I do the same with C# ?
Thank you.
As other answerers have said, there is no equivalent of Number in C#. The best you can get is struct, IConvertible. However, there is another way of doing the generic wildcard.
Just use another generic parameter:
public class Generic_Class<T> where T : struct, IConvertible
{
T[] nums;
public Generic_Class(T[] o)
{
nums = o;
}
public double Average()
{
double sum = 0.0;
for(int i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(null);
return sum / nums.Length;
}
// this is the important bit
public bool SameAvg<U>(Generic_Class<U> ob) where U : struct, IConvertible
{
if(Average() == ob.Average())
return true;
return false;
}
}
Taking the average of a sequence of numbers is built-in to C#:
var iNums = new int[] { 1, 2, 3, 4, 5 };
var dNums = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0 };
var iAvg = iNums.Average();
var dAvg = dNums.Average();
var areEqual = iAvg == dAvg;
areEqual == true after running the above.
You can even do this with complex types using the Average overload that takes a Func<TSource, T> to return a value:
public class MyValue
{
private static Random rnd = new Random();
public int SomeInt { get; set; } = rnd.Next();
}
var myObjArray = new MyValue[] { new MyValue(), new MyValue(), new MyValue(), new MyValue() };
var myAvg = myObjArray.Average(o => o.SomeInt);
So no, wildcards are not available in C#, but using Generics you can simulate wildcards by having multiple overloads of the Func in this case.
See IEnumerable Methods
Just add simple interface with method double Average so you can do:
interface IAbleToGetAverage
{
double Average();
}
class GenericClass<T> : IAbleToGetAverage
where T : struct, IConvertible
{
private readonly T[] nums; // array of Number or subclass
public GenericClass(T[] o)
{
nums = o;
}
private readonly IFormatProvider formatProvider = new NumberFormatInfo();
public double Average()
{
var sum = 0.0;
for(var i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(formatProvider);
return sum / nums.Length;
}
public bool SameAvg(IAbleToGetAverage ob)
{
if(Math.Abs(Average() - ob.Average()) < double.Epsilon)
return true;
return false;
}
}
What you're expressing in your Java code is boxed numeric types, which all extend the Number class, so it's trivial to enforce a constraint that the generic type is a number.
Types work a little differently in C# because int rather that being primitive in the same sense as Java, is just a type alias for System.Int32 which is a struct.
Also, there is no common base type (class, struct, interface, etc.) that is shared by ONLY numbers in C#, so its IMPOSSIBLE to create a constraint to enforce that the generic type is a number, has a numeric value, and therefore can have mathematical calculations performed on it.
Some suggestions here seem to be to use where T : IComparable, struct but I could argue that the constraint also applies to DateTime, Guid and TimeSpan - none of which are integral or floating point numbers.

issue with Arrays.asList()

I have a very simple program and I just need to check an array for a value in it.
I have a class called bulkBean. this is it.
public class bulkBean {
private int installmentNo;
private double amount;
public int getInstallmentNo() {
return installmentNo;
}
public void setInstallmentNo(int installmentNo) {
this.installmentNo = installmentNo;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}
Now I have an array of this bulkBean type in my program, this is my program.
import java.util.Arrays;
public class test {
public static boolean scan_bulkList(bulkBean[] bulkList, int i) {
int[] arr = new int[bulkList.length];
for(int x=0;x<bulkList.length;x++){
arr[x] = bulkList[x].getInstallmentNo();
}
for(int j = 0; j< arr.length ;j++){
System.out.println("INFO: array "+j+" = "+arr[j]);
}
if (Arrays.asList(arr).contains(i) == true) {
return true;
} else {
return false;
}
}
public static void main(String[] arg){
bulkBean bb1 = new bulkBean();
bb1.setInstallmentNo(1);
bb1.setAmount(5500);
bulkBean bb2 = new bulkBean();
bb2.setInstallmentNo(2);
bb2.setAmount(4520);
bulkBean[] bulkArray = new bulkBean[2];
bulkArray[0] = bb1;
bulkArray[1] = bb2;
boolean a = scan_bulkList(bulkArray,1);
System.out.println("val = "+a);
}
}
I create 2 instances of bulk bean and I set values to them. Then I added those two instances to an array. Then I pass that array to the method to check for a value(also given as a parameter. In this case it is 1.). If the array contains that value, it should return true, otherwise false.
whatever value I enter, it return false.
Why do I get this issue?
Arrays.asList() returns a List which has a single element - an array. So, you are actually comparing against an array. You need to compare against each value in the array.
As TheListMind told, Arrays.asList() taken on an int[] gives you a list containing the array.
Personally, I would construct directly the List instead of constructing the array, or even better (no need of array instanciation), test while iterating the bulk array :
for(int x=0;x<bulkList.length;x++){
if (bulkList[x].getInstallmentNo() == i){
return true;
}
}
return false;
The mistake you made here is , you created the int array which must be Integer array because Arrays.asList().contains(Object o); makes the input parameter also Integer(Integer i). int is not an object Integer is the object. Hope it will work.
int[] arr = new int[bulkList.length];
change to:
Integer[] arr = new Integer[bulkList.length];
Change the method as below to avoid complications:
public static boolean scan_bulkList(bulkBean[] bulkList, int i) {
int[] arr = new int[bulkList.length];
for(int x=0;x<bulkList.length;x++){
arr[x] = bulkList[x].getInstallmentNo();
if (bulkList[x].getInstallmentNo()==i) {
return true;
}
}
return false;
}

Java Generics: Comparing an Integer to a Double

Can anyone help me compare an Integer to a Double using generics?
This is what I have:
public static <T extends Comparable<? super T>> int compare(T arg1, T arg2)
{
return arg1.compareTo(arg2);
}
public static void main(String[] args)
{
Number i = new Integer(5);
Number j = new Double(7);
System.out.println(GenericsTest.compare(i, j));
}
The error message I get is:
Bound mismatch: The generic method compare(T, T) of type GenericsTest is not applicable for the arguments (Number, Number). The inferred type Number is not a valid substitute for the bounded parameter >
The idea of this solution is to widen to BigDecimal and then compare the two numbers (now is cleaner but somehow formatting doesn't work). Note you may reuse this static comparator without having to cast to double anywhere else. In the implementation you do need conversion to double not to lose information, basically you widen to the most general representation.
private static final Comparator<Number> NUMBER_COMPARATOR = new Comparator<Number>() {
private BigDecimal createBigDecimal(Number value) {
BigDecimal result = null;
if (value instanceof Short) {
result = BigDecimal.valueOf(value.shortValue());
} else
if (value instanceof Long) {
result = BigDecimal.valueOf(value.longValue());
} else
if (value instanceof Float) {
result = BigDecimal.valueOf(value.floatValue());
} else
if (value instanceof Double) {
result = BigDecimal.valueOf(value.doubleValue());
} else
if (value instanceof Integer) {
result = BigDecimal.valueOf(value.intValue());
} else {
throw new IllegalArgumentException("unsupported Number subtype: " + value.getClass().getName());
}
assert(result != null);
return result;
}
public int compare(Number o1, Number o2) {
return createBigDecimal(o1).compareTo(createBigDecimal(o2));
};
};
public static void main(String[] args) {
Number i = Integer.valueOf(5);
Number j = Double.valueOf(7);
// -1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(7);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(-7);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Double.MAX_VALUE;
// -1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(Long.MAX_VALUE - 1);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
// sorting Long values
Long[] values = new Long[] {Long.valueOf(10), Long.valueOf(-1), Long.valueOf(4)};
Arrays.sort(values, NUMBER_COMPARATOR);
// [-1, 4, 10]
System.out.println(Arrays.toString(values));
}
As aready said in the comments, Number does not implement Comparable.
But Double and Integer do.
One way to make this work is like this:
public static <T extends Comparable<? super T>> int compare(T arg1, T arg2)
{
return arg1.compareTo(arg2);
}
public static void main(String[] args)
{
Double i = new Integer(5).doubleValue();
Double j = new Double(7);
System.out.println(GenericsTest.compare(i, j));
}
Number doesn't implement Comparable.
Declare both variables as Integer.
private boolean compareObject(Object expected, Object actual) {
if (expected instanceof Number && actual instanceof Number) {
double e = ((Number) expected).doubleValue();
double a = ((Number) actual).doubleValue();
return e == a;
} else {
return com.google.common.base.Objects.equal(expected, actual);
}
}
Create a class that implements Comparable which takes a Number in the constructor.
e.g.
public class GenericNumber implements Comparable<GenericNumber> {
private Number num;
public GenericNumber(Number num) {
this.num = num;
}
// write compare function that compares num member of two
// GenericNumber instances
}
Then simply do this:
GenericNumber i = new GenericNumber(new Integer(5));
GenericNumber j = new GenericNumber(new Double(7));
System.out.println(GenericsTest.compare(i,j));

Categories