how polymorphism method matches in java - java

I'm puzzled how Java polymorphism works.
In the case below, there are three polymorphism methods of showText, for distinguishing clearly, these methods names method-1, method-2, method-3. codes as below:
public class PolymorphismTest {
public static void main(String[] args) {
showText("def");
}
// method-1
private static void showText(Object abc) {
print("1.....");
showText(abc, "abc");
}
// method-2
private static void showText(Object abc, String item) {
// print(abc.getClass().getName());
print("2.....");
String text;
if (abc == null) {
text = null;
} else {
text = abc.toString();
}
showText(text, item);
}
// method-3
private static void showText(String abc, String item) {
print("3.....");
}
private static void print(String text) {
System.out.print(text);
}
}
method-1 has one parameter of type Object
method-2 has two parameters, the parameter type are Object and String
method-3 has two parameters, the same param count with method-2, while its first param type is String
The main() calls method-1 with a parameter of type String, in the body of method-1 it calls another method, which one is matched, method-2 or method-3?
I test it in java 8, the out put is
1.....2.....3.....

Overload is decided at compile-time, so when the first method gets the abc parameter it sees it as an Object (not a String) and calls method-2 which has the appropriate signature for it.
You are probably confused because this is different from the dynamic linking mechanism, which applies to class instances (objects) methods, and resolves the method at runtime based on the actual class of the instance on which the call is made (for example toString() in abc.toString()).

Related

Store references to instance methods in a static context

I would like to have a static map where the values are instance methods. Someting like:
public class MyClass {
static Map<MyEnum, Consumer<String>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, MyClass::firstMethod);
methodMapping.put(MyEnum.SECOND, MyClass::secondMethod);
}
void firstMethod(String param) {
...
}
void secondMethod(String param) {
...
}
}
This gives me an error saying "Non-static method cannot be referenced from a static context". I understand why this would be a problem if I would try to call the methods from the static context, but isn't it possible from an instance method to retrieve the method from the map and pass it this? Like:
MyClass.methodMapping.get(MyEnum.FIRST).accept(this, "string");
This is solvable as easy as changing Consumer to BiConsumer, turning the receiver instance of MyClass to a parameter of the function:
public class MyClass {
static Map<MyEnum, BiConsumer<MyClass,String>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, MyClass::firstMethod);
methodMapping.put(MyEnum.SECOND, MyClass::secondMethod);
}
void firstMethod(String param) {
...
}
void secondMethod(String param) {
...
}
void callTheMethod(MyEnum e, String s) {
methodMapping.get(e).accept(this, s);
}
}
You initialize methodMapping in a static initialization block. At that point, your instance methods can't be referred to yet because you haven't called new MyClass() yet.
You could fix this by either making your methods static, or moving the methodMapping initialization from the static block to a constructor.
PS: The keyword static can be omitted from the initialization block
isn't it possible from an instance method to retrieve the method from the map and pass it this
No. A Consumer only has a single parameter accept() method, so there's no such thing as "passing this at calling time".
You need an instance when creating the method reference, so this questions boils down to "can't call instance method from a static context".
It seems that you don't understand that
static Map<MyEnum, Consumer<String>> methodMapping;
static {
does exactly that, trying to call the methods from the static context where they don't exist.
The key thing to understand here: you intend to create a method reference; and a method reference needs some object to invoke that method on. Thus there is no "delaying"; there is no way in java to express "wait for this to be meaningful"; or in other words: there is no way in a static context to express: "you will be used in a non-static context later on; and then pick the corresponding this from there".
The key is to defer the specification of this or to be more specific: The particular instance on which a method is to be called. So instead of storing method references directly we store functions that accept an instance and return a method reference for that instance.
MyClass.java
public class MyClass {
static Map<MyEnum, Function<MyClass, Consumer<String>>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, t -> t::firstMethod);
methodMapping.put(MyEnum.SECOND, t -> t::secondMethod);
}
private String id;
public MyClass(String id) {
this.id = id;
}
void firstMethod(String param) {
System.out.println(id + ", 1st method, " + param);
}
void secondMethod(String param) {
System.out.println(id + ", 2nd method, " + param);
}
void dispatchMethod(MyEnum myEnum, String param) {
methodMapping.get(myEnum).apply(this).accept(param);
}
}
Main.java
public class Main {
public static void main(String[] args) {
MyClass instance = new MyClass("MyInstance");
MyClass.methodMapping.get(MyEnum.FIRST).apply(instance).accept("Using mapping directly");
instance.dispatchMethod(MyEnum.SECOND, "Using dispatch method");
}
}
Ideally methodMapping should be shielded against direct access from other classes so I'd suggest taking the dispatchMethod approach and making methodMapping private and immutable.

