Printing Single Item from ArrayList Created in Another Generic Class? - java

Trying to get an understanding of generics in Java. I've created an ArrayList using non-generic methods and casting to print them out, everything works fine using the usual array.get(index) but when I use generics to create the list, the get method doesn't work. I can print the whole list just fine, but I want to pick out individual elements. I've tried a few different things which have made the code a little messy probably, so sorry about that. I know things could probably be done an easier way, I'm just trying to learn about Generics in Java and I ran into this issue. I've watched several different videos and found several examples, so I may be trying to put two concepts together the incorrect way. Tried researching, can't find the answer.
First class Generic.java is to create the generic ArrayList.
import java.util.ArrayList;
import java.util.List;
public class Generic<T> {
private ArrayList<T> data;
public Generic() {
data = new ArrayList<T>();
}
public void add(T element){
data.add(element);
}
//Not even sure if I need these get/set but I put them in there for testing
public ArrayList<T> getData() {return data;}
public void setData(ArrayList<T> data) {this.data = data;}
public String toString(){
return data.toString();
}
}
Second class is the main test class:
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List nonGenericList = new ArrayList();
nonGenericList.add("Enzo");
nonGenericList.add(458);
String nonGen1 = (String) nonGenericList.get(0);
Integer nonGen2 = (Integer) nonGenericList.get(1);
System.out.println(nonGen1);
System.out.println(nonGen2);
Generic<Object> genericList = new Generic<>();
genericList.add("Enzo");
genericList.add(458);
//This is where the .get(0) isn't working for me
System.out.println(genericList.get(0));
}
}
Thanks for any help!

Your Generic<T> class doesn't have the method get(int index), you should create the method if you want to call it...
Try adding this to your Generic<T> class
public T get(int index){
return data.get(index);
}

You can define get method like this in your Generic class:
public T get(int i) {return data.get(i);}

You do not have add method you have defined the getData() method,
so write
ArrayList a=genericList.getData();
System.out.println(a.get(0));

Related

I cant show an arraylist in a jlist

