Dynamic Binding in Java with subclasses - java

interface I {
public void m1();
public void m3();
}
class A implements I {
public void m1() {
System.out.println("A.m1");
this.m2(this);
}
public void m2(I obj) {
System.out.println("A.m2");
obj.m3();
}
public void m3() {
System.out.println("A.m3");
}
}
public class B extends A {
public void m2(I obj) {
System.out.println("B.m2");
super.m2(obj);
}
public void m3() {
System.out.println("B.m3");
}
public static void main(String[] args){
I obj = new B();
obj.m1();
}
}
When calling a method, the java compiler firstly checks if the apparent type of the obj has such method(in this case, it checks if the Interface I has the method m1() ) and then checks the actual type for the actual method call(and thus it calls the A's m1() method since the class B doesnt have it ).
However, why doesnt java compiler, when calling this.m2() inside A's m1() method, also checks if the Interface I has m2() method?
The output of this program is the following:
A.m1
B.m2
A.m2
B.m3

Related

How to invoke the method in abstract class that has been overriden in the subclass in java?

In this below code:
interface I1 {
void m1();
}
interface I2 {
void m2();
}
abstract class A implements I1, I2 {
public void m1() {
System.out.println("Inside A: m1()");
}
}
class B extends A {
public void m1() {
System.out.println("Inside B: m1()");
}
public void m2() {
System.out.println("Inside B: m2()");
}
}
public class Test {
public static void main(String[] args) {
// invoke A's m1()
A a = new B();
a.m1();
}
}
How can I just invoke m1() in A without making any changes to class B i.e. we can't add super.m1() in the m1() in B? With my code I just get the m1() in B because of dynamic method dispatch or runtime polymorphism.
An interviewer asked me this question. And I told him that it wasn't possible to do so but he replied that there is a way but didn't told me how.

java anonymous class as parameter with new methods

When I search for the method by reflection it shows the newly provided method. But I don't know how to invoke that method, if someone has got any idea how to do it please tell me.
//some pakage
pakage xyz;
class A {
// a simple method of class A
public void aMethod() {
//simple print statement
System.out.println("A class method");
}
}
class B {
// a method of class B that takes A types as an argument
public void bMethod(A arg) {
Class c = Class.forName("xyz.A");
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
}
}
class Test {
public static void main(String[] args) {
B bObj = new B();
bObj.bMethod(new A() {
public void anotherMethod() {
System.out.println("another method");
}
});
}
}
I suppose maybe this is what you want.
package xyz;
import java.lang.reflect.Method;
class A {
// a simple method of class A
public void aMethod() {
//simple print statement
System.out.println("A class method");
}
}
class B {
// a method of class B that takes A types as an argument
public void bMethod(A arg) throws Exception {
Class c = Class.forName(arg.getClass().getName());
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
method.invoke(arg);
}
}
}
class Test {
public static void main(String[] args) throws Exception {
B bObj = new B();
bObj.bMethod(new A() {
public void anotherMethod() {
System.out.println("another method");
}
});
}
}
You can use reflection to invoke the method on particular object:
public void invokeSomeMethodOnA(A arg, String methodName) {
Method method = arg.getClass().getDeclaredMethod(methodName);
//To invoke the method:
method.invoke(arg, parameters here);
}

Overload enum abstract method

