Multiple sub-class that similar but different - java

I've 2 similar classes, one that receives 1 parameters (lets says int type) and the other receives the same type of parameter twice. For both input I need to have the same check (and throw exception if data isn't good) and both classes will have some functionality.
I thought of creating supertype that will have 2 constructors, one with 1 parameter, and the other one with 2 parameters. That will work but the question, what should be done in case there was the option of having three or more parameter.
So I thought to try here if there is any better option.
Thanks.

What should be done in case there was the option of having three or more parameter?
Try with Varargs that took an arbitrary number of values required you to create an array and put the values into the array prior to invoking the method/constructor.
Read the chapter here on Varargs from Eclipse.
Java Variable Arguments
arargs is a helper syntax and it enables use of variable number of arguments in a method call. In method definition variable aruguments are indicated by elipsis (…) and is called as variable arity method and variable arity parameter in java language specification. While invoking the varargs method we can use any number of arguments of type specified and separated by comma.
Varargs Sample
public class VarArgSample {
static int sum(int i, int... marks) {
int total = 0;
for (int mark : marks) {
total = total + mark;
}
return total;
}
public static void main(String[] args) {
// invoking with variable arguments
System.out.println(sum(1, 2, 3));
// same invocation using an array
int arr[] = { 2, 3 };
System.out.println(sum(1, arr));
}
}
How Varargs Works?
When invoking with variable arguments, compiler matches the argument list from left-to-right with the formal parameters. Once initial set of parameters are matched, then whatever arguments are remaining are constructed as an array and passed to the method.
In the given example, value ’1′ is passed as argument for variable ‘i’ then there are no other arguments remaining except varargs. So the remaining values ’2, 3′ are constructed as array and passed as parameter. This is how the dynamism is achieved.
solution
In your case there was the option of having three or more parameter then simply try with
MyClass(int i, int j, int... k){}

Related

How to pass an arbitrary number of the same type arguments to a method using varargs?

These arguments are specified by three dots after the type. but i don't know what mean of ... in the method
public static void printNumberOfArguments(int... numbers) {
System.out.println(numbers.length);
}
and also in documentation
public static void method(long.. vararg) { /* do something */ }
this is wrong i don't know why?
It's possible to pass an arbitrary number of the same type of arguments to a method using the special syntax named varargs (variable-length arguments). These arguments are specified by three dots after the type. In the body of the method, you can process this parameter as a regular array of the specified type.
Your method takes an integer vararg parameter and outputs the number of arguments in the standard output using the length property of arrays.
... is a special syntax used here to specify a vararg parameter.
i am trying to provide you both types or passing varargs in methods in java:
incorrect example:
public static void method(double... varargs, int a) { /* do something */ }
The correct version of the method is:
public static void method(int a, double... varargs) { /* do something */ }
A variable-length argument is specified by three periods(…).
you can invoke the method passing several integer numbers or an array of ints. these some examples will help you to understand this:
printNumberOfArguments(1);
printNumberOfArguments(1, 2);
printNumberOfArguments(1, 2, 3);
printNumberOfArguments(new int[] { }); // no arguments here
printNumberOfArguments(new int[] { 1, 2 });
This code outputs:
1
2
3
0
2

Array Containing Methods/Functions for Argument Passing

