Constructors with "too many" parameters [duplicate] - java

This question already has answers here:
Managing constructors with many parameters in Java
(8 answers)
Closed 6 years ago.
Assume that I have some subclasses that extend a superclass. These subclasses differ by the parameters passed to the superclass. Unfortunately, like the following example, I can end up with "many" parameters. Is there a general method of avoiding this? Are constructors with "many" arguments considered good practice? Would it be better to have getter/setter methods instead of passing every parameter via constructor?
public abstract class SuperClass {
private int a;
private int b;
.
.
private int z;
public SuperClass(int a, int b, ... int z) {
this.a = a;
this.b = b;
.
.
this.z = z;
}
}
public class SubClass1 extends SuperClass {
public SubClass1() {
super(4, 3, ..., 9);
}
}
public class SubClass2 extends SuperClass {
public SubClass2() {
super(1, 7, ..., 2);
}
}

If your subclasses vary only in the parameters passed to the superclass, you might be looking for the Builder Pattern. A builder for the superclass lets you pass in whatever parameters you need without cluttering your constructor, and if you want subclasses for readability, you can just wrap a call to the builder and return its result from the subclass constructors.

Generally, constructors with many parameters is a code smell. It means you probably have a class that breaks the "Single Responsibility Principle". If you can't avoid it, try using the builder pattern!

I would not have constructors in my classes as the behavior of the objects instantiated by each constructor may be different and hard to determine.

