Generics, Casting, and ArrayList (oh my) - java

I've just started working with Java for a Data Strutures and Algorithms class (my background is mainly C++) and I've run into something quite clunky in my first assignment.
We were to create a "set" data structure - a bag that does not accept duplicates. From what I can tell, this is essentially just an ArrayList with some extra checks made during the add().
It all works, but I was forced to do something quite clunky when returning the set as an array:
class Set<T> implements SetInterface<T> {
// Properties
private ArrayList<T> _set = new ArrayList<T>();
// Methods
public Object[] toArray() {
return this._set.toArray();
}
}
public static void main(String[] args) {
SetInterface<Integer> mySet = new Set<Integer>();
// set is filled, other tests are performed...
Object[] myArray = mySet.toArray().clone();
for (int i = 0; i < myArray.length; i++)
System.out.print((int)myArray[i] + " ");
}
I originally tried to return an array of type T[] but that threw ClassCastException:
public T[] toArray() {
#SuppressWarnings("unchecked")
T[] temp = (T[])new Object[this._set.size()];
temp = this._set.toArray(temp);
return temp;
}
public static void main(String[] args) {
SetInterface<Integer> mySet = new Set<Integer>();
// set is filled, other tests are performed...
Integer[] myArray = mySet.toArray().clone();
for (int i = 0; i < myArray.length; i++)
System.out.print(myArray[i] + " ");
}
Now, my solution up top works, but it just... feels wrong. Is there a more elegant way to accomplish this? That is, is there a way to avoid having to cast each element in the array after the fact?
Hope this is clear.

Related

