If you're not interested in a story, skip the first 2 paragraphs.
I was talking to a friend about arrays and why they (still) crash if you try to access an object that is out of bounds in "modern" languages like Objective C (That's my main language). So we got into a debate and I said that I could write him an Array (I named it GeniusArray) that returns null and prints out an error if you try to access something out of bounds but does not crash.
After sleeping over it I realized that if you are accessing elements that are out of bounds you have some serious errors in your code and it's maybe not bad for app to crash so you get forced to fix it. :-D
But still: I'd like to prove my point and subclass an Array and override the get() method by basically adding this one if statement that every programmer writes relatively often:
// Pseudo code...
if (index < array.count) element= array[index];
I want to do it in Java and not Objective C because that's what my friend "knows" (btw, we are both students).
To cut a long story short: I tried to subclass an Array but it doesn't seem to work. I'm get ting this:
Access restriction: The type
Attribute.Array is not accessible due
to restriction on required library:
/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/classes.jar GeniusArray.java
Only classes can be subclassed. Array types are not classes. (From here: "There are three kinds of reference types: class types, interface types, and array types.")
Languages such as C, C++ and Objective-C do not check array bounds (and hence result in unpredictable behaviour if you try to access an array with an invalid index) for performance reasons.
Java does check array bounds on every array access and you'll get an ArrayIndexOutOfBoundsException if you use an invalid index. Some people argue that because of this built-in check arrays in Java are less efficient than in other programming languages.
Yes. As you've discovered you can't subclass from an array. You'll have to subclass from (say) an ArrayList and use the Decorator pattern to intercept the get() methods (and related).
Unfortunately you can't provide an operator overload for [] either, so you're going to be some distance from your original objective.
As far as I recall, you really can't subclass an Array in Java (it is a special type). The VM makes some assumptions about arrays that subclassing might mess up.
Normally, I would just try to stay away from arrays. Use ArrayLists instead.
Related
Arrays don't have a "toList" function, so we need "Arrays.asList" helper functions to do the conversion.
This is quite odd: List has its own function to convert to an array, but arrays need some helper functions to convert to a List. Why not let arrays have a "toList" function, and what's the reason behind this Java design?
Thanks a lot.
Because List instances are an actual object, while arrays are (for MOST intents and purposes) a primitive and don’t expose methods. Although technically arrays are an object which is how they can have a field length and a method call such as clone(), but their classes are created after compilation by the JVM.
Another point to consider is that toArray() is declared on an INTERFACE (specifically, the java.util.List interface).
Consequently, you must call toArray() on some object instance that implements List.
This might help explain at least one part of your question: why it's not static ...
As others have pointed out: An array in Java is a rather "low-level" construct. Although it is an Object, it is not really part the object-oriented world. This is true for arrays of references, like String[], but even more so for primitive arrays like int[] or float[]. These arrays are rather "raw, contiguous blocks of memory", that have a direct representation inside the Java Virtual Machine.
From the perspective of language design, arrays in Java might even be considered as a tribute to C and C++. There are languages that are purely object-oriented and where plain arrays or primitive types do not exist, but Java is not one of them.
More specifically focusing on your question:
An important point here is that Arrays#asList does not do any conversion. It only creates List that is a view on the array. In contrast to that, the Collection#toArray method indeed creates a new array. I wrote a few words about the implications of this difference in this answer about the lists that are created with Arrays#asList.
Additionally, the Arrays#asList method only works for arrays where the elements are a reference type (like String[]). It does not work for primitive arrays like long[] *. But fortunately, there are several methods to cope with that, and I mentioned a few of them in this answer about how to convert primitive arrays into List objects.
* In fact, Arrays#asList does work for primitive arrays like long[], but it does not create a List<Long>, but a List<long[]>. That's often a source of confusion...
From the modern perspective, there's no good reason why arrays lack the method you mention as well as a ton of other methods, which would make them so much easier to use. The only objective reason is that "it made the most sense to the designers of Java twenty two years ago". It was a different landscape in 1996, an era where C and C++ were the dominant general purpose programming languages.
You can compare this to e.g. Kotlin, a language that compiles to the exact same bytecode as Java. Its arrays are full-featured objects.
Arrays are primitives which don't have methods(With the exception of String) so you have to use methods from another class. A list is a reference type so it can have methods.
This question already has answers here:
Where is array's length property defined?
(7 answers)
Closed 9 years ago.
Since most other classes seem to let the developer retrieve the length or size of its content by calling a method, usually length() or size(), how come the length of an array is retrieved by reading the instance variable length? It just seems inconsistent to me, especially since a String object is immutable as well and still uses a length() method.
It is inconsistent. I suppose the actual reason for the distinction can only be found in the early history of Java language development. Perhaps it was for what seemed at the time to be performance reasons. I suspect that if Java were being (re)designed from scratch today, the length field would disappear and instead there would be a java.lang.Array class* (similar to java.lang.Enum) from which all arrays would derive and which would include a length() method inherited by all arrays.
Actually, the lack of an Array class (in the above sense) may indicate why there's a length attribute: arrays are more "built in" to the language than, say, the collection classes (which are part of a class library).
* Java does have java.lang.reflect.Array, but that does something completely different from what I'm talking about.
Most of the collections have dynamic sizes, so they need a method to verify the length/size in that specific time. An array has a fixed length, so it doesn't need to be recalculated all the time.
An array is of fixed size - it will never change. As such, you don't need the overhead of a method.
The reason why is that the JLS says so:
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array. length may be positive or zero.
Regarding the underlying motivation: only the people who created the language could answer...
Interestingly, Oak, which is the language at the origin of Java, already had that notion. If you read its specifications, you will see that:
The length of any array can be found by using .length
So the best guess here is that it is the result of a decision made by a few guys more than 20 years ago.
A method is executed every time it's called.
Optimization exists, such as cache etc.. but the point is that an array never gets its size changed.
Thus, what could better fit the case than a "final" (not sure about the implementation under the hood but same concept) instance's field?
java.util.Collection describes some classes wrapping arrays like ArrayList, HashSet etc..
In their case, size is altered since the concept of collection is to have an extensible array.
Thus, the size must be calculated thanks to a method (size()), not a field in this case.
We did they make the decision to not implement a toString method for int[], but instead let it inherit the toString method from Object?
They did implement more reasonable toString methods for arrays. They are located in the java.util.Arrays class.
As for reasoning. I'm assuming by the overrides provided in the Arrays class, that trying to implement a generic toString for different types of arrays is either complex or impossible. The toString method would have to know what type of array it was working on, and output the data approrpiately. For instance, Object[] must use toString on each element, while char[] must output the character, and the numeric datatypes must be converted to a numeric string.
The methods in Arrays get this for free, because the types are fixed due to the overrides.
I guess because of the following reasoning: how would they know how users would want to present their array? It might "array size: 10" or it might be "[x,y,z]".
They gave you a default, if you want to make it something else it is easy to do.
You can use apache's ToStringBuilder make it easier...
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/ToStringBuilder.html
My guess would be is that because Array objects weren't created in Java source code by the language designers - they are created by the Java compiler. Remember, you can have an array of any object type and so the compiler creates the Array object as appropriate for the type you require.
If they were to create a standard method, it's not immediately obvious how this should work. For example, executing toString() and concatenating the results might be OK for a small array but it doesn't work for a multidimensional array or an array with 1,000 entries. So I think no toString() method is created to keep all arrays consistent.
Admittedly, it is annoying and sometimes I do think something along the lines of "Array[" + size + "] of " + getClassName() would be so much better than the default.
A bit of guesswork here, but...
There isn't an obvious string representation of an int array. People do it in different ways: comma separated, space separated, enclose in brackets or parentheses or nothing. That probably drove the decision not to implement it in Java 1.1, along with it being low priority code (since anyone can implement a method to write an array as a string themselves very simply).
Now you can't upgrade it in Java 1.2 or later because that would break back compatibility for anyone already using the old behaviour. You can however add a utility class that implements some functionality, and that's what they did with java.util.Arrays.
I've been told that
int[] numbers
and
int numbers[]
are equivalent. I've only ever seen the former though. What impetus is there, if ever, to write the latter?
None. It's just a legacy from C syntax. However, it should be noted that C and Java arrays are very different. Java arrays are more like a malloc-allocated pointer with a length field.
Doesnt really matter, but, my personal preference is for int[] numbers as it more logically follows the class instance_name pattern.
After all you are really delcaring an "array of integers" called "numbers", the second form is slightly misleading as its more of declaring "an integer" called "numbers" oh and by the way its actually an array of "numbers".
just becoz of- the way earlier we used to declare in C.
two options are available...chose as per ur convenience. No big deal, java provided new way of declaring array & remained the old way of declaring array also. Full freedom for programmer....cool stuff. no confusion at all.
private ArrayList<String> colors = new ArrayList<String>();
Looking at the example above, it seems the main point of generics is to enforce type on a collection. So, instead of having an array of "Objects", which need to be cast to a String at the programmer's discretion, I enforce the type "String" on the collection in the ArrayList. This is new to me but I just want to check that I'm understanding it correctly. Is this interpretation correct?
That's by far not the only use of generics, but it's definitely the most visible one.
Generics can be (and are) used in many different places to ensure static type safety, not just with collections.
I'd just like to mention that, because you'll come accross places where generics could be useful, but if you're stuck with the generics/collections association, then you might overlook that fact.
Yes, your understanding is correct. The collection is strongly-typed to whatever type is specified, which has various advantages - including no more run-time casting.
Yeah, that's basically it. Before generics, one had to create an ArrayList of Objects. This meant that one could add any type of Object to the list - even if you only meant for the ArrayList to contain Strings.
All generics do is add type safety. That is, now the JVM will make sure that any object in the list is a String, and prevent you from adding a non-String object to the list. Even better: this check is done at compile time.
Yes. To maintain type safety and remove runtime casts is the correct answer.
You may want to check out the tutorial in the Java site. It gives a good explanation of in the introduction.
Without Generics:
List myIntList = new LinkedList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = (Integer) myIntList.iterator().next(); // 3
With Generics
List<Integer> myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'
I think it as type safety and also saving the casting. Read more about autoboxing.
You can add runtime checks with the Collections utility class.
http://java.sun.com/javase/6/docs/api/java/util/Collections.html#checkedCollection(java.util.Collection,%20java.lang.Class)
Also see checkedSet, checkedList, checkedSortedSet, checkedMap, checkedSortedMap
Yes, you are correct. Generics adds compile-time type safety to your program, which means the compiler can detect if you are putting the wrong type of objects into i.e. your ArrayList.
One thing I would like to point out is that although it removes the visible run-time casting and un-clutters the source code, the JVM still does the casting in the background.
The way Generics is implemented in Java it just hides the casting and still produces non-generic bytecode. An ArrayList<String> still is an ArrayList of Objects in the byte-code. The good thing about this is that it keeps the bytecode compatible with earlier versions. The bad thing is that this misses a huge optimization opportunity.
You can use generic anywhere where you need a type parameter, i.e. a type that should be the same across some code, but is left more or less unspecified.
For example, one of my toy projects is to write algorithms for computer algebra in a generic way in Java. This is interesting for the sake of the mathematical algorithms, but also to put Java generics through a stress test.
In this project I've got various interfaces for algebraic structures such as rings and fields and their respective elements, and concrete classes, e.g. for integers or for polynomials over a ring, where the ring is a type parameter. It works, but it becomes somewhat tedious in places. The record so far is a type in front of a variable that spans two complete lines of 80 characters, in an algorithm for testing irreducibility of polynomials. The main culprit is that you can't give a complicated type its own name.