Java Method using generic parameter? - java

I am new to Java and writing a method for a generic Linked List that accepts another Linked List as a parameter. As I understand, this new Linked List should be of the same type as the Linked List calling the method.
So, instead of
public void insertList(MyLinkedList<AnyType> otherList, int idx) {
I should be specifying the type of otherList to match the list that calls insertList()?
list.insertList(MyLinkedList<???>, 0);
How would I do this if I don't know the type of list, since it's generic, but know that otherList needs to be the same type? I hope that makes sense. As I mentioned, I am new to Java, so if I am misunderstanding generics, please correct me. Thank you.

I am inferring that you are writing your own linked list and that your declaration looks something like this:
class MyLinkedList<T> {
…
If so, the <T> means that your class has a generic type variable, T, that represents the type of the list's elements.
Given that, the insert method could look something like this:
void insertList(List<? extends T> list, int index) {
/* Count links to find the insertion point */
/* Remember the link that used to follow */
…
for(T obj : list) {
/* Create link for obj and link it to previous */
/* Update previous */
…
}
/* Attach the old link you remembered to previous */
…
}
Here, ? extends T means that you accept anything that extends the generic type of your list.
There's no need to require the collection of inserted elements to be MyLinkedList, or even List—it could be any type of collection that you could iterate.

For what I understand you have sue that the object passed to the function will be a LinkedList, even if you did not know you could make use of 'instanceof' to test if the object is an instance of some type, after you can make use of "cast" resources to "transform" an generic object to another type.
Se the code bellow and adapt for your use.
public static void main(String[] args) {
List<Banana> lista = new LinkedList<Banana>();
testingAndCastingSomeObject(lista);
}
/**
* This method will receive a generic object and test if it is a LinkedList, if it is it will cast the object "transforming" it in a LinkedList
* Afte this I can make what I want
* #param object
*/
static void testingAndCastingSomeObject(Object object) {
LinkedList<?> test = null;
if(object instanceof LinkedList<?>) {
test = (LinkedList<?>) object;
}
//If the List is not empty and the first objetct is a Banana I can cast it too
if(!test.isEmpty() && test.get(0) instanceof Banana ) {
Banana banana = (Banana) test.get(0);
System.out.println("Here is my banana: " +banana);
}
}
public class Banana{
//Banana members and methods
}

Related

Passing in type of elements in collection to a function which initialises an ArrayList (Java)?

I would like a function which takes in a parameter that then sets E in the ArrayList where E is the type of elements in this collection. So the simplest code showing what I want to do is as such, where E is what I don't know.
private void createArray(E dataType) {
ArrayList<dataType> list = (ArrayList<dataType>) message.getArray();
}
Is this at all possible? I tried to find an answer by looking at the ArrayList class but I don't have much experience with Java.
Edit:
I am not sure if my question is clear enough... I don't need to pass the variable dataType. I need the variable dataType to be what goes into <> when I do the line where I initialise the ArrayList. I have found the following answer: Pass class type as parameter to use in ArrayList? but it doesn't really work for me. I need to use the elements in the arraylist and call a method which only applies to that class...
private <T> void createModel(String SQLcomm, Class<T> dataType, DefaultTableModel table) {
Parcel parc = SQLtask(SQLcomm, "array");
ArrayList<T> list = (ArrayList<T>) parc.getData();
for (T t: list) {
Vector<Object> newRow = t.getinfo(); //can't do t.getinfo()?
table.addRow(newRow);
}
An array isn't an ArrayList. But you can use something that method:
If you have an array you can use:
Arrays.asList(array);
Otherwise:
List<E> list = new ArrayList<>();
list.add(element);
I hope this answers your question.
Sure it's "possible" - you can write:
private <E> void createArray(E dataType) {
ArrayList<E> list = (ArrayList<E>) message.getArray();
}
You can, but you have to pass the data type as a class parameter, this is called genericity in java (for more info on genericity, here is a link to the official java doc)
Example :
// E your data type
public class A<E> {
//Maybe you get data from database (ResultSet)
public void createArray(ResultSet message, String index) throws SQLException {
ArrayList<E> list = (ArrayList<E>) message.getArray(index);
//the rest of the code...
}
}
For more info on handling arrays here is the official doc.

Generic list conversion to an array

Assuming that I have the following class
public class A <T>{
private T [] datas;
// more code here ...
}
And I desire to take advantage of the constructor to initialize the array. Suppose that I have the following constructor
public A(T element){....}
Java does not allow me to use something like
datas = new T[10]
And it will complain that I cannot create a generic array of T
But I can still use a work around like:
#SuppressWarnings("unchecked")
public A(T element){
List<T> datasList = new ArrayList<T>();
datasList.add(element);
datas =(T[]) datasList.toArray();
}
I have a warning from the compiler that's why I had to add the #SuppressWarnings, but my point is related to the following comment from the toArray method documentation (Please take a look at the picture)
It talks about the returned array being safe. So does that means it is safe to use this method? If not why? And what would be a better way to do such an initialisation in a constructor? I would like to also consider the case of a variable list of T elements in an overloaded constructor like
public A(T... elements){....}.
You can create an instance of a generic array using the following:
public A(T element){
int length = 10;
datas = (T[])Array.newInstance(element.getClass(), length);
}
However, there's a problem if element would be a subclass of T, e.g. if you'd call it like this:
A<Number> numberA = new A<>( Integer.valueOf(1) );
Here T would be Number but the class of element would be Integer.
To mitigate that you could pass a vararg array of type T, e.g. like this:
//firstElement only exists to force the caller to provide at least one element
//if you don't want this then just use the varargs array
A(T firstElement, T... furtherElements){
int length = 10;
Class<?> elementClass = furtherElements.getClass().getComponentType();
datas = (T[])Array.newInstance( elementClass, length);
}
Since varargs always result in an array (even of length 0) you'll get an array of type T and can get the component type of that.
So in the case above numberA.datas would be a Number[] array and not an Integer[] array.
You can pass generics, but you can't call new T (or new T[ ]).
Keep in mind that generics are gone after compilation, so it actually only helps when writing the code. Knowing it's gone during runtime, it's also obvious that new T( ) can't be called as generic, T is removed in runtime.
It's safe to do, because you create that list in full control, accepting only objects of your generic type.
A nicer way (imho) is to create a static method as it is purely input-->output. You have to declare your generics before the method return type:
public < T > T[ ] toArray(T... objects) { ... }

Map a generic method over a list and produce list of results

I have a generic method (called map) which takes a parameter of type Funcn where Funcn<K,T> is an interface having only one method, T eval(K), which takes a K and returns a T. In map, I need use the Funcn to iterate through a List<K> (which is defined in the main method — I use this in the map to access it) and apply the Funcn to each element in the list. Finally, a new List<T> of all the results of eval should be returned. However, I am not sure how this can be done, since I am unfamiliar with the syntax of generics.
/// the Funcn interface ///
package arrayList;
import java.util.*;
public interface Funcn <K,T> {
public T eval(K k);
}
/// the generic map method(in its own class) ///
public java.util.ArrayList<T> map(Funcn<T,K> fn){
for(T value:this){
//fn must be applied to all elements in 'this'
}
}
The problem in your code
In your code, the interface Funcn<K,T> declares a method eval that takes a K as an argument and returns a T. Note that K is the first type parameter and T is the second.
public interface Funcn <K,T> {
public T eval(K k);
}
In the declaration of your map method, though, you've got the type parameters to your Funcn reversed:
public java.util.ArrayList<T> map(Funcn<T,K> fn){ /* … */ }
// * *
This means that fn.eval takes a T and returns a K. Instead, it should be Funcn<K,T> fn so that fn.eval takes a K and returns a T. This would explain the error message that you mentioned in a comment: "The method apply(K) in the type Function<T,K> is not applicable for the arguments (T)" (It wouldn't explain why you've got Function in one place and Funcn in another, though. Are you showing us the real code?)
In general
Swapping the order of those arguments will solve your immediate problem, but in general the type parameters are a little bit more complicated. It's tricky to get the input and output types for these generic functions exactly right, since you should be able map a function that expects an argument of type C over a list whose elements are of a subtype of C. The comments in the code explain this in a bit more detail.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MapExample {
/**
* A Function maps an input to an output.
*/
interface Function<InputType,OutputType> {
OutputType call( InputType input );
}
/**
* Map returns a list of elements obtained by applying the function
* to each element of the input list. The input and output types
* of the function do not need to align exactly with the type of
* elements in the input list; but the function's input type must
* be some supertype of the element type of the input list. Similarly,
* the output type of the function does not need to be the element type
* of the output list; but it must extend that type so that the result
* of the function can be stored in the output list.
*/
public static <OutputType,InputType> List<OutputType> map(
final Function<? super InputType,? extends OutputType> function,
final List<? extends InputType> list ) {
final List<OutputType> results = new ArrayList<>( list.size() );
for ( InputType in : list ) {
results.add( function.call( in ));
}
return results;
}
public static void main(String[] args) {
// f takes an integer n to the string "*<n+1>*" (where <n+1> is the value of n+1).
Function<Integer,String> f = new Function<Integer, String>() {
#Override
public String call(Integer input) {
return "*"+new Integer( input + 1 ).toString()+"*";
}
};
System.out.println( map( f, Arrays.asList( 1, 3, 6, 8 )));
}
}
The output is:
[*2*, *4*, *7*, *9*]
(Optional) A case for instance initializers
As an aside, I find that some of these functional problems are nice places to use instance initialization blocks in objects. While the implementation above creates the results list, then populates, and then returns it, you could also have the body of map be:
return new ArrayList<OutputType>( list.size() ) {{
for ( final InputType in : list ) {
add( function.call( in ));
}
}};
which I kind of like, although you'll get a warning about the fact that the new (anonymous) class doesn't have a serialization ID, so you'd either need to #SuppressWarnings("serial") on the map method, or add an ID to the class. Those might not be so desirable, though. There are other issues with this kind of object too, though, as discussed in Efficiency of Java "Double Brace Initialization"?.
I assume that T is the input of Funcn, and K the return type of it. It then has to return a list of K to work, else the generic signature of Funcn is useless.
public java.util.ArrayList<K> map(Funcn<T,K> fn){
ArrayList<K> lst = new ArrayList<K>();
for(T value:this){
lst.add( fn.eval(value) );
}
return lst;
}

I'm studying Head First Java, but I can't understand Page 544

"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);

Can an ArrayList of Node contain non-Node type?

Can an ArrayList of Node contain a non-Node type?
Is there a very dirty method of doing this with type casting?
Yes, but you will get class cast exceptions if you try to access a non-node element as if it were a node. Generics are discarded at (for) runtime.
For example:
import java.util.*;
import java.awt.Rectangle;
public class test {
public static void main(String args[]) {
List<Rectangle> list = new ArrayList<Rectangle>();
/* Evil hack */
List lst = (List)list;
/* Works */
lst.add("Test");
/* Works, and prints "Test" */
for(Object o: lst) {
System.err.println(o);
}
/* Dies horribly due to implicitly casting "Test" to a Rectangle */
for(Rectangle r: list) {
System.err.println(r);
}
}
}
Given:
List<Node> nodelist = new ArrayList<Node>();
Object toAdd = new Object();
then:
((List) nodelist).add(toAdd);
or
((List<Object>) nodelist).add(toAdd);
will do the hack. Ick. I feel dirty. But, you should not do this. If you really need to mix types, then do this:
List<Object> mixedList = new ArrayList<Object>(list);
mixedList.add(toAdd);
That solution, at least, will indicate to others that they have to beware that any subclass of Object can be in the list.
Assuming you are using Generic to have an ArrayList, you can add non-Node into it by using reflection because during runtime the type information is not kept.
Depend on how you get the object out of the ArrayList, you might get hit by ClassCastException.
If you really have a need on non-specific type in your ArrayList, then why don't you just use it without Generic?

Categories