Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have an odd problem in Java. I can solve it but the solution seems inefficient.
I have a class, which simplified is
class Zot
{
double edges[];
}
The problem is that in many cases I want instance A and instance B to share ONE of the edge instances. In other words, instance A may allocate edge[2] and want instance B to share edge[2]. This is easy enough in that I can just set instance B to point at instance's A edge[2]. But how can I do it efficiently? If I allocate the edges[] in instance A, I can then simply assign B's instance to point to A. But often I only want to allocate a single edge (e.g. edge[2]) in A and then assign it in B. But in Java, one cannot (as far as I know) allocate a single member of an array (as one can in C++). Ideally, I only want to allocate the useful member and assign it. I could, of course, allocate all 4 members, assign the ones I need, then set the unwanted members to null and let GC clean it all up, but if there are hundreds or thousands of instances that seems clumsy.
Suggestions?
You can declare and allocate double edges[] outside of both classes, then pass this array as a parameter in the constructor into both of the instances that want to share it.
In Java an array is also an object. When you make an instance like double edges[] = new double[2]; edges will be passed around as a pointer, not as a copy.
This means if you make a change in the array in your class A, then class B will also see this change.
As I understand the question, you appear to want to share an individual element from your edges array between classes, and not share the whole array itself.
If your edges array was an array of Objects then this would be possible, and could make sense. However, since your array is a primitive array then there is no real concept of sharing an individual element.
You can assign an element of your array to equal the element of another array, but subsequent changes to the element in one array will not be reflected in the other array.
You can share the entire array between classes, in which case any changes will be reflected in both arrays (well, there is only one array, so both classes will see the changes to the single array that they both reference).
Most importantly:
When you declare an array of primitives in java, the memory is allocated immediately so there is no benefit (or mechanism) to declare only a single element of the array. So with your current data model, there is no reason for you to not predeclare your arrays since you cannot save space with them.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 months ago.
Improve this question
I'm new to java and trying to understand where implementations of the Collection interface are storing the elements I add to it. I understand how to work with collections using the various methods, but what I don't understand is what is happening under the hood when I write for example:
Collection<Integer> intList= new ArrayList();
intList.add(3);
Is a new field created in the class for the element 3? If so how are these various fields linked to one another when I create the iterator?
Iterator<Integer> intIter = intList.iterator();
boolean test = intIter.hasNext();
Or how are the various elements attached to indices when working with a less general interface like a List?
First of all, Collection is just an interface, the implementation is ArrayList. So we just focus on the detail of ArrayList
ArrayList is implemented with an array internal. So add(3) means set the arr[index] = 3; The index is from zero.
View the source code, you will see the iterator(); is a wrapper for the array visitor. Some key variables is cursor, lastRet, expectedModCount.
Finally as a new beginner, view source code maybe resolve all your problems.
Collection<Integer> intList= new ArrayList();
This is syntax sugar. So lets desugar it, to understand what happens. Specifically, this code does 3 mostly unrelated things:
Declare a new typed variable, named intList.
Create a new ArrayList object. Objects do not have names.
Copy over the reference to this object into the intList variable.
In java, all variables (so also all parameters, and all fields) are either "primitive" or "reference". That's exhaustive: Those are the only 2 options. Primitives are all variables whose type is one of the primitive types. The primitive types are hardcoded into the java lang spec. They are int, long, double, float, short, byte, char, and boolean - and that's it. Those are the 8. Note that String is not amongst them.
For the primitives, a variable just stores the value. This is simple: all the primitives have the property that their size is fixed and small. At most they are 64 bits, and all CPUs built in the last decade pretty much operate on 64-bit units so that lines up nicely.
For the refs, not so much. A string, for example, can be incredibly large. So, instead, the variable does not contain the data. It instead contains a reference to the data - a pointer. Except we don't like to call it that because the term 'pointer' has baggage, but make no mistake: It's a pointer.
Here, intList is the variable that can only hold references (because its type is not primitive). new ArrayList() creates an entire object and the expression resolves to a reference, which is then assigned to the intList variable.
Think of it like a gigantic beach. new ArrayList() creates a new treasure chest out of thin air, and buries it in the sand. intList is not the treasure chest. No, it's a map to the treasure chest. The . operator is java-ese for: Follow the map and dig up the chest. intList.add(5) means: Take your treasure map called intList, and walk to the X. Now dig. Now open the treasure chest. Now yell add(5) at it. Which does.. whatever the docs say it does. Could be anything, that's the joy of programming.
If you then say intList = null, you're not destroying the treasure chest. Nope, you merely erase out your treasure map. The treasure chest is still buried in the sand. However, java has automatic garbage collection: Any treasure with the property that no maps exist anymore that could let you find it, are 'garbage' and will eventually be dug up and tossed out by the garbage collector. In C and some other languages, you can go on arbitrary digging sprees. Not so in java - you cannot dig, the language will not let you, unless you have a treasure map to lead the way.
That beach is 'the heap' and it is huge - by default gigabytes or so large, it grows as needed and the garbage collector tosses out the garbage whenever it is neccessary to make some room.
So how does ArrayList work, what is in that treasure chest? Simple: Every non-static field as defined in the class ArrayList along with every field in the class mentioned in the extends clause (ArrayList is defined as class ArrayList extends AbstractList, so every field AbstractList has too, and so on). Of course, fields are primitive or treasure maps too, so really those treasure chests aren't as large as you might imagine. They really just store numbers and maps, that's all.
So how does arraylist work internally? With arrays, hence the name. ArrayList makes an array of 10 and tracks how many slots are actually 'used' (initially, arraylists are empty, so 0 slots used). As you call .add, it just fills the array at the current 'used' slot and then increments 'used' by 1. Of course, once you try to add an 11th element that can't be done, so what arraylist's code does is make a new array (poof! a new treasure chest springs into existence, with 20 blank treasure maps inside, as well as a note with room to write down a single number), copies over the 10 existing maps, and then updates its one map that points at 'the treasure chest with all the maps in it' (it's a lot of maps that lead to treasure chests with maps that lead to more chests, and so on!). This means the old treasure chest (the old array) is still around, but garbage. (No map exists that could get you there). Eventually it'll get collected.
If you try to add the 21st element, again this copy thing happens. ArrayList's implementation multiplies by 1.5, I think, every time it needs to grow (so, from 10, to 15, to 23, to 35, etcetera).
I was reading about data locality and want to use it to improve my game engine that I'm writing.
Let's say that I have created five objects at different times that are now all in different places in the memory not next to each other. If I add them all to an array, will that array only hold pointers to those objects and they will stay in the same place in the memory or will adding them all to an array rearrange them and make them contiguous.
I ask this because I thought that using arrays would be a good way to make them contiguous, but I don't know if an array will fix my problem!
tl;dr
Manipulating an array of references to objects has no effect on the objects, and has no effect on the objects’ location in memory.
Objects
An array of objects is really an array of references (pointers) to objects. A pointer is an address to another location in memory.
We speak of the array as holding objects, but that is not technically accurate. Because Java does not expose pointers themselves to us as programmers, we are generally unaware of their presence. When we access an element in the array, we are actually retrieving a pointer, but Java immediately follows that pointer to locate the object elsewhere in memory.
This automatic look-up, following the pointer to the object, makes the array of pointers feel like an array of objects. The Java programmer thinks of her array as holding her objects when in reality the objects are a hop-skip-and-a-jump away.
Arrays in Java are implemented as contiguous blocks of memory. For an array of objects, the pointers to those objects are being stored in contiguous memory. But when we access the elements, we are jumping to another location in memory to access the actual object that we want.
Adding elements may be “cheap” in that if memory happens to be available next door in memory, it can be allocated to the array to make room for more elements. In practice this is unlikely. Chances are a new array must be built elsewhere in memory, with all the pointers being copied over to the new array and then discarding the original array.
Such a new-array-and-copy-over is “expensive”. When feasible, we want to avoid this operation. If you know the likely maximum size of your array, specify that size when declaring the array. The entire block of contiguous memory is claimed immediately, with empty content in the array until you later assign a pointer to the elements.
Inserting into the middle of an array is also expensive. Either a new array is built and elements copied over, or all the elements after the insertion point must be moved down into their neighboring position.
None of these operations to the array affect the objects. The objects are floating around in the ether of memory. The objects know nothing of the array. Operations on the array do not affect the objects nor their position in memory. The only relationship is that if the reference held in the array is the last reference still pointing to the object, then when that array element is cleared or deleted, the object becomes a candidate for garbage-collection.
Primitives
In Java, the eight primitive types (byte, short, int, long, float, double, boolean, and char) are not objects/classes and are not Object-Oriented Programming. One advantage is that they are fast and take little memory, compared to objects.
An array of primitives hold the values within the array itself. So these values are stored next to one another, contiguous in memory. No references/pointers. No jumping around in memory.
As for adding or inserting, the same behavior discussed above applies. Except that instead of pointers being shuffled around, the actual primitive values are being shuffled around.
Tips
In business apps, it is generally best to use objects.
That means using the wrapper classes instead of primitives. For example, Integer instead of int. The auto-boxing facility in Java makes this easier by automatically converting between primitive values and their object wrapper.
And preferring objects means using a Collection instead of arrays, usually a List, specifically a ArrayList. Or for immutable use, a List implementation returned from the new List.of method.
In contrast to business apps, in extreme situations where speed and memory usage are paramount, such as your game engine, then make the most of arrays and primitives.
In the future, the distinction between objects and primitives may blur if the work done in Project Valhalla comes to fruition.
The data or the values are stored in the objects and the values are retrieved using the references of the objects. lemme clear one more thing arrays in Java are stored in the form of objects. so there is no doubt that objects stores values and accessed using reference variable of that particular object. Hope you got it.
Java deals with references to objects only. As such, there's no guarantee that the elements of an array will be contiguous in memory.
Edit: Guess this answer wasn't that clear. My bad. I meant that there's no guarantee that the objects themselves will be contiguous, in spite of the fact that the references will be, as 1-D arrays are stored contiguously. Still, Basil Bourque's answer perfectly explains how this works.
I want to know why an array created in Java static even when we use the new keyword to define it.
From what I've read, the new keyword allocates a memory space in the heap whenever it is encountered during run time, so why give the size of the array at all during definition.
e.g. Why can't
int[] array1=new int[20];
simply be:
int[] array1=new int[];
I know that it does not grow automatically and we have ArrayList for that but then what is the use of keyword new in this? It could have been defined as int array1[20]; like we used to do it in C, C++ if it has to be static.
P.S. I know this is an amateurish question but I am an amateur, I tried to Google but couldn't find anything comprehensive.
This may be an amateurish question, but it is one of the best amateurish questions you could make.
In order for java to allow you to declare arrays without new, it would have to support an additional kind of data type, which would behave like a primitive in the sense that it would not require allocation, but it would be very much unlike a primitive in the sense that it would be of variable size. That would have immensely complicated the compiler and the JVM.
The approach taken by java is to provide the bare minimum and sufficient primitives in order to be able to get most things done efficiently, and let everything else be done using objects. That's why arrays are objects.
Also, you might be a bit confused about the meaning of "static" here. In C, "static" means "of file scope", that is, not visible by other object files. In C++ and in Java, "static" means "belongs to the class" rather than "belongs to instances of the class". So, the term "static" is not suitable for describing array allocation. "Fixed size" or "fixed, predefined size" would be more suitable terms.
Well, in Java everything is an object, including arrays (they have length and other data). Thats why you cannot use
int var[20];
In java that would be an int and the compiler would be confused. Instead by using this:
int[] var;
You are declaring that var is of type int[] (int array) so Java understands it.
Also in java the length of the array and other data are saved on the array, for this reason you don't have to declare size of array during declaration, instead when creating an array (using new) the data are saved.
Maybe there is a better reason that oracle may have answered already, but the fact that in Java everything is an object must have something to do with it. Java is quite specific about objects and types, unlike C where you have more freedom but everything is more loose (especially using pointers).
The main idea of the array data structure is that all its elements are located in the sequential row of memory cells. That is why you can not create array with variable size: it should be unbounbed space vector in memory for this purpose, which is impossible.
If you want change size of array, you should recreate it.
Since arrays are fixed-size they need to know how much memory to allocate at the time they are instantiated.
ArrayLists or other resizing data structures that internally use arrays to store data actually re-allocate larger arrays when their inner array data
structure fills up.
My understanding of OP's reasoning is:
new is used for allocating dynamic objects (which can grow like, ArrayList), but arrays are static (can't grow). So one of them is unnecessary: the new or the size of the array.
If that is the question, then the answer is simple:
Well, in Java new is necessary for every Object allocation, because in Java all objects are dynamically allocated.
Turns out that in Java, arrays are objects, different from C/C++ where they are not.
All of Java's variables are at most a single 64bit field. Either primitives like
integer (32bit)
long (64bit)
...
or references to Objects which depending on JVM / config / OS are 64 or 32 bit fields (but unlike 64bit primitives with atomicity guaranteed).
There is no such thing as C's int[20] "type". Neither is there C's static.
What int[] array = new int[20] boils down to is roughly
int* array = malloc(20 * sizeof(java_int))
Each time you see new in Java you can imagine a malloc and a call to the constructor method in case it's a real Object (not just an array). Each Object is more or less just a struct of a few primitives and more pointers.
The result is a giant network of relatively small structs pointing to other things. And the garbage collector's task is to free all the leaves that have fallen off the network.
And this is also the reason why you can say Java is copy by value: both primitives and pointers are always copied.
regarding static in Java: there is conceptually a struct per class that represents the static context of a class. That's the place where static instance variables are anchored. Non-static instance variables are anchored at with their own instance-struct
class Car {
static int[] forAllCars = new int[20];
Object perCar;
}
...
new Car();
translates very loosely (my C is terrible) to
struct Car-Static {
Object* forAllCars;
};
struct Car-Instance {
Object* perCar;
};
// .. class load time. Happens once and this is referenced from some root object so it can't get garbage collected
struct Car-Static *car_class = (struct Car-Static*) malloc(sizeof(Car-Static));
car_class->forAllCars = malloc(20 * 4);
// .. for every new Car();
struct Car-Instance *new_reference = (struct Car-Instance*) malloc(sizeof(Car-Instance));
new_reference.perCar = NULL; // all things get 0'd
new_reference->constructor();
// "new" essentially returns the "new_reference" then
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I was just wondering if there is a way to rename the variable assigned to an ArrayList... Or if I just need to create another one, just making it exactly the same.
Just create a new reference with the name you want and assign it from the old reference:
ArrayList original = ...;
ArrayList newList = original;
I should point out that since ArrayList is a reference type, original and newList are both pointing to the same data in memory. If you add an item to original or to newList, it is going to affect both. It is not creating a second copy of the ArrayList. It is a little difficult to understand what you are asking for, though.
If you are talking about refactoring your code to rename the variable across the entire application, then it sort of depends on what IDE you are using, but any good IDE will have this capability.
First, I would just like to point out that 'renaming' a variable is not really a concept that bares any resemblance to the way that changing a 'reference' or 'identifier' works. You can't change a variables identifier (kind of like a variable's name), but you can pass the variable's value to another variable with a different identifier.
When a variable refers to an Object or child of the Object class (such as ArrayList), your reference type variable holds data indicating the position of that object in memory. So passing that reference's data to another reference just means there are now two Object references that 'refer' to the same object in memory.
Technically speaking, if you wanted to give that object a name that you could use to identify it later with, this is possible by creating a custom class that extends ArrayList (or whatever object). For example;
public class NamedArrayList extends ArrayList{
private String listName = "default_name";
public String getListName(){
return listName;
}
public void setListName(String listName){
this.listName = listName;
}
}
Alternatively, you could create a Wrapper class which holds an ArrayList as well as a name for identifying it. Apologies if the last part is a little off subject, but I hope it helps.
You can try this
List<Double> original =new ArrayList<Double>();
List<Double> copy = new ArrayList<Double>(original);
You can't rename any variable while the programm is running.
But you could rename it while developing. Then compile and run.
If you mean by renaming using a different reference than you can simply do
ArrayList newListRef = oldListInstance;
//use newListRef thereafter
If you mean to change some of the elements retaining the order then -
ArrayList is dynamic in size. You can add and remove elements to and from specific index and ordering in retained. So no need to create separate List. If you want to change a specific element simply remove it and add new element at that index.
APIs
public E remove(int index)
public void add(int index, E element)
In Java, we can always use an array to store object reference. Then we have an ArrayList or HashTable which is automatically expandable to store objects. But does anyone know a native way to have an auto-expandable array of object references?
Edit: What I mean is I want to know if the Java API has some class with the ability to store references to objects (but not storing the actual object like XXXList or HashTable do) AND the ability of auto-expansion.
Java arrays are, by their definition, fixed size. If you need auto-growth, you use XXXList classes.
EDIT - question has been clarified a bit
When I was first starting to learn Java (coming from a C and C++ background), this was probably one of the first things that tripped me up. Hopefully I can shed some light.
Unlike C++, Object arrays in Java do not store objects. They store object references.
In C++, if you declared something similar to:
String myStrings[10];
You would get 10 String objects. At this point, it would be perfectly legal to do something like println(myStrings[5].length); - you'd get '0' - the default constructor for String creates an empty string with length 0.
In Java, when you construct a new array, you get an empty container that can hold 10 String references. So the call:
String[] myStrings = new String[10];
println(myStringsp[5].length);
would throw a null pointer exception, because you haven't actually placed a String reference into the array yet.
If you are coming from a C++ background, think of new String[10] as being equivalent to new (String *)[10] from C++.
So, with that in mind, it should be fairly clear why ArrayList is the solution for an auto expanding array of objects (and in fact, ArrayList is implemented using simple arrays, with a growth algorithm built in that allocates new expanded arrays as needed and copies the content from the old to the new).
In practice, there are actually relatively few situations where we use arrays. If you are writing a container (something akin to ArrayList, or a BTree), then they are useful, or if you are doing a lot of low level byte manipulation - but at the level that most development occurs, using one of the Collections classes is by far the preferred technique.
All the classes implementing Collection are expandable and store only references: you don't store objects, you create them in some data space and only manipulate references to them, until they go out of scope without reference on them.
You can put a reference to an object in two or more Collections. That's how you can have sorted hash tables and such...
What do you mean by "native" way? If you want an expandable list f objects then you can use the ArrayList. With List collections you have the get(index) method that allows you to access objects in the list by index which gives you similar functionality to an array. Internally the ArrayList is implemented with an array and the ArrayList handles expanding it automatically for you.
Straight from the Array Java Tutorials on the sun webpage:
-> An array is a container object that holds a fixed number of values of a single type.
Because the size of the array is declared when it is created, there is actually no way to expand it afterwards. The whole purpose of declaring an array of a certain size is to only allocate as much memory as will likely be used when the program is executed. What you could do is declare a second array that is a function based on the size of the original, copy all of the original elements into it, and then add the necessary new elements (although this isn't very 'automatic' :) ). Otherwise, as you and a few others have mentioned, the List Collections is the most efficient way to go.
In Java, all object variables are references. So
Foo myFoo = new Foo();
Foo anotherFoo = myFoo;
means that both variables are referring to the same object, not to two separate copies. Likewise, when you put an object in a Collection, you are only storing a reference to the object. Therefore using ArrayList or similar is the correct way to have an automatically expanding piece of storage.
There's no first-class language construct that does that that I'm aware of, if that's what you're looking for.
It's not very efficient, but if you're just appending to an array, you can use Apache Commons ArrayUtils.add(). It returns a copy of the original array with the additional element in it.
if you can write your code in javascript, yes, you can do that. javascript arrays are sparse arrays. it will expand whichever way you want.
you can write
a[0] = 4;
a[1000] = 434;
a[888] = "a string";