Java - Indexing an Interface? - java

This is probably a really stupid question, so please forgive me. But this morning, I've come across a piece of Java syntax that I am completely unfamiliar with. The syntax is as follows:
public MyInterface[] getThings() {
return new MyInterface[0];
}
Obviously, I've changed the name of the interface, and of the method, but otherwise this code sample is unchanged.
I'm confused by this syntax, as it seems to be indexing an interface/class (not even an object)?! Also, the use of the new keyword, to instantiate an interface?!
I've genuinely attempted to Google this, in order to find an answer. But as it's syntax that I'm unfamiliar with, in addition to using the line of code itself as a search term, I've just been guessing at what terminology to use. And unfortunately, I've failed to find anything that explains this syntax for me. Hence, I'm hoping that someone on Stack Overflow might be kind enough to help me to understand this.

It's just creating an empty array. No instances of the interface are being created. It's equivalent to:
return new MyInterface[] { };
Or:
MyInterface[] array = {};
return array;
Specifically, it's an ArrayCreationExpression, as seen in section 15.10 of the JLS.

The function returns an empty array supposed to holding objects of type MyInterface.
It's similar as if you would use String[] to return an array of strings.

it just returns an empty array of MyInterface (size is 0). an array is an array, no matter, of which type the array is. it can be a primitive datatype, a class or an interface, too.

Related

having trouble making a method that creates a 2d array out of a T type unrolled linked list