One thing to check is: should SuperClass be split into simpler classes?
If this can't be done: if you have too many parameters then you can have a special class that holds the parameters; with setters and getters for each parameter.
One can fill the values in from property files, so you can have profiles for common cases.
class SuperClassParam
{
void seta(int a);
int geta();
//...
}
class SuperClass
{
public SuperClass( SuperClassParam params )
{
}

If the number of parameters can vary, then use a variable arity ("varargs") parameter. Declare an array instead of all those other instance variables. The variable arity parameter is typed as an array when in the method.
private int[] all;
public SuperClass(int... all) {
this.all = all;
}
Your subclass constructors will not have to change at all.

Related

Can I construct more than one type of object from same class data with the help of constructor in Java?

suppose I have a class (let's say class name is "MyClass") with data (a,b,c,d) can define two constructor, one used to create to object1 using data (a,b,c) and another constructor to create object2 using data (a,c,d). In this case all data type are same lets say double.
No, you can't do that.
The two constructors would have the same signature: MyClass(double, double, double).
In order to distinguish the two, you'd have to give them different names, and you can't do that with constructors.
You can however create differently named static methods to use instead of constructors, e.g.
public class MyClass {
// fields here
public static MyClass forObject1(double a, double b, double c) {
return new MyClass(a, b, c, 0);
}
public static MyClass forObject2(double a, double c, double d) {
return new MyClass(a, 0, c, d);
}
private MyClass(double a, double b, double c, double d) {
// assign to fields here
}
// methods here
}
Yes you can do it.
You can use overloaded constructors, just as you would use overloaded methods. You just need to make sure that you are overloading them properly such that there is no ambiguity for the JVM when it instantiates an object.
You can or cannot do it depending on what the types of object1 and object2 are.
Let's say that you have a class Foo. If you want object and object2 both of type Foo, then you can achieve this, like this:
class Foo{
//some methods....
public Foo(int arg1forObj1, int arg2ForObj1...){
//some code
}
public Foo(String arg1forObj2, String arg2ForObj2...){
//some code
}
}
Do note that the two constructors should not take the same type of arguments, otherwise they will be ambiguous.
However you want object1 and object2 to be of different types, no you can't achieve this. When you do new Foo()(ie create an instance of the class), the instance will always be of a Foo type.

I cannot understand the purpose of using and not using "void",(what does returning a value mean?" [duplicate]

This question already has answers here:
What does it mean to return a value?
(3 answers)
Closed 7 years ago.
so in this code we have three methods and I dont understand why we use voids in two of the methods and dont in one
can someone explain with detail
class Point {
private double anan;
private double baban;
public void print(){
System.out.println("(" + anan + "," + baban + ")");
}
public Point(double anan, double baban) {
this.anan = anan;
this.baban = baban;
}
public void scale(){
anan = anan/2;
baban = baban/2;
}
Constructor dont have returntype
public Point(double anan, double baban) {} // is a constructor
public void print(){} // is a method
public void scale(){} // is a method
From the Providing Constructors for Your Classes , Deifining Methods
Constructor declarations look like method declarations—except that
they use the name of the class and have no return type
The only required elements of a method declaration are the
method's return type, name, a pair of parentheses, (), and a body
between braces, {}.
The return type—the data type of the value returned by the method, or
void if the method does not return a value.
When a method does not return something then return type should be void.
As your method Point()
public Point(double anan, double baban) {
this.anan = anan;
this.baban = baban;
}
is the constructor method, so there has no return type.
Here is a discussion about Methods vs Constructors
The important difference between constructors and methods is that constructors create and initialize objects that don't exist yet, while methods perform operations on objects that already exist.
Constructors can't be called directly; they are called implicitly when the new keyword creates an object. Methods can be called directly on an object that has already been created with new.
The definitions of constructors and methods look similar in code. They can take parameters, they can have modifiers (e.g. public), and they have method bodies in braces.
Constructors must be named with the same name as the class name. They can't return anything, even void (the object itself is the implicit return).
Methods must be declared to return something, although it can be void.
For further reading see methods and constructors.

How to access (shadowing) member variables in subclass from method in superclass?

Let me know if someone does not understand the question. I tried my best to frame the question below.
I have a common method in parent class for generating pattern. For re usability, I thought to retain this method under parent class.
Inside the method, I use several variables. So I thought it is better to pass the object as the parameter to the method generatePattern. But since variables cannot be overridden, how can I use respective variables from these sub classes? Any other feature in java other than using subclass? Will "Generic types" as parameter work in such case?
class Parent {
int var1;
String[] values;
void generatePattern(Parent obj1) {
// This will not make use of respective values of
// subclass object that is passed I guess.
newPattern(obj1.values, obj1.var1);
}
}
class AscendSubClass extends Parent {
int var1 = 5;
String[] values = {"S", "R"};
}
class DescendSubClass extends Parent {
int var1 = 10;
String[] values = {"N", "D"};
}
I may pass either AscendSubClass or DescendSubClass above to generatePattern().
Inside this method, I need to use the variables var1, values and many other variables of subclasses.
These variables are of same type and have same name, but the values are different and depends on the subclass. How can I refer these variables now in generatePattern() so that method does not change?
It is possible to achieve this by making variables as a parameters to methods or by if/else statements, but I have several variables to pass and it is big inconvenience.
Add a getter method and override it in either subclass.
public int getVar() {
return var1;
}

Polymorphism: Least cumbersome way to assign data fields?

I'm currently taking a Java course and have a question about polymorphism.
Given
public class A {
private int a1;
public A(){}
public A(int a1) { this.a1 = a1;}
}
class B extends A {
private int b1;
public B() {}
public B(int b1, int a1) {
super(a1);
this.b1 = b1;
}
}
class C extends B {
private int c1;
public C(){}
public C(int c1, int b1, int a1) {
super(b1, a1);
this.c1 = c1;
}
}
What would be the best way to assign to fields a1, b1, and c1, all in one swoop? My first guess would be to make an instance of C and call its three-arg constructor.
But what happens when each class contains 10s or 100s of data fields? Wouldn't this approach mean calling constructors with huge numbers of arguments, like
C(arg1, arg2, ..., arg100), setting k of C's fields, then making a call to
B(arg1, arg2, ..., arg100-k), and so on,
all the way up to the top? Is there a better way to proceed?
Having so many parameters is a definite code smell; in all probability you want to split the object up into smaller self-contained objects and/or or collections.
On the other hand, there is the Builder pattern, where you use a helper class to set all the parameters and it constructs the object for you, possibly sanity-checking that all required fields are set and there are no conflicts.
Not in this particular case because the fields in the parent classes are declared private.
If they were protected then you could set all 3 of them from the class C constructor. However this breaks encapsulation because if the constructor for B did something else after the value was assigned you'd have to duplicate that logic in C in order to not violate it's contract, and as you can imagine that gets very messy when you have more constructors or parent classes in the type tree.
Having multiple calls chained in the manner you proposed is the safest way at the cost of having to call all those constructors up the chain. I'd recommend profiling your code to see if this is actually a problem and not just a premature optimization.
What you're suggesting would work if you set the class fields to public. Class C will have a1 and c1, but won't be able to access them due to them being private.

Final keyword in method signatures [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Final arguments in interface methods - what’s the point?
While trying to experiment a few things, I've ran into a problem that it's described in this page.
interface B {
public int something(final int a);
}
abstract class C {
public int other(final int b);
}
class A extends C implements B {
public int something(int a) {
return a++;
}
public int other(int b) {
return b++
}
}
Why is such feature possible? I don't know why it's possible to to make a final parameter into a non-final one by just overriding the method. Why is the final keyword ignored in a method signature? And how do I obligate sub-classes to use in their methods final variables?
Java passes arguments to a method by value.
Therefore, no changes to a parameter can propagate back to the caller. It follows that whether or not the parameter is declared final makes absolutely no difference to the caller. As such, it is part of the implementation of the method rather than part of its interface.
What's your motivation for wanting to "obligate sub-classes to use in their methods final variables"?
final for a parameter only means that the value must not be changed within the method body. This is not a part of the method signature, and is not relevant to subclasses.
It should be invalid to have final parameters in interface or abstract methods, because it's meaningless.
Final variables are the only ones that can be used in closures. So if you want to do something like this:
void myMethod(int val) {
MyClass cls = new MyClass() {
#override
void doAction() {
callMethod(val); // use the val argument in the anonymous class - closure!
}
};
useClass(cls);
}
This won't compile, as the compiler requires val to be final. So changing the method signature to
void myMethod(final int val)
will solve the problem. Local final variable will do just as well:
void myMethod(int val) {
final int val0;
// now use val0 in the anonymous class
Java's final is not C++ const; there is no such thing as const-correctness in Java.
In Java, one achieves const-ness using immutable classes. It turns out to be quite effective because unlike C++, one cannot simply mess with memory. (You can use Field.setAccessible(true), and then use Reflection. But even that corruption-vector can be prevented by running the JVM with an appropriately configured security manager.)
The final keyword for arguments is not part of the method signature, and is only important for the body of the method, because Java passes all arguments by value (a copy of the value is always made for the method call).
I only use the final keyword (for arguments) if the compiler forces me to make it final, because the argument is used inside an anonymous class defined in the method.
In Java parameters are passed by value. Whether a parameter is final or not only affects that method, not the caller. I don't see why a class needs to obligate the subtypes.
Note that final parameters have one main purpose: you can't assign new values to them.
Also note that parameters are always passed by value, thus the caller won't see any assignments to the parameter inside the method.
If you really want to force parameters to be final (in order to prevent bugs that might be introduced when reassigning a parameter accidentially), employ a code anaylzer such as checkstyle.

Categories