So basically im creating a list with a lot of information that i get from the user, and i need to display that "Estudiante" created on a list asside. So this is what i first tried, but it tells me that setListData is for arrays, so i tried other thing that i found that included the using .toArray(array) but that didnt work too.
Just to clarify what modelo is i copied this first code
public class VentanaEstudiante extends javax.swing.JFrame {
private Sistema modelo;
/**
* Creates new form VentanaEstudiante
*/
public VentanaEstudiante(Sistema unSistema) {
modelo = unSistema;
this.setSize(400, 280);
initComponents();
}
private void BotonCrearEstudianteActionPerformed(java.awt.event.ActionEvent evt) {
Estudiante unEst=new Estudiante(NombreEstudiante.getText(), Integer.parseInt(CedulaEstudiante.getText()),MailEstudiante.getText(), Integer.parseInt(NumeroEstudiante.getText()), Integer.parseInt(SemestreEstudiante.getText()));
modelo.agregarEstudiante(unEst);
ListaEstudiantesJ.setListData((modelo.getListaEstudiantes()).toArray());
Estudiante has a toString method, and the superclass, also does.
public String toString(){
return super.toString() + "Numero:" + this.getNumero() + "Semestre: " + this.getSemestre();
}
Here you have my lists and i only copied the listaEstudiantes methods because this are the ones im asking right now. This class Sistema, doesnt have any toString methods because i throught that this arraylist didnt needed one.
public class Sistema {
private ArrayList<Estudiante> listaEstudiantes;
private ArrayList<Docente> listaDocentes;
private ArrayList<Equipo> listaEquipos;
public Sistema(){
listaEstudiantes = new ArrayList<>();
listaDocentes= new ArrayList<>();
listaEquipos=new ArrayList<>();
}
public void agregarEstudiante(Estudiante unEstudiante){
listaEstudiantes.add(unEstudiante);
}
public ArrayList<Estudiante> getListaEstudiantes(){
return listaEstudiantes;
}
I need to use ArrayList in case you have something that may work better, i just need to use them
This whole project has a lot of showing Lists and sometimes i have to even let the user select things from them, something that i also dont know how to do but i dont know if i can ask more than one question here. The list is also going to need to refresh and all of that but i think i can handle that. Thanks
JList.setListData() has two variants, one expecting an array of elements, the other expecting a vector of elements.
Behind the scenes these two methods create an instance of an anonymous subclass of AbstractListModel and pass that instance to JList.setModel().
You can easily implement similar code for any List instance:
static <E> void setListData(JList<E> jList, List<? extends E> listData) {
jList.setModel(new AbstractListModel<E>() {
public int getSize() { return listData.size(); }
public E getElementAt(int i) { return listData.get(i); }
});
}

Calling method in java arraylist which contains obects created by class with generic arguments

Calling the method name sales() in codes below cannot be accessed.
The objects in arraylist are the class Group1which uses generic arguments. And,division_a.list.get(0)shoud have the Group1 object. And,division_a.list.get(0).getComponent()should returnComponent1object. Then thesales()method should be usable.
But, the exception message shows "The methodsales()` is undefined for the type capture#2-of ?" It's a mystry for me that division_a.list.get(0).getComponent() does not return objects of Component1 class, although the return type is defined as "public T getComponent().."
import java.util.ArrayList;
public class Division_a {
public ArrayList<Group1<?>> list=null;
public Division_a() {
list=new ArrayList();
}
public void put(Group1<?> group1) {
list.add(group1);
}
public static void main(String[] args) {
Group1<Component1> groupcomponent1 = new Group1<>(new Component1());
Division_a division_a = new Division_a();
division_a.put(groupcomponent1);
division_a.list.get(0).getComponent().sales(); //excetion occur
}
}
class Component1 {
public void sales() {
System.out.println("component1 sold");
}
}
class Group1<T> {
public T component;
Group1(T component){
this.component=component;
}
public T getComponent() { //return type T
return component;
}
public void setComponent(T component) {
this.component=component;
}
}
The sales method is only available in Component1. So if you need to call that method you should have either Component1 of any subtype of that. If you want to make it either Component1 or a subtype of it then you have to use a bounded wildcard instead of using an unbounded wildcard which can literally be anything. Here's the corrected code.
public ArrayList<Group1<? extends Component1>> list = null;
public void put(Group1<? extends Component1> group1) {
list.add(group1);
}
So, you need to understand how class erasure works in java. The generic information is never actually passed to the container, it's only enforced on the compiler side. Here is a good tutorial explaining it.
The easiest way to accomplish what you're looking to accomplish is to have an appropriate interface, like:
public interface WithSales {
Sales sales();
}
and make sure that your components implmeent them. Then you declare your wrappers appropriately, so your list declaration would look like:
public List<Group1<? extends WithSales>> list = new ArrayList<>();
Then the rest of your code would work fine as long as all of the instances of Component implement WithSales

Assigning ArrayList object to Instance variable - java

The code snippet below is part of some code I am reading for an assignment but I cant understand the role of the copy variable in the snippet or what it does. I know its an instance of the Sample class, but why it is then assigned an ArrayList is not clear to me.
public class Sample implements Var{
private List lst1;
private List lst2;
public Sample() {
super();
}
public Sample(List lst1) {
this();
this.lst1 = lst1;
}
public List getLst1() {
return lst1;
}
public void setLst1(List lst1) {
this.lst1 = lst1;
}
#Override
public Var copy(){
Sample copy = new Sample(lst1);
copy.lst2 = new ArrayList(lst2);
return copy;
}
#Override
public void randomize(){
}
}
In fact the error message is explicit to show that you can't iterate over the variable copy because you haven't implemented the Iterable interface which allows you to do it. If you insist to loop over it and to have functions allowing you to do so: just visit this link Java Generics - Implementing the Iterable Interface where you can for exemple (if this is what you want) iterate over the elements of the two lists of an instance lst1 and lst2

How to log List interface method for existing code

I have existing codebase that sometimes uses ArrayList or LinkedList and I need to find a way to log whenever add or remove is called to track what has been either added or removed.
What is the best way to make sure I have logging in place?
So for example.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
and
LinkedList<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList.add(333);
Not sure if I can intercept add method to achieve this or create overriding class that implements java.util.List interface then use it instead. Either way I'm looking for a good solution that requires minimum intervention and prefrerrably without using any third party packages...
I would use the so called Decorator Pattern to wrap your lists.
This would be a simple example code just to give you an idea:
private static class LogDecorator<T> implements Collection<T> {
private final Collection<T> delegate;
private LogDecorator(Collection<T> delegate) {this.delegate = delegate;}
#Override
public int size() {
return delegate.size();
}
#Override
public boolean isEmpty() {
return delegate.isEmpty();
}
#Override
public boolean contains(Object o) {
return delegate.contains(o);
}
#Override
public Iterator<T> iterator() {
return delegate.iterator();
}
#Override
public Object[] toArray() {
return delegate.toArray();
}
#Override
public <T1> T1[] toArray(T1[] a) {
return delegate.toArray(a);
}
#Override
public boolean add(T t) {
// ADD YOUR INTERCEPTING CODE HERE
return delegate.add(t);
}
#Override
public boolean remove(Object o) {
return delegate.remove(o);
}
#Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends T> c) {
return delegate.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
#Override
public void clear() {
delegate.clear();
}
}
There is not really a simple way to get there.
Those classes are part of the "standard libraries"; so you can't change their behavior. You could create your own versions of them; and use class path ordering to get them used; but this really dirty hack.
The only other option: extend those classes; #Override the methods you want to be logged; and make sure all your sources use your own versions of those classes. Or if you prefer composition over inheritance you go for the decorator pattern; as suggested by JDC's answer.
The "third" option is really different - you turn to aspect oriented programming (for example using AspectJ) and use such tools to manipulate things on a bytecode level. But that adds a whole new layer of "complexity" to your product; thus I am not counting it as real option.
EDIT on your answer: it seems that you don't understand the difference between interface and implementation?! An interface simply describes a set of method signatures; but in order to have real code behind those methods, there needs to be an implementing class. You see, when you do
List<X> things = new ArrayList<>();
the real type of things is ArrayList; but you rarely care about that real type; it is good enough to know that you can all those List methods on things. So, when you create some new implementation of the List interface ... that doesn't affect any existing
... = new ArrayList ...
declarations at all. You would have to change all assignments to
List<X> things = new YourNewListImplementation<>();
JDC has given a good way to follow.
I would like bring important precisions.
The decorator pattern allows to create a class which decorates another class by adding or removing dynamically a new responsibility to an instance.
In your case, you want to add responsibility.
Decorator is not an intrusive pattern but the decorator class have to conform to the class that it decorates.
So in your case, having a decorator which derives from the Collection interface is not conform to the decorated object since List has methods that Collection has not.
Your need is decorating List instances, so decorator should derive from the List type.
Besides, the decorator class can do, according its needs, a processing before and or after the operation of the class that it decorates but it is also responsible to call the original operation of the decorated class.
In your case, you want to know if an element was added or in or removed from the List. To achieve it, as the method result has consequences on whether you log or not the information, it is preferable to delegate first the processing to the decorated object and then your decorator can perform its processings.
Sometimes, you don't need to decorate a method, don't do it but don't forget to delegate suitably to the decorated object.
import java.util.Iterator;
import java.util.List;
public class DecoratorList<T> implements List<T> {
private static final Tracer tracer = ....;
private List<T> decorated;
private DecoratorList(List<T> decorated) {
this.decorated=decorated;
}
// no decorated methods
....
#Override
public int size() {
return this.decorated.size();
}
#Override
public boolean isEmpty() {
return this.decorated.isEmpty();
}
#Override
public boolean contains(Object o) {
return this.decorated.contains(o);
}
#Override
public Iterator<T> iterator() {
return this.decorated.iterator();
}
....
// end no decorated methods
// exemple of decorated methods
#Override
public void add(int index, T element) {
tracer.info("element " + element + " added to index " + index);
this.decorated.add(index,element);
}
#Override
public boolean remove(Object o) {
final boolean isRemoved = this.decorated.remove(o);
if (isRemoved){
tracer.info("element " + o + " removed");
}
return isRemoved;
}
}
As explained, a decorator is not intrusive for the decorated objects.
So the idea is not changing your code that works but add the decorating operation just after the list be instantiated.
If don't program by interface when you declare your list variables, that is you declare ArrayList list = new ArrayList() instead of List list = new ArrayList() , of course you should change the declared type to List but it doesn't break the code, on the contrary.
Here is your example code :
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
LinkedList<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList.add(333);
Now, you could do it :
List<Integer> list = new ArrayList<Integer>();
list = new DecoratorList<Integer>(list); // line added
list.add(123);
List<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList = new DecoratorList<Integer>(anotherNewList); // line added
anotherNewList.add(333);
To ease the task and make it safer, you could even create a util method to apply the decoration on the list :
private static <T> List<T> decorateList(List<T> list) {
list = new DecoratorList<T>(list);
return list;
}
and call it like that :
List<Integer> list = new ArrayList<Integer>();
list = decorateList(list); // line added
list.add(123);
You can use Aspects - but it will log every add and remove call:
#Aspect
public class ListLoggerAspect {
#Around("execution(* java.util.List.add(..))")
public boolean aroundAdd(ProceedingJoinPoint joinPoint) throws Throwable {
boolean result = (boolean) joinPoint.proceed(joinPoint.getArgs());
// do the logging
return result;
}
}
You'll need to configure the aspect in META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="com.example.ListLoggerAspect"/>
</aspects>
</aspectj>
An easy way to accomplish this is wrapping your source list in a ObservableList and use that as base list. You can simply add an listener to this list to catch every modification (and log out if you wish)
Example:
List obs = FXCollections.observableList(myOriginalList);
obs.addListener(c -> {
for(Item it : c.getRemoved())
System.out.println(it);
for(Item it : c.getAddedSubList())
System.out.println(it);
});
See the javafx documentation on how to add a good listener
Your List is the source here. You need to keep track of the changes to the source. This is a good and natural example of the Observer pattern. You can create an Observable which is your list. Then create some Observers and register them to the Observable. When the Observable is changed, notify all the registered Observers. Inside the Observer you can log the changes using the input event. You should literally implement some ObservableCollection here. You can use Java Rx to get this work done. Please find the sample code given below.
package com.test;
import java.util.ArrayList;
import java.util.List;
import rx.Observable;
import rx.subjects.PublishSubject;
public class ObservableListDemo {
public static class ObservableList<T> {
protected final List<T> list;
protected final PublishSubject<T> onAdd;
public ObservableList() {
this.list = new ArrayList<T>();
this.onAdd = PublishSubject.create();
}
public void add(T value) {
list.add(value);
onAdd.onNext(value);
}
public Observable<T> getObservable() {
return onAdd;
}
}
public static void main(String[] args) throws InterruptedException {
ObservableList<Integer> observableList = new ObservableList<>();
observableList.getObservable().subscribe(System.out::println);
observableList.add(1);
Thread.sleep(1000);
observableList.add(2);
Thread.sleep(1000);
observableList.add(3);
}
}
Hope this helps. Happy coding !
We need a little more information to find the right solution. But I see a number of options.
You can track changes, using a decorator.
You can copy the collection and calculate the changes
You can use aspects to 'decorate' every List in the JVM
Change the existing codebase (a little bit)
1) works if you know exactly how the list is used, and once it is returned to your new code, you are the only user. So the existing code can't have any methods that add to the original list (because would invoke add/remove on the delegate instead of the decorated collection).
2) This approach is used when multiple classes can modify the list. You need to be able to get a copy of the list, before any modifications begin, and then calculate what happened afterwards. If you have access to Apache Collections library you can use CollectionUtils to calculate the intersection and disjunction.
3) This solution requires some for of weaving (compile or load time) as this will create a proxy for every List, so it can add callback code around the method calls. I would not recommend this option unless you have a good understanding of how aspects work, as this solution has a rather steep learning curve, and if something goes wrong and you need to debug you code, it can be a bit tricky.
4) You say existing codebase, which leads me to believe, that you could actually change the code if you really wanted. If this is at all possible, that is the approach I would choose. If the user of the List needs to be able to track changes, then the best possible solution is that the library returns a ChangeTrackingList (interface defining methods from tracking), which you could build using decoration.
One thing you have to be aware of when decorating, is that List has a removeAll() and a addAll(), these methods may or may not call the add() and remove(), this depends on the list implementation. If you are not aware of how these methods are invoked internally you could end up seeing an object as removed twice (unless you can use a set).

