Overriding method with a lower-visibility one results in compilation error - java

I have one class and one interface:
public interface A {
public void getNum();
}
public class B {
public void getNum() {
System.out.println("4");
}
}
public class C extends B implements A {
protected void getNum() {
System.out.println("3");
}
}
Now my question is, why this code is giving compilation error and how can we avoid it. Is there any way in which we can override this method in class C?

From Java Language Specification:
jls-8.4.8.3
The access modifier (ยง6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
...
Notice that you are trying to override public method getNum() inherited from class B (and also from interface A) with new one that has protected access modifier. It means that you are trying to reduce visibility of this method which according to specification is incorrect.
To be able to override this method you need to use public access modifier with your new version of that method.
Why you cant reduce visibility? Take a look at below code which uses your classes but is placed inside some other package and ask yourself "how should this code behave?".
package my.pckage;
import your.pckage.A;
import your.pckage.C;
public class Test{
public static void main (String[] args){
C C = new C();
c.getNum();// ERROR: Test class doesn't have access to `c`s protected method.
// Why should it have, Test doesn't extend C.
A a = (A)c;// Lets try using other reference
a.getNum();// Should `a` have access to method that is protected in `C`?
// If yes, then what is the point of declaring this method
// protected if all I would have to do to get access to it is
// casting instance of C to A interface?
}
}

Fix the typos and try again ;)
public interface A {
public void getNum();
}
public class B {
protected void getNum() {
System.out.println("4");
}
}
public class C extends B implements A {
public void getNum() {
System.out.println("3");
}
}

