As you can see I have a StaffMember class and trying to make a list of StaffMember objects, but when I go to get them out of the list I get errors. What could be causing this (Or java lists are different from other languages).
Since you're not using a generic List variable, the compiler has no way of knowing what type of objects the List contains, and so you'll have to cast the object returned by the get(...) method to the type you believe it to be.
A better solution is to declare your list variable to be a generic List<StaffMember>.
public class StaffList {
private List<StaffMember> list;
I think your life will be better if you do it this way:
public class Staff {
private List<StaffMember> roster;
public Staff() {
this.roster = new ArrayList<StaffMember>();
}
// add the rest
}
Related
I'm fairly new to programming and we do have an exercise, we have to use the Consumer interface, we have a generic class (genClass) that has a Consumer<T> attribute (conAtt). In another class we have to use the accept method of Consumer, but somehow it doesn't work. I have already read through the Java API of the Consumer interface, but it didn't help.
The error message says:
The method accept(capture#4-of ?) in the type Consumer<capture#4-of ?> is not applicable for the arguments (capture#5-of ?)
I know it says not applicable, but why not?
public abstract class GenClass<T> {
protected Consumer<T> conAtt;
public abstract T getData();
}
class Otherclass{
private List<GenClass<?>> helparray= new ArrayList<>();
private void testmethod() {
Iterator<GenClass<?>> hilfe = helparray.iterator();
while (hilfe.hasNext()) {
GenClass<?> help = hilfe.next();
help.conAtt.accept(help.getData());//here is the problem
}
}
}
public class thirdclass extends GenClass<Character> {
#Override
public Character getData() {
return 't';//t is just an example
}
}
This is not really a question about how the Consumer - or other interfaces - in Java work, but about Generics.
Generics aim to simplify the way of writing code and avoid code repetitions. E.g. you need to do a similar task, but for different types you can write it once by using Generics instead of writing it over and over again, just with concrete types being replaced.
For example one day you have the need to keep track of a list of Strings. As easy as that, your going ahead and implementing a solution for that, whereby the first implementation can look like the following (note: a very simplified example, but it'll show the purpose):
public class CustomListString {
private String[] elements = new String[10];
public void add(String newElement) {
int nextFreeIndex = findNextFreeIndex();
elements[nextFreeIndex] = newElement;
}
public String get(int index) {
return elements[index];
}
}
So you can use the above implementation of the List in your code like the following:
public static void main(String[] args) {
CustomListString listOfStrings = new CustomListString();
listOfStrings.add("A");
listOfStrings.add("B");
}
Simple, specific and sufficient!
But the other day, you also have the requirement to keep track of a list of Integers. What to do now?
A way to solve this is to just repeat your previous approach and to implement another CustomList only for the Integers now. Where the corresponding implementation would look like this (the implementation of CustomListString has been copied and all occurrences of String have been replaced by Integer):
public class CustomListInteger {
private Integer[] elements = new Integer[10];
public void add(Integer newElement) {
int nextFreeIndex = findNextFreeIndex();
elements[nextFreeIndex] = newElement;
}
public Integer get(int index) {
return elements[index];
}
}
As you can imagine now already, this is not flexible and can be very cumbersome in the future. This approach will require a new implementation of each type you want to store in the future. So you might end up to also create implementations like CustomListDouble, CustomListCharacter, ... and so on, in which only the type of the elements within the array change - nothing else which would be of importance!
This will additionally lead to the situation, that you'll duplicate a lot of similar code (like findNextFreeIndex() method would have been) and in case of a bugfix need to adjust it in a lot of places instead of in only one.
To solve this issue and remain the type safety in the CustomList.get method Generics have been introduced to Java!
With the Generics approach you'll be able to create a single implementation of the CustomList to store all of your data types without unnecessarily duplicating any shared, basic code and remain the type safety!
public class CustomList<T> {
private Object[] elements = new Object[10]; // Java doesn't supprort easily support generic arrays, so using Object
// here. But the compiler ensures only elements of the generic type T
// will end up here
public void add(T newElement) {
int nextFreeIndex = findNextFreeIndex();
elements[nextFreeIndex] = newElement;
}
#SuppressWarnings("unchecked")
public T get(int index) {
return (T) elements[index];
}
}
Using the new list following the Generics approach we can use it like this now:
public static void main(String[] args) {
CustomList<String> genericList = new CustomList<>();
genericList.add("Hello World");
genericList.add(5); // Compile error! Integer and String types cannot be mixed in
// a single instance of the list anymore => Nice, prevents errors!
genericList.get(0).substring(6); // No compile error, also the compiler knows Strings
// are contained in the list
}
The generic CustomList can now also be reused for any other type and still provide type safety.
What does it mean for your implementation
You can see how we specified the generic type in the CustomList class as T - this is similar like you specified it with ? (probably you'll also want to replace it with T, since you'll run into other issues later when working with the Consumer). But when we used the implementation in our other classes, it wouldn't have been possible to specify it as CustomList<T> or CustomList<?> anymore. We needed to decide and specifiy which exact type of elements the list should contain. This has been the String class, so we specified it as CustomList<String>.
Note: ? is a generic wildcard and means something like "I don't know the real type of the classes now and I'll also don't know it in the future". That's why it'll be hard for you working with the concrete types later in the Consumer. You'll be not able to call any conrete methods on your objects therein. Therefore ? should be avoided as a generic type argument and something like T should be used instead. T means something like "I don't know the real type of the classes now, but I'll do later, as soon as you tell me". Therfore you'll be able to call concrete methods on the objects later in the Consumer, what will simplify your work there a lot.
For your code this means, wherever you want to use your implementation of GenClass<T> you need to specify with which exact kind of elements the class is going to work with. In case of String it is GenClass<String> in case of Character GenClass<Character>.
So the place you'll need to replace the occurrences of GenClass<?> is wherever you refer to it in Otherclass and Otherclass.testmethod.
The way you used the Consumer is fine
I think that a final reference to an array of enums should be immutable.
The uniqueness and singularity of enums is enforced by the JVM, so I believe it is safe to say that they are immutable.
A final reference cannot be changed, so the reference is immutable.
But ... what about the array? Might it still be possible to subvert the array that contains the enum references?
I have a list of enums that correspond to database columns. These column names and their associated data do not change, so ... I would like to have the list as a class variable like so:
static final List<MetaData<Client>> C_COLUMNS =
DataTables.CLIENTS.getTableColumnsAsEnums();
where CLIENTS is the DataTable enum for which a list of column enums is being generated. The method that does this follows:
public <T extends DB> List<MetaData<T>> getTableColumnsAsEnums() {
Class<? extends MetaData> cls = this.columnsEnumToken();
return new ArrayList(Arrays.<MetaData<T>>asList(cls.getEnumConstants())); }
Am I right? This ought to become part of a multi-threaded design, and so I am concerned about the way that making this critical list of static data would render by app very vulnerable ... if it actually were mutable.
But ... what about the array? Might it still be possible to subvert the array that contains the enum references?
Yes. All arrays in Java are mutable, irrespective of how you declare the variable that holds the reference to the array.
If you want to avoid this "risk", then you must not expose the array; i.e. you need to declare it as private. You could then do one (or more) of the following:
Define a static method that will create and return a copy of the array. (Probably not the best option here ...)
Define a static get(int) method that returns the ith element of the array.
Wrap the array in a list (using Arrays.asList) and create an unmodifiable wrapper for it (using Collections.unmodifiableList).
If you want to get the public <T extends DB> List<MetaData<T>> getTableColumnsAsEnums() to return an immutable List you need to use Collections.unmodifiableList()
Also when you are using an unmodifiable list you don't have to worry about the internal array because the toArray method will return an copy of the internal array, not a reference to the internal array itself. This is true for all the Collections.
The REFERENCE is immutable, the content of that reference is not, that's just how things work.
So the following won't work
public enum TheEnum {
//......
}
final TheEnum[] arr = new TheEnum[5];
var = new TheEnum[6];
but this will work
public enum TheEnum {
OPTION_ONE;
//......
}
final TheEnum[] arr = new TheEnum[5];
var[1] = TheEnum.OPTION_ONE;
In my Java EE project, I have 2 ArrayList objects:
private ArrayList<Sales_personRef> sales_personsRef = new ArrayList<Sales_personRef>();
private ArrayList<Sales_person> sales_persons = new ArrayList<Sales_person>();
My question is : How can I add my first list(sales_personsRef) in the second list?
These lists have different types and I cannot cast it...
If Sales_personRef and Sales_person both extend another class, let's say Person, then you could add both of those types to an ArrayList<Person>.
Keep in mind that if you do it this way, then what you get out of the list later will be of type Person. You will then have to cast it back to its original class.
You need to convert each items of the first list in the items accepted by the second List
sales_persons.addAll(convertSalesPersons(sales_personsRef));
with:
private static Collection<? extends Sales_person> convertSalesPersons(ArrayList<Sales_personRef> sales_persons) {
List<Sales_person> persons = new ArrayList<Sales_person>();
for (Sales_personRef sales_personRef : sales_persons) {
persons.add(converSalesPersonRefToSalesPerson(sales_personRef));
}
return persons;
}
private static Sales_person converSalesPersonRefToSalesPerson(Sales_personRef sales_personRef) {
//implement the conversion here
return new Sales_person();
}
By declaring your second list as an List<Object>.
you have to use polymorphism concept here . make a parent class say person and then extend it that would work
i am trying to create a abstract array method that specify's that this abstract object of an array can only hold 3 items.
Now i have tried doing something like this public abstract BaseAdapter[3] adapters(); but it complains with an error that it cant be done this way.
is their another way or do i need to just do public abstract BaseAdapter[] adapters();?
That will work fine but the sub class can still pass an array larger than 3 items
You could solve it like this:
Create an abstract helper method (which you can override) named createAdapters() with return type BaseAdapter[]
protected abstract BaseAdapter[] createAdapters();
In your super-class you have a final method adapters that does the following:
public final BaseAdapter[] adapters() {
BaseAdapter[] adapters = createAdapters();
if (adapters.length != 3)
throw new Exception("Error: Please return 3 adapters.");
return adapters;
}
Another alternative would be to create a simple class called BaseAdapterTriple (perhaps with a more descriptive name) containing the three BaseAdapters, and use that as return value.
As far as I'm aware there is no way to place restrictions like that on objects in a method signature. Either use exceptions in implementing methods, or use custom classes.
You seem to misunderstand the meaning of the abstract modifier in Java.
abstract applies to classes and methods, not to fields / variables, so what you are trying cannot work.
Please describe what you want to accomplish, then we can help :-).
See e.g. http://download.oracle.com/javase/tutorial/java/IandI/abstract.html for an explanation of abstract.
No, you can't do this neither with arrays nor lists. You can throw an exception if number exceeds 3 and document this behavior.
If you want an adapters() method which can only return 3 BaseAdapter at most and having subclasses to implement the "return" themselves while respecting the 3max contract, you should do the verification in your adapters() method, and invoke an abstract method.
For example :
abstract class YourAbstractClass{
public BaseAdapter[] adapters(){
BaseAdapter[] adapters = internalAdapters();
if(adapters.length > 3){
throw new IllegalStateException();
}
return adapters;
}
protected abstract BaseAdapter[] internalAdapters();
}
aioobe's answer is a good approach to take, but I'd also suggest something a little bit different:
If you are requiring a method to return an array of a certain size, you might want to question why an array is the appropriate return type for this method in the first place, rather than using a simple POJO which can easily encapsulate the idea of "3 BaseAdapters", i.e.:
public class ThreeAdapters {
BaseAdapter getAdapter1() { ...}
BaseAdapter getAdapter2() { ...}
BaseAdapter getAdapter3() { ...}
}
It's a lot clearer to everyone involved if you encapsulate the idea of "return 3 adapters" into it's own class so that this can be used as the return type (of course, you may find a more appropriate name for the class).
In Java, the size of an array is not part of its type. Or to put it another way, all array types with a given base type are the same. Furthermore, you cannot a method signature that places restrictions on the size of an array typed parameter or result.
This means that you are left with the coding the method to test (in your case) the length of the array it is about to return. This is probably not going to help you much, since I assume that you are trying leverage static typing to enforce the "tripleness" of your arrays. From this perspective #matt b's answer is on the money, though you could make do it in a way that still gives you arrays (of length 3):
public class AdapterTriple {
private Adapter[] adapters;
/**
* This constructor may throw an exception
*/
public AdapterTriple(Adapter[] adapters) {
if (adapters.length != 3) {
throw new IllegalArgumentException("array length is wrong");
}
this.adapters = adapters;
}
/**
* This constructor won't throw an exception (apart from Errors)
*/
public AdapterTriple(Adapter adapter1, Adapter adapter2, Adapter adapter3) {
this.adapters = adapters = new Adapters[] {
adapter1, adapter2, adapter3};
}
/**
* #return an array of 3 adapters.
*/
public Adapter[] {
return adapters;
}
}
In summary, you cannot enforce array size constraints statically in Java. You have to do it dynamically, but you can take steps to make runtime errors unlikely.
Hi is it possible to cast a List?
i have an abstract class that has a method that takes some sort of List<>, iterate through it in a for loop getting each object in that list and calling the insertItem abstract method that is implemented by the sub class to basically pull out the proper data in the items and then finaly inserting them into a database table.
here is the super class method:
protected void insertAllItemsToDb(List<Object> items, String table) {
// open db and table
database().beginTransaction();
// clear all data from table
clearTable(table);
// call a insert statement to insert each column from an item
for (Object object : items) {
insertItem(object, table);
}
// close db
database().endTransaction();
database().close();
}
In the subclass here is one of the override methods: Which i am able to cast the object fine here.
#Override
protected void insertItem(Object object, String table) {
CalendarEventItem item = (CalendarEventItem) object;
eventItemValue = new ContentValues();
eventItemValue.put(LABEL_EVENTS_TITLE, item.getEventTitle());
eventItemValue.put(LABEL_EVENTS_LOCATION, item.getEventLocation());
eventItemValue.put(LABEL_EVENTS_DATE, item.getEventStartTime()
.getDate());
eventItemValue.put(LABEL_EVENTS_TIME, item.getEventStartTime()
.getTime());
eventItemValue.put(LABEL_EVENTS_TIMEZONE, item.getEventStartTime()
.getTimeZone());
database.insert(TABLE_NAME_EVENTS, null, eventItemValue);
}
i then call that method from the superclass using this:
events = (List<CalendarEventItem>) items;
insertAllItemsToDb(events, TABLE_NAME_EVENTS);
But i recieve a compile error saying you cant cast it. Any ideas on how i can achieve this without having to duplicate the same steps and code you see inside the insertAllItemsToDb()
Use a Type parameter
Add a generic Parameter to the abstract class:
public abstract class BaseClass<T>{
protected abstract void insertItem(T object, String table);
protected void insertAllItemsToDb(List<T> items, String table) {
//...
for (T object : items) {
insertItem(object, table);
}
//...
}
}
Now you don't need any casting, a child class just has to use the correct type:
public class FooBar extends BaseClass<Phleem>{
protected void insertItem(Phleem object, String table){
// ...
}
}
A List<Object> is not a List<CalendarEventItem>, so the compiler is right that they aren't castable. For a quick reason why, here's an example:
final List<Object> listOne = new ArrayList<Object>();
listOne.add("Hello World");
final List<CalendarEventItem> listTwo = new ArrayList<CalendarEventItem>();
listTwo.addAll(listOne); // Correctly disallowed by compiler
// This is what you're trying to do
List<CalendarEventItem> sneakyList = (List<CalendarEventItem>)listOne;
listTwo.addAll(sneakyList);
So casting between two incompatible types is disallowed because it would destroy the type-safety guarantees.
You almost certainly want to be declaring your insertAllItemsToDb method to take a List<?> rather than a List<Object>, since you don't care what the element type is so long as it's a subclass of Object (which is trivially true).
This should prevent you having to cast between inconvertible types, and is generally much nicer to work with.
For more information take a look at the Wildcard Bounds section of Angelika Langer's excellent Java Generics FAQ. In fact, you should probably look over the whole thing if you haven't already. The general principle to take away is that in most cases you should likely use wildcards on collections used for method arguments - the only time you wouldn't is if you both read from and write to the collection (which is actually surprisingly rare).
You could also just declare the method parameter as a regular list and then cast it to whatever generic list you want inside the method, ie your method would be protected void insertAllItemsToDb(List items, String table) and the first line you would cast it: List<CalendarEventItem> newItems = (List<CalendarEventItem>) items... of course implementing whatever type of checking/error catching that you should when doing such a thing.