This question already has answers here:
How to add new elements to an array?
(19 answers)
Closed 8 years ago.
I need to port code from blackberry to android and facing small problem:
Example: the bb code is:
public class MyClass{
private MyObject[] _myObject;
public void addElement(MyObject o){
if (_myObject == null){
_myObject = new MyObject[0];
}
Arrays.add(_myObject, o);
}
}
unfortunately android does not have Arrays.add() which is part of net.rim.device.api.util.Arrays (static void add(Object[] array, Object object))
Is there any replacement for android to dynamically extend and append in to simple array so I don't change the rest of my code.
I tried to write my own utility but it does not work:
public class Arrays {
public static void add(Object[] array, Object object){
ArrayList<Object> lst = new ArrayList<Object>();
for (Object o : array){
lst.add(o);
}
lst.add(object);
array = lst.toArray();
}
}
.. after I call
public void addElement(MyObject o){
if (_myObject == null){
_myObject = new MyObject[0];
}
Arrays.add(_myObject, o);
}
the _myObject still contain 0 elements.
Yes, because the _myObject reference is passed by value. You'd need to use:
public static Object[] add(Object[] array, Object object){
ArrayList<Object> lst = new ArrayList<Object>();
for (Object o : array){
lst.add(o);
}
lst.add(object);
return lst.toArray();
}
...
_myObject = Arrays.add(_myObject, o);
However, it would be better to just use an ArrayList<E> to start with...
There are two important things to understand here:
Java always uses pass-by-value
The value which is passed is either a reference (a way of getting to an object, or null) or a primitive value. That means if you change the value of the parameter, that doesn't get seen by the caller. If you change the value of something within the object the parameter value refers to, that's a different matter:
void doSomething(Person person) {
person.setName("New name"); // This will be visible to the caller
person = new Person(); // This won't
}
Arrays are fixed-size in Java
You can't "add" a value to an array. Once you've created it, the size is fixed. If you want a variable-size collection (which is a very common requirement) you should use an implementation of List<E> such as ArrayList<E>.
commons-lang has ArrayUtils.add(..)
guava has ObjectArrays.concat(..).
Here's the code of ObjectArrays.concat(object, array):
public static <T> T[] concat(#Nullable T element, T[] array) {
T[] result = newArray(array, array.length + 1);
result[0] = element;
System.arraycopy(array, 0, result, 1, array.length);
return result;
}
The apache-commons code is a bit longer.
Related
I've got a generic array class and I want to return an array in the main so I can use the sort method that I have ready in the main. I understand that the constructor has an array in it so I'm wondering if I can use that. Or do I need to set up a new method to return this.array ? Also it returns a generic array, how do I choose the type in main?
public class dynamicArray <T>{
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
Here I chose the integer type for the class. I'm not sure how can I extract the
array from the constructor.
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int [] arr = array.populate();
mergeSort(arr);
System.out.println(array.toString());
}
Unfortunately, arrays and generics don't work well together. Take a look at the source code of java's ArrayList - it is implemented with an Object[] and not a T[] - then every method will cast to T (which costs literally zero, it's just ugly and causes compiler warnings). I advise you do the same here: Arrays actually KNOW their component type (unlike a list of Ts, which does not, there is no method on a java.util.List that you can invoke to get the component type), and therefore casting Object[] to T[] is just wrong; java allows this solely for backwards compatibility reasons.
Basically, you can't work with T[] without things being subtly wrong and a lot of compiler errors.
In this specific case? I would strenuously advise you to use a private List<T> array; field instead of a T[] field.
Your call to array.populate() (that seems like a bizarre name for this method!) IS retrieving the array you created in the constructor. You are doing what you're asking for: "Extracting the array from the constructor" - invoking populate() on the object returned by the new dynamicArray<Integer>() is doing exactly that.
NB: You have a typo in your source code. it's new dynamicArray<Integer>();, not new<Integer>dynamicArray();. Perhaps that's causing some issues?
NB2: Java conventions dictate it's DynamicArray, and something like getBackingArray (instead of populate).
I think you ask two question :
How to set Integer type of that array object.
How to get Integer[] to int[]
Here is the code :
private int index;
private T[] array;
public dynamicArray() {
array = (T[])new Object[10];
this.index = 0;
}
public T [] populate() {
return this.array;
}
public void add(T x) {
array[++index] = x;
}
public static void main(String[] args) {
dynamicArray<Integer>array = new<Integer>dynamicArray();
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
int[] arr = Arrays.stream(array.populate())
.mapToInt(i -> i)
.toArray();
System.out.println(array.toString());
}
Answer for 1st question is you can not set Integer type because there wasn't any add method in your class. Answer for 2nd question is you try to convert Integer[] to int[] but there is no direct way to cast this. you just need to change Integer -> Object then Object -> int. This can be done easily using streams which is in Java 8 and i have used lambda here for showing power of lambda function.
Here is a possible alternative. Pass the type of array to the constructor. But essentially you are creating a limited form of ArrayList so you may just as well use that. Note that this still has the limitation that you can't use primitive arrays as the array type.
dynamicArray<Integer> array = new dynamicArray<>(new Integer[0]);
array.add(10);
array.add(5);
array.add(6);
array.add(11);
array.add(13);
array.add(20);
Integer[] a = array.getArray();
System.out.println(Arrays.toString(a));
}
class dynamicArray<T> {
private int size = 0;
private T[] array;
public dynamicArray(T[] a) {
array = a;
}
public void add(T value) {
if (array.length == size) {
array = Arrays.copyOf(array, size == 0 ? 10 : size*2);
}
array[size++] = value;
}
#SuppressWarnings("unchecked")
public T[] getArray() {
// need to copy the array since the length and size could be different.
T[] arrayCopy = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
System.arraycopy(array, 0, arrayCopy, 0, size);
return arrayCopy;
}
}
This question already has answers here:
why does List<String>.toArray() return Object[] and not String[]? how to work around this?
(5 answers)
Closed 3 years ago.
I want to create a static array from a dynamic array of whatever generic type the dynamic array was. I saw List#toArray() which returns Object[] and it doesn't use generics. Is it just safe to cast it to T[] or does the entire array have to be instantiated from the type of class using it?
I went on to try and create my own method in case java didn't provide one but, I got stuck with a compile errors
public static <T> T[] toArray(List<T> list)
{
T[] li = (T[]) Array.newInstance(T.class, list.size());
int index = 0;
for(T obj : list)
{
li[index++] = obj;
}
return li;
}
First of all, you don't need that method. You can use:
List<String> list = new ArrayList<>();
list.add("ff");
list.add("bb");
String[] array = list.toArray (new String[list.size ()]);
In order for your method to work, you have to pass the Class of the generic type parameter:
public static <T> T[] toArray(List<T> list, Class<T> clazz)
{
T[] li = (T[]) Array.newInstance(clazz, list.size());
int index = 0;
for(T obj : list)
{
li[index++] = obj;
}
return li;
}
Then you can call the method with:
String[] array = toArray(list, String.class);
The method proposed by Eran doesn't work if you have a generic element type, because you can't get a Class<List<T>>, say.
Instead, pass an IntFunction<T[]>:
public static <T> T[] toArray(List<? extends T> list, IntFunction<T[]> arraySupplier)
{
T[] li = arraySupplier.get(list.size());
int index = 0;
for(T obj : list)
{
li[index++] = obj;
}
return li;
}
Or, easier, use streams:
return list.stream().toArray(arraySupplier);
Then call like:
String[] array = toArray(list, String[]::new);
List<List<String>> listOfLists = ...
List<?>[] arrayOfLists = toArray(listOfLists, List<?>::new);
Notice that whilst this does support generic array elements, you can only create arrays with a reified element type, so your array type has to be List<?>[]; it still can't be List<String>[].
If your business requirement/Use Case requires an array to be no longer dynamic then you should first create a static array of size equal to your size of dynamic array.
ArrayList<Integer> al = [............] // assuming that ArrayList named al is having some data
int[] arr = new int[al.size()];
// from here you can use a for loop and initialize your static array
for(int i=0; i<arr.length;i++) {
arr[i] = (int) al.get(i); // Unboxing will also be done but still you can type cast to be on safe side
}
// Now you can de-reference the ArrayList object and call garbage collection which will wipe it out of the Heap Memory of your JVM.
al = null; // de-referencing the object by making the reference variable null
System.gc(); // GC happens periodically but to boost performance you can explicitly call it right away.
You can create a method accepting the list of objects and can handle all sorts of arrays using instanceof operator.
I have a piece of code:
public class Check {
private ArrayList<Integer> diameters; // Array of diameters
public Check(int num) {
diameters = new ArrayList<>(num); // Create an ArrayList object.
for(int i = 0; i < num; i++) { // Initialize the ArrayList.
diameters.add(i, i + 1);
}
}
public ArrayList<Integer> getDiameters() {
return new ArrayList<Integer>(diameters);
}
}
Does the getDiameters() method return the memory address of diameters ArrayList (if so, do I need to copy each value individually like I did in the constructor) or does it return a copy of all the integers in the diameters ArrayList?
Does the return value of getDiameters() method and the variable diameters point to the same memory location?
Would the below return statement in the getDiameters() method be a valid statement without any compromise to security instead of writing "return new ArrayList<Integer>(diameters);"?
return diameters;
What are the security issues faced, if any, if I write the above statement?
For objects, Java passes the reference to the object, so the method will not return a deep copy of the list.
As for security issues, this means that if a user manipulates the object returned by return diameters, these changes will also affect the object referenced by the Check object since they are the same object, which might be an issue.
public ArrayList<Integer> getDiameters()
{
return new ArrayList<Integer>(diameters);
}
Creates a new ArrayList of Integer, let's quote this from the docs:
public ArrayList(Collection c)
Constructs a list containing the elements of the specified collection,
in the order they are returned by the collection's iterator.
Parameters:
c - the collection whose elements are to be placed into this list Throws:
NullPointerException - if the specified collection is null
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#ArrayList-java.util.Collection-
Now, you have passed a Collection to the constructor, which, on its turn yields an ArrayList, which is similar, but not the same to your data member. It's not recommended to do this if you do not have a very good reason to do so, because diameters already contains the elements you have.
As about security, the only concern of security that I see is that the code using the diameters would have write operation privileges on the actual ArrayList. If you intend to prevent that, then don't return the actual ArrayList. You can clone it or create another ArrayList (as you did), or you can (and this is the most elegant solution in my opinion) call unmodifiableList in order to return a readonly version of your Collection.
If you do return diameters; your whole diameters ArrayList would be mutable, as you provide a link to it directly. That means you can affect it size and content from outside.
When you do new ArrayList<Integer>(diameters) - you're providing a copy of ArrayList with the copied values (which are copied by a reference, so basically are the same objects as in original collection).
For primitive wrapper like Integer - it's safe, but if you were passing mutable Object within the collection - its change would change the original ArrayList content.
Simple example:
public class Arrayz {
public static void main(String[] args) {
List<Integer> array1 = new ArrayList<>();
array1.add(new Integer(1));
array1.add(new Integer(2));
List<Integer> array2 = new ArrayList<>(array1);
// you can't mutate Integer - it's immutable
Integer first = array2.get(0);
System.out.println(array1);
System.out.println(array2);
List<Nom> array3 = new ArrayList<>();
array3.add(new Nom(1));
array3.add(new Nom(2));
List<Nom> array4 = new ArrayList<>(array3);
Nom third = array4.get(0);
// Nom is muttable - this will affect initial data as the Object itself mutated
third.a = 88;
// this will not - you replaced the Object in copied array only
array4.set(1, new Nom(33));
System.out.println(array3);
System.out.println(array4);
}
}
public class Nom {
public int a;
Nom(int a) {
this.a = a;
}
#Override
public String toString() {
return "" +a;
}
}
//////////// output:
[1, 2] // array1
[1, 2] // array2
[88, 2] // array3
[88, 33] // array4
Generally to protect everything you need to pass an immutable collection with immutable objects.
First can be achieved by using com.google.common.collect.ImmutableList.of for example.
The getDiameters() will return the address memory of the new created ArrayList. They don't point to the same address memory. it will copy the diameters elements to the new ArrayList. If you have many threads use the Arraylist, for security you can use:
Collections.synchronizedList(list);
I have this:
private ArrayList<ArrayList<Object>> models;
and in the constructor I have:
models = new ArrayList<ArrayList<Object>>();
Later, I do things like:
models.add(new ArrayList<Object>());
as well as other operations.
I want to make the external ArrayList to something with a fixed size (Array, List) and I am really lost to how I am going to write the declaration, initialization, addition, etc. because of the nested objects. Can someone save me time by answering this for me?
You can use Arrays.asList() to created fixed sized Lists.
Examples:
A List of size 3, initialized with null values:
List<ArrayList<Object>> models = Arrays.asList (null,null,null);
A List of size 3, initialized with non-null values:
List<ArrayList<Object>> models = Arrays.asList (new ArrayList<Object> (),new ArrayList<Object> (),new ArrayList<Object> ());
A List of size 10, initialized with null values:
List<ArrayList<Object>> models = Arrays.asList ((ArrayList<Object>[])new ArrayList[10]);
Note that add operation is not supported for fixed sized lists. You'll have to use models.set(index,new ArrayList<Object>()) instead.
EDIT:
Here's another way to initialize the List using Streams:
List<ArrayList<Object>> models = Arrays.asList (Stream.generate (ArrayList::new).limit (10).toArray (ArrayList[]::new));
A slightly more verbose - but generic-compatible way - of doing it is to extend AbstractList.
The methods you need to override are described in the Javadoc:
To implement an unmodifiable list, the programmer needs only to extend this class and provide implementations for the get(int) and size()methods.
To implement a modifiable list, the programmer must additionally override the set(int, E) method (which otherwise throws an UnsupportedOperationException).
So, implement these three methods, delegating to an ArrayList:
class FixedSizedList<T> extends AbstractList<T> {
private final List<T> delegate;
FixedSizedList(int size) {
delegate = new ArrayList<>(Collections.nCopies(size, null));
}
public T get(int i) { return delegate.get(i); }
public int size() { return delegate.size(); }
public T set(int i, T e) { return delegate.set(i, e); }
}
Or, for that matter, just use an array:
class FixedSizedList<T> extends AbstractList<T> {
private final Object[] array;
FixedSizedList(int size) {
array = new Object[size];
}
public T get(int i) { return (T) array[i]; }
public int size() { return array.length; }
public T set(int i, T e) {
T old = (T) array[i];
array[i] = e;
return old;
}
}
There isn't an Array class in java, but there is the plain old array declaration:
ArrayList<Object> [] array...
Problem is that you will not be able to instantiate it like this, since arrays can not be generic.
You are really looking for either Arrays.asList or much better ImmutableList of some kind.
When I try and return my int[] it says it's an object and I cannot return it to int[].
public class CostMatrix {
LinkedList matrix = new LinkedList<int[]>();
CostMatrix() {
}
void addToMatrix(int[] toAdd) {
matrix.add(toAdd);
}
int[] returnCost(int pos){
return matrix.get(pos)
}
}
You're missing a type parameter on the declaration.
LinkedList matrix -> LinkedList<int[]> matrix
To understand why you get this error, search for "raw types" in http://download.oracle.com/javase/1.5.0/docs/guide/language/generics.html
Basically, your code creates a correctly parameterized list but assigns it to a property with a raw type.
Then when you get from it, the compiler only knows that the property is a LinkedList and assumes that its content can be any type of Object.