public T[][] getArrayOfBlocks() {
Node node = this.first;
#SuppressWarnings("unchecked")
T[][] result = (T[][]) new Object[this.nNodes][this.arraySize];
for(int i = 0; i < this.nNodes; i++)
{
for(int j = 0; j < this.arraySize; j++)
if(node.a[j] != null)
result[i][j] = node.a[j];
node = node.next;
}
return result;
}
(Im a newbie in java so my wording will be a bit weird)
Im trying to make a method that creates a 2d array out of a T type unrolled linked list. When i test out the method above using the Integer class instead of the T type i get an error that says
Exception in thread "main" java.lang.ClassCastException: class [[Ljava.lang.Object; cannot be cast to class [[Ljava.lang.Integer; ([[Ljava.lang.Object; and [[Ljava.lang.Integer; are in module java.basa of loader 'bootstrap')
So yeah i would like to know if theres any way to solve this error without changing the return type.
Thanks in advance :)
y out of a T type unrolled linked list.
This is impossible.
Generics are a figment of the compiler's imagination. Generics completely disappear once your java code has been turned into a class file, or if they don't (generics in signatures), the JVM treats it as a comment. It has absolutely no effect. Instead, the compiler uses it to generate errors or warnings and inject invisible casts. This:
List<String> x = new ArrayList<String>();
x.add("Hello");
String y = x.get(0);
ends up in class code as indistinguishable from compiling:
List x = new ArrayList();
x.add("Hello");
String y = (String) x.get(0);
Try it if you're having a hard time getting your head around this idea. Write both, compile it, run javap -c -v to see the bytecode. Identical.
The reason x.add(5) would not work as replacement for x.add("Hello") is simply because javac won't let it happen. If you hack javac to allow it, you get a class file just fine and it verifies just fine. The x.add(5) will even execute just fine. You'd get a ClassCastException on the next line, simply because you're casting an instance of Integer to String.
As a consequence, there is no way to tell the difference between a new ArrayList<String>(); and a new ArrayList<Integer>() at runtime. Obviously; generics disappears; those are both just new ArrayList(), that's it.
In contrast, arrays are 'reified': They aren't a figment of javac's imagination. You can actually get this stuff at runtime. There is a difference between new String[0] and new Integer[0]:
Object[] arr1 = new String[0];
System.out.println(arr1.getClass().getComponentType()); // prints 'String'
It is impossible to write the identical code for generics:
List<?> list1 = new ArrayList<String>();
System.out.println(--nothing you can write here will print String--);
Hence, in your 'unrolled code with T', T is not something you can translate to an actual runtime type, and that means it is impossible to make an array of T.
Still having a hard time believing this? Peruse the API of java.util.List, specifically the various toArray methods it contains.
Look at the no-args one: toArray(). There are two explanations here:
The designer of this class was an utter idiot, because that returns Object[], which is stupid, because clearly that should return T[].
Or, perhaps something else is going on and they 'know' that it is in fact impossible to return a T[] there.
It's, as the rest of this post hopefully already suggested, the second reason.
Fortunately, there are 2 other toArray methods and those two do both return T[] as you desire. They are both based around the notion that the caller puts in the effort of providing that T type for you.
The first version is toArray(T[] in). The toArray code will use the provided array if it is large enough, but if not, it just makes a new one that is the right size and returns it. In practice, you always call listOfStrings.toArray(new String[0]) (you may think new String[list.size()] would be faster - no, that is slower1. A nice example of why writing more complex code because it seems faster is a bad idea. JVMs are far too complex to predict performance like this).
The trick here is that the code in list's toArray will take that array, grab its class (tossing the created array aside), get the component type from that, and then use that to make a new array.
There is another one, too: toArray(IntFunction<T[]> arrayCreator) (you need to look at the javadoc of Collection to see it; it is inherited).
Here we ask the caller to provide code that makes a new array. You use it like this: listOfStrings.toArray(String[]::new).
Pick your poison, or add both. Either trick will work here:
public T[][] getArrayOfBlocks(T[] dummy) {
Class<?> componentType = dummy.getClass().getComponentType();
#SuppressWarnings("unchecked")
T[][] arr = (T[][]) java.lang.reflect.Array.newInstance(componentType, this.nNodes, this.arraySize);
.. code continues here ..
}
or:
public T[][] getArrayOfBlocks(BiFunction<Integer, Integer, T[][]> arrayMaker) {
T[][] arr = arrayMaker.apply(this.nNodes, this.arraySize);
.. code continues here ..
}
Yes, they are both annoying. There are other options but they have significant downsides - the above 2 options are your best bet. That or forget about arrays. Why do you even want a `T[][]` in the first place? Arrays can't grow or shrink, assuming it's not a primitive array (and this isn't, by definition; generics cannot be primitive) they are not more performant, and their toString/equals/hashCode implementations are surprising (that's programmer-ese for 'basically broken'). Their API is non-existent. Why would you want to offer it?
1) In case you desire explanations for this one: It's because the toArray code is hotspot intrinsiced and knows it doesn't need to wipe out the memory space, whereas with `new String[100]`, those 100 references all need to be nulled out first because java guarantees you can't 'see' uninitialized memory.

Vararg initialization with parameters from array (Java)

Antescript: I'm aware that there's a prior SO question whose title sounds like it refers to the exact same question. It doesn't.
Anyway, this question is a little weird - there are plenty of better ways to work around the issues here, but I'm curious as to how I could solve my particular dilemma.
Let's say I have a method that uses varargs to accept an arbitrary number of elements, perhaps of type Integer. If I have an arbitrary-length array of Integers, is there a way for me to call my method with a comma-separated param list composed of each element of said array?
Here's a brief, contrived example:
Integer[] paramList = new Integer {1, 2, 3};
varMethod(paramList[0], paramList[1], paramList[2]);
// varMethod({{for (param : paramList) {param;}}});
public void varMethod(Integer...values) {
for (Integer value : values) {
foo(value);
}
}
That commented-out line hints at what I want to do. Since the paramList integer is arbitrary length, calling varMethod with each element explicitly requested (line 2) won't work. What I'm wondering is if there's a way to dynamically generate the comma-separated param list from the elements of an array.
Again, I realize that in an example like this, there are better ways to approach the entire problem, but please be aware that I've simplified the code so that it's only relevant to the particular issue we're discussing here. Any workarounds that address my posted code won't generalize to the problem I'm really working on that led me to formulate this question in the first place.
I think you're just looking for:
varMethod(paramList);
Perhaps you didn't realize that Integer... is a special variant of a normal Integer[] array. Thus since paramList is already an Integer[] array, you can just pass it directly into the method.
You can just call
varMethod(paramList);

Java - It's possible add an int and an String in the array?

It's possible add an int and an String in the array ? I said in the same array.
No, Java is a strongly-typed language. So you cannot add a String and an int to the same array if the array is typed as either String or int.
However if your array is typed as Object, you can add a String and an Integer (an integer literal will be autoboxed) to that same array. This is not recommended and is probably a sign that you should think more about your design. The first question you need to ask yourself is why you need to do this. If you do have a valid reason, then it would be better to convert from one to the other instead of having an array typed as Object.
Having a catch-call array where you can shove in any object in a bad idea for many reasons:
You are enforcing no separation between the objects. Are the objects actually related to each other? If so you type then using an interface or create an abstract class that each of the types extend.
Since you have no separation between the objects, anything you pull out of the array is an Object. How would you know what it is? You need to inspect its type explicitly. This is an extremely cumbersome and unmaintainable design.
You essentially end up losing type-safety and will not be able to benefit from type-mismatch errors that will show up during compilation. This will hide possible errors in your code where you may have forgotten to inspect the type, or where you are casting an object to the wrong type. This can lead to all kinds of nightmarish bugs.
Your code is going to be littered with explicit checks and casts and will be unmaintainable (by you or anyone else).
Your code leaks abstraction everywhere. No one can look at the array and realize what the array contains. Anyone who uses your code needs to remember an overwhelming amount of detail as to what types of objects the array can contain.
Obfuscation is never a valid reason. Code should be clear, easy to read, easy to maintain, and easy to understand (for you and for anyone else who will read your code). Any code that looks obfuscated or is "clever" either needs to be rewritten or documented extensively to explain the reason for its "cleverness". As far as obfuscating the source, it is a non-issue since you're going to be distributing the .class files anyway. You can run that through a decompiler to look at the source code. There is nothing you can do at the source level to satisfactorily obfuscate your code; you're only going to make it difficult for you or anyone else to maintain. Obfuscation can be done at the byte-code level and so that doesn't really apply to this situation.
Yes it is possible, but it is not good practice.
Object[] myObjects = new Object[] {array1[i], array2[i], "name1", value1, value2, "name2", value1, value....};
It must be array of objects
Strictly speaking: No.
Otherwise: Yes for most practical purposes:
Object[] array = { 42, "foo" };
Please note, that the 42 is not an int but an `IntegerĀ“. But due to autoboxing and unboxing you wont notice the difference. The tradeoff is of course performance and garbage collector overhead.
Also the array must be of type Object[], not of type String[] nor of type int[].
In your string array you could have "123" and then convert it to an int later when you need it.
You can't add a primitive types (including int) to an array with Objects such as String. However, autoboxing of int to Integer will make this possible if you declare an Object[] array.
Object[] array = new Object[2];
array[0] = "Hello";
array[1] = 42;
Though I wouldn't recommend doing this if modeling this String and int as attributes of a class would work.
You can use java.util.ArrayList to do this. You will need to make sure that you check carefully what you are getting when you pull items out though.
Yes it definitely is possible, just have an array of raw objects.
For example:
Object[] arr = new Object[10];
arr[0] = 10; // boxed to Integer class
arr[1] = "foo"; // String class
Then you can use instanceof to determine the type of object stored at a particular index.
For example:
if (arr[0] instanceof Integer) ((Integer) arr[0]) += 10;
Note that this is not necessarily a good practise to get used to, but it does have applications.

code factory method

I want to create something I can only describe as a "code factory method".
To avoid code repetition, I want to create a method which contains the code to be executed, but with "placeholders" where the types are supposed to go. The method would of course take these types as parameters and place each one in its appropriate spot. For example:
void factory(placeholder1, placeholder2){
ArrayList<placeholder1> List = new ArrayList<placeholder1>;
Placeholder2 variable;
}
factory(String, Integer);
would yield:
ArrayList<String> List = new ArrayList<String>;
Integer variable;
any ideas how I would go about this?
Your help is much appreciated.
EDIT: Thank you for all the feedback. I was going with the generic approach and it was working for awhile until I came across what I believe someone mentioned earlier. I want to use one of the methods within one of the generic objects like:
Integer variable = new Integer();
variable.isInteger();
It doesn't appear that I will be able to do this using generics. Is there possibly a workaround to this?
Rather than simply adopting generics, it looks like you want some sort of macro facility. Java doesn't have that. For example, to expand your example a bit, you couldn't do anything like this:
factory(String, Integer);
List.get(variable);
Here's how it would look:
<placeholder1, placeholder2> void factory(){
ArrayList<placeholder1> List = new ArrayList<placeholder1>;
placeholder2 variable;
}
this.<String, Integer> factory();
But I agree with matt that you should read up on generics. Also, be cautious of type-erasure as this might not do everything you expect.

Casting an array of Objects into an array of my intended class

Just for review, can someone quickly explain what prevents this from working (on compile):
private HashSet data;
...
public DataObject[] getDataObjects( )
{
return (DataObject[]) data.toArray();
}
...and what makes this the way that DOES work:
public DataObject[] getDataObjects( )
{
return (DataObject[]) data.toArray( new DataObject[ Data.size() ] );
}
I'm not clear on the mechanism at work with casting (or whatever it is) that makes this so.
Because toArray() creates an array of Object, and you can't make Object[] into DataObject[] just by casting it. toArray(DataObject[]) creates an array of DataObject.
And yes, it is a shortcoming of the Collections class and the way Generics were shoehorned into Java. You'd expect that Collection<E>.toArray() could return an array of E, but it doesn't.
Interesting thing about the toArray(DataObject[]) call: you don't have to make the "a" array big enough, so you can call it with toArray(new DataObject[0]) if you like.
Calling it like toArray(new DateObject[0]) is actually better if you use .length later to get the array length. if the initial length was large and the same array object you passed was returned then you may face NullPointerExceptions later
I asked a question earlier about Java generics, and was pointed to this FAQ that was very helpful: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
To ensure type safety when casting an array like you intended (DataObject[] dataArray = (DataObject[]) objectArray;), the JVM would have to inspect every single object in the array, so it's not actually a simple operation like a type cast. I think that's why you have to pass the array instance, which the toArray() operation then fills.
After Java 8 with introduction of streams and Lambda you can do the following too:
For casting a normal Array of objects
Stream.of(dataArray).toArray(DataObject[]::new);
For casting a List
dataList.stream().toArray(DataObject[]::new);

Categories