Assuming I have a super class that has 3 parameters in it's constructor and i am inheriting this class that also has a constructor with 3 parameters, and I want to call the super class constructor but before I want to do some logic on the sub class first, I can call a static method that receives those 3 parameters but I have to return only one, so this is the solution I came up with
public class someClass extends SuperClass {
public someClass(int a,int b,int c) {
super(func(a,b,c),b,c);
}
public static int func(int a,int b,int c){
//usage a b c
return a;
}
}
It seems a bit ugly and I was wondering if there is a better solution to use the parameters myself and then call super regularly. Note that i cannot change the Super class or that usages of the sub classes and therefore factory Design Pattern
To get the logic out of your constructor, you can easily create a factory method in your subclass:
public class SomeClass extends SuperClass {
private SomeClass(int a, int b, int c) {
super(a, b ,c);
}
public static SomeClass create(int a, int b, int c){
// calculate a for constructor
return new SomeClass(a, b, c);
}
}
Then you can create instances as follows:
SomeClass someClass = SomeClass.create(1, 2, 3);
In Java you are not allowed to execute another statement before the call to super. The trick you mentioned works, but you cannot refactor your code to have the call to func in a statement before the call to super.
In my experience, issues like this often hint at some design issue. Maybe you can solve the underlying problem by re-thinking about the responsibilities of the two involved classes.
You could also use the builder pattern
public class SomeClass extends SuperClass {
public static class Builder {
private int a, b, c;
public Builder withA(int a) {
this.a = a;
return this;
}
public Builder withB(int b) { ... }
public Builder withC(int c) { ... }
public SomeClass build() {
// logic goes here
return new SomeClass(...)
}
}
// hide this from public use, use Builder instead
protected SomeClass(int a, int b, int, c) {
super(a, b, c);
}
}
SomeClass someClass = new SomeClass.Builder().
withA(1).
withB(2).
withC(3).
build();
Related
I'm learning the super keyword and accidentally get this, here's an example :
public class A {
double a;
public A (double a) {
this.a = a;
}
}
public class B extends A {
public B (double b) {
super.a = b; //***
}
}
The usual way to do this as in the tutorials is super(b) to reusing its parent constructor, but what is wrong with super.a = b?
There is no "constructor inheritance" in Java. If the super class doesn't have a no-arg constructor, you must explicitly call its constructor (or one of them if there are several). If you don't, you'll get a compilation error.
When you write your class A like this:
public class A {
double a;
public A(double a) {
this.a = a;
}
}
you overwrite the default constructor and in the line this.a = a you are accessing instance variable and setting the values and in class B:
public class B extends A {
public B(double b) {
super.a = b; // ***
}
}
you are trying to access instance variables of Class B through the constructor because super.a in here , the super referes to the constructor and its wrong and throwing the Implicit super constructor A() is undefined. Must explicitly invoke another constructor which means: in Class B its looking for a constructor which has no parameter because you overwrite the default constructor of class and it can't recognize it by calling super.a = b so you have to call the super constructor as a function and in the first line of code:
public class B extends A {
public B(double b) {
super(b);
super.a = b; // ***
}
}
I know I'm asking some serious 101 question here...
I have some class Foo and a class Bar that extends Foo. In Foo I have a constructor that takes a set of parameters that it sets to its fields. Deriving classes such as Bar will typically not need to modify this. Now my IDE is giving me "There is no default constructor available in Foo". From a bit of Googling this appears to be because "constructors are not inherited". So all nice and well, but how do I now get this to work without duplicating this constructor in every deriving class? I'm assuming there is a more sane approach?
Use the super constructor:
public Bar(int a, double b, ...) {
super(a, b, ...);
}
So all nice and well, but how do I now get this to work without duplicating this constructor in every deriving class?
You do need to duplicate the constructor signatures - if you want the subclass to have constructors with the same signatures. But you don't need to duplicate the code - you just chain to the superclass constructor:
public Bar(int x, int y) {
super(x, y);
// Any subclass-specific code
}
Of course if you can work out the superclass parameters from a different set of parameters, that's fine. For example:
public Bar(int x) {
super(x, x * 2);
// Any subclass-specific code
}
You really need to work out what information is required to construct a Bar - that should dictate your constructors.
If this is a problem, it's possible that you're overusing inheritance. It's hard to say for sure without any idea of what your actual classes are, but you should look at using composition instead of inheritance. It's no panacea, but it can avoid this sort of thing.
No, there's no more "sane" approach. If your base class has no default constructor, then you must explicitly call the correct constructor from all the children classes.
Note this doesn't mean children classes need to have the exact same constructor than base class. For example this is perfectly valid:
class Foo {
protected int a;
protected int b;
protected Foo(final int a, final int b) {
this.a = a;
this.b = b;
}
}
class Bar extends Foo {
protected Bar() {
super(0,0);
}
}
The problem is solved with this:
class Foo{
Foo(int a, int b){}
}
class Bar extends Foo{
//Here must be a constructor OR declare a constructor in Foo without parameters
Bar(){super(1,1)} //this is an example
}
Other solution is:
class Foo{
Foo(int a, int b){}
Foo(){}
}
class Bar extends Foo{
}
Remember that if have a constructor with parameters in the SuperClass (in this case Foo), the implicit constructor on the child class (in this case Bar), always will have a implicit call to "Super()" (always have to be one unless explicit).
This error could also happen because you are calling your super constructor last. You might have to move it to be the first statement:
public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
mFragmentList = fragmentList;
super(manager);
}
public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
super(manager); --> this should come first
mFragmentList = fragmentList;
}
JVM will not provide a default constructor if you have provided one due to design reasons. What you can do define constructor in Bar with same signature and call super().
public Bar(int x,int y) {
super(x,y);
}
If parameters are not required and/or have default values then you can define default constructor (without parameters):
class Foo
{
public final int DEFAULT_A = 42;
protected int a;
protected int b;
public Foo(final int a, final int b)
{
this.a = a;
this.b = b;
}
// Is equal to new Foo(Foo.DEFAULT_A, 0);
public Foo()
{
this.a = this.DEFAULT_A;
}
}
class Bar extends Foo {}
class PiBar extends Bar
{
public final int DEFAULT_A = Math.PI;
}
I am trying to create a constructor in a subclass, but I want to change one of its "inherited" variables to something more appropriate for the subclass without changing the functionality of the superclass (specifically, I am trying to change the type of the variable from a String to an Object I made in another class). Problem is, I can't directly change or access the variable because it is private in the superclass and there is no setters for this variable.
Is there some other way to effectively override the superclass constructor so I can modify this "inherited" variable without editing the superclass? Or should I not be inheriting from the superclass in this case, even though all the other methods would remain mostly untouched?
Essentially, what I want to do is something like this:
//This should not be changed
public class Super
{
private SomeArrayObject<String> o;
private String a;
private SomeObject b;
public Super(String a, SomeObject b)
{
this.a = a;
this.b = b;
o = new SomeArrayObject<String>();
}
public void someMethod()
{
//Does something
}
}
public class Sub
{
private SomeArrayObject<ObjectFromOtherClass> o; //Notice the diff?
public Sub(String a, SomeObject b)
{
super(a, b);
o = new SomeArrayObject<ObjectFromAnotherClass> o;
}
}
As a quick note, there is no "default constructor" in the superclass, so I can't just use super() and fill in the variables as needed.
I can see your problem. You can't modified it because is private right? and it's ok to be private variable, but in this such of cases, you can change the visibility of the variable to protected, so the subclass can see it and modify it.
Edit:
Seeing the new info, you have to do a few little changes more, add a generic, and makke the variable protected, an create a new generic class:
public class SuperClassGen<A> {
protected ArrayList<A> o;
private String a;
private int b;
public SuperClassGen(String a, int b) {
this.a = a;
this.b = b;
this.o = new ArrayList<A>();
}
}
public class SuperClass extends SuperClassGen<String> {
public SuperClass(String a, int b) {
super(a, b);
}
}
public class SubClass extends SuperClassGen<ObjectFromOtherClass> {
public SubClass(String a, int b) {
super(a, b);
}
}
That will allow change the type from the subclass in the constructor, without
I have a super class named TestSuper
public class TestSuper {
int a = 0;
}
and I have 2 sub classes named TestSub and TestSub2 that extend TestSuper
public class TestSub extends TestSuper{
int a=1;
}
public class TestSub2 extends TestSuper{
int a=2;
}
in my main class i created a method that takes in a type TestSuper and returns the a value of it and in the main i display it on the console
public class Main {
public static void main(String[] args){
System.out.println(test(new TestSub())+" "+test(new TestSub2()));
}
public static int test(TestSuper b){
return b.a;
}
}
but the output is "0 0" instead of "1 2", what do I do?
You need to cast the reference so say which one you want.
public static int test(TestSuper b){
return b instanceof TestSub ? ((TestSub) b).a :
b instanceof TestSub2 ? ((TestSub2) b).a :
b.a;
}
If this seems needlessly complicated, it is. You should use polymorphism instead.
public class TestSuper {
int a = 0;
public int getA() { return a; }
}
public class TestSub extends TestSuper {
int a = 1;
public int getA() { return a; }
}
public class TestSub2 extends TestSuper {
int a = 2;
public int getA() { return a; }
}
public static int test(TestSuper b) {
return b.getA();
}
First understand the difference between hiding and overriding: https://docs.oracle.com/javase/tutorial/java/IandI/override.html
Then create a getter method in the base-class which you can override in the subclass.
You can look into the theory behind this, and then do the only reasonable thing -forget about writing such kind of code.
In good OOP you consider your fields to be part of your "secret" internal implementation. You don't use fields of sub classes in the super class context. Period.
You are even very conservative about making a field protected in the superclass and to use that in subclasses.
When you call test method like this:
test(new TestSub())+" "+test(new TestSub2())
You use upcasting. Upcasting seperates interface and implementation for an object. But for seperating interface and implementation and achieving true implementation in polymorphism, you must use polymorphic structures. The instance variables aren't polymorphic. Because of this, actually you call a variable which is in TestSuper class.
Only instance methods are polymorphic.
If I have a constructor with two arguments, can I call super like this?
super(a,b).method
For example:
public class Money (){
int euro=0;
int count=0;
public Money(int a,int b) {
a=euro;
b=count;
}
public int getPay(){
return 100;
}
}
public class Pay extends Money{
super(a,b).getPay();
}
Is this possible?
It is not possible and does not make any sense. If getPay() is the parent class' method, it will be available to the child and can be called as such getPay() or like super.getPay() in case the child overridden the method.
Not exactly. However, it seems that you are trying to do two things:
Use the super constructor (Money) to define the Pay constructor
Call the super (Money) version of `getPay()` when you call this version of `getPay()`.
If so, then what you want to do is this:
public class Money (){
int euro=0;
int count=0;
public Money(int a,int b) {
a=euro;
b=count;
}
public int getPay(){
return 100;
}
}
public class Pay extends Money{
public Pay(int a, int b) {
super(a, b);
}
public int getPay() {
//This is redundant, see note below
return super.getPay();
}
}
Note: getPay() calling super.getPay() is totally redundant at this point (because you're overriding super.getPay(), and if you didn't you'd have access to it anyway). But what you can do now is modify the method (for example, return super.getPay() + someVariable;).
No, but you can call
public class Pay extends Money{
public Pay(int a,int b){
super(a,b);
}
}
and later on do
new Pay(1,4).getPay();