I'm trying to create a genetic ArrayList of my class Team but I can't cast Comparable to T despite that T extends Comparable
(I tried extends Comparable without putting < T > and same problem is happening)
public class ArrayList<T extends Comparable>
{
static int MaxSize = 1003;//some random maximum size for our array lists
public int Size = 0;
public int Capacity = 0;
T[] MyList;
public ArrayList()//Default Constructor
{
this(MaxSize);
}
public ArrayList(int Capacity)
{
MyList = (T[]) new Comparable[Capacity]; // Casting
}
}
public class Team implements Comparable<Team>
{
public String Name;
public int Points;
public int GamesCount;
public int Wins;
public int Loses;
public int GoalDifference;//Goals Scored - Goals Against
public int GoalsScored;
public int GoalsAgainst;
public Team(String s)
{
Name = s;
Points = 0;
GamesCount = 0;
Wins = Loses = 0;
GoalDifference = GoalsAgainst = GoalsScored = 0;
}
}
public class Test
{
public static void main(String args[])
{
ArrayList<Team> Teams = new ArrayList<Team>(10);
for(int i = 0 ;i < 10;i++)
{
String TeamName = in.next();
Teams.MyList[i] = new Team(TeamName);//exception here
}
}
}
I am getting the following exception. Many thanks in advance for your help.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Comparable; cannot be cast to [LTeam;
at Test.main(Test.java:21)
That's obvious, just think about it for a second.
new Comparable[Capacity];
Here you're creating an array which will contain Comparable elements.
Then you're trying to downcast it to an array of Team, which means trying to use a more specific type, and which is not allowed (Upcasting and downcasting in Java), and as you see, throws a ClassCastException.
As your array will contain only types which extends Comparable, you can have a Comparable array inside your ArrayList implementation.
Comparable[] MyList;
Then you can initialize it without casting
MyList = new Comparable[Capacity];
And remember to implement the Comparable#compareTo method in your Team class, otherwise the code won't compile.
You asked for an example.
public class ArrayList<T extends Comparable> {
private static final int MAX_SIZE = 1000;
private final Comparable<T>[] list;
public ArrayList() {
this(MAX_SIZE);
}
public ArrayList(int capacity) {
list = new Comparable[capacity]; // Casting
}
public T get(final int index) {
return (T) list[index];
}
public void set(final int index, final T value) {
list[index] = value;
}
}
Usage is pretty simple
final ArrayList<Team> teamArrayList = new ArrayList<>(3);
teamArrayList.set(0, new Team("One"));
teamArrayList.set(1, new Team("Two"));
teamArrayList.set(2, new Team("Three"));
final String name = teamArrayList.get(0).Name;
As you extended the Comparable<T> interface, you need to implement it
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object
A basic example is
#Override
public int compareTo(final Team other) {
return name.compareTo(other.name);
}
In your code, T is Team.
Team IS-A Comparable. Hence, you can cast Team to Comparable.
But every Comparable is not a Team. Therefore, Comparable cannot be cast to Team.
watch this statement: MyList = (T[]) new Comparable[Capacity]; it initializes an array from Comparable interface and put it in to MyList field with type of Team[].
you can test it with:
{
MyList = (T[]) new Comparable[Capacity]; // Casting
System.out.println( MyList.getClass().toString());
}
it writes class [Ljava.lang.Comparable; in output... so in the first attempt to access this field from outside of class you will get ClassCastException even by calling length in test method like this:
public class Test
{
public static void main(String args[])
{
MArrayList<Team> Teams = new MArrayList<Team>(10);
int length = Teams.MyList.length; // this line throws ClassCastException
....
}
}
To solve your problem I suggest change your ArrayList class like this:
public class ArrayList<T extends Comparable<T>>
{
...
Comparable<T>[] MyList;
...
public ArrayList(int Capacity)
{
MyList = new Comparable[Capacity]; // Casting
}
}
Related
In my Spring Boot app, I have the following methods:
public class ContainsIntegerFilter implements CsvToBeanFilter {
private final int index;
private final List<Integer> values; // list types are different (Integer)
public boolean allowLine(String[] line) {
return values.contains(Integer.parseInt(line[index]));
}
}
public class ContainsStringFilter implements CsvToBeanFilter {
private final int index;
private final List<String> values; // list types are different (String)
public boolean allowLine(String[] line) {
return values.contains(line[index]);
}
}
And calling these methods like this:
final CsvToBeanFilter filter = new ContainsIntegerFilter(0, idList);
I want to merge these methods into a single method using generics. But I am not sure if the following approach is the most proper way? Or should I use an interface and call that interface instead of the merged method:
public abstract class ContainsFilter<T> implements CsvToBeanFilter {
private final int index;
private final List<T> values;
public boolean allowLine(T[] line) {
return values.contains(line[index]);
}
}
So, how can achieve this?
In first approach, you are always passing String[] array as method arguments (both for string and int).
In second approach, you are passing T[] array which will change based on type T.
If you pass can String[] array in one case & Integer[] array in another as method arguments, you can use first one. That keeps code clean.
Update:
Sample code for second approach:
public class ContainsFilter<T> {
private final int index = 1;
private List<? extends Object> values1 = List.of("test1", "test2");
private List<? extends Object> values2 = List.of(1, 2);
public void allowLine(T[] line) {
System.out.println(values1.contains(line[index]));
System.out.println(values2.contains(line[index]));
}
public static void main(String[] args) {
String[] line1 = new String[] {"test111", "test2"};
Integer[] line2 = new Integer[] {1, 2};
ContainsFilter<String> c1 = new ContainsFilter<String>();
c1.allowLine(line1);
ContainsFilter<Integer> c2 = new ContainsFilter<Integer>();
c2.allowLine(line2);
}
}
I am having trouble with my code to add iterator support to ArrayList
this is the class i create to implement Iterator
class MyArrayListIterator<E> implements Iterator<E> {
private E[] list = null;
private int currentIndex = 0;
#Override
public boolean hasNext() {
if (currentIndex < list.length) {
return true;
} else {
return false;
}
}
#Override
public E next(){
return list[currentIndex++];
}
}
This must include, which i think i did correct
"list" of type MyArrayList
"currentIndex" of type int, initially at zero
This is my main method for testing
public static void main(String[] args) throws Exception {
MyList<String> names = new MyArrayList<>();
names.add("Steve");
names.add("Frank");
names.add("Heather");
names.add("Chris");
names.add("Oliver");
for (String string : names) { // error at names Can only iterate over an array or an instance of java.lang.Iterable
System.out.println(string);
}
}
}
In the myArrayList i have added as the requirement is Make MyArrayList implement the Iterable interface by adding the iterator() method, which should return an instance of MyArrayListIterator.
public Iterator<E> iterator() {
return new MyArrayListIterator();
}
Please let me know what I am doing wrong.
As already mentioned in the comments, your problem is that you read from list in MyArrayListIterator without initializing it. This causes a NullPointerException.
You can fix this in two different ways:
Make MyArrayListIterator a non-static nested (they are also called inner classes) class of MyArrayList.
By doing so, you get access to all fields of the outer-class, which in this case is MyArrayList. For example, see this code snippet:
public class MyArrayList<E> implements MyList<E> {
private Object[] list = new Object[10];
private int size = 0;
public Iterator<E> iterator(){
return new MyArrayListIterator<>();
}
// more of your implementation...
// This is the inner class
private class MyArrayListIterator<T> implements Iterator<T> {
private int currentIndex = 0;
#Override
public boolean hasNext() {
// Since this is a inner class, we have access to the
// "list" field defined by MyArrayList.
return currentIndex < list.length;
}
#Override
public T next() {
// Since this is a inner class, we have access to the
// "list" field defined by MyArrayList.
return (T) list[currentIndex++];
}
}
}
Make MyArrayListIterator a static nested class or a separate class.
In this case, you don't have access to the fields defined in MyArrayList, which means you have to provide them yourself. This can be done using the constructor.
public class MyArrayList<E> implements MyList<E> {
private Object[] list = new Object[10];
private int size = 0;
public Iterator<E> iterator(){
return new MyArrayListIterator<>((E[])list);
}
// More of your list implementation
// This is a static inner class, which means we do not have access to
// the fields of the outer class.
private static class MyArrayListIterator<T> implements Iterator<T> {
private final T[] elements;
private int currentIndex = 0;
public MyArrayListIterator(T[] elements) {
this.elements = elements;
}
#Override
public boolean hasNext() {
// Since we got the elements as constructor argument, they are not
// null (assuming you did not call it with null as parameter).
return currentIndex < elements.length;
}
#Override
public T next() {
// Since we got the elements as constructor argument, they are not
// null (assuming you did not call it with null as parameter).
return elements[currentIndex++];
}
}
}
For more information on nested classes, see this tutorial by Oracle on nested classes.
Is it possible to create a generic class with empty constructor?
To something like this:
public class ArrayListGeneric1<T> {
private int capacity;
private int size;
private T [] array;
public ArrayListGeneric1() {
capacity = 1;
array = Array.newInstance(T.getClass(), capacity); //Cannot get the class for T
size = 0;
}
}
I can only find solutions where we need to pass an element
Is it possible to create a generic class with empty constructor?
Sure, do it without a generic array, just like ArrayList does:
public class ArrayListGeneric1<T> {
private int capacity = 1;
private int size = 0;
private Object[] array = new Object[capacity];
public ArrayListGeneric1() {}
public T get(int i) {
return (T) array[i];
}
public void set(int i, T element) {
array[i] = element;
}
}
You can actually do it with a generic array, if you make the type abstract, and subclass it when you create an instance:
public abstract class ArrayListGeneric1<T> {
private int capacity = 1;
private int size = 0;
private T[] array = Array.newInstance(getElementType(), capacity);
public ArrayListGeneric1() {}
Class<?> getElementType() {
ParameterizedType pt = (ParameterizedType) getClass().getGenericSuperclass();
Type[] typeArgs = pt.getActualTypeArguments();
// Will fail if it's not a class type.
return (Class<?>) typeArgs[0];
}
// ...
}
Then:
ArrayListGeneric1<String> list = new ArrayListGeneric1<String>() {}
Demo: https://ideone.com/fgJ5dl
Yes. Given below is an example from Java OOTB class:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private int size;
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}
...
...
...
}
It's not a problem. ArrayList is a generic class with no-args constructor:
List<Integer> a = new ArrayList<>();
List b = new ArrayList<>();
var c = new ArrayList<>();
You can find the exemplary implementation here.
I am doing an tutorial task on implementing Graph using Adjacency List but got problem with the constructor.
In the given GraphTester.java I have:
//Constructor cannot be applied to given types
FriendShipGraph<String> graph = new AdjList<String>();
Then the FriendShipGraph.java provides an interface:
public interface FriendshipGraph<T extends Object> {
public static final int disconnectedDist = -1;
public abstract void addVertex(T vertLabel);
public abstract void addVertex(T srcLabel, T tarLabel);
//Other abstract methods
}
So I need to write a class to implement a LinkedList:
public class SinglyLinkedList implements LinkedListInterface {
private Node head;
private int length;
public int getLength() {
return length;
}
public SinglyLinkedList() {
head = null;
length = 0;
}
//Other methods to manage the linked list
public class Node
{
private String value;
private Node nextNode;
public Node(String value) {
this.value = value;
nextNode = null;
}
//Other methods to manage node
}
}
And I have to use an array of LinkedList to implement the Graph:
public class AdjList <T extends Object> implements FriendshipGraph<T> {
SinglyLinkedList[] AdjList = null;
//This is the constructor containing the error
public AdjList(T vertices) {
int qty = Integer.parseInt((String) vertices);
AdjList = new SinglyLinkedList[qty];
for (int i = 0; i < AdjList.length; i++)
AdjList[i] = new SinglyLinkedList();
}
}
However when I write my own test file I create AdjList object like this without error but this is not what the class requires:
AdjList<String> aList = new AdjList<String>("9");
So anyone please suggest me how to fix the constructor. Thank you so much!
FriendShipGraph<String> graph = new AdjList<String>();
You do not have a zero-argument constructor in AdjJust. A default zero-argument constructor is not generated if you provide your own constructor(s), as you did with AdjList(T vertices).
You need to provide a default constructor. Maybe something like the following might be sufficient depending on other code that isn't shown:
public class AdjList <T extends Object> implements FriendshipGraph<T> {
SinglyLinkedList[] AdjList = null;
public AdjList() {
}
//This is the constructor containing the error
public AdjList(T vertices) {
int qty = Integer.parseInt((String) vertices);
AdjList = new SinglyLinkedList[qty];
for (int i = 0; i < AdjList.length; i++)
AdjList[i] = new SinglyLinkedList();
}
}
I'm not exactly sure why you're passing a string to represent a quantity but this should at least fix the compilation error you're asking about.
In addition to the correct answer from Trey, some more remarks:
Your one-arg constructor says T vertices; but then you are doing a "hard" cast to (String) in there. That code will throw an exception if T is anything else but String.
So, you should either make AdjList (horrible name by the way) go like class AdjList implements FriendshipGraph<String>; or when you don't want to "fix" the generic type to string, you could go for qty = Integer.parseInt(verties.toString())
But looking at that - doesn't that sound weird? You know, turning something that seems to be a number into a string, to parse a number from it? Maybe it should be an Integer all the time?
Then: work on your naming. There is absolutely no need to use abbreviations like "qty"; why don't you call it numberOfLists or something alike?!
How do I create a generic array list in Java that could accept both integers and array?
[123,[],112,[],10]
Both int (Integer wrapper) and array's common base class is Object. So create ArrayList using Object type.
ArrayList<Object> list= new ArrayList<Object>();
But this is not the right way to solve this problem and there is no use of Generics here to make run-time safety. So, re-design your program and allocate each type in seperate list or use any other appropriate Collection type.
Well, the fastest way might be create an auxiliar object that is composed by boths Integers and array letting you to use boths by equal
Create the array list at the Generalization level for all the objects you need in the List. In this case,i.e for int and array, it is java.lang.Object.
Here's a small test I ran:
public static void main(String[] args) {
List<Object> both = new ArrayList<Object>();
both.add(1);
both.add(args);
System.out.println(both);
}
Produces:
[1, [Ljava.lang.String;#1db9742]
As #AbtPst suggested, the most suitable solution would be to have a list of lists. This can be done in many different ways. Personally, I'd create a class with two constructors.
class NumericElement
{
private ArrayList<int> elements;
public NumericElement(int newElement)
{
elements = new ArrayList<int>();
elements.add(newElement);
}
public NumericElement(ArrayList<int> newElements)
{
elements = new ArrayList<int>(newElements); // copying array elements to the new array.
}
public ArrayList<int> getElements()
{
return elements;
}
}
Use a class which has an int and an array as its instance variables. Then create an ArrayList like
import java.util.ArrayList;
public class Hello {
public static void main(String[]args) {
ArrayList<Intarray> myArrayList = new ArrayList<Intarray>();
int[] arr = {3,4,5};
myArrayList.add(new Intarray(2,arr));
}
}
class Intarray {
private int numbers;
private int[] myArray;
public Intarray(int numbers, int[] myArray){
this.numbers = numbers;
this.myArray = myArray;
}
}
You can define a List class with a type-safe interface, hiding an unsafe List<Object> as an internal implementation detail.
This is more work than just using a List<Object> directly. If your list is used only by one class, just use a List<Object>, as an implementation detail of that one class. But if your list is exposed to access by more than just one class, consider using this type-safe approach.
First, define an interface that can represent either an int or a array of ints.
public interface IScalarOrArrayInt { }
And define a sub-interface for each possible element type:
public interface IScalarInt extends IScalarOrArrayInt {
public int getScalarInt();
}
public interface IArrayInt extends IScalarOrArrayInt {
public int[] getIntArray();
}
Then define your list class and its representation. It's interface can be a List<IScalarOrArrayInt>. The representation can be a List<Object>, so that you can put Integer and int[] objects into it directly, without wrapper objects.
public class ListOfScalarsAndArray extends AbstractList<IScalarOrArrayInt> {
private static List<Object> m_list = new ArrayList<Object>();
As noted in the AbstractList documentation, you'll want to define several methods to allow modifying your list. You can delegate them to the internal list, but wrap the return values.
#Override
public void add(int index, IScalarOrArrayInt element) {
m_list.add( index, element );
}
#Override
public IScalarOrArrayInt remove(int index) {
return wrap( m_list.remove( index ));
}
#Override
public IScalarOrArrayInt set(int index, IScalarOrArrayInt element) {
return wrap( m_list.set( index, element ));
}
For the convenience of callers, you can add some methods that accept an unwrapped int or int[]. For example:
public void add( int element ) {
m_list.add( element );
}
public void add( int[] element ) {
m_list.add( element );
}
To satisfy the standard List<> interface, you can wrap return values. Your class controls the internal list, so it alone controls the possible types of list members.
private IScalarOrArrayInt wrap( Object o ) {
if ( o instanceof Integer ) {
final int i = (Integer) o;
return new IScalarInt() {
#Override
public int getScalarInt() {
return i;
}
};
}
else {
assert( o instanceof int[] );
final int[] a = (int[]) o;
return new IArrayInt() {
#Override
public int[] getIntArray() {
return a;
}
};
}
}