I want a generic method to print all the elements of a multidimensional array.
In the below code i am able to print all the elements of any multidimensional array which belongs to the parent Object class but not of any primitive types.
Is it possible to print all elements of a multidimensional array of primitive type.
One more doubt if int value can be hold in a Object type then why not int[] can be cast to Object[] but, String[] can be cast to Object[].
public class MultiDimension {
public static void main(String[] args) {
//final String ar[][][] = {{{"1","2"},{"3","4","5"}},{{"6","7","8"}},{{"9","10"},{"11"},{"12","13","14","15"}}};//new String[1][3][2][2];
Integer intAr[][][][][][] = {{{{{{1},{2},{3}},{{4},{5},{6}}},{{{7}},{{8}}}}}};
recPrintArray(intAr);
}
public static void recPrintArray(Object ar) {
recPrintArray((Object[])ar,getDimensions(ar));
}
public static void recPrintArray(Object[] ar,int noODDimension) {
for (Object obj:(Object[]) ar) {
if (noODDimension > 0)
recPrintArray((Object[])obj, noODDimension - 1);
else {
System.out.print("> " + obj + " ");
}
}
}
/*return the number of dimension of an array
* takes any type as argument
* using the Object class getClass() and Class class getName() methods
*/
public static int getDimensions(Object intAr) {
return intAr.getClass().getName().lastIndexOf("[");
}
}
To answer your question, we need to introduce the concept of autoboxing first. Primitive types have their class matches. int has Integer, double has Double and so on. When a primitive type needs to be handled as an Object, the compiler will automatically convert the primitive into an instance of its wrapper class. Since you have an array of Objects, your primitive values are needed as Objects, so autoboxing will happen. If you want this to happen in a generic way, then you need to just check whether you have an array and if not, print the Object by calling its toString method.
As for your second question, you cannot convert a primitive array to an array of Objects, because your array was allocated for primitive types, not for Objects, but you can upcast a String array to an Object array, because all Strings are Objects.
since in java multidimensional arrays are array of array and array is an object. so if i recursively iterate on any array references in the last i will get only one dimensional array which i can type cast explicitly in the type supplied by using getClass().getName()
package learning;
public class MultiDimension {
public static void main(String[] args) {
final String ar[][][] = {{{"1","2"},{"3","4","5"}},{{"6","7","8"}},{{"9","10"},{"11"},{"12","13","14","15"}}};//new String[1][3][2][2];
//Integer integerAr[][] = {{1},{2}};
//byte byteAr[][] = {{1},{2}};
//int[] intAr = (int[])byteAr;
recPrintArray(ar);
}
public static void recPrintArray(Object ar) {
recPrintArray(ar,getDimensions(ar));
}
public static void recPrintArray(Object ar,int noOfDimension) {
for (Object obj:(Object[]) ar) {
if (noOfDimension > 1)
recPrintArray(obj, noOfDimension - 1);
else {
String dataType = obj.getClass().getName();
switch (dataType) {
case "[B":
printAll((byte[]) obj);
break;
case "[S":
printAll((short[]) obj);
break;
case "[I":
printAll((int[]) obj);
break;
case "[J":
printAll((long[]) obj);
break;
case "[F":
printAll((float[]) obj);
break;
case "[D":
printAll((double[]) obj);
break;
case "[Z":
printAll((boolean[]) obj);
break;
case "[C":
printAll((char[]) obj);
default:
printAll((Object[]) obj);
}
//System.out.print("> " + obj + " ");
}
}
}
public static void printAll(byte[] ar) {
for (byte val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(short[] ar) {
for (short val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(int[] ar) {
for (int val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(long[] ar) {
for (long val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(float[] ar) {
for (float val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(double[] ar) {
for (double val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(char[] ar) {
for (char val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(boolean[] ar) {
for (boolean val: ar)
System.out.print(">" + val + " ");
}
public static void printAll(Object[] ar) {
for (Object val: ar)
System.out.print(">" + val + " ");
}
/*return the number of dimension of an array
* takes any reference type as argument
* using the Object class getClass() and Class getName() methods
*/
public static int getDimensions(Object intAr) {
return intAr.getClass().getName().lastIndexOf("[");
}
}
Related
In an interview, I was asked to write a function using Generics that adds the numbers and Strings passed to it. The number could be Integer, Double, etc.
If 2 strings are passed to the function, it should append the strings. Finally, the added result should be returned.
I used Lambda as mentioned below.
public class WorkAround {
public static void main(String[] args) {
MyAdd myAdd = new MyAdd();
System.out.println("Adding Integers: " + myAdd.add(1, 2, (a,b) -> a+ b));
System.out.println("Adding Double: " + myAdd.add(1.2, 1.2, (a,b) -> a+ b));
System.out.println("Adding String: " + myAdd.add("James ", "Bond", (a,b) -> a + b));
}
}
class MyAdd {
public <T> T add(T a, T b, BinaryOperator<T> operation) {
return operation.apply(a, b);
}
}
Output:
Adding Integers: 3
Adding Double: 2.4
Adding String: James Bond
But then, I was asked to achieve the same result with Generics alone. Something like the below code snippet.
public class Trial {
public static void main(String[] args) {
MyAdd myAdd = new MyAdd();
System.out.println("Adding Integers: " + myAdd.add(1, 2));
System.out.println("Adding Double: " + myAdd.add(1.2, 1.2));
System.out.println("Adding String: " + myAdd.add("James ", "Bond"));
}
}
class MyAdd {
public <T> T add(T a, T b) {
return a + b;
}
}
Obviously, this did not work because of the following.
The operator + is undefined for the argument type(s) T, T
I found this thread the closet to my question. But that question did not handle Strings. Is there any other way that I might be missing?
We have 2 cases, String or Number. This differentiation should be made.
The following solves the problem.
import java.math.BigDecimal;
public class Trial {
public static void main(String[] args) {
MyAdd myAdd = new MyAdd();
System.out.println("Adding Integers: " + myAdd.add(1, 2));
System.out.println("Adding Double: " + myAdd.add(1.2, 1.2));
System.out.println("Adding String: " + myAdd.add("James ", "Bond"));
}
}
class MyAdd {
public String add(String a, String b) {
return a + b;
}
public <T extends Number> T add(T a, T b){
return (T) new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
}
}
This question already has answers here:
Java Pass Method as Parameter
(17 answers)
How to pass a function as a parameter in Java? [duplicate]
(8 answers)
Closed 3 years ago.
I have a class with bunch of methods. In another class, I need to write a method, that handles the input values. To that method, I want to pass the method of the class that I want to call. How can we do that with Java after 1.8?
There are similar questions already, but those usually assume that we can use an interface with a single method, therefore can use lambda expressions, etc.
class MyClass {
public Object myToString(String a) {
return new String(a);
}
public Object myToString(String a, String b) {
return new String(a + ", " + b);
}
public Object mySum(int a) {
return new Integer(a);
}
public Object mySum(int a, int b) {
return new Integer(a + b);
}
}
class Test {
public Object handleInputs(MyClass myClass, MethodAsParameter theMethod, List<Object> inputs) {
if (type of inputs are Strings) {
myClass.myToString(inputs.get(0));
} else if (.....) {
myClass.mySum(inputs.get(0));
}
}
}
Since Java 8 you can use method reference. Method references can be assigned to Function<A, B> functional interface variables and their subclasses.
For example, method with such signature:
class Test {
public static int DoSomething(String s) {...}
}
can be assigned to a Function<String, Integer> variable like:
Function<String, Integer> method = Test::DoSomething;
and then called:
int result = method.apply("Hello!");
So with small improvements in your code, this is the way you can use your methods as method references and passed to other function as parameters.
class MyClass {
public static String myToString(String a, String b) {
return a + ", " + b;
}
//notice the boxing in here
public static int mySum(int a, int b) {
return a + b;
}
//not kind of an revolutionary function, just for demonstration
public static<T> T Invoke(BinaryOperator<T> bo, T o1, T o2) {
return bo.apply(o1, o2);
}
public static void main(String[] args) {
int sum = Invoke(MyClass::mySum, 10, 20);
String str = Invoke(MyClass::myToString, "a", "b");
System.out.println(sum);
System.out.println(str);
}
}
I think something like this is as far as you would get:
import java.util.List;
import java.util.Arrays;
import java.util.function.Function;
import java.util.function.BiFunction;
class MyClass {
public Object myToString(String a) {
return new String(a);
}
public Object myToString(String a, String b) {
return new String(a + ", " + b);
}
public Object mySum(int a) {
return Integer.valueOf(a);
}
public Object mySum(int a, int b) {
return Integer.valueOf(a + b);
}
}
public class MethodParams {
public static Object handleInputs(Function<Object,Object> method, List<Object> inputs) {
return method.apply(inputs.get(0));
}
public static Object handleInputs(BiFunction<Object,Object,Object> method, List<Object> inputs) {
return method.apply(inputs.get(0), inputs.get(1));
}
public static void main(String args[]) {
MyClass mc = new MyClass();
String str = (String)handleInputs((a) -> mc.myToString((String)a), Arrays.asList("string"));
System.out.println(str); // string
Integer sum = (Integer)handleInputs((a) -> mc.mySum((int)a), Arrays.asList(1));
System.out.println(sum); // 1
Integer sum2 = (Integer)handleInputs((a,b) -> mc.mySum((int)a, (int)b), Arrays.asList(1, 2));
System.out.println(sum2); // 3
}
}
Not very nice, but at least you have some leeway as to which method you want to use. Code as demonstrated here has lots of casts due to using Objects - using generic types as demonstrated by t2dohx is better way of doing this, but even further from your question.
Here is a simple example:
public class TestMain {
public static void main(String [] args) {
Long a = 15L, b = 20L;
Long sum = combineTwoNumbers(a, b, (p1, p2) -> p1 + p2);
Long product = combineTwoNumbers(a, b, (p1, p2) -> p1 * p2);
System.out.println("Sum is " + sum);
System.out.println("Product is " + product);
}
public static Long combineTwoNumbers(Long a, Long b, BiFunction <Long, Long, Long> combiner) {
return combiner.apply(a, b);
}
}
Here, the functional parameter is BiFunction, which takes two parameters in input and returns an output. Specifically, it takes two long numbers and produces a third one as a result. The name of the method is kept generic so that it can cover more instances of different functions that may take place. In our example we are passing a sum and a product function as you can see.
The following code is correct with respect to method overloading.
public class class7A {
public static void main(String[] args) {
testing obj_1 = new testing();
int a=12,b=14,c=20;
obj_1.func1(a,b,c); //invokes the 3rd method in the testing class
}
}
class testing{
void func1(int a,int b){
System.out.println("The values of length and breadth entered for the box is "+a+" "+b);
}
void func1(int a){
System.out.println("We can only talk about length here folks which is "+a);
}
void func1(double a,double b,double c){ //This method is invoked
System.out.println("The value of length ,breadth and height is "+a+","+b+","+c+" respectively");
}
}
Now the explanation given for the fact that the 3rd method is invoked even when the parameters defined for the 3rd method are "double" is that java automatically converts double into int here.I also know java does any operation on the primitive type by first converting the types into int at the back end which holds true for bytes as well.
However when i change the parameters of the 3rd method to be of byte type instead of double,the code gives an error .Foe example the code below gives an error :
Why it is happening so ?
public class class7A {
public static void main(String[] args) {
testing obj_1 = new testing();
int a=12,b=14,c=20;
obj_1.func1(a,b,c);
}
}
class testing{
void func1(int a,int b){
System.out.println("The values of length and breadth entered for the box is "+a+" "+b);
}
void func1(int a){
System.out.println("We can only talk about length here folks which is "+a);
}
void func1(byte a,byte b,byte c){ //This gives error
System.out.println("The value of length ,breadth and height is "+a+","+b+","+c+" respectively");
You must cast the type of data int to byte when you pass as argument of the method.
example:
public class class7A {
public static void main(String[] args) {
testing obj_1 = new testing();
int a = 12, b = 14, c = 20;
obj_1.func1((byte) a, (byte) b, (byte) c);
}
}
class testing {
void func1(int a, int b) {
System.out.println("The values of length and breadth entered for the box is " + a + " " + b);
}
void func1(int a) {
System.out.println("We can only talk about length here folks which is " + a);
}
void func1(byte a, byte b, byte c) { // This gives error
System.out.println("The value of length ,breadth and height is " + a + "," + b + "," + c + " respectively");
}
}
and if you want to make another type of conversion you can check this post where it is explained more detailed how to convert from int to byte
https://stackoverflow.com/a/842900/7179674
I'm wondering if it's possible to make a method which takes part of the name of something as a parameter and then pieces it together. Let's say I have three arrays:
arrayA, arrayB, arrayC.
So, something like this:
public static void printArray(String id)
{
System.out.println("Array " + id + ": " + Arrays.toString(array + id) );
}
Where I was hoping that running
printArray(C);
would turn (array + id) into arrayC and print the content of arrayC. Unfortunately it doesn't, and just says "array" is no recognized symbol.
How can I achieve this?
IMHO, you should use a map
String[] arrayA = {"a1", "a2", "a3"};
String[] arrayB = {"b1", "b2", "b3"};
String[] arrayC = {"c1", "c2", "c3"};
HashMap<String, String[]> mapArray = new HashMap<String, String[]>();
mapArray.put("A", arrayA);
mapArray.put("B", arrayB);
mapArray.put("C", arrayC);
when you want to retrieve your array
public static void printArray(String id)
{
System.out.println("Array " + id + ": " + Arrays.toString(mapArray.get(id)));
}
This is possible using reflection:
public class TestArray {
String[] arrayA = new String[] { "A content" };
String[] arrayB = new String[] { "B content" };
String[] arrayC = new String[] { "C content" };
public void printArray(String id) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
System.out.println("Array " + id + ": " + Arrays.toString((String[]) getClass().getDeclaredField("array" + id).get(this)));
}
public static void main(String[] args) throws Exception {
(new TestArray()).printArray("C"); // prints "Array C: [C content]"
}
}
But I think this is not really a good idea, and using a HashMap may be a better idea.
Sounds like you're looking for reflection, but you cannot reflect local variables and it sounds like you want to.
Your best bet may be to adjust printArray to take the array whose contents you want to dump:
public static void printArray(String id, Object[] array)
{
System.out.println("Array " + id + ": " + Arrays.toString(array) );
}
Unfortunately, you'd need an overload for each primitive type if you want a generic solution:
public static void printArray(String id, boolean[] array){...}
public static void printArray(String id, char[] array){...}
public static void printArray(String id, double[] array){...}
...
You could keep the solution DRY by having a private static method that handled the formatting:
private static void outputArray( String arrayId, String arrayContents )
{
System.out.println("Array " + arrayId + ": " + arrayContents );
}
Then adjust the printArray method(s) to call it:
public static void printArray(String id, Object[] array)
{
outputArray(id, Arrays.toString(array) );
}
public static void printArray(String id)
{
System.out.println("Array " + id + ": content of Array" + id);
}
will do the work.
In the toString method "array" is a variable, and it is not declared before, because of this you get the error message.
Edit:
public static void printArray(String id){
if(id.equals("A")){
// print the content of array A
} else if(id.equals("B")){
// print the content of array B
} else if(id.equals("C")){
// print the content of array C
} else {
System.out.println("I don't know that array");
}
}
Is that what you want?
When running the function foo1, why does the output for this code will be: 15 30 5
and not 15 15 5 ?
I underdtand that the pointer of the object v is now points to the object va1, so the output for the code line: System.out.print(v.getI() + " ");
should be 15. So why is it 30 ?
public class Value
{
private int _i;
public Value()
{
_i=15;
}
public int getI()
{
return _i;
}
public void setI (int i)
{
_i=i;
}
}
public class TestValue
{
public static void foo1()
{
int i=5;
Value v= new Value();
v.setI(10);
foo2(v,i);
System.out.print(v.getI() + " ");
System.out.print(i+ " ");
}
public static void foo2( Value v, int i)
{
v.setI(30);
i=10;
Value va1= new Value();
v=va1;
System.out.print (v.getI() + " ");
}
}
Java only supports pass-by-value. So when you pass an object "v" to the method foo2 a copy of the reference "v" is created. So when you set v = val1 in foo2 the copy of the reference is being changed in foo2 not the original reference "v" in foo1.