I am writing a program in Java and having a problem with inheritance.The code I am running has this structure:
public class BaseClass
{
ObjectInputStream a;
ObjectOutputStream b;
public BaseClass(ObjectInputStream a, ObjectOutputStream b)
{
this.a = a;
this.b = b;
}
//Some other code....
Thread subClass = new Thread(new SubClass());
subClass.start();
}
And then here is the SubClass:
public SubClass extends BaseClass implements Runnable
{
//Code for SubClass...
}
Then, when I compile the code, the only error I receive is
./SubClass.java:6: error: constructor BaseClass in class BaseClass'
cannot be applied to given types;
public class SubClass extends BaseClass implements Runnable
^
required: ObjectInputStream,ObjectOutputStream
found: no arguments
I am assuming that the problem is coming from the fact that I am extending a BaseClass that has a constructor, so it is invoked when I inherit the class, but I am not completely sure. Is there a way for me to invoke that constructor with the correct arguments? Or, better yet, a way to not invoke the constructor at all? Any help is appreciated, and thank you for your responses.
Your subclass should have a constructor that takes in
ObjectInputStream a, ObjectOutputStream b
and than pass it to the base class using
super(a, b):
I believe it would look like this:
class Subclass extends BaseClass {
SubClass(ObjectInputStream a, ObjectOutputStream b) {
super(a, b);
}
}
EDIT---
You can't 'not call' constructor. Even if base class has default constructor (no arguments), it will be implicitly called from your sub class.
You don't have a call for super - the parent cunstractor:
public SubClass extends BaseClass implements Runnable
{
//must implement the following contractor:
public SubClass(ObjectInputStream a, ObjectOutputStream b /*some other parameters*/){
super(a,b);
}
// the rest of the code.....
}
The base class has no default constructor, witch implies that it must receive one ObjectInputStream and one ObjectOutputStream. So, SubClass must have a constructor like this, or one that call super, passing the arguments. I would like you to:
Review your inheritance
See if Base Class could have a default constructor
Create a default constructor in SubClass passing null to super -> super(null,null)
Create a default constructor in SubClass passing the two objects required
There's is no way to not call the parent constructor. The compiler automagically adds the call super to you.
The basic idea behind inheritance is that the public methods and variables of the Superclass will be available in the Subclass. (There is more to it than just this statement, but this should suffice for now). So in your case, when you extend the BaseClass to the SubClass, you have the two variables ( ObjectInputStream and ObjectOutputStream) available to you in the SubClass.
Thus you HAVE to provide them with some initial values when you create an Object of the SubClass. Hence you should add the following constructor to your SubClass.
public SubClass(ObjectInputStream a,ObjectOutputStream b){
super(a,b); // The order in super should be same as the order of arguments in your BaseClass constructor! Make a not of this.
}
Note: The order of arguments in the super() method is important!
When you create a class that inherits from another class, one of the implications is that you are going to depend on some code in the base class. That means you need to setup the base class properly. Since your base class has only that one constructor that takes parameters, your class needs to provide a constructor that takes the same parameters so it can initialize its base class. So you need to add an additional constructor that takes the same parameters as the base class.
Related
Why is the constructor in B required?
IntelliJ suggests to remove =null as it is redundant presumably because it is initialized through the given constructor in A.
However, this removal (which is presumably also performed by the compiler) then (presumably) requires the constructor in B.
Any other explanation?
public abstract class A {
private Object foo = null;
public A(Object foo){this.foo=foo;}
}
public class B extends A {
public B(Object foo){super(foo);}
}
Java does not have "constructor inheritance". The only way to initialize A is to pass the foo parameter to its constructor, and the only way to do this is to create a constructor for B that does so.
Note, however, that they don't have to have the same signature (like you have in the question) - B's constructor only needs to pass some parameter to A. E.g.:
public class B extends A {
public B() {
super("Arbitrary default passed to A");
}
public B(Object passedToA, Obejct notPassedToA) {
super(passedToA);
System.out.println("This argument was not passed to A():" + notPassedToA);
}
}
Why is the constructor in B required?
If the class B extends A, the class B must be instantiated in all possible ways as the class A can be and the class B can have additional ways to be instantiated. It means that class B is forced to have a constructor.
The only exemption can be in case of a no-arg constructor because the compiler makes it up with a default constructor i.e. if you put a no-arg constructor in the class A the child classes are not forced to have this.
Consider
class MyClass{
public MyClass(Integer i){}
}
class MyExtendedClass extends MyClass{
public MyExtendedClass(SomeType s){ ... }//Compile error if SomeType!=Integer
public MyExtendedClass(Integer i){
super(i);
...
}
}
Why we cant define constructor of MyExtendedClass with signature different from MyClass's constructor? Why we must call a constructor of superclass firstly?
You can define a constructor with a different signature. But in the constructor of the subclass you have to call the constructor of the base class. The base class needs to initialize itself (e.g. its private members) and there is no other way to do it other than by calling one of its constructors.
Why we cant define constructor of MyExtendedClass with signature different from MyClass's constructor?
You can of course do it. The error you are getting is for a different reason.
Why we must call a constructor of superclass firstly?
Because that is how the objects of your class are initialized. An object's state comprise of all the fields in it's own class, plus all the non-static fields of all the superclasses.
So, when you create an instance, the state should be initialized for all the superclasses and then finally of it's own class. That is why the first statement of a constructor should be super() chaining to the superclass constructor, or this() chain to it's own class constructor.
The reason your code probably failed is, you are trying to call the superclass constructor with string argument. But there is no such constructor currently. The super class has just a single constructor taking an int argument. Also, adding super() would not work too. Because your superclass doesn't have a 0-arg constructor.
Try changing your constructor to:
public MyExtendedClass(SomeType s){
super(0);
}
and it would work. Alternatively, add a 0-argument constructor to your super class, and leave the subclass constructor as it is. It would also work in that case.
Suggested Read:
I wrote a blog post on Object Creation Process
Your constructor can have a different signature. But you must call one of super constructors. This is how Java works, see the Java Language Specification.
Alternative 1: You can call a static method, like following:
public MyExtendedClass(SomeType s){ super(convertToInt(s)); }
private Integer convertToInt(SomeType st){ ... }
Alternative 2: Use composition / delegate instead of inheritance.
class MyExtendedClass [
private MyClass delegate;
public MyExtendedClass(SomeType s){
do what you want
delegate = new MyClass(...);
}
public void doSomething(... params){
delegate.doSomething(params);
}
For example, I have an interface with 4 methods.
If I implement this interface incomplete in a class, the class must be abstract. Right?
For example, I leave one method out. So now I am writing a subclass which extends this class. Now I implement the last method of the interface.
What happens, if I call this method in the abstract superclass? Nothing! It works. But why?
What will happen, if I write several classes, extending this abstract class and implement the fourth method of the interface? Which one will be called?
A interface is a contract you define the signature of your methods, only behaviour and constants, all methods are public and abstract.
In an Abstract Class you define behaviour and state, you can have some implementation and abstract methods.
For example for your question:
If I implement this interface incomplete in a class, the class must be
abstract. Right?
Right
For example, I leave one method out. So now I am writing a subclass
which extends this class. Now I implement the last method of the
interface.
What happens, if I call this method in the abstract superclass?
Nothing! It works. But why?
Will run cause in runtime execution knows what class is. this is polymorphism.
What will happen, if I write several classes, extending this abstract
class and implement the fourth method of the interface. Which one will
be called?
The one you instanciate in your client code :D
public interface Operation{
void operation1();
void operation2();
}
I don't implement operation2
public abstract class ClaseBase implements Operation{
//with final im saying childs wont override
public final void operation1{
// do something
operation2();
// do something
}
}
//have to implements operation2 cause it's a concrete class
public class Child extends ClaseBase{
void operation2(){
System.out.println("Something");
}
}
You can't instanciate an AbstractClass.
In your client code
ClaseBase base = new Child();
base.operation1(); // and it's gonna to call operation2 in childClass
Abstract class is useful with Template Method pattern.
It depends on the object that you created. Super class can refer to subclass objects. So the actual object's method would be called.
interface A{
public void test1();
public void test2();
}
public abstract class B implements A{
public void test1(){
}
public abstract public void test2();
}
public class C extends B{
public void test2(){
}
}
B b = new C();
b.test2();//This works because the object that is refered by B is actually an object of C
Infact you can also do:
A a = new C();
a.test1();
a.test2();
Again though A is an interface(super type), but it is actually referring to a concrete implementation C(subtype) object and hence this works.
So at the compile time, compiler checks if A/B has a method called test2(), if yes compile is happy and it compiles successfully. But at the runtime, you invoke test2() method on the object and object actually is of class C which has the complete implementation.
Keep in mind that when you instantiate a subclass and refer it as super/abstract class or interface, it's still the instance of the subclass. Any method called on the object bubbles up from subclass to super class if its not available in the sub class.
Thus if you have:
interface GemeInterface
getStartScreen()
getCloseScreen()
abstract class AndroidGame implement GemeInterface
getCloseScreen()
class MrNomGame extends AndroidGame
getStartScreen()
class MrPetNomGame extends AndroidGame
getStartScreen()
and using as
//You can't instantiate AndroidGame hence the it has to be instance of a subclass
AndroidGame androidGame1 = new MrNomGame ();
androidGame1.getStartScreen();
//You can't instantiate AndroidGame hence the it has to be instance of a subclass
AndroidGame androidGame2 = new MrPetNomGame ();
androidGame2.getStartScreen();
Then also it works as androidGame1.getStartScreen() --> calls the method from MrNomGame, while androidGame2.getStartScreen() --> calls the method from MrPetNomGame.
Both the calls i.e. androidGame1.getCloseScreen() and androidGame2.getCloseScreen() will end up calling the method from AndroidGame as it's not available in the sub classes.
What happens, if I call this method in the abstract superclass? Nothing! It works. But why?
You cannot invoke this method on the abstract superclass because it can't be instantiated. You would only be invoking it on a sub-class of this abstract super-class which would be forced to provide an implementation (or be declared abstract itself).
So, when you invoke this method, its the implementation provided by the non-abstract sub-class that gets executed.
The funny thing is that a method of the class 'AndroidGame' calls 'getStartScreen()'. But there could be several classes like 'MrNomGame' which extending 'AndroidGame'. Then which method would be executed?
The method code executed would depend on the runtime type of the actual object that you invoke this method on. So, you could have a code like this
AndroidGame game1 = new MrNomGame();
AndroidGame game2 = new SomeOtherGame();
game1.getStartScreen(); // invokes MrNomGame's version
game2.getStartScreen(); // invokes SomeOtherGame's version
and due to dynamic binding the JVM would invoke the getStartScreen() as implemented by the class type of the actual object that the reference points to.
If Abstract class cannot be instantiated, then how can the variables
access and methods access of the abstract class A even without
extending is achieved in the class check (as you can see in the below
code)
Is the created a an object of abstract class A?
CODE
abstract class A
{
int a=10;
public A()
{
System.out.println("CONSTRUCTOR ONE");
}
public A(String value)
{
System.out.println("CONSTRUCTOR "+value);
}
void add(int sum)
{
System.out.println("THE SUM IS:"+sum);
}
int sub(int a,int b )
{
return(a-b);
}
}
public class check
{
public check()
{
new A("TWO"){};
}
public static void main(String args[])
{
int a,b,sum;
a=10;
b=15;
sum=a+b;
A s = new A() {};
new check();
s.add(sum);
int subb=s.sub(35,55);
System.out.println("THE SUB IS:"+subb);
System.out.println("THE VALUE OF A IS:"+s.a);
}
}
OUTPUT
CONSTRUCTOR ONE
CONSTRUCTOR TWO
THE SUM IS:25
THE SUB IS:-20
THE VALUE OF A IS:10
BUILD SUCCESSFUL (total time: 0 seconds)
The new A() {} call creates an anonymous subclass and instantiates that. Since A does not contain any abstract methods, this works.
You are creating subclass of A with this code -
A s = new A() {};
and here as well -
public check()
{
new A("TWO"){};
}
Whereas, the normal syntax for instantiation is this -
A a = new A();
which would give compilation error if you try to run this code. As such, you don't have any abstract method in your class, and hence a nominal subclass suffices and you get your code executed.
HTH,
- Manish
The normal use case is, you'd write new MyAbstractClass(){ and then implement whatever abstract methods you need to implement (and/or override existing non-abstract methods), and the compiler will infer a non-abstract subclass for you. Since your class doesn't have any abstract methods, it's not necessary to override anything.
A is marked abstract but has no abstract methods so when you do new A() {} you are providing an implementation that has nothing in it thus you are providing a concrete implementation and the class is complete.
Disregarding "visibility" (public, private, package scope, etc)... you generally need a class instance to access class members.
An exception is static classes.
Otherwise, if you have an abstract base class, you'll need to subclass to get an instance.
In your case, however, the class isn't really "abstract" (despite your attempting to label it as such). Simply because there are no abstract members or methods.
You created abstract class A without any abstract method.
Abstract classes cannot be instantiated, but they can be subclassed.
An abstract method is a method that is declared without an implementation.
In the constructor check() you just created anonymous class and call constructor A(String value).
new A("TWO"){};
This is a anonymous subclass .
1. This class create and instantiate at the same time...
2. No name of that class..
3. Because there is no name so it must need a parent .
You can get name by s.getClass().getName(); which return A$1....
A s = new A() {};
on the right side there is a new anonimus class which is inherited from A.A class haven't abstract methods so in your new anonimus class you don't need to override any methods.
Why default constructor is required(explicitly) in a parent class if it has an argumented constructor
class A {
A(int i){
}
}
class B extends A {
}
class Main {
public static void main(String a[]){
B b_obj = new B();
}
}
This will be an error.
There are two aspects at work here:
If you do specify a constructor explicitly (as in A) the Java compiler will not create a parameterless constructor for you.
If you don't specify a constructor explicitly (as in B) the Java compiler will create a parameterless constructor for you like this:
B()
{
super();
}
(The accessibility depends on the accessibility of the class itself.)
That's trying to call the superclass parameterless constructor - so it has to exist. You have three options:
Provide a parameterless constructor explicitly in A
Provide a parameterless constructor explicitly in B which explicitly calls the base class constructor with an appropriate int argument.
Provide a parameterized constructor in B which calls the base class constructor
Every subclass constructor calls the default constructor of the super class, if the subclass constructor does not explicitly call some other constructor of the super class. So, if your subclass constructor explicitly calls a super class constructor that you provided (with arguments), then there is no need of no arguments constructor in the super class.
So, the following will compile:
class B extends A{
B(int m){
super(m);
}
}
But the following will not compile, unless you explicitly provide no args constructor in the super class:
class B extends A{
int i;
B(int m){
i=m;
}
}
Why default constructor is required(explicitly) in a parent class if it has an argumented constructor
I would say this statement is not always correct. As ideally its not required.
The Rule is : If you are explicitly providing an argument-ed constructer, then the default constructor (non-argumented) is not available to the class.
For Example :
class A {
A(int i){
}
}
class B extends A {
}
So when you write
B obj_b = new B();
It actually calls the implicit constructor provided by java to B, which again calls the super(), which should be ideally A(). But since you have provided argument-ed constructor to A, the default constructor i:e A() is not available to B().
That's the reason you need A() to be specifically declared for B() to call super().
Assuming that you meant to write class B extends A:
Every constructor has to call a superclass constructor; if it does not the parameterless superclass constructor is called implicitly.
If (and only if) a class declares no constructor, the Java compiler gives it a default constructor which takes no parameters and calls the parameterless constructor of the superclass. In your example, A declares a constructor and therefor does not have such a default constructor. Class B does not declare a constructor, but cannot get a default constructor because its superclass does not have a parameterless constructor to call. Since a class must always have a constructor, this is a compiler error.
Why default constructor is required(explicitly) in a parent class if it
has an argumented constructor
Not necessarily!
Now in your class B
class B extends A {
}
you have not provided any constructor in Class B so a default constructor will be placed. Now it is a rule that each constructor must call one of it's super class constructor. In your case the default constructor in Class B will try to call default constructor in class A(it's parent) but as you don't have a default constructor in Class A(as you have explicitly provided a constructor with arguments in class A you will not have a default constructor in Class A ) you will get an error.
What you could possibly do is
Either provide no args constructor in Class A.
A()
{
//no arg default constructor in Class A
}
OR
Explicitly write no args constructor in B and call your super with some default int argument.
B()
{
super(defaultIntValue);
}
Bottom line is that for an object to be created completely constructors of each parent in the inheritance hierarchy must be called. Which ones to call is really your design choice. But in case you don't explicitly provide any java will put default constructor super() call as 1st line of each of your sub class constructors and now if you don't have that in superclass then you will get an error.
There are a few things to be noted when using constructors and how you should declare them in your base class and super class. This can get somewhat confusing solely because there can be many possibilities of the availability or existence of constructors in the super class or base class. I will try to delve into all the possibilities:
If you explicitly define constructors in any class(base class/super class), the Java compiler will not create any other constructor for you in that respective class.
If you don't explicitly define constructors in any class(base class/super class), the Java compiler will create a no-argument constructor for you in that respective class.
If your class is a base class inheriting from a super class and you do not explicitly define constructors in that base class, not only will a no-argument constructor be created for you (like the above point) by the compiler, but it will also implicitly call the no-argument constructor from the super class.
class A
{
A()
{
super();
}
}
Now if you do not explicity type super(), (or super(parameters)), the compiler will put in the super() for you in your code.
If super() is being called (explicitly or implicitly by the compiler) , the compiler will expect your superclass to have a constructor without parameters. If it does not find any constructor in your superclass without parameters, it will give you a compiler error.
Similary if super(parameters) is called, the compiler will expect your superclass to have a constructor with parameters(number and type of parameters should match). If it does not find such a constructor in your superclass, it will give you a compiler error. ( Super(parameters) can never be called implicitly by the compiler. It has to be explicitly put in your code if one is required.)
We can summarize a few things from the above rules
If your superclass only has a constructor with parameters and has no no-argument constructor, you must have an explicit super(parameters) statement in your constructor. This is because if you do not do that a super() statement will be implicitly put in your code and since your superclass does not have a no-argument constructor, it will show a compiler error.
If your superclass has a constructor with parameters and another no-argument constructor, it is not necessary to have an explicit super(parameters) statement in your constructor. This is because a super() statement will be implicitly put in your code by the compiler and since your superclass has a no-argument constructor, it will work fine.
If your superclass only has a no-argument constructor you can refer to the point above as it is the same thing.
Another thing to be noted is if your superclass has a private constructor, that will create an error when you compile your subclass. That is because if you don't write a constructor in your subclass it will call the superclass constructor and the implicit super() will try to look for a no-argument constructor in the superclass but will not find one.
Say this compiled, what would you expect it to print?
class A{
A(int i){
System.out.println("A.i= "+i);
}
}
class B extends A {
public static void main(String... args) {
new B();
}
}
When A is constructed a value for i has to be passed, however the compiler doesn't know what it should be so you have specify it explicitly in a constructor (any constructor, it doesn't have to be a default one)
Of course its an error if written like this it's not JAVA.
If you would have use JAVA syntax it wouldn't be an error.
Class A and B knows nothing about each other if in separate files/packages.
Class A doesn't need a default constructor at all it works fine with only a parameter constructor.
If B extends A you simple use a call to super(int a) in B's constructor and everything is fine.
for constructors not calling a super(empty/or not) extending a super class the compiler will add a call to super().
For further reading look at Using the Keyword super
I would guess that its because when you have an empty parameter list the super variable can't be instantiated. With empty parameter list I mean the implicit super() the compiler could add if the super class had a nonparametric constructor.
For example if you type:
int a;
System.out.print(a);
You will get an error with what I think is the same logic error.
When we have parameter constructor. we explicit bound to consumer by design. he can not create object of that class without parameter. some time we need to force user to provide value. object should be created only by providing parameter(default value).
class Asset
{
private int id;
public Asset(int id)
{
this.id = id;
}
}
class Program
{
static void Main(string[] args)
{
/* Gives Error - User can not create object.
* Design bound
*/
Asset asset1 = new Asset();/* Error */
}
}
Even child class can not create. hence it is behavior of good design.
When extending a class, the default superclass constructor is automatically added.
public class SuperClass {
}
public class SubClass extends SuperClass {
public SubClass(String s, Product... someProducts) {
//super(); <-- Java automatically adds the default super constructor
}
}
If you've overloaded your super class constructor, however, this takes the place of the default and invoking super() will thus cause a compile error as it is no longer available. You must then explicitly add in the overloaded constructor or create a no-parameter constructor. See below for examples:
public class SuperClass {
public SuperClass(String s, int x) {
// some code
}
}
public class SubClass extends SuperClass {
public SubClass(String s, Product... someProducts) {
super("some string", 1);
}
}
OR...
public class SuperClass {
public SuperClass() {
// can be left empty.
}
}
public class SubClass extends SuperClass {
public SubClass(String s, Product... someProducts) {
//super(); <-- Java automatically adds the no-parameter super constructor
}
}
Because if you want to block creation of objects without any data in it, this is one good way.