I have a method that selects between the arguments of an array and returns a specific one. For instance, here is that method:
private <T> T selectOnType(T[] selection, T defaultOp){
switch(this.type){
case Resources.TEXT:
return selection[Resources.TEXT];
case Resources.LISTEN:
return selection[Resources.LISTEN];
default:
return defaultOp;
}
}
How can I construct an array full of method references (i.e. function pointers) in order to be able to pass that array into this method above?
I tried doing such things as:
java.util.function.Function<Void, Void>[] array = {ClassA::method1, ClassA::method2};
(where method1 and method1 take no arguments and return void)
But that throws a compiler error saying:
incompatible types: invalid method reference but expected no arguments. found: java.lang.Void reason: actual and formal argument lists differ in length
I have been playing around with lambdas such as:
() -> ClassA.method1()
But I haven't been able to get it to work. Does anyone know what I am doing wrong and know a solution to this problem?
EDIT:
I have seen this on Stack Overflow, but this is for C# and I haven't figured out how to mimic it in Java.
Example:
Let's say I have a Word class:
public class Word{
private final String text;
private int listenCorrect = 0, textCorrect = 0;
public Word(final String test){
this.text = text;
}
public void incListenCorrect(){
listenCorrect++;
}
public void incTextCorrect(){
textCorrect--;
}
}
And finally I have a Main class. Inside the action method (in the Main class) I want to have an array with these two methods in it in order to select between them if the type (shown below) is either listen or text:
public class Main{
int type = 0;
public void action(){
Word word = new Word("Hello");
// 'Functions' is used to represent something I tried above (just for demonstration)
Function[] array = {word::incListenCorrect, word::incTextCorrect};
Function picked = selectOnType(array, word::incTextCorrect);
picked.call();
}
/*
* Resources is another class that contains the following values:
* public static final int TEXT = 0;
* public static final int LISTEN = 1;
*/
private <T> T selectOnType(T[] selection, T defaultOp){
switch(this.type){
case Resources.TEXT:
return selection[Resources.TEXT];
case Resources.LISTEN:
return selection[Resources.LISTEN];
default:
return defaultOp;
}
}
}
A Function is a method that takes one argument and returns a result. You're using methods that take no arguments and do not return results. You can't use Function for this (using Void isn't a way to get around this), but the java.util.function package contains a number of classes for different common combinations (methods that take no arguments but return a result, methods that take one or two arguments and don't return a result, methods that take primitive arguments or return primitive results that won't work in a Function because the types aren't class types, etc.).
There isn't a class in java.util.function for a functional interface with no arguments and no result, but Runnable can be used for that.
You need to make sure you use the correct interface.
Note: I was assuming method1 and method2 are static methods, so that they don't take any arguments, even a hidden "instance" argument that instance methods take. If they're instance methods, then things have to be done differently.
Now that you've clarified that they're instance methods, things are different--but it depends on how you get the method. If you say
Word::incListenCorrect
since you're using the class name, you need to provide the instance as an argument. Therefore, Word::incListenCorrect returns a functional interface for a method that takes one argument, such as Consumer<Word>, and you have to pass the Word as the argument when you call the method with .accept(). But:
word::incListenCorrect
is very different. Now, the word instance becomes "baked into" the method reference, so it doesn't need to be passed as an argument. In this case, therefore, you'll still need the interface that takes no arguments and does not return a value, which is Runnable. When you say
Runnable r = word::incListenCorrect;
r.run();
where r is a Runnable, it will automatically use word as the instance for the instance method, since word became part of r when you assigned the method reference to it.

Is there a way to get a table with parameters of a function?

Say I had a function like this
public static boolean test(int a, int b)
is there some sort of way to access the parameters in some sort of array somewhere? The reason why is i have a function with a lot of parameters but i want to get them all through a for loop so I want to be able to do something like
for(int i; i < 3; i++) test.args[1] do stuff
Are you asking can you pass an array as a parameter? If so then the answer is yes. Below I pass an array of doubles as a parameter to a method.
public void meth1 (double[] myList){
for(int i =0; i<myList.length; i++){
//Process entries here
}
}
Java supports "varargs" - see Arbitrary Number of Arguments:
You can use a construct called varargs to pass an arbitrary number of values to a method. You use varargs when you don't know how many of a particular type of argument will be passed to the method. It's a shortcut to creating [and accepting] an array manually ..
To use varargs, you follow the type of the last parameter by an ellipsis (three dots, ...), then a space, and the parameter name. The method can then be called with any number of that parameter, including none.
For instance, in this case that might look like like:
public static boolean test(int... args) {
// now args, a variable of type int[], can be accessed
for(int i; i < args.length; i++) {
doStuff(args[i]);
}
}
This is exclusive of individually named parameters and as such there is no way to enforce the multiplicity in the type system - the above method will accept 0..n integers.
As far as individual parameters: they can only be accessed by bound identifier name and there is no "table lookup" available at runtime. A collection could be built/used internally, of course:
public static boolean test(int a, int b) {
int args[] = {a, b};
// yay, now we got an array of argument values and the method
// must be invoked with exactly 2 arguments
}

