mirror of https://github.com/deavmi/JavaOCP
314 lines
9.4 KiB
Java
314 lines
9.4 KiB
Java
package ocp.collections.Arrays;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Here we play with Java arrays and the Java Collections API
|
|
*
|
|
*/
|
|
public class App
|
|
{
|
|
public static void main( String[] args )
|
|
{
|
|
/**
|
|
* Arrays in java are pretty easy to work with
|
|
*/
|
|
String[] myArray = new String[] {"Alice", "Bob"};
|
|
System.out.println(Arrays.toString(myArray)); // [Alice, Bob]
|
|
|
|
/**
|
|
* Any array is an object too, hence we can store
|
|
* it in the <code>Object</code> super-type
|
|
*/
|
|
Object thing = myArray;
|
|
|
|
/**
|
|
* You can also cast the array <code>T[]</code>
|
|
* to <code>A[]</code> so long as T is a kind-of
|
|
* A (which is true as T=String, and A=CharSequence)
|
|
* and String is a kind-of CharSequence
|
|
*/
|
|
CharSequence[] thing2 = myArray;
|
|
thing2[0] = "Eve";
|
|
System.out.println(Arrays.toString(myArray)); // [Eve, Bob]
|
|
|
|
/**
|
|
* Remember the object's actual type is
|
|
* <code>String[]</code>, so we must check
|
|
* when we downcast
|
|
*/
|
|
if(thing2 instanceof String[])
|
|
{
|
|
String[] myCastedArray = (String[])thing2;
|
|
myCastedArray[1] = "Peter";
|
|
System.out.println(Arrays.toString(myCastedArray)); // [Eve, Peter]
|
|
}
|
|
|
|
/**
|
|
* We can also do it via <code>thing</code>
|
|
*/
|
|
if(thing instanceof CharSequence[])
|
|
{
|
|
CharSequence[] myCastedArray = (CharSequence[])thing;
|
|
myCastedArray[1] = "John";
|
|
System.out.println(Arrays.toString(myCastedArray)); // [Eve, John]
|
|
}
|
|
|
|
/**
|
|
* We can also do it via <code>thing</code>
|
|
*/
|
|
if(thing instanceof String[])
|
|
{
|
|
String[] myCastedArray = (String[])thing;
|
|
myCastedArray[0] = "Nick";
|
|
System.out.println(Arrays.toString(myCastedArray)); // [Nick, John]
|
|
}
|
|
|
|
/**
|
|
* The Arrays class has a bunch of helper methods that we can
|
|
* use to help us working with arrays
|
|
*
|
|
* The binarySearch does a binary search on our array
|
|
*/
|
|
int[] numbers = {5,4,1,2,1};
|
|
int pos = Arrays.binarySearch(numbers, 0);
|
|
System.out.println("Position: "+pos); // -1 because not found
|
|
pos = Arrays.binarySearch(numbers, 1);
|
|
System.out.println("Position: "+pos); // non-negative because found
|
|
|
|
/**
|
|
* Apply in-place sorting
|
|
*/
|
|
System.out.println("Before sorting: "+Arrays.toString(numbers));
|
|
Arrays.sort(numbers);
|
|
System.out.println("After sorting: "+Arrays.toString(numbers));
|
|
|
|
/**
|
|
* You can make copies of arrays using copyof
|
|
* which takes in the original array, the
|
|
* length to copy and then a Class object
|
|
* to specify the new array to be made
|
|
*/
|
|
|
|
Object[] bruh = new Object[] {new Object(), new Object()};
|
|
Object[] bruhCopy = Arrays.copyOf(bruh, 2, bruh.getClass());
|
|
System.out.println(bruh == bruhCopy); // false
|
|
|
|
/**
|
|
* The equals method will look at two arrays
|
|
* and if the elements are objects, check equality
|
|
* between them.
|
|
*
|
|
* However an array of arrays, means that the references
|
|
* will be checked on the inner array (as they are outer
|
|
* array elements).
|
|
*
|
|
* For a full equality we use deepEquals
|
|
*
|
|
*/
|
|
Arrays.deepEquals(bruh, bruhCopy);
|
|
Arrays.equals(bruh, bruhCopy);
|
|
|
|
/**
|
|
* It should be noted that this will
|
|
* give us a {@link ClassCastException}.
|
|
*
|
|
* Remember the object's ACTUAL type
|
|
* is that of a <code>Object[]</code>
|
|
* and casting can only be to <code>Object</code>
|
|
* (as all arrays are Objects) OR to
|
|
* a compatible type according to
|
|
* the T[] to S[] where T is a kind-of S
|
|
*
|
|
* But if T=Object and S=String, well,
|
|
* T is not a kind of S.
|
|
*
|
|
* Object is not a kind-of String
|
|
*/
|
|
Object[] arr2 = new Object[] {"Hello", "World"};
|
|
|
|
try
|
|
{
|
|
String[] arr2Casted = (String[])arr2;
|
|
}
|
|
catch(ClassCastException e)
|
|
{
|
|
System.out.println("Sorry but got: '"+e+"'");
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* We create a custom array list
|
|
*/
|
|
ArrayList<String> strList = new ArrayList<String>();
|
|
strList.add("Hello");
|
|
|
|
/**
|
|
* Compiler does static type checking of
|
|
* anything with parameterized type `T`
|
|
* being `Object`
|
|
*/
|
|
ArrayList<?> l = strList;
|
|
|
|
ArrayList<Integer> intList = (ArrayList<Integer>)l;
|
|
|
|
/**
|
|
* The below work fine of course, all they
|
|
* are doing is calling the methods.
|
|
*
|
|
* There is no compile-time to-type request
|
|
* in this code that the static type checker
|
|
* would need to enforce
|
|
*/
|
|
intList.size();
|
|
intList.get(0);
|
|
intList.add(2);
|
|
|
|
/**
|
|
* As soon as we assign then we have a
|
|
* runtime type type occur of the
|
|
* to-type (Integer (from variable))
|
|
* and the actual type of the object
|
|
* returned from `get(0)`.
|
|
*
|
|
* Compile-time wise, it checks out
|
|
* as the `T` type it `Integer`
|
|
* and the to-type (of the variable)
|
|
* is `Integer.
|
|
*
|
|
* So it is generalized probably to
|
|
* check the object's runtime type
|
|
* against the paramaterized type `T`
|
|
* as compile-time guaranteed we had
|
|
* to-type (of variable) compatible with
|
|
* the parameterized type `T` and therefore
|
|
* we need check the runtime type to
|
|
* `T`.
|
|
*
|
|
* So yes because the objects actual
|
|
* type of `String` and `String`
|
|
* is not compatible type-wise with
|
|
* `T` (which is `Integer`) we then
|
|
* get a `ClassCastException`.
|
|
*
|
|
* By the way this phenomenom
|
|
* is known as HEAP POLUTTION!
|
|
*
|
|
* (https://en.wikipedia.org/wiki/Heap_pollution)
|
|
*/
|
|
// Integer myInt = intList.get(0);
|
|
|
|
/**
|
|
* This will work because the actual
|
|
* type of the Object at index 1 is
|
|
* an Integer or Integer-compatible
|
|
* object (in this case exactly an
|
|
* Integer).
|
|
*
|
|
* Therefore the actual runtime type
|
|
* matches the to-type which is the
|
|
* type of the variable being assigned
|
|
* t.
|
|
*/
|
|
Integer myIntFr = intList.get(1);
|
|
|
|
/**
|
|
* Var-args will create an array
|
|
* who's actual type is determined
|
|
* at compile-time by the lowest common
|
|
* denominator of compatible types
|
|
* across all the types of the provided
|
|
* arguments
|
|
*/
|
|
thing(1,1); //Integer[] actual type
|
|
thing("Hello", 1); //Serializable[] actual type
|
|
thing("Hello", "World"); //String[] actual type
|
|
thing("Hello", new Object()); //Object[] actual type
|
|
|
|
System.out.println();
|
|
|
|
/**
|
|
* We call `getArray(T...)` with certain
|
|
* arguments and the most common type will
|
|
* be used as the kind-of array to construct.
|
|
*
|
|
* Here we then expect it to be a `String[]`
|
|
*
|
|
* This follows from the exact same logic
|
|
* as calling `thing(T...)` above.
|
|
*/
|
|
Object retObj1 = getArray("hello");
|
|
System.out.println(retObj1.getClass()); // String[]
|
|
|
|
/**
|
|
* See the definition of `get()` for
|
|
* an explanation
|
|
*/
|
|
Object retObj = get("Hello");
|
|
System.out.println(retObj.getClass()); //Object[]
|
|
}
|
|
|
|
private static <E> void thing(E... items)
|
|
{
|
|
System.out.println(items.getClass());
|
|
}
|
|
|
|
@SafeVarargs
|
|
private static <T> T[] getArray(T... items)
|
|
{
|
|
return items;
|
|
}
|
|
|
|
private static <T> T[] get(T item)
|
|
{
|
|
/**
|
|
* The problem here is that if we call
|
|
* a var-args method with a parameterized
|
|
* ARGUMENT (the `item` here) then it
|
|
* will always seem to choose the common
|
|
* type as `Object` therefore making the
|
|
* array passed in an `Object[]` and of course
|
|
* that, in this case,is immediately returned
|
|
* to us.
|
|
*
|
|
* Not sure why it's like this in Java, perhaps
|
|
* they don't explore all the calls but they
|
|
* probably only do template code generation
|
|
* based on like a first level call and
|
|
* maybe not based off of calls-to-calls
|
|
* (which D definitely does)
|
|
*
|
|
* From the docs (https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html):
|
|
*
|
|
* "When the compiler encounters a varargs method,
|
|
* it translates the varargs formal parameter into an array.
|
|
* However, the Java programming language does not permit the
|
|
* creation of arrays of parameterized types."
|
|
*
|
|
* Yeah, so it's the same thing, cannot
|
|
* construct an array of a parameterized type
|
|
* T which is exactly what `item` IS!
|
|
*
|
|
* Compared to the inner call, `getArray`
|
|
* when used by itself is a concrete type
|
|
*
|
|
* We can use @SafeVarargs to get the compiler
|
|
* warnings to shut up if we know exactly what
|
|
* it is that we are doing as in the case of
|
|
* `multipleItems_weKnowWhatWeAreDoingVersion`
|
|
* as we know its going to be an `Object[]`
|
|
* but it would for any call using parameterized
|
|
* arguments, hence if we know for sure then
|
|
* we get compile rwarnings supressed
|
|
*/
|
|
// T[] gg = new T[];
|
|
Object[] multipleItems_weKnowWhatWeAreDoingVersion = getArray(item, item, item);
|
|
T[] multipleItems = getArray(item, item, item);
|
|
return multipleItems;
|
|
}
|
|
}
|