I am puzzled by this inheritance example found in a quizz from a Coursera Java course:
class B is a subclass of class A
class B getPrefix() method overrides class' A method
class B number attribute overrides class' A attribute
class ClassA {
protected int number;
public ClassA() {
number = 20;
}
public void print() {
System.out.println(getPrefix() + ": " + number);
}
protected String getPrefix() {
return "A";
}
}
class ClassB extends ClassA {
protected int number = 10;
protected String getPrefix() {
return "B";
}
}
public class Quizz {
public static void main(String[] args) {
ClassB b = new ClassB();
b.print();
ClassA ab = new ClassB();
ab.print();
}
}
When we run this program, the printed result is:
B: 20
B: 20
However, I was expecting this result instead:
B: 10
B: 10
Can you explain how come class A number attribute is printed, and not class B?
Can you explain how come class A number attribute is printed, and not class B?
ClassB does not inherit ClassA.number field, but rather hides it.
See:
The Java™ Tutorials - Hiding Fields
Within a class, a field that has the same name as a field in the superclass hides the superclass's field.
Yeah so you can override a method from a super class but you cannot declare another class member with the same name. You're creating a new class member with the name number. It would only refer to 10, the value from the super class #number if you used super.number instead of this.number.
Related
I have 2 classes, and I have made one class (Class A) instantiate a Class B object.
I have a method in Class B that I want to call a method in Class A.
I'm working on a larger project for practicing Java, so I am simplifying things here.
// Class A:
public class ClassA {
private int number;
private ClassB instanceOfB = new ClassB();
public ClassA {
number = 0;
}
public void incrementNumber {
number++;
}
public void incrementNumberLongWay {
instanceOfB.incrementNumberInA()
}
}
// Class B:
public class ClassB {
public void incrementNumberInA() {
// My desire: Call Class A's incrementNumber method
// What should I put here?
}
}
How do I make sure incrementNumberLongWay works? Class A has been instantiated, and it's method incrementNumberLongWay is called, so this should call ClassB's method incrementNumberInA
I know this seems extremely convoluted, but the reason I'm doing this, is because in my program I'm not incrementing numbers, but instead doing some logic in Class B, and only wanting to affect Class A in certain cases.
You can't do this with the code provided. Relationships are by default one way. B doesn't know about A so cannot access it.
What you can do is pass a reference of A to B in it's construction process and then access A via that reference.
One solution would be to pass a method of A as a callback.
For example:
public class ClassA {
private int number;
private ClassB instanceOfB = new ClassB();
public ClassA {
number = 0;
}
public void incrementNumber {
number++;
}
public void incrementNumberLongWay {
instanceOfB.incrementNumberInA(this::increment);
// alternatively
// instanceOfB.incrementNumberInA(() -> incrementNumber());
}
}
public class ClassB {
public void incrementNumberInA(Runnable callbackMethod) {
callbackMethod.run();
}
}
This removes B's dependency on A, and instead allows a general callback mechanism.
However, for such a simple scenario this approach isn't advised.
It's probably a bad idea in general to have a circular dependency in this way. One approach to break the cycle would be to have a third class (classC?) that implements the increment logic (or whatever your real-world equivalent is), and have classA and classB instances each reference classC. That way there's no case where two classes know about each other.
ClassB doesn't know anything about ClassA. So, you couldn't do it.
The ugly decision is
public void incrementNumberLongWay() {
instanceOfB.incrementNumberInA(this);
}
and in
public class ClassB {
public void incrementNumberInA(ClassA cl) {
cl.incrementNumber();
}
}
You can't call methods from class A from class B as class B has no reference to an object of class a. You could, however, pass class A's current number state to class B as parameter, and return a value from class B which class A can then get and use.
For example:
public class A {
private int number;
public A(int number) {
this.number = number;
}
public void incrementNumber(boolean largeIncrement) {
if(largeIncrement) {
B bInstance = new this.B();
number = bInstance.incrementNumberLongWay(number);
}
else {
number++;
}
}
private class B {
private B() {
// if some initialization is needed...
}
public int incrementNumberLongWay(int num) {
num += 1000;
return num;
}
}
}
Hope this is what you wanted.
I want to access a protected field of a super-class from a sub-class in Java:
Class Super {
protected int field; // field set to a value when calling constructor
}
Class B extends Super { // field of super class is set to value when calling
// constructor
}
Class C extends Super { // same here
}
B b = new B();
C c = new C();
b.super.field ?
The class can access the field directly, as if it were its own field. The catch is that the code doing the access must be in the code of the derived class itself, not in the code using the derived class:
class B extends Super {
...
int getSuperField() {
return field;
}
}
The protected modifier allows a subclass to access the superclass members directly.
But the access should be made inside the subclass or from the same package.
Example:
package A;
public class Superclass{
protected String name;
protected int age;
}
package B;
import A.*;
public class LowerClass extends SuperClass{
public static void main(String args[]){
LowerClass lc = new LowerClass();
System.out.println("Name is: " + lc.name);
System.out.println("Age is: " + lc.age);
}
}
From Javadoc:
The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.
In either Super or B, create a getter method:
public int getField() {
return field;
}
Then you can do:
B b = new B();
int field = b.getField();
It's not allowed to access a protected field outside the body of the declaring and extending class.
See here 6.6.2 Access to a protected Member
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.
The solution would be any of the answers with a setter/getter or making it public.
extending class B in Class A, now I am printing value of variable a in Class A.The result i am getting is a=0 . How can i get the value a=2
Class A
package testing;
public class ClassA extends ClassB {
public void print(){
System.out.println("a= " +a);
}
public static void main(String arg[]){
ClassA ca = new ClassA();
ca.print();
}
}
Class B
package testing;
public class ClassB {
int a;
public void send(){
a=2;
}
}
Initially the value of a is 0, as you have not set it to anything, and by default, when you call new ClassA(); it is initialized to 0. Hence you get 0 as the output.
You need to call the send method, to set the value of a to 2.
ClassA ca = new ClassA();
ca.send(); //Here
ca.print();
Another easier way to understanding of parsing of variables between classes is using the get-set methods.
Class A coding:
public class ClassA extends ClassB {
public static void main (String [] args)
{
ClassB ClassBValue = new ClassB();
System.out.println(ClassBValue.getA());
}
}
Class B coding:
public class ClassB {
int A = 2;
public int getA()
{
return A;
}
public void setAValue(int A)
{
this.A = A;
}
}
Hope this helps
You are calling ca.print() without assigning any value to it, so basically it is printing initialized value for int a which is 0.
Put a call to send() before the print function, Compiler will first check for function send in ClassA, when it does not find it there it will call send function of the SuperClass which is B, this will assign value '2' to your variable a, When you call print(), print function present in Class A is called, Now Class A has no variable called a, so the value of variable a is called from it's super class and you will get value of 2 printed.
Code should look like ->
public class ClassA extends ClassB {
public void print(){
System.out.println("a= " +a);
}
public static void main(String arg[]){
ClassA ca = new ClassA();
ca.send();
ca.print();
}
}
public class ClassB {
int a;
public void send(){
a=2;
}
}
Your int variables, by default, are initialized with 0.
Some options:
A) Alter your main method to call the send method
ClassA ca = new ClassA();
ca.send(); //set the value to 2
ca.print();
B) If don't want to alter your main method (for any reason), you can move the variable initialization to the class construtor:
ClassA() {
a = 2
}
Now, when you instantiate your the class (new ClassA()), 'a' gonna be equals 2.
There are two classes. One inherited from the other one. Test results surprise me
since I called the child class constructor and its method. However I do not call the super class constructor like this new Cougar().go();. But output shows the the super class constructor is called. Could you explain me why this happens?
public class Feline {
public String type = "f";
public Feline() {
System.out.println("feline");
}
}
public class Cougar extends Feline {
public Cougar() {
System.out.println("cougar");
}
public static void main(String[] args) {
new Cougar().go();
}
private void go() {
type = "c";
System.out.println(this.type + " " + super.type);
}
}
Output: feline
cougar
c c
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass.
The constructor of the superclass is always invoked. You can call the desired constructor of your superclass using "super()" in the first line of your child class constructor.
For example:
public class Feline {
public Feline() {
System.out.println("Feline");
}
public Feline(String type) {
System.out.println(type);
}
...
}
public class Cougar extends Feline{
public Cougar() {
super("Cougar");
}
...
}
It is Because of line
new Cougar().go();
Inside the "go" method you have redefined the variable "type".
I hope it is making sense.
When we invoke child class constructor,the java compiler automatically calls super class
constructor.If it is not present in super class,we will get compile time error.
If Object is the super class of our class then no issue since Object contains no-arg constructor.
Reason- The reason to have super constructor called is that if super class could have private fields which need to be initialized by its constructor.
Refer this link for more info.
When you call parameter-less constructor of the derived class the run-time automatically calls the parameter-less base class constructor before executing the derived class constructor. Because of this behavior you see feline cougar as first two string in your output.
Now for the 'c c' part of the output, you are not defining new String type variable in your Cougar class. You are using the same 'type' variable if the super class in go() method/function and setting it to "c". This is the reason you are getting 'c c' in the output.
Make Cougar as below. The syntax is C#.
public class Cougar : Feline
{
public String type = "c";
public Cougar()
{
Console.Write("cougar ");
}
static void Main(String[] args)
{
new Cougar().go();
}
private void go()
{
Console.Write(this.type + " " + base.type);
}
}
public class BaseClass {
private String className;
public BaseClass() {
className = "[BaseClass]";
}
public void executeAB() {
System.out.println(className + " executingAB()");
executeA();
executeB();
}
public void executeA() {
System.out.println(this.className + " executingA()");
}
public void executeB() {
System.out.println(this.className + " executingB()");
}
}
public class SubClass extends BaseClass {
private String className;
public SubClass() {
this.className = "[SubClass]";
}
public void executeA() {
System.out.println(className + " executingA()");
}
public void executeC() {
System.out.println(className + " executingC()");
}
public static void main(String[] args) {
BaseClass t = new SubClass();
t.executeAB();
// t.executeC();
}
}
In above case , Calling t.executeAB() results in output:
[BaseClass] executingAB()
[SubClass] executingA()
[BaseClass] executingB()
My Question is:
How does BaseClass know about excuteA() method from SubClass, while at the same time t.executeC() call is not possible because BaseClass is not aware of executeC().
You have a misunderstanding of what you should be doing in inheritance. extends is a reserved word that was wisely chosen. The point of B extending A is to say that B is a subset of A with additional attributes. You're not supposed to redefine x in B; A should be handling x. You should have not className declared in both classes.
As for your example:
BaseClass t = new SubClass();
Calls the constructor for SubClass, which sets className of SubClass to [SubClass]. The super contructor is also called, and className in BaseClass is set to [BaseClass].
t.executeAB();
Prints the className for BaseClass which is [BaseClass] and then calls:
executeA();
executeB();
executeA() is a called from SubClass, since t is a SubClass and it's defined, so we get [SubClass] and finally, executeB() is called from BaseClass so again, we get [BaseClass]. As for why you can't call:
t.executeC()
Despite using the constructor for SubClass, t is a BaseClass. According to the principles of OOP, it makes sense that you can't call t.executeC(), since it is not defined for BaseClass.
You're defining your variable as BaseClass t = new SubClass(); which means you allow space for a different subclass to instantiate. However, in order for this to be possible without breaking existing code, you can only use methods that are defined in the baseclass.