This could well be a stupid question, but I'm new to Java, so...
I've currently got some code where currently this is being used
clazz.asSubclass(asSubclassOfClass).getConstructor().newInstance()
I need to pass some arguments to the contructort so I want to change it to: clazz.asSubclass(asSubclassOfClass).getConstructor(params).newInstance(args)
What I don't understand is what I need to pass in as params and what I need to pass in as args.
Let's say I wanted to pass in a String "howdy" and some object of type XYZ called XyzObj in. How would I specify that? WHat would I pass as params and what would I pass as args?
In Java this is called Reflection.
Assuming the class has this constructor, otherwise you will get a NoSuchMethod exception I believe.
clazz.asSubclass(asSubclassOfClass)
.getConstructor(String.class,XYZ.class)
.newInstance("howdy",XyzObj);
Since you are new to Java, let me give you an easier so that you can understand what's going on under the hood when you do this.
Assume you have the following class:
public class ParentClazz{
String someVar;
public ParentClazz(){
someVar="test";
}
public ParentClazz(String someVar){
System.out.println("I have been invoked");
this.someVar=someVar;
}
}
Then you have the following main method:
public static void main(String[] args) throws ParseException, IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
ParentClazz.class.asSubclass(ParentClazz.class).getConstructor(String.class).newInstance("howdy");
}
If you run this you will notice the console output print message - I have been invoked. This means that using reflection you have invoked the constructor of ParentClazz.
You can do the same thing if the scenario allows you is by using standard object creation process:
ParentClazz clazz = new ParentClazz("howdy");
Hope this helps you understand it.
Here is an example of creating classes without the new keyword.
The classes take other classes both primitives and Objects as their parameters.
The example also shows the instance of a subclass and a Parent class being created
public class ConstructorInstantiateWithoutNew
{
#SuppressWarnings("rawtypes")
public static void main( String [] args )
{
Class<Drinker> clazz_drinker = Drinker.class;
Class [] paramTypes = { Fizz.class, Colour.class, int.class };
Object [] paramValues = { new Fizz(), new Colour(), new Integer(10) };
Class<Drunk> clazz_drunk = Drunk.class;
Class [] paramTypesSub = { Fizz.class, Colour.class, int.class, boolean.class };
Object [] paramValuesSub = { new Fizz(), new Colour(), new Integer(10), true };
try
{
Drinker drinker = clazz_drinker.getConstructor( paramTypes ).newInstance( paramValues );
drinker.drink();
Drunk drunk = clazz_drunk.getConstructor(paramTypesSub).newInstance(paramValuesSub);
drunk.drink();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class Drinker
{
int n;
public Drinker( Fizz f, Colour c, int n)
{
this.n = n;
}
public void drink()
{
System.out.println( "Dad drank " + (n*10) + " ml");
}
}
class Drunk extends Drinker
{
boolean trouble;
public Drunk(Fizz f, Colour c, int n, boolean inDogHouse)
{
super(f,c,n);
trouble = inDogHouse;
}
public void drink()
{
System.out.println(
"Dad is Grounded: " + trouble +
" as he drank over "+
(n*10) + " ml");
}
}
class Fizz {} class Colour {}
Hope this is useful
Kind regards
Naresh Maharaj
clazz.asSubclass(asSubclassOfClass)
.getConstructor(String.class, XYZ.class)
.newInstance("howdy", XyzObj)
Which assumes that the constructor args are in the specified order
Related
While reading online, I came across the following:
public interface UnaryFunction<T>
{
T apply(T arg);
}
.......
private static UnaryFuntion<Object> ID_FUNC = new UnaryFunction<Object>
{
Object apply(Object arg)
{
return arg;
}
};
public static <T> UnaryFunction<T> idFunction()
{
return (UnaryFunction<T>) ID_FUNC;
}
In main:
public static void main(String[] args)
{
String[] strings = {"Peter", "Paul", "Mary"};
UnaryFunction<String> names = idFunction();
for(String s : strings)
{
System.out.println(names.apply(s));
}
Number[] numbers = {1, 2.0, 3L};
UnaryFunction<Number> nums = idFunction();
for(Number n : numbers)
{
System.out.println(nums.apply(n));
}
}
My question is, why do we need a generic interface here?
Would simply the following suffice:
public interface UnaryFunction
{
Object apply(Object arg); //Object as return type and argument type, instead.
}
? What is the need here to use generics?
And, what is actually a generic singleton factory? What is it good for?
Thanks.
The generic singleton factory is the idFunction in your example. Without it you would have a choice between two ugly alternatives, either require a cast wherever you use it, like this:
public class ExampleWithoutGenericSingletonFactory {
static UnaryFunction<Object> ID_FUNC = new UnaryFunction<Object>() {
public Object apply(Object arg) {
return arg;
}
};
public static void main(String[] args) {
BigDecimal b = new BigDecimal("1234.1241234");
BigDecimal b1 = (BigDecimal)(ID_FUNC.apply(b)); // have to cast here >_<
System.out.println("engineeringstring val of b1 = "
+ b1.toEngineeringString());
}
}
or make separate implementations for every type you want to support:
public static UnaryFunction<String> ID_FUNC_STRING = new UnaryFunction<String>() {
public String apply(String arg) {
return arg;
}
};
public static UnaryFunction<Number> ID_FUNC_NUM = new UnaryFunction<Number>() {
public Number apply(Number arg) {
return arg;
}
};
public static UnaryFunction<BigDecimal> ID_FUNC_DECIMAL = new UnaryFunction<BigDecimal>() {
public Number apply(BigDecimal arg) {
return arg;
}
};
giving you some ugly verbose cut-n-pasted code with a different name for every type that you have to keep straight. But since you know it's a pure function and the types get erased, you can have only one implementation (ID_FUNC) and have the singleton factory idFunction return it.
You would use this for cases where you have one function implementation that you want to be able to specify different types on, where the implementation is stateless.
The example could be better, since it only calls toString on the objects returned from the function call there's no demonstrated benefit from the factory. If the example showed using type-specific methods on the objects returned then the benefit might be more apparent.
An unchecked cast warning comes up when you do this, but it's safe to suppress it (which is what Joshua Bloch advises).
I have the following code which allows me to input in the scanner the Employee getter method that I want to call and it will do it using reflection (the name of the method should not appear anywhere in the code). This works for getter methods but I now need to modify the code to do something similar for setter methods. I have been trying to figure how to do it for the past week but I have been unable. Any help would be appreciated.
Thanks.
public static void main(String[] args) {
Employee e = Employee.testEmployee(); // a sample employee
Class cls = e.getClass();
Scanner scanner = new Scanner (System.in); // to parse data the user types in
String nextCommand;
// until the user enters "quit", get the next input from the user, and if it matches
// a given command, get the desired information from the employee object
do {
System.out.print("Enter command >> ");
nextCommand = scanner.next();
Method method = null;
try{
method = cls.getMethod(nextCommand);
}
catch(NoSuchMethodException x) {
}
try{
System.out.println(method.invoke(e));
}
catch(IllegalAccessException x) {
}
catch(java.lang.reflect.InvocationTargetException x) {
}
catch(NullPointerException x) {
}
} while (! nextCommand.equals("quit"));
}
Here's a code sample that does what you want to achieve:
public class Test {
private static HashSet<Class<?>> classes = new HashSet<>();
static {
classes.add(String.class);
classes.add(Integer.class);
classes.add(GregorianCalendar.class);
}
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
X obj = new X();
obj.setField("lala");
Method method = obj.getClass().getMethod("getField", null);
System.out.println(method.invoke(obj, null));
Method setMethod = getWorkingMethod(obj);
setMethod.invoke(obj, "who let the dogs out");
System.out.println(obj.getField());
}
private static Method getWorkingMethod(Object obj) {
Method method = null;
for (Class<?> c : classes) {
try {
method = obj.getClass().getMethod("setField", c);
} catch (NoSuchMethodException | SecurityException e) {
continue;
}
if(method != null){
return method;
}
}
throw new IllegalArgumentException("No such method found!");
}
}
class X {
private String stringField;
public void setField(String s) {
stringField = s;
}
public String getField() {
return stringField;
}
}
Output:
lala
who let the dogs out
Notes:
Create a collection (I used a HashSet) that stores Class<?> objects. You will use these to iterate over the possibilities and see if a method with that argument exists.
Use a try-catch to see if the method exists (an exception is thrown when it can't find it).
This will not work for overloaded methods. If this is your scenario, you'll have to make adjustments. I expect it to be no problem though, since you said this was meant for setters (which typically don't have overloads).
You can avoid calling the getter and setter methods by directly accessing the Field through reflection.
The Field object has various get and set methods that can be used to manipulate field values.
See: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getField%28java.lang.String%29
EXAMPLE
import java.lang.reflect.Field;
public class MyObject {
private String fieldA;
public String getFieldA() {
return fieldA;
}
public void setFieldA(String fieldA) {
this.fieldA = fieldA;
}
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
MyObject myObject = new MyObject();
myObject.setFieldA("Test");
Class clazz = myObject.getClass();
Field field = clazz.getDeclaredField("fieldA");
field.setAccessible(true);
String fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.set(myObject, "Test2");
fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.setAccessible(false); //be sure to return field to private
}
}
Resolution (method or field resolution) in java slows down you execution time by 'orders of 10 or 100', hence not a smart design decision. So, resolve once at start time, cache method instance, and execute it from cache. Avoid frequent lookups using reflection.
it's been quite a few months that i quite Java in favor of Python. Now i'm go back to java to project constraints.
now, i'm wondering if there's a way to get all the aprameters (with values) of a functions programmatically inside the function itself.
something like this
public void foo(String arg1,String arg2, Integer arg3){
... pars = ...getpars();
}
foo("abc","dfg",123);
where getpars() should return an HashMap with name,value pairs.
so from the example should be
arg1,"abc"
arg2,"dfg"
arg3,123
is there anything like this?
Unfortunately this is impossible. The only thing you can do is to retrieve the list of parameters types of a particular method using reflection.
But there is no way to get a map with name -> value of each argument passed into the method itself.
You can't get the name of the parameter, because it's no value just a name. If you wanna have the name of the parameter in your Map define a String which matches your parameter name and put it in.
Read this similar question. The accepted answer seems to have a solution for this using a third party library.
You can't get the names of the parameters dynamically, nor can you find the values in any way other than using the variable names. However, JAVA has the next best thing: variable arguments. If you want to have a dynamic number of arguments, you can declare your method as follows:
public void foo(Object... args)
When you call the method, you will call it with any number of arguments; foo(1, 2, "ABC") and foo(new File("config.dat"), new Scanner(), 88.5D) are both valid calls. Inside the function, args will be an array containing all of the parameters in order.
Just a few usage tips, though. The method declaration above is, in general, not considered good form. Usually, you can be much more specific. Think hard about whether or not you need all this flexibility, and consider using a few overloaded methods or possibly passing a HashMap to the function instead. Very rarely will you actually need to have dynamic parameters in that broad of a sense.
You could use:
void foo(String... args) {
for (String arg: args) { }
for (int i = 0; i < args.length - 1; i += 2) {
map.put(args[i], args[i + 1];
}
}
foo("a", "1", "b", "2");
Or use a Map builder, see builder-for-hashmap.
There are some hacky ways of getting the parameters values of an invoked method (But you have to understand that the parameters are unnamed, the best you can do is to get arg0.... argN).
Use Proxies
Aspect oriented programming (AspectJ, Spring AOP)
Let's consider the 1st approach. Say we want to log parameters before executing the method of some interface MethodParamsInterface, here you go. If you want to use these arguments in your logic - consider to implement them in InvocationHandler (or use EasyMock instead)
interface MethodParamsInterface {
void simpleMethod(int parm1, int parm2);
void simpleMethod(int parm1, int parm2, int param3);
}
public class MethodParams implements MethodParamsInterface {
public void simpleMethod(int parm1, int parm2) {
//business logic to be put there
}
public void simpleMethod(int parm1, int parm2, int param3) {
//business logic to be put there
}
public MethodParamsInterface wrappedInstance() throws Exception {
Class<?> proxyClass = Proxy.getProxyClass(MethodParams.class.getClassLoader(), MethodParamsInterface.class);
InvocationHandler invocationHandler = new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Map<String, Object> params = new LinkedHashMap<String, Object>(args.length);
for (int i = 0; i < args.length; i++)
params.put("arg" + i, args[i]);
//printing out the parameters:
for (Map.Entry<String, Object> paramValue : params.entrySet()) {
System.out.println(paramValue.getKey() + " : " + paramValue.getValue());
}
return MethodParams.this.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(MethodParams.this, args);
}
};
return (MethodParamsInterface) proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(invocationHandler);
}
public static void main(String[] args) throws Exception {
MethodParams instance = new MethodParams();
MethodParamsInterface wrapped = instance.wrappedInstance();
System.out.println("First method call: ");
wrapped.simpleMethod(10, 20);
System.out.println("Another method call: ");
wrapped.simpleMethod(10, 20, 30);
}
}
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Test01 {
public int method01(int i, int j) {
System.out.println("Original method01");
return i + j;
}
}
class ParameterWriter {
public static <T> T getObject(T inp) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(inp.getClass());
factory.setFilter(
new MethodFilter() {
#Override
public boolean isHandled(Method method) {
return true;
}
}
);
MethodHandler handler = new MethodHandler() {
#Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
for (int i = 0; i < args.length; i++) {
System.out.println(proceed.getParameters()[i].getName() + ":" + args[i]);
}
return proceed.invoke(self, args);
}
};
return (T) factory.create(new Class<?>[0], new Object[0], handler);
}
}
public class Main {
public static void main(String[] args) {
try {
Test01 test01 = ParameterWriter.getObject(new Test01());
test01.method01(2, 3);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
output:
arg0:2
arg1:3
Original method01
I have an issue with one of my class. I'm using a "varargs" constructor for unknown number of parameter.
public Groupe(String...nom){
for(String item:nom){
this.nom.add(item.toLowerCase());
}
}
public Groupe(String nom){
String[] list =nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The first constructor is called...that's fine, but there is a conflict when passing only ONE parameter with the second contructor. I would like to use the second constructor when passing only one string, and the first if 2 and more parameters.
I'd want to handle this
new Groupe("Foo,Bar");
This is where I call it. I suspect the "error" comes from there
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
I don't pass a String, but a Varargs (tab?)...
It should be fine, with the caveat that null can be converted to either String[] or String:
public class Test {
public Test(String single) {
System.out.println("Single");
}
public Test(String... multiple) {
System.out.println("Multiple");
}
public static void main(String[] args) {
new Test("Foo"); // Single
new Test("Foo", "Bar"); // Multiple
new Test(); // Effectively multiple
// new Test(null); // Doesn't compile - ambiguous
new Test((String) null); // Single
}
}
EDIT: Now that you've shown us the calling code, that's definitely the problem:
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
Here, the type of nom is String[] - so it will always call the first constructor. You've got an array of strings there - under what circumstances do you want to call the second constructor?
To be honest, given that the two constructors act significantly differently, I would actually make both constructors private, and provide static methods:
public static Groupe fromStringArray(String... nom)
public static Groupe fromCommaSeparatedString(String nom)
Then it will be absolutely clear what you're expecting in each case.
Maybe this can be a solution:
public Groupe(String...nom){
if (nom.length == 1) {
add(nom[0].split(","));
} else {
add(nom);
}
}
private void add(String[] list) {
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The varargs part can be empty. So you can get what you want with
public Groupe(String nom){
String[] list = nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
public Groupe(String nom1, String nom2, String...nom){
this.nom.add(nom1);
this.nom.add(nom2);
for(String item:nom)
this.nom.add(item.toLowerCase());
}
You could also, of course, use one ctor with an if statement on the length of the input array, splitting out cases 0 (not handled with the code above), 1, and > 1.
public class OverloadVarArgs {
public static void main(String... args){
OverloadVarArgs a = new OverloadVarArgs("One Argument");
OverloadVarArgs b = new OverloadVarArgs("Two", "Arguments");
OverloadVarArgs c = new OverloadVarArgs("One, Argument");
}
public OverloadVarArgs(String a){
System.out.println("Constructor 1");
}
public OverloadVarArgs(String... a){
System.out.println("Constructor 2");
}
}
Output:
Constructor 1
Constructor 2
Constructor 1
I would like to use Class.newInstance() but the class I am instantiating does not have a nullary constructor. Therefore I need to be able to pass in constructor arguments. Is there a way to do this?
MyClass.class.getDeclaredConstructor(String.class).newInstance("HERESMYARG");
or
obj.getClass().getDeclaredConstructor(String.class).newInstance("HERESMYARG");
myObject.getClass().getDeclaredConstructors(types list).newInstance(args list);
Edit: according to the comments seems like pointing class and method names is not enough for some users. For more info take a look at the documentation for getting constuctor and invoking it.
Assuming you have the following constructor
class MyClass {
public MyClass(Long l, String s, int i) {
}
}
You will need to show you intend to use this constructor like so:
Class classToLoad = MyClass.class;
Class[] cArg = new Class[3]; //Our constructor has 3 arguments
cArg[0] = Long.class; //First argument is of *object* type Long
cArg[1] = String.class; //Second argument is of *object* type String
cArg[2] = int.class; //Third argument is of *primitive* type int
Long l = new Long(88);
String s = "text";
int i = 5;
classToLoad.getDeclaredConstructor(cArg).newInstance(l, s, i);
Do not use Class.newInstance(); see this thread: Why is Class.newInstance() evil?
Like other answers say, use Constructor.newInstance() instead.
You can get other constructors with getConstructor(...).
Follow below steps to call parameterized consturctor.
Get Constructor with parameter types by passing types in Class[]
for getDeclaredConstructor method of Class
Create constructor instance by passing values in Object[] for
newInstance method of Constructor
Example code:
import java.lang.reflect.*;
class NewInstanceWithReflection{
public NewInstanceWithReflection(){
System.out.println("Default constructor");
}
public NewInstanceWithReflection( String a){
System.out.println("Constructor :String => "+a);
}
public static void main(String args[]) throws Exception {
NewInstanceWithReflection object = (NewInstanceWithReflection)Class.forName("NewInstanceWithReflection").newInstance();
Constructor constructor = NewInstanceWithReflection.class.getDeclaredConstructor( new Class[] {String.class});
NewInstanceWithReflection object1 = (NewInstanceWithReflection)constructor.newInstance(new Object[]{"StackOverFlow"});
}
}
output:
java NewInstanceWithReflection
Default constructor
Constructor :String => StackOverFlow
You can use the getDeclaredConstructor method of Class. It expects an array of classes. Here is a tested and working example:
public static JFrame createJFrame(Class c, String name, Component parentComponent)
{
try
{
JFrame frame = (JFrame)c.getDeclaredConstructor(new Class[] {String.class}).newInstance("name");
if (parentComponent != null)
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
else
{
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
frame.setLocationRelativeTo(parentComponent);
frame.pack();
frame.setVisible(true);
}
catch (InstantiationException instantiationException)
{
ExceptionHandler.handleException(instantiationException, parentComponent, Language.messages.get(Language.InstantiationExceptionKey), c.getName());
}
catch(NoSuchMethodException noSuchMethodException)
{
//ExceptionHandler.handleException(noSuchMethodException, parentComponent, Language.NoSuchMethodExceptionKey, "NamedConstructor");
ExceptionHandler.handleException(noSuchMethodException, parentComponent, Language.messages.get(Language.NoSuchMethodExceptionKey), "(Constructor or a JFrame method)");
}
catch (IllegalAccessException illegalAccessException)
{
ExceptionHandler.handleException(illegalAccessException, parentComponent, Language.messages.get(Language.IllegalAccessExceptionKey));
}
catch (InvocationTargetException invocationTargetException)
{
ExceptionHandler.handleException(invocationTargetException, parentComponent, Language.messages.get(Language.InvocationTargetExceptionKey));
}
finally
{
return null;
}
}
I think this is exactly what you want
http://da2i.univ-lille1.fr/doc/tutorial-java/reflect/object/arg.html
Although it seems a dead thread, someone might find it useful
This is how I created an instance of Class clazz using a dynamic constructor args list.
final Constructor constructor = clazz.getConstructors()[0];
final int constructorArgsCount = constructor.getParameterCount();
if (constructorArgsCount > 0) {
final Object[] constructorArgs = new Object[constructorArgsCount];
int i = 0;
for (Class parameterClass : constructor.getParameterTypes()) {
Object dummyParameterValue = getDummyValue(Class.forName(parameterClass.getTypeName()), null);
constructorArgs[i++] = dummyParameterValue;
}
instance = constructor.newInstance(constructorArgs);
} else {
instance = clazz.newInstance();
}
This is what getDummyValue() method looks like,
private static Object getDummyValue(final Class clazz, final Field field) throws Exception {
if (int.class.equals(clazz) || Integer.class.equals(clazz)) {
return DUMMY_INT;
} else if (String.class.equals(clazz)) {
return DUMMY_STRING;
} else if (boolean.class.equals(clazz) || Boolean.class.equals(clazz)) {
return DUMMY_BOOL;
} else if (List.class.equals(clazz)) {
Class fieldClassGeneric = Class.forName(((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].getTypeName());
return List.of(getDummyValue(fieldClassGeneric, null));
} else if (USER_DEFINED_CLASSES.contains(clazz.getSimpleName())) {
return createClassInstance(clazz);
} else {
throw new Exception("Dummy value for class type not defined - " + clazz.getName();
}
}