I was trying to use reflection to call funcA() of a class ClsA. However Eclipse Juno is showing a warning in TestA class remark with warning (A) as shown below.
The ClsA is like this:
public class ClsA {
String varA;
...
...
private String funcA() {
return varA;
}
}
This is the code I use the reflection call on funcA():
public class TestA {
public static void main(String[] args) {
ClsA clsA = new ClsA();
Class noparam[] = {};
Method funcA;
String retStr;
funcA = ClsA.class.getDeclaredMethod("funcA", noparam);
funcA.setAccessible(true);
retStr = (String) funcA.invoke(clsA, null); // warning (A)
}
}
And this is the warning I get. Basically I just don't really understand what is the message that warning trying to bring? How could I explicitly cast a null?
The argument of type null should explicitly be cast to Object[] for
the invocation of the varargs method invoke(Object, Object...) from
type Method. It could alternatively be cast to Object for a varargs
invocation
There can be 2 types of method invocation, one is to call with fixed argument, other is to call with variable arguments.
If you are providing just null as argument, it is not clear to java whether that method is for variable parameters or no parameter at all (as variable parameters may also accept no agrument).
So it asks to mention explicitly like (Object[])null or (Object)null, even if you don't want to provide any argument.
Invoking Methods
Since the method signature is (Object obj, Object... vars) unless you declare the null cast the most forward approach is to not include any arguments.
Example from your code above:
retStr = (String) funcA.invoke(clsA);
Anytime there are VarArgs (Something...) it means 0 or more.
Related
I have the following code:
String methodName = "main";
Method[] methods = classHandle.getMethods();
for (Method m : methods)
{
System.out.println(m.getName().equals(methodName);
}
Method classMethod = null;
try
{
classMethod = classHandle.getMethod(methodName);
}
catch(Exception e)
{
}
System.out.println(classMethod == null);
The first print prints true, but the second one also prints true.
Why is that happening?
To get hold of static void main(String [] args) use the following
classHandle.getDeclaredMethod("main", String[].class);
Possible causes (written before we knew we were after static void main)
Class.getMethod(name, parameters) returns only public methods, perhaps you want to use getDeclaredMethod(name, parameters) for a protected, default or private method
Parameters don't match. Does "main" take any parameters? The parameters passed to getDeclaredMethod() or getMethod() have to match exactly.
Consider the following.
private class Horse {
protected void makeNoise(int level) {
}
}
// OK
System.out.println(Horse.class.getDeclaredMethod("makeNoise", new Class<?>[]{int.class}));
// throws NoSuchMethodException - parameters don't match
System.out.println(Horse.class.getDeclaredMethod("makeNoise"));
// throws NoSuchMethodException, not a public method
System.out.println(Horse.class.getMethod("makeNoise", new Class<?>[]{int.class}));
I assume that 'classHandle' is a type of Class?
Your first loop only checks for the method name and does not care about method arguments.
The full signature of 'public Method getMethod(String name, Class... parameterTypes)' tells us that you are actually trying to find 0-argument method with name 'methodName'.
Are you sure that method with such a name and 0 arguments exists?
Because the parameters of the method do not match. You need to specify the parameter types in your call to getMethod().
The getMethods method returns an array of all Methods, and you are only checking the name. It will return true for main, but false for all methods inherited from Object.
When you call the getMethod method with only the method name as a parameter, you are asking for a Method that takes no parameters.
But main takes one parameter, a String[], so getMethod throws a NoSuchMethodException. You're catching it, but doing nothing with it. (You're "swallowing" the exception, generally a bad idea.) So, classMethod remains null and true is outputted.
To find main, pass the parameter's type as an additional parameter:
Method classMethod = classHandle.getMethod(methodName, String[].class);
I really am a little confused here. Normal signature to call accessible class method or variable is (Class/Object).(method/variable). Then how do we give System.out.println()? Since System.out only gives the return type but does not belong to same class. Also in servlets, "this.getServletConfig().getInitParameter("defaultUser")" is not making sense to me, since getServletConfig() and getInitParameter are both member functions of same class, so signature becomes something like, class.method1().method2(), where method1 and method2 are member functions of same class. Can someone please explain..
Example:
Class CascMethodClassB()
{
public CascMethodClassA methodTest()
{
CascMethodClassA obj1 = new CascMethodClassA();
return obj1;
}
} /*Class CascMethodClassB ends*/
Class CascMethodClassA()
{
public int varTest;
public CascMethodClassA()
{
varTest = 7;
}
} /*Class CascMethodClassA ends*/
Class CascMethodClassC()
{
CascMethodClassB obj2 = new CascMethodClassB();
int varTestC = obj2.methodTest().varTest
public static void main(String[] args)
{
System.out.println("varTest in CascMethodClassA is: "+ varTestC);
} /*Class CascMethodClassC ends*/
}
Thankyou,
Fraggy.
Both are different cases.
In the first case, outis a public static member in the System class. The member out is of type PrintStream, so the call
System.out.println()
will call the method println() from the PrintStream object (out).
The second case, is something called method chaining. What happens is that class.method1() will return an object instance, according to Java docs it will return a ServetConfig object. So, you can again call a method from that returned object. Another way of seeing that call is (brackets are redundant, just there so you can visualize the order of the calls):
(ClassName.someMethod1()).someMethod2();
System.out is a public class variable of type PrintStream, not a
method. Therefore you can invoke the println method on it, which returns void.
this.getServletConfig().getInitParameter("defaultUser") makes
perfect sense once you understand chaining method invocations. In
this case, you are:
calling the present instance of Servlet
getting its instance field's value of type ServletConfig
getting whichever String value is returned by invoking the getInitParameter method on the ServletConfig object
Finally, a method's signature is made of the method's name and parameter types
Each non-void method returns a type, which may be a different type to the declaring class, so the chained method/field will have the methods of the returned type (not the class it's called from or the class that the first method is defined in).
For example, to break down System.out.printkln():
System.out // out is a public field of type PrintStream
.println() // println() is a method of PrintStream, not System
I have added three methods with parameters:
public static void doSomething(Object obj) {
System.out.println("Object called");
}
public static void doSomething(char[] obj) {
System.out.println("Array called");
}
public static void doSomething(Integer obj) {
System.out.println("Integer called");
}
When I am calling doSomething(null) , then compiler throws error as ambiguous methods. So is the issue because Integer and char[] methods or Integer and Object methods?
Java will always try to use the most specific applicable version of a method that's available (see JLS §15.12.2).
Object, char[] and Integer can all take null as a valid value. Therefore all 3 version are applicable, so Java will have to find the most specific one.
Since Object is the super-type of char[], the array version is more specific than the Object-version. So if only those two methods exist, the char[] version will be chosen.
When both the char[] and Integer versions are available, then both of them are more specific than Object but none is more specific than the other, so Java can't decide which one to call. In this case you'll have to explicitly mention which one you want to call by casting the argument to the appropriate type.
Note that in practice this problem occurs far more seldom than one might think. The reason for this is that it only happens when you're explicitly calling a method with null or with a variable of a rather un-specific type (such as Object).
On the contrary, the following invocation would be perfectly unambiguous:
char[] x = null;
doSomething(x);
Although you're still passing the value null, Java knows exactly which method to call, since it will take the type of the variable into account.
Each pair of these three methods is ambiguous by itself when called with a null argument. Because each parameter type is a reference type.
The following are the three ways to call one specific method of yours with null.
doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);
May I suggest to remove this ambiguity if you actually plan to call these methods with null arguments. Such a design invites errors in the future.
null is a valid value for any of the three types; so the compiler cannot decide which function to use. Use something like doSomething((Object)null) or doSomething((Integer)null) instead.
Every class in Java extends Object class.Even Integer class also extends Object. Hence both Object and Integer are considered as Object instance. So when you pass null as a parameter than compiler gets confused that which object method to call i.e. With parameter Object or parameter Integer since they both are object and their reference can be null. But the primitives in java does not extends Object.
I Have tried this and when there is exactly one pair of overloaded method and one of them has a parameter type Object then the compiler will always select the method with more specific type. But when there is more than one specific type, then the compiler throws an ambiguous method error.
Since this is a compile time event, this can only happen when one intentionally passes null to this method. If this is done intentionally then it is better to overload this method again with no parameter or create another method altogether.
class Sample{
public static void main (String[] args) {
Sample s = new Sample();
s.printVal(null);
}
public static void printVal(Object i){
System.out.println("obj called "+i);
}
public static void printVal(Integer i){
System.out.println("Int called "+i);
}
}
The output is Int called null and so ambiguity is with char[] and Integer
there is an ambiguity because of doSomething(char[] obj) and doSomething(Integer obj).
char[] and Integer both are the same superior for null that's why they are ambiguous.
From Effective Java :
One noteworthy feature of generic methods is that you needn’t specify
the value of the type parameter explicitly as you must when invoking
generic con- structors. The compiler figures out the value of the type
parameters by examining the types of the method arguments.
So how does the compiler infer type in case of a method that takes no parameter ?
For example consider the following static factory method that creates a new HashMap every time it is called :
// Generic static factory method
public static <K,V> HashMap<K,V> newHashMap() {
return new HashMap<K,V>();
}
And when the method is called like :
Map<String,String> pair = newHashMap(); //it returns a Map<String,String>
and when it called like
Map<String, List<String>> anagrams =newHashMap(); // it returns a Map<String,List<String>
It infers it based on the variable type that the return is assigned too.
public class GenericTest {
public static void main(final String[] args) {
final GenericTest test = new GenericTest();
String data = test.echo();
}
public <T> T echo() {
return null;
}
}
In code example above, the compiler infers the generic parameter type based on the type of the data field, in this case String.
The compiler has only a limited number of variables on which to infer types. If a method takes no arguments, then the method can only be a simple override, since return values cannot be used to type methods, that leaves the name of the method itself. The compiler has to choose how far up the inheritance chain to select which parent/child class has the method to actually be called.
I was wondering what is the difference between the following two method declarations:
public Object doSomething(Object obj) {....}
public <T> T doSomething(T t) {....}
Is there something you can/would do with one but not the other? I could not find this question elsewhere on this site.
Isolated from context - no difference. On both t and obj you can invoke only the methods of Object.
But with context - if you have a generic class:
MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();
Then:
Foo newFoo = my.doSomething(foo);
Same code with object
Foo newFoo = (Foo) my.doSomething(foo);
Two advantages:
no need of casting (the compiler hides this from you)
compile time safety that works. If the Object version is used, you won't be sure that the method always returns Foo. If it returns Bar, you'll have a ClassCastException, at runtime.
The difference here is that in the first, we specify that the caller must pass an Object instance (any class), and it will get back another Object (any class, not necessarily of the same type).
In the second, the type returned will be the same type as that given when the class was defined.
Example ex = new Example<Integer>();
Here we specify what type T will be which allows us to enforce more constraints on a class or method. For example we can instantiate a LinkedList<Integer> or LinkedList<Example> and we know that when we call one of these methods, we'll get back an Integer or Example instance.
The main goal here is that the calling code can specify what type of objects a class will operate upon, instead of relying on type-casting to enforce this.
See Java Generics* from Oracle.
*Updated Link.
The difference is that with generic methods I don't need to cast and I get a compilation error when I do wrong:
public class App {
public static void main(String[] args) {
String s = process("vv");
String b = process(new Object()); // Compilation error
}
public static <T> T process(T val) {
return val;
}
}
Using object I always need to cast and I don't get any errors when I do wrong:
public class App {
public static void main(String[] args) {
String s = (String)process("vv");
String b = (String)process(new Object());
}
public static Object process(Object val) {
return val;
}
}
You don't need to do additional class casting. In first case you will always get an object of class java.lang.Object which you will need to cast to your class. In second case T will be replaced with the class defined in generic signature and no class casting will be needed.
At runtime, nothing. But at compile time the second will do type checking to make sure the type of the parameter and the type of the return value match (or are subtypes of) whatever type T resolves to (the first example also does type checking but every object is a subtype of Object so every type will be accepted).
T is a generic type. Meaning it can be substituted by any qualifying object at runtime. You may invoke such a method as follows:
String response = doSomething("hello world");
OR
MyObject response = doSomething(new MyObject());
OR
Integer response = doSomething(31);
As you can see, there is polymorphism here.
But if it is declared to return Object, you can't do this unless you type cast things.
in the first case it takes a parameter of any type e.g.string and return a type foo. In the second case it takes a parameter of type foo and returns an object of type foo.
There are few reasons that you can consider Generics over Object type in Java:
Generics is flexible and safe. At the same time, working with Object that requires type-casting is error-prone
Type Casting in Java is slow
ref : [1]: https://www.infoworld.com/article/2076555/java-performance-programming--part-2--the-cost-of-casting.html