Can `greetSomeone("world")` be replaced by `greetSomeone(name)`? Is there any side effect to this change?

I'm new to Java and is trying to learn the concept of inner class. I saw the code below from Java tutorial Oracle. My question is, for
String name = "world";
#Override
public void greet() {
greetSomeone("world");
}
Can greetSomeone("world") be replaced by greetSomeone(name). The reason why I'm asking this question is because I have noticed if greetSomeone("world") is indeed replaced by greetSomeone(name), inside the public void greetSomeone() method, the passed "name" argument will be set to itself. I was just wondering if there are side effect to code like this?
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
class EnglishGreeting implements HelloWorld {
String name = "world";
#Override
public void greet() {
greetSomeone("world");
}
#Override
public void greetSomeone(String someone) {
name = someone;
System.out.println("hello " + name);
}
}
HelloWorld eg1 = new EnglishGreeting();
eg1.greet();
}
public static void main(String[] args) {
HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
First of all why is that #Override annotation there?
You will use Override when you want to change the behaviour of the parent's methods. Your parent's methods have no behaviour as it is an interface. As a further note I guess that it will teach you that the signature of an overriden method must always match the one from the parent.
Secondly the design is kind of dodgy. It can be simplified.
Thirdly yes you can refer to the String object name as it is defined in that class and you can access the object's primitive just by calling 'name'. Why will you not get the reference printed when System.out? Because the String object handles that for you ensuring the toString will show you the primitive. When you do System.out.print(myObject); The console will show you the Object default or the overriden toString method.
So if you create an object and you do System.out.print(myObject) you will see the reference. If you override toString returning "test" you will see test.
Technically, name can be passed and name = name; is valid Java.
However, this is a horrible design and was probably used for demonstrative purposes only. Don't do this.

Last Variable argument not optional when calling method using reflection

I am trying to invoke a method using reflection
Method mi = TestInterface.class.getMethod("TestMethod", java.lang.String.class,java.lang.String.class,java.lang.String.class,java.lang.Object[].class);
this method has 3 mandatory string arguments, the last argument, which is the variable argument is optional.
However when I invoke this method as below.
mi.invoke(new TestImplementation(), new Object[]{"arg1", "arg2","arg3"});
then it gives me an error java.lang.IllegalArgumentException: wrong number of arguments
but the last arguement should be optional right?
or this doesn't work in case of invoking methods using reflection??
Code:
public interface TestInterface {
public void TestMethod(String str, String str1, String str2, Object... objects);
}
public class TestImplementation implements TestInterface {
public void TestMethod(String str1, String str2, String str3, Object... objects) {
// ....
}
}
public static void main(String[] args) throws Exception {
// works perfectly
TestInterface obj = new TestImplementation();
obj.TestMethod("str", "str1", "str2");
// doesn't work
Method mi = TestInterface.class.getMethod("TestMethod", java.lang.String.class, java.lang.String.class,
java.lang.String.class);
mi.invoke(new TestImplementation(), new Object[] { "arg1", "arg2", "arg3" });
}
Thanks in advance
In Java don't exists optional parameters. You can only override methods or use varargs.
In your case of varargs you are explicitly request Method object with paramters: String, String, String, Object[].
So you must invoke method with same parameters:
mi.invoke(new TestImplementation(), new Object[]{"arg1", "arg2","arg3", new Object[0]);
To understand your problem in general way see this topic.

Mockito How to mock void method with output argument?

I have a void method "functionVoid" that informs a parameter.
public class MyMotherClass {
#Inject
MyClass2 myClass2
public String motherFunction(){
....
String test = "";
myClass2.functionVoid(test);
if (test.equals("")) {
IllegalArgumentException ile = new IllegalArgumentException(
"Argument is not valid");
logger.throwing(ile);
throw ile;
}
....
}
}
public class MyClass2 {
public void functionVoid(String output_value)
{ ....
output_value = "test";
....
}
}
How do I mock this method in the JUnit method my method "motherFunction"?
In my example, the "test" variable is still empty.
#RunWith(MockitoJUnitRunner.class)
public class MyMotherClassTest {
#Mock
private MyClass2 myClass2 ;
#InjectMock
private final MyMotherClass myMotherClass = new MyMotherClass ();
#Test
public void test(){
myMotherClass.motherFunction();
}
}
If you want to mock the return result of motherFunction then you need not worry about the internal implementation of the method (which ends up calling functionVoid). What you do need to do is provide Mockito with an instruction as to what to do when the method, motherFunction is invoked, this can be achieved via the when clause with syntax;
when(mockedObject.motherFunction()).thenReturn("Any old string");
If that misses the point of what you are attempting to achieve then look at how to mock void methods in the documentation and determine whether the use of doAnswer is applicable here, something like;
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
String output_value = invocation.getArguments()[0];
output_value = "Not blank";
return null;
}
}).when(myClass2).functionVoid(anyString());
If you can change functionVoid() to accept a mutable object as the parameter, then you should be able to achieve what you want.
For example, if you change functionVoid() as follows:
public void functionVoid(StringBuilder output_value)
{ ....
output_value.append("test");
....
}
and invoke it in your motherFunction as follows:
public String motherFunction(){
....
StringBuilder test = new StringBuilder();
myClass2.functionVoid(test);
if (test.toString().equals("")) {
Now modifying OceanLife's answer above, you should be able to do the following:
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
StringBuilder output_value = invocation.getArguments()[0];
output_value.append("Not blank");
return null;
}
}).when(myClass2).functionVoid(any(StringBuilder.class));
Of course, if you can change functionVoid(), you could also just make it return a String instead of void.
In my example, the "test" variable is still empty.
This is not a Mockito problem.
Take a look at this question and especially this answer.
The gist of it is that Java is pass by value (this is explained far better at the links above). Nothing in Mockito or Java will ever be able to make the test var anything other than an empty String. It's an empty String before the method call, and will be an empty String after the call.
You can change an object's state within a method (e.g. adding objects to a collection within a method) and see those changes when you exit the method, but you cannot change what object a var references within a method and expect those changes to "stick" once you exit the method. Strings however, are effectively immutable (no state to change), so you can't even do this.
Thus no modifications to test can be made within that method call.
If you want to check method someMethod(String arg) of object Obj then:
String argument = "";
Mockito.verify(Obj, Mockito.times(1)).someMethod(argument);
Obj has to be Mock or Spy.
This works when you want to check if proper argument was passed to void method.
If your method modifies somehow argument then you should use assertion:
someMethod(StringWrapper wrapper) that changes string.
// given
String argument = "a";
String expected = "a_changed";
String wrapped = new StringWrapper(a);
// when
someMethod(wrapped);
// then
Assert.assertEquals(wrapped.getString(), expected)
I am not sure if this what you were looking for?

