When I cast to E[] (the class parameter), it requires me to add
#SuppressWarnings("unchecked")
For example:
E[] anArray = (E[]) new Object[10];
Should I be doing something different, or is it supposed to be like this?
Thanks
It is correct. Imagine:
Object[] o = new Object[10];
o[0] = new A(); // A is not a subclass of E
E[] e = o; // Now you have broken the type system: e[0] references something that is not an E.
The way it works, you have to explicitly cast in order to make the compiler ignore this possibility.
You should probably read the Effective Java book. In short, it is impossible to tell exactly what is the right course of action for you is because we don't know what you are doing, but generally you should not be suppressing this warning. So most likely the solution for you is to use typesafe generic collections instead of arrays.
It's supposed to be doing that because of type erasure.
To avoid having to suppress that warning, the only thing you can do is use a List<E> (or similar Collection).
Yes, you are supposed to do it this way, since we can't initialise arrays of generics like this:
E[] array = new E[10]; // Compile error
You really have to do it as you wrote. There is no way around that I know.
Another approach is to use an array of Objects (instead of E). You can see that the Java API developers did it also like this inside the ArrayList class:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
And they simply initialise this array like this:
elementData = new Object[size];
And everywhere they use it they cast the array content:
/**
* Returns the element at the specified position in this list.
*
* #param index index of the element to return
* #return the element at the specified position in this list
* #throws IndexOutOfBoundsException {#inheritDoc}
*/
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
I'm not really sure, but I think that the first approach is faster since the casting is not needed at runtime. The Java VM will spent some time casting it, I think. Why do I think that? Because this gives an error at runtime:
Integer i = new Integer(34);
Object o = i;
String s = (String) o; // Runtime error
So this means that the VM really checked if it is a String. But the fact that the compiler does type erasure makes me think it doesn't make any difference. Can someone clarify?
Related
I am going through the Java Arrays and additionally, I am looking into generics. Below are the two methods of initializing an array
int[] data = {1,2,3,4,5,6,7,8,9};
// or
int[] data;
data = new int[] {1,2,3,4,5,6,7,8,9};
But when I am using generics, I have mixture of data types for example,
String[] outcome = {"0 wins", "Tie" , "X wins"};
Above array has a single data type of String. What if in an array I have something like below
outcome = {7, "Tie" , 9.0};
now I have a mixture of data types in an array. How I can write it or if it is possible to do with generics? Can I do it with ArrayList?
Thank you
I'd like to correct this:
But when I am using generics, I have mixture of data types
Generics require homogeneous data types. For instance, a List<Integer> is a list that can only ever hold an Integer, and a List<? extends Number> can only ever hold Numbers, which covers other number types like Long, Short, Double, etc...but are referred to by the single type Number.
Anyway, what you're looking for is a Bag - a collection which can hold any arbitrary object. You can implement this with an Object[] or a List<Object>, and you're going to have to check the type of each element you pull out when you want to use it, since there's no way in Java to have a heterogeneous data type, which is what you're looking for.
tl;dr: In my opinion, arrays are not a good fit for the problem, you should use objects instead.
This is not a direct answer to your question, but an answer in the form of a redesign.
First of, let us tackle your statement about generics and arrays. Arrays are covariant and retained, while generics are invariant and erased.
Covariant means that when B extends A, you can Write A[] aArray = new B[someSize];. Invariant means that this is not possible: ArrayList<A> aList = new ArrayList<B>(); will lead to a compile time error.
Retained means that the information about the type is retained at runtime: an array always "knows* what type its elements has. Erased means that the type information is gone after compilation. This is also called Type Erasure.
The mixture of covaraint and retained vs. invariant and erased has good potential to get you into trouble. That is the reason why ArrayList uses an Object[] instead of a T[] as its backing datastructure.
Now to the actual question. As was already said by others, we could go down the road ande create an Object[]. I would strongly advice against this since we loose all type information. The only way to get back that information is a instanceof check, which makes your code rigid. Imagine you change the type of an entry. In this case, the instanceof will return false, possibly leading to unwanted behavior and (best case) some test turning red or (worst case) we may not notice it.
Now how to get around this? We create a class representing (what I infer are) match results:
public class MatchResult {
private final int firstTeamScore;
private final int secondTeamScore;
public MatchResult(final int firstTeamScore, final int secondTeamScore) {
this.firstTeamScore = firstTeamScore;
this.secondTeamScore = secondTeamScore;
}
public int getFirstTeamScore() {
return firstTeamScore;
}
public int getSecondTeamScore() {
return secondTeamScore;
}
public String getResultForFirstTeam() {
if (firstTeamScore > secondTeamScore) {
return "Win"; // In an actual implementation, I would replace this with an enum
} else if(firstTeamScore = secondTeamScore) {
return "Tie";
} else {
return "Lose";
}
}
// You can add a method public String getResultForSecondTeam(), I omitted it for brevity
}
What have we won? We have types. The scores are always ints, the results always Strings. If we were, for example, change the type of the getReultforFirstTeam() from String to, e.g., an Enum, we would get compiler errors for all locations where the type does not match anymore. Thus, we hone the fail-fast design and are forced to modify the code where necessary. And thus, we do not even have the chance to get the sneaky, unwanted behaviour we had before.
1 way to handle this is that you create an array of Object, that can accommodate all of data types
Object[] outcome = {7, "Tie" , 9.0};
And later you can access objects like:
if(outcome[0] instanceof Integer){
Integer i = (Integer) outcome[0];
}
and vice versa..
outcome = {7, "Tie" , 9.0};
is simply not legal.
You can only use this syntax - an array initializer, where the element type is omitted after the equals - in a variable declaration, e.g.
Object[] outcome = {7, "Tie" , 9.0};
As mentioned earlier, you could use an Object array. Alternatively, you can use a generic class. Here's an example:
public class Queue<E> {
private ArrayList<E> queue;
/**Unparametrized constructor**/
public Queue() {
queue = new ArrayList<E>();
}
/**Enqueues an element into the queue.**/
public void enqueue(E val) {
queue.add(val);
}
/**Dequeues an element from the queue.**/
public E dequeue() {
E output = queue.get(0);
queue.remove(0);
return output;
}
/**Gets the current size of the queue.**/
public int size() {
return queue.size();
}
}
Read up on generics and how to use them.
You're going to have to create an array of objects, since all objects in java extends Object:
Object[] arr = new Object[3];
//to add objects to it:
arr[0]=new String("element at index 0");
arr[1]=new Integer(1);
arr[2]=new Character('2');
And to find if the object at index x is (for example) an Integer then your going to have to use a cast:
int x = (Integer)arr[x]; //x could be 0 or 1 or 2
Also you can do it with an ArrayList:
List<Object> listObjects = new ArrayList<Objects>();
If i try to make array of Object class in java, it works fine
Object[] o = new Integer[]{1,2,3};
for(Object x : o)
System.out.print(x);
Output is: 123
I found out that you can also do
Object o = new Integer[]{1,2,3};
It doesn't give compile fail. I want to know that can we iterate through the Integers in reference 'o' ?
Then i tried this
class A{ }
class B extends A{ }
class App{
public static void main(String[] args) throws InterruptedException {
A a = new B[4];
}
}
But her A a = new B[4]; gives CF
Every single Object-type in Java inherits from the Object class.
So, basically: an Integer is an Object, which is why you can do this:
Object[] o = new Integer[]{1,2,3};
On the other hand, Arrays are Objects, too, meaning you can do this:
Object o = new Integer[]{1,2,3};
In the first example, the Integers are the Objects, in your second, the Object o is a reference to the Array of Integers
UPDATE: The reason between your A and B classes, you do have an Exception, is because even though each B is an A, the Array in which you store your B's is not an A.
Java arrays are covariant. Meaning that, You can use a Sub type in place of Type.
So if you have an array of "Type", you can actually fill that array with "SubType"'s. Well, any class in Java is a Subtype of Object. Hence no error in that case.
Object o = new Integer[]{1,2,3};
It doesn't give compile fail.
Again the same things, as Array is also an Object in the end, hence you are free to assign that to an Object.
I want to know that can we iterate through the Integers in reference 'o' ?
By default, Object is not iterable. Where as Array object is.
So before you going to iterate, you have to cast it to type Array.
Update :
But her A a = new B[4]; gives CF
Ofcourse that is not a valid declaration You should write
A[] a = new B[4]; // just to satisfy the compiler. At run time you are not allowed to store A's in it.
But if you are trying to achive the style
Object o = new Integer[]{1,2,3};
No that won't work here and you can only write
Object o = new B[4];
That is because array is a sub type of Object class and not A class.
The reason this is possible is that an array is a subclass of Object. However, by storing the array in o, the program "forgets" the fact that o is holding an array. For that reason, you cannot iterate over o.
The compiler will only allow you to do things that it "knows" you can do to that particular class. Here's an analogy: you want to haul 1 metric ton of sand for a few miles. Would you request a "vehicle," or would you specifically request some kind of truck that you knew would be large enough to haul the sand? If you request a "vehicle of some kind," for all you know they might send you a Prius, which obviously wouldn't do you any good - a Prius can't haul 1 ton of sand. In this case, the compiler would "complain" that there's absolutely no guarantee that you'll be sent a vehicle that has the capacity to do what you want.
Types work that way, too - by default, it's perfectly valid to upcast the array to type Object, since everything in Java is a subtype of Object. But, from the compiler's perspective, there's absolutely guarantee that you can iterate over something of that type, so it won't let you do that.
After reading multiple posts (here's one) about how clone( ) from the ArrayList class is broken, I was wondering no one has re-implemented it so that it isn't broken where people can be more comfortable using the method.
Is there something I'm missing here for a reason why no one has re-implemented it so that it is not broken?
The clone() itself is not broken: it's implemented well according to the specification of the clone() method. The problematic place is this specification itself. As it was already discussed in the linked question, there are several drawbacks, namely the necessity to do the unchecked cast, the potential problems which arise if your ArrayList is overridden and the necessity to know that the input List is actually an ArrayList. A good practice for any code requiring the ArrayList is to accept any List (or even Collection) implementation: this way your code becomes more flexible.
As it was already noted, there's a better alternative: using
ArrayList<Type> copy = new ArrayList<>(source);
It's universal: it will work for any source collection and the result will be exactly ArrayList (not derived class). And you should not worry about the performance. According to the implementation it's about the same. See the clone() method code:
public Object clone() {
try {
#SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
So it makes a shallow copy (fast operation of comstant complexity as shallow size is constant and small), then makes single array copy and replaces the mod count. Let's check the constructor:
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
It calls the toArray of original collection, uses its result as the internal array for itself and updates the size. It copies the array only in the case if original collection incorrectly returned typed array from the toArray method. What happens if the input collection is also ArrayList? Check the ArrayList.toArray:
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
See, it's exactly the same operation as in clone() method. Thus in both cases (clone and copy-constructor) you have single Arrays.copyOf(elementData, size) call and small constant overhead.
As a sample, I am developing a simple MySortedSet in java which implements SortedSet interface. It is backed up with a simple array which is E[] array.
I have several questions regarding that:
This is the class: (I am not writing entire code, instead of related parts)
public class MySortedSet<E> implements SortedSet<E>, Iterator<E> {
private E[] array;
private Comparator<? super E> _comparator;
private int size = 0;
private int capacity;
#SuppressWarnings("unchecked")
public MySortedSet() {
this.capacity = 10;
this.array = (E[]) new Object[this.capacity];
// this.array = Array.newInstance(Class<E> var,int size);
// We have to get Class<E> from outside caller.
}
}
Since it accepts all sort of type from primitive to reference types etc. I am not really sure when removing an item, assigning null is a good way in place of the removed item. Since Java initializes primitive types with 0. So null only works for reference types.
Below is probably very bad design:
#Override
public boolean remove(Object o) {
int indexOfElement = this.find(o);
boolean removed = false;
if (indexOfElement != -1) {
this.array[indexOfElement] = null;
removed = true;
}
return removed;
}
Can someone tell me what the best way is to remove an element from an array?
Edit:
Honestly what I am thinking to remove an element from an simple array is like copy the entire array without the removed item into a whole new array but I am not sure how efficient it would be in terms of performance and etc.
It kinda depends on the context of how you want to use your array. For example, if you are going to be iterating over the array and using the contents of it for standard methods like Arrays.sort(), they might generate NullPointerExceptions if you have null values in your array.
If you really want to remove items from an array in a safe way, I'd suggest changing your array to an ArrayList like this...
ArrayList<Object> list = new ArrayList<Object>();
list.add(object);
list.remove(object);
As this will actually remove the item from the list completely - no nulls or anything will remain, and performing methods like length() will return a real value.
For instances when I have used an array, I set the value to null, and ensure that all iterations over the array check that value != null before I try to query it. After setting the nulls for the removed items, I usually loop over the array and manually sort all the nulls to the end of the array, and then do System.arraycopy() to resize the array. This will leave you with a new array of the correct size, with all items in it except for the removed ones. However, I suggest this only if you really must use an array, as it is slower and introduces much greater potential for errors and NullPointerExceptions.
Alternatively, if you're not worried about sort-order, you can simple move the last item in the array over the top of the item you want to remove, and keep a count of the real array size. For example...
Object[] array = new Object[20];
int realSize = 15; // real number of items in the array
public void remove(int arrayIndex){
array[arrayIndex] = array[realSize-1];
realSize--;
}
This method removes an item in the array by 'replacing' it with the item in the last position of the array - its very quick and pretty to implement, if you don't care about sort order.
I had two classes: ParentClass and SubClass. SubClass inherit from ParentClass.
I had the following code: (inside class)
List<SubClass> lstSub;
//some initialization
public ListIterator getLstIterator(int i) {
return lstSub.listIterator(i);
}
And client class uses it the following way:
ListIterator<ParentClass> lstParent = getLstIterator(0); //assign ListIterators
So, the question:
What does the program do while assigning ListIterators:
1) it creates a new list and copies there elements from source list, casting them to ParentClass;
2) it simply creates a link to lstSub and from this time this list is interpreted as List for ListIterator?
Or it does something else?
I'm interested in it because of program performance. I'm new to Java and appreciate any help.
It doesn't create another list. If you get a list iterator without knowing the class in the list, that's going to be an error in your generics usage. You should get a warning when you do that assignment, but it's just a warning. When you actually use it it'll cast to whatever class. Properly you'd hold on to that as ListIterator<? extends ParentClass> if you wanted a list iterator, but actually holding on to an iterator is a little weird.
Finally, just a bit of advice, I'd not worry about performance of the language features too much, especially if you're just getting your feet in the language.
A new instance of ListIterator is created. The reference to the new object is copied into lstParent
See here
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
Disclaimer: This example is specific to ArrayList.
Performance-wise, there's no list copying going on.
But to have the compiler check the type-safety of the code, you should declare the type parameters like this:
public ListIterator<SubClass> getLstIterator(int i) {
return lstSub.listIterator(i);
}
...
ListIterator<? extends ParentClass> lstParent = getLstIterator(0);