java: call static method from unknown class with polymorphy [duplicate] - java

This question already has answers here:
Why doesn't Java allow overriding of static methods?
(22 answers)
Closed 7 years ago.
I have superclass Token with some subclasses like Knight, King, Queen, etc.
I need a random Token Type so I call this method:
public Class randomTokenType(){
Class[] classes = {
Bishop.class, King.class, Knight.class, Pawn.class, Queen.class, Rook.class
};
Random random = new Random();
return classes[random.nextInt(6)];
}
Class<Token> tokenType = randomTokenType();
Now I want to call a static method on this tokenType, for example:
tokenType.displayString()
The compiler can't resolve this method even tough it's implemented in Token and all of its subclasses.
What is my mistake?

What you are actually looking for is reflection - see Invoking a static method using reflection
in you case that would be:
Method method = tokenType.getMethod("displayString");
method.invoke(null);
A Class-object is a sort of an index. It contains methods that allow you to query what the actual .class file contains (like its methods, fields, annotations et al).
You cannot access them directly (like an index points only to WHERE the information is - not the information itself) - instead you need to query the index with i.e. Class.getMethod("nameofMethod")
once you got the "pointer" to the method you can try to call it (via Method.invoke).
Depending on what kind of method it is, you need to pass the invoke method only null (for static methods) or an instance of the object (for non-static).
Reflection allows you to create such an instance on-the-fly as well.
For more information I suggest reading up on reflection and especially the javadoc of Class. It explains a lot.
Edit: this only works if the method displayString is declared like this:
public class Bishop{
public static void displayString() {
System.out.println("Bishop");
}
}
public class Test {
public static void main(String args[]) throws Exception {
Class<?> tokenType = Bishop.class;
Method method = tokenType.getMethod("displayString");
method.invoke(null);
}
}
if there are parameter or it is private, then this will not work

There are quite a few problems with your code. Few of them are
You are asking a class to return something.
public Class randomTokenType() //dont know what this is supposed to mean ?
If you add static to a method definition that method can never be overrriden

Related

JAVA - Cannot make a static reference to the non-static method [duplicate]