How can I write an anonymous function in Java?

Is it even possible?
if you mean an anonymous function, and are using a version of Java before Java 8, then in a word, no. (Read about lambda expressions if you use Java 8+)
However, you can implement an interface with a function like so :
Comparator<String> c = new Comparator<String>() {
int compare(String s, String s2) { ... }
};
and you can use this with inner classes to get an almost-anonymous function :)
Here's an example of an anonymous inner class.
System.out.println(new Object() {
#Override public String toString() {
return "Hello world!";
}
}); // prints "Hello world!"
This is not very useful as it is, but it shows how to create an instance of an anonymous inner class that extends Object and #Override its toString() method.
See also
JLS 15.9.5 Anonymous Class Declarations
Anonymous inner classes are very handy when you need to implement an interface which may not be highly reusable (and therefore not worth refactoring to its own named class). An instructive example is using a custom java.util.Comparator<T> for sorting.
Here's an example of how you can sort a String[] based on String.length().
import java.util.*;
//...
String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
#Override public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"
Note the comparison-by-subtraction trick used here. It should be said that this technique is broken in general: it's only applicable when you can guarantee that it will not overflow (such is the case with String lengths).
See also
Java Integer: what is faster comparison or subtraction?
Comparison-by-subtraction is broken in general
Create a Sorted Hash in Java with a Custom Comparator
How are Anonymous (inner) classes used in Java?
With the introduction of lambda expression in Java 8 you can now have anonymous methods.
Say I have a class Alpha and I want to filter Alphas on a specific condition. To do this you can use a Predicate<Alpha>. This is a functional interface which has a method test that accepts an Alpha and returns a boolean.
Assuming that the filter method has this signature:
List<Alpha> filter(Predicate<Alpha> filterPredicate)
With the old anonymous class solution you would need to something like:
filter(new Predicate<Alpha>() {
boolean test(Alpha alpha) {
return alpha.centauri > 1;
}
});
With the Java 8 lambdas you can do:
filter(alpha -> alpha.centauri > 1);
For more detailed information see the Lambda Expressions tutorial
Anonymous inner classes implementing or extending the interface of an existing type has been done in other answers, although it is worth noting that multiple methods can be implemented (often with JavaBean-style events, for instance).
A little recognised feature is that although anonymous inner classes don't have a name, they do have a type. New methods can be added to the interface. These methods can only be invoked in limited cases. Chiefly directly on the new expression itself and within the class (including instance initialisers). It might confuse beginners, but it can be "interesting" for recursion.
private static String pretty(Node node) {
return "Node: " + new Object() {
String print(Node cur) {
return cur.isTerminal() ?
cur.name() :
("("+print(cur.left())+":"+print(cur.right())+")");
}
}.print(node);
}
(I originally wrote this using node rather than cur in the print method. Say NO to capturing "implicitly final" locals?)
Yes, if you are using Java 8 or above. Java 8 make it possible to define anonymous functions, which was impossible in previous versions.
Lets take example from java docs to get know how we can declare anonymous functions, classes
The following example, HelloWorldAnonymousClasses, uses anonymous
classes in the initialization statements of the local variables
frenchGreeting and spanishGreeting, but uses a local class for the
initialization of the variable englishGreeting:
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
Syntax of Anonymous Classes
Consider the instantiation of the frenchGreeting object:
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
The anonymous class expression consists of the following:
The new operator
The name of an interface to implement or a class to extend. In this
example, the anonymous class is implementing the interface
HelloWorld.
Parentheses that contain the arguments to a constructor, just like a
normal class instance creation expression. Note: When you implement
an interface, there is no constructor, so you use an empty pair of
parentheses, as in this example.
A body, which is a class declaration body. More specifically, in the
body, method declarations are allowed but statements are not.
You can also use Consumer and BiConsumer type regarding to how many parameters you need. Consumer accepts one parameter, BiConsumer accepts two.
public void myMethod() {
// you can declare it here
Consumer<String> myAnonymousMethod = s -> {
System.out.println(s);
};
// you can call it here
muAnonymousMethod.apply("Hello World");
}

Categories

Resources