Is it possible to overload Enum abstract method?
I have tried this in my code with no effect.
Presented class
public class Test {
public void test(String string){
System.out.println(string);
}
public void test(Object object){
System.out.println("Test1");
}
public static void main(String[] args) {
Object object = new Object();
test.test(object);
test.test("what if?");
}
}
gives expected result of
Test1
what if?
while enum
public enum TestEnum {
TEST1{
public void test(String string){
System.out.println(string);
}
public void test(Object object){
System.out.println("Test1");
}
},
TEST2{
public void test(Object object){
System.out.println("Test2");
}
};
public abstract void test(Object object);
}
public class Test {
public static void main(String[] args) {
Object object = new Object();
TestEnum.TEST1.test("what if?");
TestEnum.TEST1.test(object);
}
}
returns
Test1
Test1
Is it even possible to overload Enum methods or am I doing something wrong? Or maybe should I check for type inside of overriden method and then act accordingly? But then I remove switch statement only to introduce another switch statement.
The thing about enums is that values with bodies are implemented as anonymous subclasses of TestEnum; so they look like this:
final TestEnum TEST1 = new TestEnum() { /* body */ };
Whilst the concrete class of TEST1 is, say TestEnum$1 (or whatever name the compiler decides to give it), the reference is of type TestEnum, so any code outside the body of TEST1 can only access methods defined on TestEnum.
Yes is possible, you are somehow not implementing that in a particular way....
you should
define an interface with the methods you want to override
interface Ifoo {
public void test(Object object);
public void test(String object);
}
then remove the abstract method of the enum and make the enum implement that interface, but override those methods in every constant of the enumerator...
enum TestEnum implements Ifoo {
TEST1 {
#Override
public void test(String string) {
System.out.println(string);
}
#Override
public void test(Object object) {
System.out.println("Test1");
}
},
TEST2 {
#Override
public void test(Object object) {
System.out.println("Test2");
}
#Override
public void test(String string) {
System.out.println(string);
}
};
}
finally implement it like>
Object object = new Object();
TestEnum.TEST1.test("what if?");
TestEnum.TEST1.test(object);
TestEnum.TEST2.test("why not?");
TestEnum.TEST2.test(object);
your result should looks like:
what if?
Test1
why not?
Test2
You are showing an example with a class and then you are showing an example with an enum. I believe you think these examples are equivalent, however, they are completely different each other.
For the example of your class to be equivalent to the example of your enum, you should modify your Test class so that it extends an abstract AbstractTest class:
public abstract class AbstractTest {
public abstract void test(Object object);
}
public class Test extends AbstractTest {
public void test(String string) {
System.out.println(string);
}
#Override
public void test(Object object) {
System.out.println("Test1");
}
}
Now, if you try the same lines you've tried in your first main:
AbstractTest test = new Test();
Object object = new Object();
test.test(object);
test.test("what if?");
You'll notice that the output has now become:
Test1
Test1
Which is something to be expected, because Java doesn't provide a feature called dynamic dispatch. Informally, dynamic dispatch means that the overloaded method to be executed is decided at runtime, based on the polymorphic types of the parameters. Instead, Java decides the method to be executed at compilation time, based on the declared type of the object whose method is to be invoked (in this case AbstractTest).
With enums, this is exactly what happens. All the elements of the enum (TEST1 and TEST2 in your example) belong to the type of the enum (TestEnum in your case), so the compiler always goes for the method that is declared as abstract.
The reason why you get twice "Test1" is because you have declared only this method
public abstract void test(Object object);
Precisely, this method will "catch" all calls whit any type of parameter. String extends Object (indirectly), so String is Object and this method we be called.
In other words, method wich receives parameter String will be hidden by the method which receives parameter Object.
The solution is to add next method declaration in enum
public abstract void test(String string);
You will have to add the implementation of this method to TEST2 constant.
Code
public enum TestEnum {
TEST1 {
public void test(String string) {
System.out.println(string);
}
public void test(Object object) {
System.out.println("Test1");
}
},
TEST2 {
public void test(Object object) {
System.out.println("Test2");
}
#Override
public void test(String string) {
// TODO Auto-generated method stub
}
};
public abstract void test(Object object);
public abstract void test(String string);
}
This code gives output
what if?
Test1

Can I use default method in is override? [duplicate]