[Ljava.lang.Object; cannot be cast to [Ljava.lang.String; when I use generic

When I run code below:
public class GenericTest<T> {
private T[] arr = (T[]) new Object[5];//泛型不能直接创建,但是可以这样转型
public static void func(GenericTest<String> gt){
for(int i = 0; i < gt.arr.length; i++){
if(gt.arr[i] == null)
System.out.print(i);
}
}
public static void main(String[] args){
GenericTest<String> gt = new GenericTest<>();
//gt.func();
func(gt);
}
}
I got a error:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.String; [duplicate]
But when I run code like this (though they like very similar):
public class GenericTest<T> {
private T[] arr = (T[]) new Object[5];//泛型不能直接创建,但是可以这样转型
public void func(){
for(int i = 0; i < arr.length; i++){
if(arr[i] == null)
System.out.print(i);
}
}
public static void main(String[] args){
GenericTest<String> gt = new GenericTest<>();
gt.func();
//func(gt);
}
}
I can get what I want to see:
01234
Process finished with exit code 0
Well, they may look similar, but they are not.
The thing is that with func(), the compiler knows nothing about the actual generic type of GenericTest, except that is is eventually an Object. Retrieving arr.length will just work fine.
But then look at void func(GenericTest<String> gt). The argument mandates that a GenericTest<String> is passed in. So the compiler inserts a type cast for arr to a String[]:
((String[]) gt.arr).length
And guess what – gt.arr is actually an Object[], which can, of course, not be converted to a String[].

Initializing 2D ArrayList for for-loop summation (Java)

I am trying to sum N pairs of ints--an Nx2 ArrayList--and return the N summations as an ArrayList. While I understand it is not necessary to set up a class to accomplish this, I would like to do so as practice for future projects.
import java.util.ArrayList;
public class SumsInLoop {
public SumsInLoop(int numberOfPairs, ArrayList<ArrayList<Integer>> numbersList) {}
public ArrayList<Integer> getSums(int numberOfPairs, ArrayList<ArrayList<Integer>> numbersList) {
ArrayList<Integer> pairsOfSums = new ArrayList<Integer>();
for (ArrayList<Integer> Pair : numbersList) {
int x = Pair.get(0);
int y = Pair.get(1);
int sum = x + y;
pairsOfSums.add(sum);
}
System.out.println(pairsOfSums);
return pairsOfSums;
}
The data that I am given is a random assortment of N pairs (numbersOfPairs) of integers, e.g. 612673 108695. I would like to add these pairs of integers to a 2D ArrayList (numbersList) that will be called by getSums.
However, I am having difficulties initializing numbersList. My main function is as follows:
public static void main(String[] args) {
int myNumberOfPairs = 13;
ArrayList[][] myNumbersList = new ArrayList[13][2];
myNumbersList[0][0] = new ArrayList<>();
myNumbersList[0][0].add(612673);
myNumbersList[0][1].add(108695);
myNumbersList[1][0] = new ArrayList<>();
myNumbersList[1][0].add(756875);
myNumbersList[1][1].add(496058);
SumsInLoop mySum = new SumsInLoop(myNumberOfPairs,myNumbersList);
mySum.getSums(myNumberOfPairs, myNumbersList);
The last two lines of code throw errors, asking me to change myNumbersList to type ArrayList<List<Integer>> which throws even more errors, even after changing all 2D ArrayLists to type ArrayList<List<Integer>>.
So, my two questions are as follows:
How can I initialize an NxM ArrayList and populate it correctly?
Is there a faster way of accomplishing this task while still using a class method?
P.S. I'm used to coding in Python and am self-teaching myself Java, so any other information or resources you can provide me with are much appreciated.
You may want to simplify your input by using 2D array of int : int[][] myNumbersList = new int[13][2];
The expected output in that case is a 1D array of int[13] that can be obtained as follows (demonstrated with 2 pairs. See mcve ) :
public class SumsInLoop {
//pairsOfInts should be an [n][2] array
private static int[] sumOfPairs(int[][] pairsOfInts) {
int[] sums = new int[pairsOfInts.length];
for(int pairIndex = 0; pairIndex < pairsOfInts.length; pairIndex++) {
sums[pairIndex]= pairsOfInts[pairIndex][0]+pairsOfInts[pairIndex][1];
}
return sums;
}
public static void main(String[] args) {
int numberOfPairs = 2;
int[][] pairsOfInts = new int[numberOfPairs][2];
pairsOfInts[0] = new int[] {612673,108695 };
pairsOfInts[1] = new int[] {756875,496058 };
int[] sumOfPairs = sumOfPairs(pairsOfInts);
System.out.println(Arrays.toString(sumOfPairs));
}
}
If you want a solution implemented with List you can make use of javafx Pair (or make your own pair class.
The input can be defined as List<Pair<Integer,Integer>> pairsOfInts = new ArrayList<>();
The out put can be an array as above, or a List<Integer>:
import java.util.ArrayList;
import java.util.List;
import javafx.util.Pair;
public class SumsInLoop {
private static List<Integer> sumOfPairs(List<Pair<Integer, Integer>> pairsOfInts) {
List<Integer> sums = new ArrayList<>();
for(Pair<Integer,Integer> pair : pairsOfInts) {
sums.add(pair.getKey()+ pair.getValue());
}
return sums;
}
public static void main(String[] args) {
List<Pair<Integer,Integer>> pairsOfInts = new ArrayList<>();
pairsOfInts.add (new Pair<>(612673,108695 ));
pairsOfInts.add (new Pair<>(756875,496058));
List<Integer> sumOfPairs = sumOfPairs(pairsOfInts);
System.out.println(sumOfPairs);
}
}
The (compile) exception you are getting is due to the fact that you expect a ArrayList<ArrayList<Integer>>, but pass an ArrayList[][]. (which is not the same in Java)
In your case you'd need (in the main method):
ArrayList<ArrayList<Integer>> myNumbersList = new ArrayList</* when java > 6 ;)*/>(13);
this only sets the capacity of the (parent) list (..and the underlying/internal backing array)
to initialize the child lists, you'd not come around looping (somehow...even not in python :):
for (int i = 0; i < 13; i++) {
myNumbersList.add(new ArrayList<Integer>(2));
}
Depends on what means "correctly" ...but I assume with "random data", ideally you would again inner loop:
java.util.Random rnd = new Random(/*seed default current timestamp*/);
//...
for (int i = 0; i < 13; i++) {
ArrayList<Integer> innerList = new ArrayList<>(2);
for (int j = 0; j < 2; j++) {
innerList.add(rnd.netxInt(/*bound default Integer.MAX_VALUE*/) /*+/-/% offset*/);
}
myNumberList.add(innerList);
}
Sorry I am not aware of one (faster way), but much depends on the "input format".
Since you already know the amount of values in a pair, an ArrayList is unnecessary. You can create your own, simpler implementation of a pair.
class Pair {
public final int left;
public final int right;
public Pair(int left, int right){
this.left = left;
this.right = right;
}
}
You can then access the values by creating a pair object and accessing its fields.
Pair p = new Pair(10, 7);
System.out.println(p.left); // 10
System.out.println(p.right); // 7
You can then more easily redefine your getSums method.
public static List<Integer> getSums(List<Pair> pairs){
List<Integer> pairsOfSums = new ArrayList<>();
for(Pair pair : pairs){
int sum = pair.left + pair.right;
pairsOfSums.add(sum);
}
return pairsOfSums;
}
Please also notice the function can be static and you don't need to pass the number of pairs. The for-each loop will cycle through all of them regardless.
Initializing the array is then easier than the method you have described in the question.
List<Pair> pairs = new ArrayList<>();
pairs.add(new Pair(7, 10));
pairs.add(new Pair(18, 3));
pairs.add(new Pair(-6, 0));
pairs.add(new Pair(4, 2));
System.out.println(SumsInLoop.getSums(pairs));

Collections is private

I keep getting a "collections is private" error. I wanted to create an ArrayList. How do you properly extend the Collections class?
import java.util.Collections;
public class lists extends Collections {
public static void main(String[] args) {
Arraylist <Integer> x = new Arraylist<>();
int[] y = new int[100];
for(int i = 0; i<100-1; i++) {
y[i] = i;
}
for(int j = 0; j<100-1; j++) {
Integer z = new Integer(y[j]);
x.set( j , z );
System.out.println(x.get(j));
}
}
}
Perhaps if you are only trying to use ArrayList then you don't need to extend that.
It's ArrayList (not Arraylist)
Use y.length on your first loop rather than 100-1.
You can just use x.add() to add your integer value in without setting index it should be added into since there you are strictly specifying a pattern.
Try this solution:
import java.util.ArrayList;
public static void main (String[] args) throws java.lang.Exception
{
ArrayList <Integer> x = new ArrayList<Integer>();
int[] y = new int[100];
for(int i = 0; i<y.length; i++){
y[i] = i;
}
for(int j = 0; j<100-1; j++){
x.add(new Integer(y[j]));
System.out.println(x.get(j));
}
}
But, here is better solution, same achievement with one loop:
public static void main (String[] args) throws java.lang.Exception
{
ArrayList <Integer> x = new ArrayList<>();
for(int j = 0; j<100-1; j++){
x.add(new Integer(j));
System.out.println(x.get(j));
}
}
First off, if all you want to do is create an instance of ArrayList, there's no reason to extend anything. In your example code there's no need for it.
If you really do want your own collection class, then Collections is the wrong class. You need to implement Collection<E>, singular, or List<E>.
Implementing those interfaces is a lot of work. You can save a lot of time by sub-classing AbstractList<E>. When you do that you only have to implement get(int) and size(); the rest is done for you. If the list is modifiable then you'll also want to override set(int, E), add(int, E), and remove(int).
From the source of Collections class. Collections class is non-instantiable since it has a private constructor. If you have a Subclass which calls the Collections class, the subclass will invoke the super class constructor since the super class does not define any other constructor to invoke. You cannot instantiate the Collections super class and its sub-classes.
// Suppresses default constructor, ensuring non-instantiability.
private Collections() {
}
From your question, if you want to just instantiate an ArrayList class. The line ArrayList <Integer> x = new ArrayList<>(); will suffice with an import of java.util.ArrayList.
Check your code and add variables where needed and you can improve further on the logic.
final int RANGEVAL = 100;
for(int i = 0; i < RANGEVAL -1 ; i++) {
x.set( i , i ); //You can also use x.add(i);
System.out.println(x.get(i));
}

iterate through ArrayList<T> java?

I'm learning Android and Java i have created a class let's say like this
class x(){
public int a;
public string b;
}
and then i initiate a list of this class and then added values to its properties like this
public ArrayList<x> GetList(){
List<x> myList = new ArrayList<x>();
x myObject = new x();
myObject.a = 1;
myObject.b = "val1";
mylist.add(x);
y myObject = new y();
myObject.a = 2;
myObject.b = "val2";
mylist.add(y);
return myList;
}
My Question is how can i loop through what GetList() return
i have tried
ArrayList<x> list = GetList();
Iterator<x> iterator = list.iterator();
but i don't know if this is the right way of doing this, plus i don't know what to do next i have added a breakpoint on the Iterator but it seemed to be null , the list have values thought
There are two ways to do this:
A for loop
Using the iterator method.
for loop:
for(x currentX : GetList()) {
// Do something with the value
}
This is what's called a "for-each" loop, and it's probably the most common/preferred method of doing this. The syntax is:
for(ObjectType variableName : InCollection)
You could also use a standard for loop:
ArrayList<x> list = GetList();
for(int i=0; i<list.size(); i++) {
x currentX = list.get(i);
// Do something with the value
}
The syntax for this is:
for(someStartingValue; doSomethingWithStartingValue; conditionToStopLooping)
iterator method:
Iterator<x> iterator = GetList().iterator();
while(iterator.hasNext()) {
x currentX = iterator.next();
// Do something with the value
}
You can loop through your array with a for-each loop:
for (x item: GetList()) {
doSomethingWithEachValue(item);
}
I guess you can iterate through the arraylist a number of ways. One way is the iterator:-
ArrayList<String> al = new ArrayList<String>();
al.add("C");
al.add("A");
al.add("E");
al.add("B");
al.add("D");
al.add("F");
System.out.print("Original contents of al: ");
Iterator<String> itr = al.iterator();
while (itr.hasNext()) {
String element = itr.next();
System.out.print(element + " ");
}
Another way would be a loop:
for(int i = 0; i < list.size(); i++){
list[i].a = 29;
}
Hope this helps in any way.
Ref
http://www.tutorialspoint.com/java/java_using_iterator.htm
http://examples.javacodegeeks.com/core-java/util/arraylist/arraylist-in-java-example-how-to-use-arraylist/
UPDATE
I thought that I should just put this out there from research due to the comment below about performance.
The Android docs
http://developer.android.com/training/articles/perf-tips.html
states:
The enhanced for loop (also sometimes known as "for-each" loop) can be used for collections >that implement the Iterable interface and for arrays. With collections, an iterator is >allocated to make interface calls to hasNext() and next(). With an ArrayList, a hand-written >counted loop is about 3x faster (with or without JIT), but for other collections the enhanced >for loop syntax will be exactly equivalent to explicit iterator usage.
There are several alternatives for iterating through an array:
static class Foo {
int mSplat;
}
Foo[] mArray = ...
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the
loop.
one() is faster. It pulls everything out into local variables,
avoiding the lookups. Only the array length offers a performance
benefit.
two() is fastest for devices without a JIT, and indistinguishable
from one() for devices with a JIT. It uses the enhanced for loop
syntax introduced in version 1.5 of the Java programming language.
So, you should use the enhanced for loop by default, but consider a hand-written counted loop for performance-critical ArrayList iteration. Also this is stated by Josh Bloch's Effective Java, item 46. The iterator and the index variables are both just clutter. Furthermore, they represent opportunities for error.
The preferred idiom for iterating over collections and arrays
for(Element e : elements){
doSomething(e);
}
Josh also states when you see the colon : read it as "In". The loop reads as for each element e in elements. I do not claim this work as my own even though I wish it was. If you want to learn more about efficient code then I suggest reading Josh Bloch's Effective Java.
Try the following:
class x {
public int a;
public String b;
}
private void test() {
List<x> items = getList();
for (x item: items) {
System.out.print("val: " + item.a);
}
}
private List<x> getList() {
List<x> items = new ArrayList<x>();
x oneObject = new x();
oneObject.a = 1;
oneObject.b = "val1";
items.add(oneObject);
x anotherObject = new x();
anotherObject.a = 2;
anotherObject.b = "val2";
items.add(anotherObject);
return items;
}

Java array object initialization

I just want ask, is it possible to initiliaze more objects with same constructor in one command?
Example of code:
Tile[] tiles = new Tile(5,5)[20];
Thanks for response.
Impossible as far as I know.
The code Tile[] tiles = new Tile[20]; just creates an array of references. To fill the array, you should create a Tile object and then assign the reference to one index of the array, such as:
tiles[0] = new Tile(5,5);
If all elements of the array pointing to the same object is OK, you can full fill the array simply use:
Tile tiles = new Tile[20];
Arrays.fill(tiles, new Tile(5,5));
No, you have to use a loop.
Tile[] tiles = new Tile[20];
for(int i = 0; i < tiles.length; i++) {
tiles[i] = new Tile(5, 5);
}
However, it is nice that in Java 8 we will be able to shorten this using the new Supplier class and a helper method.
static <E> E[] fill(E[] arr, Supplier<? extends E> supp) {
for(int i = 0; i < arr.length; i++) {
arr[i] = supp.get();
}
return arr;
}
We can then do the following:
Tile[] tiles = fill(new Tile[20], () -> new Tile(5, 5));
I think that's sort of nifty.
There's also a couple ways to do this without Java 8 by using reflection. Here's a way you can do it if the class has a copy constructor (a constructor that takes an object of its own class as an argument):
static <E> E[] duplicate(E[] arr, E element) {
#SuppressWarnings("unchecked")
Class<? extends E> cls = (Class<? extends E>)element.getClass();
try {
Constructor<? extends E> ctor = cls.getConstructor(cls);
for(int i = 0; i < arr.length; i++) {
arr[i] = ctor.newInstance(element);
}
} catch(Exception e) {
e.printStackTrace(System.err);
}
return arr;
}
So for example:
String[] arr = fill(new String[5], "Hello world!");
Reflection is a bit more unstable than the lambda, especially when dealing with subtypes and primitives. The lambda is great.
First, it is even not possible to initialize an object array with non-null value in one line (ok, except using {...} or filling them with same reference but I think it is not what you want)
You gotta create instance of array first, and fill individual element in the array:
e.g.
Foo[] myArray =new Foo[10];
for (int i = 0; i < myArray.length; ++i) {
myArray = new Foo();
}
If you are just looking for shorter code that you don't want to write the loop again and again, here is one option for you:
write a little util like this:
public class ArrayUtil {
public static T[] fillArray(T[] array, ArrayElementFactory elementFactory) {
for (int i = 0; i< array.length; ++i) {
array[i] = elementFactory.create(i);
}
return array;
}
}
public interface ArrayElementFactory<T> {
T create(int i);
}
The way to use is something like
Foo[] fooArray = fillArray(new Foo[10], new ArrayElementFactory<Foo>() {
Foo create(int i) { return new Foo(10,10); }};
If you are using Java8, I believe (haven't tried) you can use lambda expression which give you something like
Foo[] fooArray = fillArray(new Foo[10], i -> new Foo(10,10));

Categories