Basically, when I passed arguments in Java, I knew it was passing only value.
However, the following code shows that the add method executed on SubClass's SubMethod affects ArrayList of MainClass.
MainClass.java
public class MainClass{
public satatic void main(String[] args){
List list = new ArrayList<>();
SubClass subClass = new SubClass(list);
subClass.subMethod();
System.out.println(list) // Why added value???
}
}
SubClass.java
public class SubClass{
private List list;
public SubClass(List list){
this.list = list;
}
public void subMethod(){
list.add(1);
list.add(2);
}
}
When I did the same thing with a HashMap's put, there was no effect on the HashMap of the MainClass.
I would like to know why only ArrayList is causing these results and what is happening inside Java.
Update
The code for the hashmap version is as follows:
MainClass.java
public class MainClass{
public satatic void main(String[] args){
Map map = new HashMap<>();
SubClass subClass = new SubClass(map );
subClass.subMethod();
System.out.println(map) // Not putting value
}
}
SubClass.java
public class SubClass{
private Map map;
public SubClass(Map map){
this.map= map;
}
public void subMethod(){
map = someGenerationHashMap(arg1, arg2);
}
}
It's not about ArrayList. Any object you pass as an argument can be modified. What is passed by value is the address of the object, not the object itself.
In the Map version, you are not making any operation that could modify it. In the list version instead, you are making an add.
Make sure not to confuse objects with primitives. For example, make sure not to confuse int with Integer.
Related
I am trying to up create and update an ArrayList by passing an argument, so that I will end up with a list of say 10 names; however, the current function doesn't seem to be working - any ideas pls?
public String addClient(String name) {
ArrayList<String> myList = new ArrayList<String>();
myList.add(name);
return myList;
}
You are creating a new ArrayList every time you call it. This means that every time you call this method you create a brand new Collection and only store the one client in it. You need to keep a reference of a single collection around and keep adding to that. You can do that by passing in the array you want to add it to:
public List<String> addClient(String name, List<String> array) {
array.add(name);
return array;
}
This doesn't seem like a useful function, so I'm guessing this is within a class. So this might be the approach you want:
/**
* Class is not Thread Safe
*/
public class ClientList {
private final ArrayList<string> clients;
public ClientList() {
this.clients = new ArrayList<>();
}
public void addClient(String client) {
this.clients.add(client);
}
public List<String> getClients() {
// Note: Never give a reference to the internal objects of the class
// as that means someone outside this class can own a reference to it
// and can update the object without you knowing (by not going
// through this class)
Collections.unmodifiableList(this.clients);
}
}
This is what you need to do:
ArrayList<String> myList = new ArrayList<String>();
public void addClient(String name) {
myList.add(name);
}
If you create a list inside the method, it will only have one value, and will go away once method execution finishes (unless it's returned). Have a look at different scopes here. You should create a list at a class level and add the elements into it.
Also, method does not need to return anything, so it's better to change the type to void.
The problem with your approach is that everytime you call the method addClient a new ArrayList will be created.
I think this will work for you :
static ArrayList<String> myList;
public static void main(String[] args) {
myList = new ArrayList<>();
}
public void addClient(String name){
myList.add(name);
}
It is necessary to change a container type:
import java.util.*;
public class MyContainers {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("title1");
list.add("title2");
System.out.println(list.indexOf("title1"));
// change container type
Set<String> set = new HashSet<String>(list);
}
}
But it will be better to use only one variable. I wrote such code but there was a restriction (see comment):
import java.util.*;
public class MyContainers {
public static void main(String[] args) {
Collection<String> list = new ArrayList<String>();
list.add("title1");
list.add("title1");
System.out.println(list);
// Can't call indexOf because there are no such method in inteface Collection
//System.out.println(list.indexOf("title1"));
// change container type
list = new HashSet<String>(list);
System.out.println(list);
}
}
Please, help me with such questions:
Is it possible to use one variable for different containers and use full set of containers methods?
Is it possible to convert List to Map?
Please, show a code examples.
If some method doesn't exist in one interface, it doesn't exist for a reason. Don't try to have a workaround in order to have it, that'll usually lead to troubles. For example, it doesn't make any sense to have indexOf method for the Set interface.
However, it can be useful sometimes to construct a new object of different type from an existing one, for example, if you have an ArrayList and you don't want to have duplicates, it does make sense to convert it to HashSet.
You should pick the best interface that suits your needs, if you don't find any, you can always implement your own class.
I found the solution, is it good?
import java.util.*;
public class MyContainers {
static Collection<String> collection = new ArrayList<String>();
public static void main(String[] args) {
collection.add("title1");
collection.add("title1");
System.out.println(collection); // [title1, title1]
useIndexOf();
System.out.println(collection); // [title1, title1]
deleteDublication();
System.out.println(collection); // [title1]
}
public static void useIndexOf()
{
List<String> list = new ArrayList<String>(collection);
System.out.println(list.indexOf("title1")); // 0
// Change container type back to universal
collection = list;
}
public static void deleteDublication() {
Set<String> set = new HashSet<String>(collection);
collection = set;
}
}
I have an Object named Person(name, surname, age)
This Object is populated with values from a local file.
But i want to keep this object visible through the app since there is a GUI for adding new values to this.
I was trying to put an Interface like this but doesn't work
public interface MyInterface{
public List<Person> myPersonObj = new ArrayList<Person>();
}
and to call it in app like MyInterface.myPersonObj
Can someone help me?
Thanks
You have to declare the variable static, e.g.
public static (final) List<Person> persons = new ArrayList();
For more information, read about the Singelton Pattern
Because it's in an interface it will automatically be final (read-only), thus you probably want to put it in a class instead:
public class AnyClass{
public static List<Person> myPersonObj = new ArrayList<Person>();
}
Then you can do:
AnyClass.myPersonObj
to access it.
make the list static inside the class where you populate it.
class Populate{
public static List<Person> myPersonObj;
public static void setMyPersonObj(List<Person> inst){
myPersonObj =inst;
}
public static List<Person> getMyPersonObj(){
if(MyPersonObj!=null){
return myPersonObj;
}
else {
return new ArrayList<Person>();
}
}
//populate it
}
class SomeOther {
public static void someMethod(){
Populate.getMyPersonObj();
}
}
I've just been experimenting and found that when I run the rolling code, it does not compile and I can't figure out why.
My IDE says 'Cannot make a static reference to the non-static field list', but I don't really understand what or why this is. Also what else does it apply to, i.e.: is it just private variables and or methods too and why?:
public class MyList {
private List list;
public static void main (String[] args) {
list = new LinkedList();
list.add("One");
list.add("Two");
System.out.println(list);
}
}
However, when I change it to the following, it DOES work:
public class MyList {
private List list;
public static void main (String[] args) {
new MyList().exct();
}
public void exct() {
list = new LinkedList();
list.add("One");
list.add("Two");
System.out.println(list);
}
}
static fields are fields that are shared across all instances of the class.
non-static/member fields are specific to an instance of the class.
Example:
public class Car {
static final int tireMax = 4;
int tires;
}
Here it makes sense that any given car can have any number of tires, but the maximum number is the same across all cars.
If we made the tireMax variable changeable, modifying the value would mean that all cars can now have more (or less) tires.
The reason your second example works is that you're retrieving the list of a new MyList instance. In the first case, you are in the static context and not in the context of a specific instance, so the variable list is not accessible.
In the first example you are calling non-static field from static content, which is not possible.
In the second one you are calling ext function on MyList object, which has access to that field.
So lets say that in my entry point class (i.e the class which runs when the program starts (which has the public static void main(String args[]) function). In that class I have this variable:
private ArrayList<String> myData=new ArrayList<String>();
This class instantiates another class, which needs to have access to the myData member of the entry point class. How can it retrieve this arraylist?
Edit: To clarify, in the main() method I could do this:
SomeOtherClass myClass=new SomeOtherClass();
and then I could do:
myClass.someMethod();
however, in the myClass object, how could I perform a method/retrieve something from the entry class, which instantiated the myClass object?
It sounds like your entry point is still static when it calls some other class, but your ArrayList is a member of an instance of it. You need to move out of the static world and into instances.
I'd refactor your main method into a private construtor, and put in a new main() which launches it as a new instance.
Note that this code is very rough, but it should serve to illustrate what you need to do.
public class EntryPoint {
private ArrayList<String> myData=new ArrayList<String>();
public static void main( String[] args ) {
EntryPoint ep = new EntryPoint();
ep.init();
}
private void init() {
// Populate myData perhaps?
SomeOtherClass myClass=new SomeOtherClass();
myClass.someMethod( this );
}
public List<String> getMyData() {
return myData;
}
}
public class SomeOtherClass {
public void someMethod( EntryPoint entry ) {
List<String> data = entry.getMyData();
// do stuff with data..!
}
}
The best way to give the class you instantiate access to myData would be to pass it into the constructor when it is created.
Then, in your constructor, you can save the ArrayList into a member variable of the class.
For example, your object constructor will look like:
private ArrayList<String> myData;
public YourObjConstructor(ArrayList<String> data){
myData = data;
}
The class containing main() is just an ordinary class. In your case, you'd have to make myData public and possibly static (or, of course, add an accessor). Just like you'd do with any other class.
You could also pass an Entry object to the other class, like this:
public static void main(String[] args) {
Entry entry = new Entry();
SomeOtherClass myClass=new SomeOtherClass(entry);
// continue as before
}