I was going through java source code for ArrayList i came across below code
#SuppressWarnings("unchecked")
private E[] newElementArray(int size) {
return (E[]) new Object[size];
}
Here we trying to cast object[] to any E which we use when we declare Array List.
So i wrote code to test this as below :
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
class A {
}
class CheckBox extends A {
}
public class Box<T> {
public T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> box = new Box<Integer>();
List<Integer> intList = new ArrayList<Integer>();
box.newElementArray(10);
Box[] a = (Box[]) new Object[10];
}
// prefer wild card as it does not allow to corrupt your data types
public void wildCard(Set<?> test) {
test.add(null);
}
private T[] newElementArray(int size) {
System.out.println(" casting object to t");
return (T[]) new Object[size];
}
}
Surprisingly line box.newElementArray(10); works fine but
Box[] a = (Box[]) new Object[10];
does not work , though both do same thing. Can anybody let me know what could be reason behind it or my understanding is wrong?
Because of type erasure, Java compiler replaces E with Object. So the method newElementArray(int size) becomes
private Object[] newElementArray(int size) {
return (Object[]) new Object[size];
}
which makes its invocation successful.
You can refer to http://docs.oracle.com/javase/tutorial/java/generics/genMethods.html for the details.
Related
Please explain to me why I have one example that compiles and the other one doesn't compile
This is example that compiles
import java.util.ArrayList;
public class MyClass1 <T> {
public ArrayList<MyClass1<?>> lst;
public MyClass1()
{
lst = new ArrayList<MyClass1<?>>();
}
public static void main(String[] args) {
M(new MyClass1<Double>());
}
public static <T1> void M(MyClass1<T1> t1)
{
var d0 = new MyClass1<Double>();
d0.lst.add(t1);
}
}
But that doesn't compiles
import java.util.ArrayList;
public class MyClass1 <T> {
public ArrayList<?> lst;
public MyClass1()
{
}
public static void main(String[] args) {
M(Double.valueOf(1.1));
}
public static <T1> void M(T1 t1)
{
var d0 = new MyClass1<Double>();
d0.lst.add(t1); // error — java: incompatible types: T1 cannot be converted to capture#1 of ?
}
}
Why in the first case I have wildcard, and everything is OK, but in the second case I have wildcard and it doesn't compile
The second snippet can not be compiled because the generics in Java are about type safety(type guarantee). Thus, if we are declearing List<Integer> the compiler is convinced, that the list will contain only integers. But when we have List<?> (read this like list of some type), compiler cant predict what will the list contain. Today we are adding Integers, tomorrow somebody else will add a ServerSocket. In runtime if we will try to get a value from such a list, we will get a ClassCastException. That is why this code cant even be compiled - to prevent such situations. Read about type erasure and bridge methods.
In your concrete case, i guess, you would like to have something like this:
public class MyClass<T> {
public ArrayList<T> lst;
public static void main(String[] args) {
var obj = new MyClass<Double>();
obj.foo(1.1);
}
public void foo(T s) {
lst.add(s);
}
}
The question mark also can be useful:
static void m(List<? extends Shape> list) {
for (Shape el : list) {
// we are not quite interested what type is this list of.
}
}
And the usage example:
m(new ArrayList<Circle>());
m(new ArrayList<Shape>());
I hava some problems with my code.
First of all I have an interface:
public interface Generator <T, R> {
public T next (R x);
}
Then, I have created the class "DemoClass"
public class DemoClass {
private int id;
public DemoClass (int id){
this.id = id;
}
}
And... Generic Class as well
public class GenericClass implements Generator <DemoClass, Integer> {
public DemoClass next(Integer x) {
return new DemoClass (x);
}
}
After, I have created Main Class and a generic static method that containts a method like Class . I would like to know, is there any opportunity to use such construction like Class ???
My MainClass
import java.util.*;
public class MainClass {
private static Random rand = new Random ();
public static <T> T [] arr (T [] a, Class <?> typeToken){
try{
Generator <?, ?> gen = (Generator <?, ?>)typeToken.newInstance(); // How can I pass two paramets to Generator <?, ?>???
for (int i=0; i!=a.length; i++){
a[i] = (T) gen.next(rand.nextInt(100)); // This line does not work!
}
} catch (Exception e){
throw new RuntimeException (e);
}
return a;
}
public static void main (String [] args){
DemoClass [] myarr = arr (new DemoClass[10], GenericClass.class);
}
}
If you want to make that line work, you could do this:
public static <T> T[] arr(T[] a, Class<? extends Generator<T, Integer>> typeToken) {
try {
Generator<T, Integer> gen = typeToken.newInstance();
for (int i = 0; i != a.length; i++) {
a[i] = gen.next(rand.nextInt(100));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return a;
}
Basically, the bound on Class makes it so that what is returned by newInstance is a Generator<T, Integer>.
How can I pass two paramets to Generator ???
There is no need to pass any type parameters. Since Java generics use erasure, the concrete generic type arguments are not needed at runtime.
If you are using Java 8, I would suggest using a Supplier instead of a Class, since it allows you to create an instance without having to deal with the exceptions:
public static <T> T[] arr(T[] a, Supplier<? extends Generator<T, Integer>> typeToken) {
Generator<T, Integer> gen = typeToken.get();
for (int i = 0; i != a.length; i++) {
a[i] = gen.next(rand.nextInt(100));
}
return a;
}
...
// passing reference to constructor of GenericClass
DemoClass[] myarr = arr(new DemoClass[10], GenericClass::new);
No.
Generics work at compile time only. At runtime, all of the instances of class are exactly the same, the information of the parametrized types gone.
This is known as type erasure and it was designed that way to ensure that Java 1.4 binaries were compatible with Java 5 VM.
You can get a lot of info about this by searching "type erasure java" in the search box; for example Avoiding Java Type Erasure
I found a way to create generic array inline with varargs and anonymous inner class:
import java.util.Arrays;
import java.util.Objects;
public class GenericArrayCreate<C> {
public void method() {
C[] ans = new Object() { C[] c(int length, C ... cs) { return Arrays.copyOf(cs, length); }}.c(10);
System.out.println(ans.length);
System.out.println(Objects.toString(ans));
}
public static void main(String[] args) {
new GenericArrayCreate<Class<? extends Integer>>().method();
}
}
Java compiler produces no any warning on this code, while code inspection (in IntelliJ) says:
Unchecked generics array creation for varargs parameter
What is happening here and why is it swearing?
Internally you are creating an array of "Object" instead of a array of "C"
Try this code :
public static <C> C[] method(int number) {
return new Object() {
C[] create(int length, C ... cs) {
return Arrays.copyOf(cs, length);
}
}.create(number);
}
public static void main(String[] args) {
System.out.println(Main.<Integer>method(10));
System.out.println(new Integer[10]);
}
[Ljava.lang.Object;#6bc7c054
[Ljava.lang.Integer;#232204a1
As you can see they are not the same.
It is dangerous because if you run something like these:
public static void main(String[] args) {
Integer[] integerArray1 = Main.<Integer>method(10);
Integer[] integerArray2 = new Integer[10];
}
And you will have a ClassCastException
[Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer
If you want to create any kind of array you need to send the class to construct the array, you can do it like this:
public static <C> C[] method(Class<C> clazz, int number) {
return (C[]) Array.newInstance(clazz, number);
}
public static void main(String[] args) {
Integer[] integerArray1 = Main.<Integer>method(Integer.class, 10);
Integer[] integerArray2 = new Integer[10];
}
Code inspection will note that because varargs are implemented with array, and array do not support generics. But you can suppress that warning by adding this:
#SuppressWarnings("unchecked")
Reason why this happens is it can lead to loss of information. You can read more about that here.
I am currently trying to learn how to use Generics from a book. In this chapter it says to take a piece of data T and convert it to an integer. I am trying different things in Eclipse, but none of them seem to allow this. How could you perform the following task:
LinkedList<T> arr = new LinkedList<T>();
Float fl = 8.74273123948;
arr.add(fl);
Then in another class:
public int findValue(Node node)
{
T data = node.data;
int value = Number.valueOf(data);
return value;
}
I have tried using .valueOf() and (int) among a few other things and nothing seems to satiate Java. The book insists on keeping the method generic in case floats or doubles were used instead of strings or ints.
EDIT: For other people that might have a similar question. Gleaned from all the comments to this question and the answer that was accepted:
use the .toString() on the data and then parse it as you need to whichever data type you need.
Hmm, that is an odd book. I'll try to tell you the gist of it based on what I know.
Generics are a construct that allow you compile-time check of whether a type you are trying to use in a specific collection, method, or class is actually something that knows the functionality that is necessary for that specific thing to function.
For example, you need to use the function determined by the interface called SearchParameter in your template, but you only see the <T> parameter as an object. Or maybe a better example in your case would be a custom interface called IntegerConvert like so:
public interface IntegerConvert
{
Integer returnAsInteger();
}
And you could have a class like this:
public class MyData implements IntegerConvert
{
private String data;
public MyData(String data)
{
this.data = data;
}
#Override
public Integer returnAsInteger()
{
return Integer.parseInt(data); //throws ParseException if it doesn't work
}
}
And then you could have a List of these like this:
List<IntegerConvert> listOfConvertibles = new ArrayList<IntegerConvert>();
or if you want to go a bit more generic for the future,
List<? extends IntegerConvert> listOfConvertibles = new ArrayList<IntegerConvert>();
and then you can do
listOfConvertibles.add("25");
listOfConvertibles.add("40");
listOfConvertibles.add("35");
for(IntegerConvert ic : listOfConvertibles)
{
System.out.println("" + ic.returnAsInteger());
}
Although that was a bit of an overcomplicated example, I guess. A simpler example would be the following:
public class Node<E>
{
private E data;
public Node(E e)
{
this.data = e;
}
public E getData()
{
return data;
}
public void setData(E e)
{
data = e;
}
public void print()
{
System.out.println(data.toString());
}
}
public class MyClass
{
public void doSomething()
{
List<Node<Float>> listOfFloatNodes = new ArrayList<Node<Float>>();
listOfFloatNodes.add(new Node<Float>(new Float(8.7472742f)));
listOfFloatNodes.add(new Node<Float>(new Float(5.56842742f)));
listOfFloatNodes.add(new Node<Float>(new Float(6.5467742f)));
MyOtherClass moc = new MyOtherClass();
moc.useNodeList(listOfFloatNodes);
}
}
public class MyOtherClass
{
public <E> void useNodeList(List<Node<E>> list)
{
for(Node<E> node : list)
{
printNode(node);
}
}
public <E> void printNode(Node<E> node)
{
node.print();
}
}
public class MainClass
{
public static void main(String[] args)
{
MyClass myClass = new MyClass();
myClass.doSomething();
}
}
If you have any questions, comment.
try to observe below examples:
public static void main(String[] args) {
test0("13");
test0(new Integer(13));
test1();
System.out.println(findValue(new Node("10")));
}
private static <T> void test0(T a) {
LinkedList<T> arr = new LinkedList<T>();
arr.add((T) a);
System.out.println(arr.getFirst());
}
private static <T> void test1() {
LinkedList<T> arr = new LinkedList<T>();
arr.add((T) new Integer(13));
System.out.println(arr.getFirst());
}
public static <T> int findValue(Node node) {
T data = (T) node.data;
int value = Integer.valueOf(data.toString());
return value;
}
where Node is :
public class Node {
//this should be private
public String data;
public Node(String data) {
this.data = data;
}
//use getter below to access private data
public String getData() {
return data;
}
}
all this is possible because, unchecked casts from a known type to T is allowed (of course with warnings) and compiler believes you for the casting.
Answer not entirely on the topic albeit closely related. I had a problem and didn't find the answer. Then I found solution and thought I'd share:
I was trying to cast generic value to primitive type:
<TYPE> boolean equal(TYPE val, Class<?> type) {
if (float.class == type) {
float val2 = (float) val; // incompatible types: TYPE cannot be converted to float
float val3 = (float) (Object) val; // works
...
Long story short: first version doesn't work and the second does. Quite annoying.
I have the following class which stores a list of object arrays.
public class Test {
private List<Object[]> list = new ArrayList<Object[]>();
public void addList(Object... obj) {
list.add(obj);
}
public void addList(List<Object> lst) {
list.add(lst.toArray());
}
}
When I call the following, the overloaded method addList(Object... obj) is called but I want the addList(List<Object> lst) to be called. How can I do this?
public class Main {
public static void main(String[] args) {
Test testObj = new Test();
List<String> myStrings = new ArrayList<String>();
myStrings.add("string 1");
myStrings.add("string 2");
myStrings.add("string 3");
// The variable argument method is called but this is a list!
testObj.addList(myStrings);
}
}
Change List<Object> to List<?> to capture lists of any type of object. I tried this and it printed "in List":
import java.util.ArrayList;
import java.util.List;
public class Test {
private List<Object[]> list = new ArrayList<Object[]>();
public void addList(Object... obj) {
System.out.println("in object");
list.add(obj);
}
public void addList(List<?> lst) {
System.out.println("in List<?>");
list.add(lst.toArray());
}
public static void main(String[] args) {
Test testObj = new Test();
List<String> myStrings = new ArrayList<String>();
myStrings.add("string 1");
myStrings.add("string 2");
myStrings.add("string 3");
// The variable argument method is called but this is a list!
testObj.addList(myStrings);
}
}
It's problem of Java Generic. You cannot assign List<String> to List<Object>.
See also: Java Reference assignment with generic lists
Rewrite the type of you non-variadic method to use a wildcard:
public void addList(List<?> lst) {
list.add(lst.toArray());
}
Then List<String> will be a subtype of the parameter type.
List<String> is not a subclass of List<Object>. So that overload will never be called, even if you remove the ... variant.
Change your method to
public void addList(List<?> lst) {
list.add(lst.toArray());
}