Java 8 introduces default methods to provide the ability to extend interfaces without the need to modify existing implementations.
I wonder if it's possible to explicitly invoke the default implementation of a method when that method has been overridden or is not available because of conflicting default implementations in different interfaces.
interface A {
default void foo() {
System.out.println("A.foo");
}
}
class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
// how to invoke A.foo() here?
}
}
Considering the code above, how would you call A.foo() from a method of class B?
As per this article you access default method in interface A using
A.super.foo();
This could be used as follows (assuming interfaces A and C both have default methods foo())
public class ChildClass implements A, C {
#Override
public void foo() {
//you could completely override the default implementations
doSomethingElse();
//or manage conflicts between the same method foo() in both A and C
A.super.foo();
}
public void bah() {
A.super.foo(); //original foo() from A accessed
C.super.foo(); //original foo() from C accessed
}
}
A and C can both have .foo() methods and the specific default implementation can be chosen or you can use one (or both) as part of your new foo() method. You can also use the same syntax to access the default versions in other methods in your implementing class.
Formal description of the method invocation syntax can be found in the chapter 15 of the JLS.
This answer is written mainly for users who are coming from question 45047550 which is closed.
Java 8 interfaces introduce some aspects of multiple inheritance. Default methods have an implemented function body. To call a method from the super class you can use the keyword super, but if you want to make this with a super interface it's required to name it explicitly.
class ParentClass {
public void hello() {
System.out.println("Hello ParentClass!");
}
}
interface InterfaceFoo {
public default void hello() {
System.out.println("Hello InterfaceFoo!");
}
}
interface InterfaceBar {
public default void hello() {
System.out.println("Hello InterfaceBar!");
}
}
public class Example extends ParentClass implements InterfaceFoo, InterfaceBar {
public void hello() {
super.hello(); // (note: ParentClass.super could not be used)
InterfaceFoo.super.hello();
InterfaceBar.super.hello();
}
public static void main(String[] args) {
new Example().hello();
}
}
Output:
Hello ParentClass!
Hello InterfaceFoo!
Hello InterfaceBar!
The code below should work.
public class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
void aFoo() {
A.super.foo();
}
public static void main(String[] args) {
B b = new B();
b.foo();
b.aFoo();
}
}
interface A {
default void foo() {
System.out.println("A.foo");
}
}
Output:
B.foo
A.foo
You don't need to override the default method of an interface. Just call it like the following:
public class B implements A {
#Override
public void foo() {
System.out.println("B.foo");
}
public void afoo() {
A.super.foo();
}
public static void main(String[] args) {
B b=new B();
b.afoo();
}
}
Output:
A.foo
It depends on your choice whether you want to override the default method of an interface or not. Because default are similar to instance method of a class which can be directly called upon the implementing class object. (In short default method of an interface is inherited by implementing class)
Consider the following example:
interface I{
default void print(){
System.out.println("Interface");
}
}
abstract class Abs{
public void print(){
System.out.println("Abstract");
}
}
public class Test extends Abs implements I{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
Test t = new Test();
t.print();// calls Abstract's print method and How to call interface's defaut method?
}
}

Java sub class overload does not get called from super class

Why does the following code produce the output "in super", when the object's type is the sub class (OtherClass2) and the argument to the test function is of type Person2? Shouldn't the method call test(new Person2()); call the sub class's test function?
public class HelloWorld
{
public static void main(String[] args)
{
OtherClass2 s = new OtherClass2();
s.goToThing();
}
}
public class Person
{
}
public class Person2 extends Person
{
}
public class OtherClass
{
public void hello()
{
test(new Person2());
}
public void test(Person p)
{
System.out.println("in super");
}
}
public class OtherClass2 extends OtherClass
{
public void test(Person2 g)
{
System.out.println("In sub");
}
public void goToThing()
{
hello();
}
}
public void test(Person2 g)
of OtherClass2 does not override
public void test(Person p)
of OtherClass. It overloads it. However, it only overloads it for variables whose compile time type is OtherClass2 (since overloading is determined at compile time).
Therefore
test(new Person2());
invokes the method public void test(Person p) of the super class, since OtherClass has no method with the signature public void test(Person2 g) (which could have been overridden by the test method of OtherClass2).
Had you added an #Override annotation above public void test(Person2 g), the compiler would have told you that this method is not overriding any method of the super class.
Because your test method in OtherClass2 does not override test in OtherClass (it overloads).
Would you have
public class OtherClass2 extends OtherClass
{
public void test(Person g)
{
System.out.println("In sub");
}
public void goToThing()
{
hello();
}
}
it would work as expected.
See some further details and differences between overriding and overloading.
Because hello(); method is in OtherClass. You calls goToThing() which is in OtherClass2, after that OtherClass2 calls hello() method which in OtherClass, hello() method calls test() method from OtherClass. Try this:
public class OtherClass2 extends OtherClass
{
public void hello()
{
test(new Person2());
}
public void test(Person2 g)
{
System.out.println("In sub");
}
public void goToThing()
{
hello();
}
}

Categories