This question already has answers here:
Java Error: Cannot make a static reference to the non-static method
(7 answers)
Closed 7 years ago.
public class lookFor {
//Tools
//It returns the position of an element at the ArrayList, if not found returns -1
public int User(String target, ArrayList<User> users){
for(int i = 0; i < users.size(); i++){
if(users.get(i).getUserName().equals(target)){
return i;
}
}
return -1;
}
}
For some reason, when i try to call "User" This Error appears
And asks me to make the "user" method a static method, but i don't know what repercussion will it have.
A static method belongs to the class, a non-static method belongs to an instance of the class.
You need to create an instance of the class:
lookFor look = new lookFor();
And write like this:
if(look.User(username,users)==-1){....};
Static means there is one for an entire class, whereas if it is non-static there is one for each instance of a class (object). In order to reference a non-static method you need to first create an object, and call it.
In order to use the User method in a static context (main method for the example), you need to instantiate the lookFor class and call the User method on that object :
lookFor look = new lookFor(); // Use appropriate constructor
if(look.User(username, users) == -1) {
...
}
You have to make an instance of the lookFor class in order to call it's non-static methods.
lookFor lf = new lookFor();
if(lf.User(username,users)==-1) {
...
If you are trying to access USER method within static method then you get this error.
The only way to call a non-static method from a static method is to
have an instance of the class containing the non-static method. By
definition, a non-static method is one that is called ON an instance
of some class, whereas a static method belongs to the class itself.
For example :
You could create an instance of the class you want to call the method on,
new lookFor().USER(target, list);

How to specify function types for void (not Void) methods in Java8?

I'm playing around with Java 8 to find out how functions as first class citizens. I have the following snippet:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
What I'm trying to do is pass method displayInt to method myForEach using a method reference. To compiler produces the following error:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
The compiler complains that void cannot be converted to Void. I don't know how to specify the type of the function interface in the signature of myForEach such that the code compiles. I know I could simply change the return type of displayInt to Void and then return null. However, there may be situations where it's not possible to alter the method I want to pass somewhere else. Is there an easy way to reuse displayInt as it is?
You are trying to use the wrong interface type. The type Function is not appropriate in this case because it receives a parameter and has a return value. Instead you should use Consumer (formerly known as Block)
The Function type is declared as
interface Function<T,R> {
R apply(T t);
}
However, the Consumer type is compatible with that you are looking for:
interface Consumer<T> {
void accept(T t);
}
As such, Consumer is compatible with methods that receive a T and return nothing (void). And this is what you want.
For instance, if I wanted to display all element in a list I could simply create a consumer for that with a lambda expression:
List<String> allJedi = asList("Luke","Obiwan","Quigon");
allJedi.forEach( jedi -> System.out.println(jedi) );
You can see above that in this case, the lambda expression receives a parameter and has no return value.
Now, if I wanted to use a method reference instead of a lambda expression to create a consume of this type, then I need a method that receives a String and returns void, right?.
I could use different types of method references, but in this case let's take advantage of an object method reference by using the println method in the System.out object, like this:
Consumer<String> block = System.out::println
Or I could simply do
allJedi.forEach(System.out::println);
The println method is appropriate because it receives a value and has a return type void, just like the accept method in Consumer.
So, in your code, you need to change your method signature to somewhat like:
public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) {
list.forEach(myBlock);
}
And then you should be able to create a consumer, using a static method reference, in your case by doing:
myForEach(theList, Test::displayInt);
Ultimately, you could even get rid of your myForEach method altogether and simply do:
theList.forEach(Test::displayInt);
About Functions as First Class Citizens
All been said, the truth is that Java 8 will not have functions as first-class citizens since a structural function type will not be added to the language. Java will simply offer an alternative way to create implementations of functional interfaces out of lambda expressions and method references. Ultimately lambda expressions and method references will be bound to object references, therefore all we have is objects as first-class citizens. The important thing is the functionality is there since we can pass objects as parameters, bound them to variable references and return them as values from other methods, then they pretty much serve a similar purpose.
When you need to accept a function as argument which takes no arguments and returns no result (void), in my opinion it is still best to have something like
public interface Thunk { void apply(); }
somewhere in your code. In my functional programming courses the word 'thunk' was used to describe such functions. Why it isn't in java.util.function is beyond my comprehension.
In other cases I find that even when java.util.function does have something that matches the signature I want - it still doesn't always feel right when the naming of the interface doesn't match the use of the function in my code. I guess it's a similar point that is made elsewhere here regarding 'Runnable' - which is a term associated with the Thread class - so while it may have he signature I need, it is still likely to confuse the reader.
Set return type to Void instead of void and return null
// Modify existing method
public static Void displayInt(Integer i) {
System.out.println(i);
return null;
}
OR
// Or use Lambda
myForEach(theList, i -> {System.out.println(i);return null;});