First of all scope should be from lower to higher while you are overriding method in Java. scope of subclass method should be high then super class for e.g
Valid Overriding
class B {
protected void getNum() {
System.out.println("4");
}
class C extends B {
public void getNum() {
System.out.println("3");
}
InValid Overriding
class B {
public void getNum() {
System.out.println("4");
}
class C extends B {
protected void getNum() {
System.out.println("3");
}
Your second problem is you have created two public class which is not valid you can create only one public class in your java file.

When you implement an interface you need to compulsorily override it to provide concrete implementation of function(unless the class implementing the interface is abstract). In your case you are implementing an interface which make you implement getNum() function and due to overriding class you have another function with same signature which is not allowed. So you get compilation error.
Possible solution : You can make B as an interface.

The explanation by Pshemo is perfectly right that you can not reduce visibility of overridden or the interface functions.
Lets take an exapmle
class B
{
protected void getProtected1()
{
System.out.println("4");
}
protected void getProtected2()
{
System.out.println("4");
}
public void getPublic1()
{
System.out.println("4");
}
public void getPublic2()
{
System.out.println("4");
}
}
class C extends B
{
#Override
private void getPublic1() //COMPILATION ERROR : Cannot reduce the visibility of the inherited method from myzeromqApp.B
{
System.out.println("3");
}
#Override
protected void getPublic2() //COMPILATION ERROR :Cannot reduce the visibility of the inherited method from myzeromqApp.B
{
System.out.println("3");
}
#Override
private void getProtected1() //COMPILATION ERROR : Cannot reduce the visibility of the inherited method from myzeromqApp.B
{
System.out.println("3");
}
#Override
public void getProtected2() // NO ERROR IT MEANS YOU ARE ALLOWED TO INCREASE THE VISIBILITY
{
System.out.println("3");
}
}
From the above example it is clear that you are not allowed to decrease the visibility of function in any case.
In your question you are trying to implement the interface function and we know interface in Java has rules that,
Method: only public & abstract are permitted
Field: (Variables) only public, static & final are permitted
As thumb of rule, you can never decrease the visibility, of overridden or implemented methods or variables and for interface it is always public (if visibility is concerned) so those should always be public in implemented classes.

As stated, only one public class can be used per file. So, to have them all public, one must create three separate .java files. I will write the code up below, as well as detailing how to override the method to use the correct version of it in each case.
One may always have methods with the same name, but for overriding, they must have different argument lists. This is one of the compiler errors, you have three methods with the same argument lists, namely none. You may create and call the method with the correct argument list to achieve the desired result.
A.java:
package stackOverflow.tests; // Sample package for visibility
public Interface A {
public void getNum(int a); // Method takes a single integer argument
}
B.java:
package stackOverflow.tests;
public class B {
protected void getNum(int a, int b) { // Method takes two integer arguments, differing in the argument list but equal in name
System.out.println("4");
}
}
C.java:
package stackOverflow.tests;
import stackOverflow.tests.A; // Importing both classes to use their methods
import stackOverflow.tests.B;
public class C extends B implements A {
public void getNum(int a, String x) { // Takes an integer and a string argument
System.out.println("3");
}
public void getNum(int a) {
//Do nothing, as in A.java, this code is necessary to be able to override the method.
}
public static void main(String[] arguments) { // Sample main method for implementation
C c = new C(); // Instantiating class C
int test = 0; // Initializing two integer variables and one String variable
int test2 = 0;
String test3 = "";
c.getNum(test); // takes one integer, using getNum() from A.java
c.getNum(test, test2); // takes two integers, using getNum() from B.java
c.getNum(test, test3); // takes an integer and a String, using getNum() from C.java
}
}
Output:
4
3
As seen in the code above, the argument lists define which version of the method is used. As a side tip, the definition getNum(int a) is no different from getNum(int b), so this would result in it not compiling.

In order to get this working you can do something like this since there can be only one public class per file and the file name should be the same name as that of the class
public class HelloWorld{
public static void main(String []args){
C obj=new C();
obj.getNum();
}
}
//interface
interface A {
public void getNum();
}
class B {
protected void getNum() {
System.out.println("4");
}
}
class C extends B implements A {
public void getNum() {
System.out.println("3");
}
}
output:
3

A java class file can have only one public class or interface.
Change the visibility of the interface and the defined class to default level or declare it in separate files.
Only public and abstract modifiers can be applied to interface methods. The class implementing the interface cannot change the visibility of the method (we cannot change it from public to protected).

Related

How does java resolve hidden methods at runtime

Given the following class hierarchy
package pack1;
public class A
{
private int methodOne(int i)
{
return ++i;
}
public int methodTwo(int i)
{
return methodOne(++i);
}
}
package pack2;
import pack1.A;
class B extends A
{
int methodOne(int i)
{
return methodTwo(++i);
}
}
public class MainClass
{
public static void main(String[] args)
{
System.out.println(new B().methodOne(101));
}
}
The output of the above program is 104. Class Bcreates its own version of methodOn() because methodOne() is private in Class A. However, during runtime, when inside methodTwo(), the runtime object is of type Class B. Why would java use the methodOne() in class A as oppose of class B.
This is because, despite the name, the two methods are entirely different. methodOne in class B does not override the method with the same name in class A. As you said, B can't see the private methodOne, so it can't possibly override it. So Java creates two separate methods that are not related in any way. Then A's methodTwo calls the methodOne that's defined in A. If it were public or protected, then other classes might have overridden it, resulting in the late binding we know all too well from Java. However, the methodOne that it sees has never been overridden because B didn't know to do so.
tl;dr: Internally, they're two different and unrelated methods, even though the names are the same.
At very first your code starts executing the code
public static void main(String[] args)
{
System.out.println(new B().methodOne(101)); // it invokes methodOne() of class B.
}
Above code calls methodOne() of class B. Now, MethodOne() is private so it won't override in Class B
Now definition of methodOne() in Class B
int methodOne(int i)
{
return methodTwo(++i); // calling methodTwo() from class A which is a super class of class B.
}
this code is increase the value of i by 1. So, Now i = 102. Now again the methodTwo calling the methodOne() of class B in below code.
public int methodTwo(int i) //methodTwo in class A. part of object due to public access modifier.
{
return methodOne(++i); // it increase the value of i by 1. Now i =103.
}
Now the value of i = 103. Now it calls methodOne() of class A , because methodOne() is private in Class A
private int methodOne(int i)
{
return ++i; //again this increase the value of i by 1. Now i =104.
}
increased the value of i by 1. So, variable i = 104. So, Final value of i is 104 Now.
So, The Final Output is 104.

ambiguity in invoking a method inherited from another class

I have two java class files
Hi.java which belongs to second package
package second;
public class Hi {
protected int v=20;
protected void m(){
System.out.println("i am protectTED");
}
}
S.java which belong to first package
package first;
import second.Hi;
interface i1
{
void m();
int a=200;
}
interface i2{
void m1();
int b=100;
}
class S extends Hi implements i1,i2
{
int a=50;
public void m()
{
System.out.println("hi");
}
public void m1()
{
System.out.println("hello");
}
public static void main(String[] args) {
S s=new S();
/*need correction here (i don't know the exact syntax to mention to get
the desired output)
s.m(); //should invoke method m() from class Hi only.
s.m(); //Should invoke method m() from class S only.
*/
//the following statements prints the desired values
s.m1();
System.out.println(s.v);
System.out.println(i1.a);
System.out.println(s.a);
System.out.println(b);
}
}
when i run the S.java class file method m() in class Hi should be invoked.("my intention") instead method m() of the same class i.e., class S is being invoked.
How to differentiate the 2 methods for invoking. Is it even possible?
when i run the S.java class file method m() in class Hi should be invoked.("my intention") instead method m() of the same class i.e., class S is being invoked.
Correct, because you've overridden it with m in S. Overriding methods is fundamentally different from overriding fields. (And in general, it's best to avoid overriding any fields that are visible to your subclass, as you're doing with a.)
In instance code in S, you can run the inherited m via super: super.m(). But you cannot do that from static code, not even static code in S. You could give yourself a private callSuperM in S:
private void callSuperM() {
super.m();
}
...and then use that in main:
s.callSuperM(); // "i am protectTED"
s.m(); // "hi"

How interface support multiple inheritance [duplicate]

This question already has answers here:
Multiple inheritance on Java interfaces
(5 answers)
Closed 7 years ago.
public class Test implements X, Y { //X.Y interface are shown below
public void myMethod() {
System.out.println(" Multiple inheritance example using interfaces");
}
public static void main(String[]args) {
Test t=new Test();
t.myMethod();
System.out.println(t.a); //compile time error ambigious field
}
}
Please help me to solve this issue
interface X {
public void myMethod();
int a = 0;
}
interface Y {
int a = 9;
public void myMethod();
}
Any variable defined in an interface is, by definition, public static final, in other words it's just a constant, it's not really a field (since there are no fields in interfaces).
So the compilation error you get points out that the compiler doesn't know witch constant you refer to.
You have 2 options here:
change the name of the constant in one of the interfaces, for example in interface Y declare int b = 9;
inside the main method point to a concrete constant: System.out.println(X.a);
Adding to one of the answer already provided.
If a class implements two interfaces and each interface have method with same signature and same name, then you are effectively defining only one method and they are same. If you have two methods of same name but different return types then there will be a compilation error.
Example ->
public interface A {
int a = 0;
void myMethod();
}
public interface B {
int a = 0;
void myMethod();
}
public class Test implements A, B {
#Override
public void myMethod() {
// My method is defined for both A and B
System.out.println(" Multiple inheritance example using interfaces");
}
public static void main(String[] args) {
Test object = new Test();
((A)(object)).myMethod();
((B)(object)).myMethod();
System.out.println(((A)object).a); //To print constant of A
System.out.println(((B)object).a); //To print constant of B
}
}
//Let's see other example
public interface A {
void myMethod();
}
public interface B {
boolean myMethod(); //changed void to boolean
}
public class Test implements A, B {
#Override
public void myMethod() { //Compilation error here, return type is incompatible
}
}
myMethod implements both myMethod declarations. I believe your problem is that in the two separate interfaces a has different values and is before and after the declaration of myMethod. The order is not important, since myMethod will surely be called after the declaration of a, but the difference of a values might cause some logical discrepancies. Maybe you could implement a getter for it as well, to handle the situation.

Inheritance: weaker accessibility of a method in subclass

what is the need of having a rule like this in java :
"a subclass cannot weaken the accessibility of a method defined in the superclass"
If you have a class with a public method
public class Foo {
public void method() {}
}
This method is accessible and you can therefore do
Foo foo = new Foo();
foo.method();
If you add a subclass
public class Bar extends Foo {
#Override
public /* private */ void method() {}
}
If it was private, you should not be able to do
Foo bar = new Bar();
bar.method();
In this example, a Bar is a Foo, so it must be able to replace a Foo wherever one is expected.
In order to satisfy the above statement, a sub class cannot make an inheritable member less accessible. It can however make it more accessible. (This basically only applies to methods.)
What it means
The subclass method cannot have a more restrictive visibity than the superclass method.
For example, if the superclass defined
protected void a() { } // visible to package and subclasses
the subclass can override it with one of
public void a() { } // visible to all
protected void a() { } // visible to package and subclasses
but not
void a() { } // visible to package
private void a() { } // visible to itself
Why it is
Suppose the definition was
class A {
public void a() { }
}
class B extends A {
private void a() { }
}
Now, consider the following code
A instance = new B();
instance.a(); // what does this call?
On the one hand, any B has a publically accessible a method. On the other hand, the a method of a B instance is only accessible to B.
More generally, a subclass(interface) must fulfill the contract of its superclass(interface).
Visibility is only one example of this principle. Another example is that a non-abstract class must implement all methods of any interface it implements.
class Person {
public String name() {
return "rambo";
}
}
// subclass reduces visibility to private
class AnonymousPerson {
private String name() {
return "anonymous";
}
}
It's legal to call the following method with either a Person, or an AnonymousPerson as the argument. But, if the method visibility was restricted, it wouldnt' be able to call the name() method.
class Tester {
static void printPersonName(Person p) {
System.out.println(p.name());
}
}
//ok
Tester.printPersonName(new Person());
this call is legal, because a Person is a AnonymousPerson, but it would have to fail inside the method body. This violates "type safety".
Tester.printPersonName(new AnonymousPerson());
To fulfill the interface contract. Let's say I have an interface, IFlying, as:
public interface IFlying {
public void fly();
}
And I have an implementation that weakens accessibility:
public class Bird implements IFlying {
private void fly(){
System.out.println("flap flap");
}
}
I now have some library function that accepts an IFlying, and calls fly upon it. The implementation is private. What happens now? Of course, it means that the fly method cannot be accessed.
Hence, the accessibility may not be made more restrictive in an implementation.

How to make some methods from superclass not avaliable in child class

Lets say I have a class
public class Base {}
and a child class
public class Derived extends Base {
public void Foo(Object i){
System.out.println("derived - object");
}
}
and main class
public class Main {
public static void main(String[] args) {
Derived d = new Derived();
int i = 5;
d.Foo(i);
}
}
In console we will see
derived - object
Some time later I want to modify my superclass like this :
public class Base {
public void Foo(int i) {
System.out.println("base - int");
}
}
Now if I run my programm I will see:
base - int
So can I make a method in superclass not avaliable in my child class?
In result I want to see derived - object.
I see some don't understand what I want so I'll try to explain:
I want to modify only superclass and I don't want to modify my child class.. for example if I will make jar with my superclass and jar with my childs. I don't want to change all jars.. I want to add method into superclass and make it avaliable for superclass..
And such code
public class Main {
public static void main(String[] args) {
Derived d = new Derived();
int i = 5;
d.Foo(i);
Base b = new Base();
b.Foo(i);
}
}
give me
derived - object
base - int
You should use following signature for Foo method in base class:
public void Foo(Object i) {
System.out.println("base - int");
}
This way you can override method Foo from base class. Now you do not override this method but overload it instead.
If you want to use public void Foo(int i) signature in your base class then you can define Foo method in base class as private.
PS: I hope that I've understood you.
private members are limited to the class scope.
default (no keyword for this one) are limited to other members of the same package.
protected are limited to hierarchy.
public are not limited.
So if you don't want your child class to access a member of the superclass (member means methods, enum, variables ...) you should declare your foo like this :
public class Base {
private void Foo(int i) {
System.out.println("base - int");
}
}
Edit from my comment :
if you dont want child class to access a parent's member at compile time I can't see any way to still allow external classes to access it.
You want to block access from close scope while allowing broader scope. This can only be done by overriding the method and throwing an exception for accessviolation or something which is not at compile time but at runtime. Although you could make it work with a custom annotations but I don't know how to do this.
You can make a method final, which means, that the child class cannot override it.
If you do not do that and the child class overrides the method, you cannot call the super classes method from your main.
A Convention note: Please use lowercase method names in java.
package com.abc;
public class TestParentChild {
public static void main(String[] asd) {
Base b = new ChildB();
b.foo(5);
}
}
class Base {
public void foo(int i) {
System.out.println("derived - int");
}
}
class ChildB extends Base {
public void foo(int i) {
System.out.println("derived - object");
}
}
This might help you

Categories