This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
I have a very basic doubt in Java.
Here is a code I have written. From a method in class A in package A, I try to instantiate an object of class b of a different package and call its method, to which I pass a list.
parseObjectList = new ArrayList<ParseObject>();
pullAllService.pullAllData(queryType,parseObjectList);
and in the function I do some manipulation:
public void pullAllData(String queryType,List<ParseObject> parseObjectList)
{
ParseQuery<ParseObject> query = null;
List<ParseObject> parseObjects = parseObjectList;
if(queryType.equals("a"))
{
query = new ParseQuery<ParseObject>("a");
}
else if(queryType.equals("b"))
{
query = new ParseQuery<ParseObject>("b");
}
try {
parseObjects = query.find(); //I get the list
/* final List<ParseObject> finalParseObjectList = parseObjectList;
curActivity.runOnUiThread(new Runnable() {
public void run() {
ToastMessageHelper.displayLongToast(curActivity, "Objects found : ");
for (int i = 0; i < finalParseObjectList.size(); i++) {
ToastMessageHelper.displayLongToast(curActivity, finalParseObjectList.get(i).get("Name").toString());
System.out.println();
}
}
});
*/
} catch (ParseException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
after which if I try to print the list in class A's method. I get an empty list.
But if I do this,
parseObjectList = new ArrayList<ParseObject>();
parseObjectList = pullAllService.pullAllData(queryType,parseObjectList);
and make it return the list from pullAllData() (by changing the return type and returning the list) , I get the list with the expected data.
I thought that just by passing the parseObjectList into the function, the passed parameter would behave as a reference and automatically be assigned the intended data. What's wrong here?
Java is a pass by value language. Passing a List reference to a method allows the method to mutate the List referenced by the reference, but it can't change the value of the List reference that was passed to it.
You can do something like this to add the elements to the list that was passed to your method :
parseObjectList.addAll(query.find());
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 3 years ago.
this is the test code I am using to understand how java handles object memory.
public class TestCode {
public static void main(String[] args) {
TestCode obj = new TestCode();
CustomClass cs1 = new CustomClass(5);
obj.updateExistingObj(cs1);
System.out.println(cs1.val);
CustomClass cs2 = new CustomClass(5);
obj.instantiateExistingObj(cs2);
System.out.println(cs2.val);
CustomClass cs3 = null;
obj.updateNullObj(cs3);
System.out.println(cs3.val);
}
void updateExistingObj(CustomClass cs1) {
cs1.val = 9;
}
void instantiateExistingObj(CustomClass cs2) {
cs2 = new CustomClass(9);
}
void updateNullObj(CustomClass cs3) {
cs3 = new CustomClass(9);
}
}
class CustomClass {
int val;
CustomClass next;
CustomClass(int x) { val = x; }
}
The output of the first syso where I am printing cs1.val I am getting expected value which is 9.
The output of the second syso where I am printing cs2.val I am getting 5 as output instead of 9.
The output of the third syso where I am printing cs3.val I am getting a null pointer exception.
Can anybody help me understand what is happening here under the hood? How exactly java handles the memory location when we pass an object as a function parameter? Thanks for helping!!
cs2 and cs3 are local variable, assigning a new value to them have no effect outside of the methods where they are declared.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 5 years ago.
Here is my example: I want to know if it is possible to pass an argument initialized with null, and later initialize the object with a correct value.
private class Source {
String str;
String getStringValue() {
return str;
}
void setStringValue(String str) {
this.str = str;
}
}
private class UserSource {
Source src;
UserSource(Source src) {
this.src = src;
}
String getValue() {
return src.getStringValue();
}
void setValue(String str) {
src.setStringValue(str);
}
}
Now how I'm using.
Source srcW = new Source();
UserSource userSourceW = new UserSource(srcW);
srcW.setStringValue("Second Value");
System.out.println("From UserSource:" + userSourceW.getValue());
userSourceW.setValue("Is not Second");
System.out.println("From Source:" + srcW.getStringValue());
The output:
From UserSource:Second Value
From Source:Is not Second
But, want to know if is possible to use like:
Source srcN = null; // YES I want to assign Not initialized!
UserSource userSourceN = new UserSource(srcN);
srcN = new Source();
srcN.setStringValue("First Value");
System.out.println("From UserSource:" + userSourceN.getValue());
Of course the output is
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
Is there an alternative?
Unfortunately, it's not possible to do so. When the value is initially null, then you're passing the null reference. Later you initialize it with srcN = new Source();, but then you're rewriting the source.
You could work around it with a Reference<Source>. But that would only make the code more cumbersome. Moreover, the Source class is a perfect candidate to pass it as an empty source, and then initialize it later with setString().
Am I missing something? What's your problem with the code as is?
I am using Method.Invoke in java to dynamically call methods in another class. The only issue is that if the methods have paramaters i need to start that in the class.getDeclaredMethod("method", something.class) or else it wont see those methods. The issue with this that i don't know when calling the methods what the parameters will be. How do I get around this?
Also I have done this in C# and its easy and does not require me to state the parameters but this is in Java.
Here is the code that does the Invoke:
public void DoCommand(String msg){
System.out.println(msg);
String[] temp = msg.split(" ");
String command = temp[0];
Class c = commander.getClass();
try {
Object obj = c.newInstance();
try {
System.out.println("'" + command + "'");
Method method = c.getDeclaredMethod(command);
Object[] pars = new Object[temp.length];
for(int i = 0; i < pars.length; i++){
pars[i] = temp[i + 1];
}
if((String)pars[pars.length - 1] == null){
pars[pars.length - 1] = socket;
}
Parameter[] paramaters = method.getParameters();
Object[] endParameters = AltimitConverter.ConvertParameters(pars, paramaters);
try {
method.invoke(obj, endParameters);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {}
}catch (NoSuchMethodException e){
System.out.println(e.toString());
}
}catch (Exception e){
System.out.println(e.toString());
}
}
So how do I call different methods with different parameters without stating the parameters when getting the method.
This is the C# version that does work:
private static void DoCommand(string msg, Socket soc){
string[] temp = msg.Split (' ');
string command = temp [0];
Type type = commandObject.GetType ();
MethodBase commandFunction = type.GetMethod (command);
if (commandFunction != null) {
object[] pars = new object[temp.Length - 1];
for (int i = 0; i < pars.Length; i++) {
pars [i] = temp [i + 1];
}
if ((string)pars [pars.Length - 1] == "") {
pars [pars.Length - 1] = soc;
}
ParameterInfo[] paramaters = commandFunction.GetParameters ();
object[] endParamaters = AltimitConverter.ConvertParams (pars, paramaters);
if (commandFunction != null) {
try {
commandFunction.Invoke (commandObject, endParamaters);
} catch (Exception e) {
Debug.Log (e);
}
} else {
Debug.Log ("commandFunction is null");
}
}
}
Instances of java.lang.reflect.Method reflect specific methods. Each one is associated with a specific class, has a specific parameter list, and has a specific return type. When method overloading is in play, each of the overloaded methods will be reflected by a distinct Method object; these are not interchangeable.
If you need to account for selecting among overloaded methods, then you can do so only with reference to the number and types of the intended arguments. If you have to rely on the arguments themselves to determine matching parameter types, then you're looking at duplicating Java's method-resolution logic, which is complex.
In the event that you need only worry about looking up a non-overloaded method declared by the subject class itself (i.e. not inherited) then you can invoke getDeclaredMethods() on the Class object and scan the resulting array of Method objects for one with the correct name.
You can go a little way into overloaded methods while preserving your sanity if different overloads are distinguished by different numbers of parameters, or maybe if there are specific limits on the parameter type patterns you need to account for, but at that point you really should be asking yourself whether there's a better way. This kind of design absolutely begs for trouble.
I figured out a solution. I created a function to take the intended parameters which are strings and convert them to a data type depending on if it looks like a float, Integer, or string. then i send that into another method that gets all methods in a class and get the ones with the method name i am trying to call and then gets the one with the data types i had in the object[] returned from the first method. and then i use the method i got and the converted data types to call the method.
I am trying out Java Reflection API. I am just fetching the Method objects of any given class into a JComboBox, and on it's itemSelected, creating an interface for the parameters (and of course, a calling object.)
This works fine, no issued.
But on the invokeButton's action, I am trying to invke the selected method with given params.
Initially it said that the param count differed. I was guided by one of my friend saying that the paramVals array has references to actual values, which might be causing problem, may be due to scope. I then started creating new objects of class Object and then assigning them the values. This worked for param count. But now the problem is that the parameters are not type cast properly. Even a String typecast to Object (as it has to be an array of Objects) is not being cast back to String.
The doc says that the invoke method will cast them on it's own and if cast fails, will throw an IllegalArgumentException.
I am not getting what is causing the call of invoke method fails...
Here is the code for the frame:
package nttraining.abhay.reflectiondemo;
//imports go here
public class ReflectionFrame
extends JFrame
implements ActionListener, ItemListener{
JComboBox methods;
JButton invokeButton;
public ReflectionFrame(String title) throws HeadlessException {
super(title);
//Layout components
//adding methods of class String to a combo
Class<String> c = String.class;
Method ml[] = c.getMethods();
for(Method m : ml){
methods.addItem(m);
}
invokeButton.addActionListener(this);
methods.addItemListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(invokeButton)){
Method selected = (Method) methods.getSelectedItem();
Class paramtypes[] = selected.getParameterTypes();
Object paramVals[] = new Object[paramtypes.length];
System.out.println("Method : " + selected.toString());
for(int i=0; i<paramtypes.length; i++){
Object obj = new Object();
obj = paramtypes[i].cast(params[i].getText());
paramVals[i] = obj;
System.out.println("Added " + paramtypes[i].cast(params[i].getText()).toString() + " to params");
}
try {
result.setText(selected.invoke(object.getText(), params).toString());
} catch (Exception ex) {
System.out.println(ex.getClass().getName() + ": " + ex.getMessage());
}
}
}
#Override
public void itemStateChanged(ItemEvent e) {
Method selected = (Method) methods.getSelectedItem();
if(selected==null)
return;
Class paramtypes[] = selected.getParameterTypes();
int paramCount = paramtypes.length;
object = new JTextField();
paramNames = new JLabel[paramCount];
params = new JTextField[paramCount];
panel.removeAll();
panel.setLayout(new GridLayout(paramCount+1, 2));
panel.add(new JLabel("Calling object"));
panel.add(object);
for(int i=0; i<paramCount; i++){
paramNames[i] = (JLabel) panel.add(new JLabel(paramtypes[i].getName()));
params[i] = (JTextField) panel.add(new JTextField());
}
invalidate();
validate();
}
}
A problem I found is in this line:
obj = paramtypes[i].cast(params[i].getText());
cast does not convert objects, it only verfies that the given object is of a certain class. Since you always provide a String.class as parameter (via .getText()), this will fail for anything other then a String type parameter. Even Integer.class to primitive int will fail.
Below a piece of code that demonstrates the cast problem.
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class Q21642768 {
public static void main(String[] args) {
try {
// Calls String.indexOf(str, fromIndex) via reflection.
callStringMethod("Hello reflection world", "reflection", 1);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void callStringMethod(String s, String subString, int startIndex) throws Exception {
Class<String> c = String.class;
Method ma[] = c.getMethods();
Method indexOfSub = null;
Class<?>[] indexOfSubPTypes = null;
List<Method> stringMethods = new ArrayList<Method>();
List<Type[]> stringMethodsPTypes = new ArrayList<Type[]>();
for (Method m: ma) {
stringMethods.add(m);
System.out.print(m.getName() + ": ");
Class<?>[] mptypes = m.getParameterTypes();
stringMethodsPTypes.add(mptypes);
boolean first = true;
for (Type t : mptypes) {
if (first) {
first = false;
} else {
System.out.print(", ");
}
System.out.print(t.toString());
}
if ("indexOf".equals(m.getName())
&& mptypes.length == 2
&& mptypes[0].equals(String.class)
&& mptypes[1].equals(int.class)) {
indexOfSub = m;
indexOfSubPTypes = mptypes;
System.out.println(" <-- ");
} else {
System.out.println();
}
}
if (indexOfSub == null) {
System.out.println("target method not found");
return;
}
Object[] pValues = new Object[2];
pValues[0] = indexOfSubPTypes[0].cast(subString);
// Fails:
// pValues[1] = indexOfSubPTypes[1].cast(startIndex);
// pValues[1] = indexOfSubPTypes[1].cast(startIndex + "");
pValues[1] = startIndex;
Object result = indexOfSub.invoke(s, pValues);
System.out.println("Result: " + result);
}
}
The problem is that all your parameter values are String objects, since you get them with JTextField.getText(). String is the runtime type of these values, whereas the type of the method parameters will generally be different, and this is what matters.
To successfully invoke the method, you will first need to convert each value to the proper type specified in the paramTypes array. Neither cast() nor invoke() are going to do that for you. This means you must find a way to do the conversion from a String, basically deserializing from a String value into an object of the proper class, and that may not always be possible or too complex to do. At this point, I think you can start to imagine the complexity of what you are trying to do. This is very far from trivial. Remember that each parameter value will generally not be a simple value, but rather a full object graph, that's where the complexity is.
For example, if the type of a method parameter is an interface, how will you know which concrete implementation to instantiate? If you do find a concrete class implementing it - and that may not always be possible - how will you create instances of that class? Here you're entering a domain covered by serialization frameworks in Java. There are quite a few of these frameworks that are open source and you might want to take a look at some of them. You will find a comprenhesive list of such fraleworks here.
A few years ago, I worked on a related project, where I had to provide a Swing GUI to enable end-users to create objects of arbitrary types, used as input for a rule engine. What I came up with was a JTree with multiple roots, associated with a property sheet (i.e. a JTable with 2 columns), where the tree leaves were either simple types (primitives, primitive wrappers, Date, etc.) or object references. Each reference would point to a specific tree root representing the actual object to be later instantiated. I don't remember exactly how long it took, just that it took several months to get it tested and working.
So, I don't want to crush your hopes, but you should be aware that it's going to take a huge amount of work to do this.
This question already has answers here:
Searching in a ArrayList with custom objects for certain strings
(9 answers)
Closed 9 years ago.
I'm having an list of Object type. In that I have one String property idNum. Now I want to get the index of the object in the list by passing the idNum.
List<Object1> objList=new ArrayList<Object1>();
I don't know how to give objList.indexOf(// Don't know how to give here);
Is it possible to do this without iterating the list. I want to use indexOf() method only.
Write a small helper method.
private int getIndexByProperty(String yourString) {
for (int i = 0; i < objList.size(); i++) {
if (object1 !=null && object1.getIdNum().equals(yourString)) {
return i;
}
}
return -1;// not there is list
}
Do not forget to return -1 if not found.
Implement equals (and hashCode) in Object1 class based on idNum field, then you use List.indexOf like this
int i = objList.indexOf(new Object(idNum));
or make a special class for seaching
final String idNum = "1";
int i = list.indexOf(new Object() {
public boolean equals(Object obj) {
return ((X)obj).idNum.equals(idNum);
}
});
You cannot do this with indexOf. Instead all of the objects in the list should inherit from a common interface - for example
interface HasIdNum {
String getIdNum();
}
Now you list can be List<HasIdNum> and you can loop through it to find the object by id using:
for (HasIdNum hid: objList) {
if (hid.getIdNum().equals(idNumToFind) {
return hid;
}
}
return null;
To get the index rather than the object do:
for (int i=0;i<objList.size();i++) {
HasIdNum hid = objList.get(i);
if (hid.getIdNum().equals(idNumToFind) {
return i;
}
}
return -1;
Alternatively you can use reflection to query the methods of the object, but that will be much slower and much less safe as you lose all the compile time type checking.