Java 7: Class as argument

I have a class named "Pencilcase", where the only instance variable is an ArrayList<Pencil>.
I have a method in it like this:
public int qwerty(Pencilcase p)
I've tried to do something like this: for (Pencil pen : p)
But I get an error, which says "for-each not applicable to expression type. Required: array or java.lang.Iterable; found Pencilcase".
Since it says that "Required: java.lang.iterable", I tried to use iterator, but still could not solve the problem. What am I doing wrong? Thanks
To use the for-each of Java you need to use java.lang.Iterable as the error message said. This means that the class you want to iterate needs to implement this interface. You have two ways to go about this.
First Solution: Access the internal list directly.
public class Pencilcase {
public ArrayList<Pencil> list;
}
And iterate it like this:
public int qwerty(Pencilcase p) {
for (Pencil pen : p.list) {
....
}
}
Now this solution uses a public class variable. That is a bad thing. Also it doesn't look very fancy. So we have a
Second Solution: Implement Iterable
Now for that you need to alter your Pencilcase class to implement Iterable
public class Pencilcase implements java.lang.Iterable<Pencil> {
private ArrayList<Pencil> list;
#Override
public Iterator<Pencil> iterator() {
return list.iterator();
}
}
Using this class you can iterate over the Pencilcase instance directly.
This works because the for-loop basically fetches the iterator with the iterator function and uses this to fetch all the entries in the list.
So with this your loop can look like this:
public int qwerty(Pencilcase p) {
for (Pencil pen : p) {
....
}
}

Categories

Resources