Varargs and Generics in java

Consider the following scenario:
<T> void function(T...args){
...code...
}
And then I call it using a Integer[]. How does the compiler assume that T is an Integer, and not a Integer[]? (Note, I'm glad that this is the case, but I still find the ambiguity odd).
Furthermore, if I wanted T to be Integer[], is there anyway for me to do that (assuming boxing/unboxing doesn't exist)?
The Java compiler is smart enough to know that, since you gave it an Integer[], you probably meant for T to be Integer, not Integer[]. I'd assume this is part of the Java language specification that defines ... as varargs.
If you want to specify what T is, you can do that with the following syntax:
Integer[] ary = { 1, 2, 3 };
myObj.function(ary); // T is Integer
myObj.<Integer>function(ary); // T is Integer
myObj.<Integer[]>function(ary); // T is Integer[]
<Integer>function(ary); // this is invalid; instead you could do...
this.<Integer>function(ary); // this if it's an instance method
MyClass.<Integer>function(ary); // or this if it's static
Generics works on object references, so <T> will work on object references of a class. int[] is a class that references an array of int, while int is a primitive. Integer[] is a class that references to an array of Integer, where Integer is another class.
After reviewing this, the varargs param T ... args expects an array of object references, so int[] would be a single element in the array of object references, while Integer[] is an array of object references.
If you want to send an Integer[] as each element of your varargs, you can send an Integer[][]. I wrote an example:
public class SomeMain {
static <T> void foo(T...ts) {
for(T t : ts) {
System.out.println(t);
}
System.out.println();
}
public static void main(String[] args) {
int[] ints = { 1, 2, 3 };
Integer[] integers = { 1, 2, 3 };
foo(ints);
foo(integers);
//note, here each element in the varags will behave as Integer[]
foo(new Integer[][] { integers });
}
}
Output (the hash code of the array will change on every run):
[I#8dc8569
1
2
3
[Ljava.lang.Integer;#45bab50a
There are 3 phases in finding the applicable methods. On the 1st phase, javac tries to match argument types and method parameter types exactly. The parameter type of the method is T[] on this phase, the argument type is Integer[], the two matche after T is inferred to be Integer, therefore the method is chosen as the applicable method (there are no other overloading methods to consider). No further phases are carried out.
If the 1st phase does not yield an applicable method, javac will continue to other phases. For example, if T is explicitly specified as Integer[], the method will not match on the 1st phase (because T[] would not match Integer[])
On the 3rd phase, varargs are considered; javac will match T, not T[], with trailing argument types.
This is indeed, quite confusing, and appear to be ambiguous to our intuition.
Note that Generics isn't completely relevant to the question. The exact same question would apply if the function signature were void function(Object... args) -- if you pass an expression of type Integer[], it could interpreted as either using the array as args, or as one of the elements of args.
The answer is that, basically, the compiler will prefer to use the argument as args if possible. Since the expression you are passing has "array of reference type" type, it is compatible with args, and therefore, that interpretation prevails.
Furthermore, if I wanted T to be Integer[], is there anyway for me to
do that (assuming boxing/unboxing doesn't exist)?
Since it is a generic method, you can explicitly specify the the type argument when calling: this.<Integer[]>function(...).
But back to the more general question where the function signature is void function(Object... args). You could explicitly create the array of arguments yourself:
function(new Integer[][]{ myIntegerArray });
or (simpler) you can cast the expression to a type that is no longer an array of reference type:
function((Object)myIntegerArray);

Actual and Formal arguments differ in length - don't know why

I'm a beginner Java programmer, and I have two simple files to solve a simple math problem. One of them calls the other, which calculates the factorial of the number (e.g. 4! = 24). For some reason, I can't call the Factorial constructor.
Here is the calling class:
package Permutations;
import Permutations.Factorial;
public class Permutations {
public static void main(String args[]) {
System.out.println("There are 10 students. Five are to be chosen and seated in a row for a picture. How many linear arrangements are possible?");
System.out.println(new Factorial(10) / new Factorial(5));
}
}
Here is the Factorial class
package Permutations;
public class Factorial {
public long Factorial(int num) {
long result = 1;
for(int i = num; i > 0; i--)
result *= i;
return result;
}
}
Here is the error:
Permutations\Permutations.java:7: error: constructor Factorial in class Factoria
l cannot be applied to given types;
System.out.println(new Factorial(10) / new Factorial(5));
^
required: no arguments
found: int
reason: actual and formal argument lists differ in length
Permutations\Permutations.java:7: error: constructor Factorial in class Factoria
l cannot be applied to given types;
System.out.println(new Factorial(10) / new Factorial(5));
^
required: no arguments
found: int
reason: actual and formal argument lists differ in length
2 errors
I could change it to a static method, but then I would have to call it with Factorial.Factorial(num) rather than new Factorial(num), which would be inconvenient.
I have no idea why this is happening. Please help!
Thanks.
EDIT
Thanks for the answers. I've figured out what I've done wrong.
To begin with, what you have written is not a constructor. Constructor don't have return type.
So, in absence of constructors, your class has defined a default constructor that takes no arguments (which is the one the compiler dutifully tells you to use, since you try to create a new instance).
Solutions:
use a static method instead of trying to use instance. Seems the most practical approach
if you must use a class because it is homework, define both the constructor and a getFactorial method. The getFactorial may have a return type, and provide you the value that you want. You will have to use it in something like that
Factorial fac1 = new Factorial(5);
System.out.println("Factorial " + fac1.getFactorial());
or even
System.out.println("Factorial " + (new Factorial(5)).getFactorial());
Usually the first version is prefered for readability.
There is no constructor in your class that takes a long argument. You are mistaken by the fact that this method is a constructor:
public long Factorial(int num)
Constructors don't have a return type. As you have mentioned a return type to above signature, hence it has become a normal method and not a constructor.
And when there is no constructor written in class, then compiler provides a no parameter constructor and hence it is throwing an error with reason:
reason: actual and formal argument lists differ in length
Constructors cannot have user defined return type:
They can be just:
public constructor(parameter p){
// TO DO SOMETHING
}
And you cannot pass value in System.out.println() as new Something(); . Only methods can be passed like that which have some return type.
When you declared
public long Factorial(int num)
, this isn't a constructor for Factorial, since it's typed as long. A constructor would have to be declared as follows:
public Factorial(int num)
Since you haven't declared a constructor, the only existing constructor is the default one, which takes no arguments, and so when you call
new Factorial(10)
you get an error, since new Factorial takes no arguments with the only existing constructor.
Edit: Also, even if you fix that, you can't take
new Factorial(10) / new Factorial(5)
because division isn't defined on factorials.
First please refer to the Java Code Conventions for naming packages and classes and methods.
Second you mixed up constructor and methods of a class. A constructor has the same name as the class and no return value. It is used with the new keyword to generate an instance of the class.
You have written a method called "Factorial" with the return type int (see coding guidelines why you should use lower case). Since your class is missing a constructor Java has added a default one with no parameters. But you try to call an constructor with an int parameter. This is why you get the error.
To call your method Factorial on the object Factorial you would need to generate a new instance and call the method with the int param. Like this:
int fact = new Factorial().Factorial(5)
However for your example an object creation is not needed so maybe go for a static method factorial instead.

Categories