Final keyword in method signatures [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Final arguments in interface methods - what’s the point?
While trying to experiment a few things, I've ran into a problem that it's described in this page.
interface B {
public int something(final int a);
}
abstract class C {
public int other(final int b);
}
class A extends C implements B {
public int something(int a) {
return a++;
}
public int other(int b) {
return b++
}
}
Why is such feature possible? I don't know why it's possible to to make a final parameter into a non-final one by just overriding the method. Why is the final keyword ignored in a method signature? And how do I obligate sub-classes to use in their methods final variables?
Java passes arguments to a method by value.
Therefore, no changes to a parameter can propagate back to the caller. It follows that whether or not the parameter is declared final makes absolutely no difference to the caller. As such, it is part of the implementation of the method rather than part of its interface.
What's your motivation for wanting to "obligate sub-classes to use in their methods final variables"?
final for a parameter only means that the value must not be changed within the method body. This is not a part of the method signature, and is not relevant to subclasses.
It should be invalid to have final parameters in interface or abstract methods, because it's meaningless.
Final variables are the only ones that can be used in closures. So if you want to do something like this:
void myMethod(int val) {
MyClass cls = new MyClass() {
#override
void doAction() {
callMethod(val); // use the val argument in the anonymous class - closure!
}
};
useClass(cls);
}
This won't compile, as the compiler requires val to be final. So changing the method signature to
void myMethod(final int val)
will solve the problem. Local final variable will do just as well:
void myMethod(int val) {
final int val0;
// now use val0 in the anonymous class
Java's final is not C++ const; there is no such thing as const-correctness in Java.
In Java, one achieves const-ness using immutable classes. It turns out to be quite effective because unlike C++, one cannot simply mess with memory. (You can use Field.setAccessible(true), and then use Reflection. But even that corruption-vector can be prevented by running the JVM with an appropriately configured security manager.)
The final keyword for arguments is not part of the method signature, and is only important for the body of the method, because Java passes all arguments by value (a copy of the value is always made for the method call).
I only use the final keyword (for arguments) if the compiler forces me to make it final, because the argument is used inside an anonymous class defined in the method.
In Java parameters are passed by value. Whether a parameter is final or not only affects that method, not the caller. I don't see why a class needs to obligate the subtypes.
Note that final parameters have one main purpose: you can't assign new values to them.
Also note that parameters are always passed by value, thus the caller won't see any assignments to the parameter inside the method.
If you really want to force parameters to be final (in order to prevent bugs that might be introduced when reassigning a parameter accidentially), employ a code anaylzer such as checkstyle.

Polymorphism and method overloading

I have a quick and straighforward question:
I have this simple class:
public class A
{
public void m(Object o)
{
System.out.println("m with Object called");
}
public void m(Number n)
{
System.out.println("m with Number called");
}
public static void main(String[] args)
{
A a = new A();
// why will m(Number) be called?
a.m(null);
}
}
UPDATE: actually is method with Number actually being called. Sorry about the confusion.
If I call a.m(null) it calls method with Number parameter.
My question is: why is this? where in the java language specification is this specified?
First of all, it actually calls m(Number).
It happens because both methods are applicable, but m(Number) is the most specific method, since any argument of m(Number) can be passed to m(Object), but not vice versa.
If you replace m(Object) by m(String) (or add another method such as m(Date)), compiler would report ambiguity, since the most specific method can't be identified.
See the section Choosing the Most Specific Method in the Java Specification.
This is not polymorphism or overriding. This is method overloading.
I tested this and specific method is being called (not the m(Object)) and according to the spec the specific method is always called. Which overload will get selected for null in Java?
another related question for you to think about:
public static void main(String[] args)
{
A a = new A();
Object n = new Integer(1);
a.m(n); // which method will be called?
}
My 2 cents. Method with Number argument is the one that is called, Because Number extends Object. I had a similar situation in the past, I did override a method and put Component instead of JComponent (by mistake). It took me one week to find out the reason why my method was never called. I figure it out, that if there are some inheritance relationship between the overloaded methods, the JVM matches first the deeper one in the class hierarchy.
Object is the default type in Java. If you refactor your m(Object o) method to m(String o) you'll have a compile time error saying that the call m(null) is ambiguous because Java cannot determine which class between String and Number defaults to null
Other than that, between m(Object o) and m(Number o), calling m(null) will call m(Number o) because it's the most specialized method. You would need to cast null into an Object (or anything not an instance of Number) otherwise.
a.m((String) null);

Static members in Java [duplicate]

This question already has answers here:
Are static methods inherited in Java?
(15 answers)
Closed 4 years ago.
I've read Statics in Java are not inherited. I've a small program below which compiles and produces 2 2 as output when run. From the program it looks like k (a static variable) is being inherited !! What am I doing wrong?
class Super
{
int i =1;
static int k = 2;
public static void print()
{
System.out.println(k);
}
}
class Sub extends Super
{
public void show()
{
// I was expecting compile error here. But it works !!
System.out.println(" k : " + k);
}
public static void main(String []args)
{
Sub m =new Sub();
m.show();
print();
}
}
The scope in which names are looked up in includes the super class.
The name print is not found in Sub so is resolved in the Super.
When the compiler generates bytecode, the call will be made to Super.print, rather than a call on a method in Sub.
Similarly the k is visible in the sub-class without qualifying it.
There is no polymorphism here, only inheritance of the contents of a name space. Static methods and all fields do not have polymorphic dispatch in Java, so can only be hidden by sub-classes, not overridden. The post you link to in your comments is using 'inheritance' in a somewhat unconventional way, mixing it up with polymorphism. You can have polymorphism without inheritance and inheritance without polymorphism.
Sub extends Super so it can see all the public/protected/package (static) members of Super.
I guess this is what you described as "Statics in Java are not inherited"
change
static int k = 2;
to
private static int k = 2;
and your Sub program won't see 'k' anymore and won't compile;
also try to create a new 'static int k=3;' in Sub, and see what happens.
It's pretty much the same as accessing Math.PI or any other global constant (which also have public and final modifiers).
In your case you have default (package) scope.
It's independed of inheritance only the scope restricts whether it is visible.
I think you might be wrong about static variables not being inherited. I suppose some properties of it are not inherited. For instance a static var normally means that all instances of the class have access to the same place in memory.
When you inherit, the derived class does not refer to the same memory as the base class.
Static member can be static data member and static method which can be accessed without using the object. It is used by nested class

Categories