Say I extend a Java class like java.util.List to create a custom class called MyList... Is there any way if my peers write code using List, I can convert it into MyList during compilation/runtime?
i.e. If they have something like:
List groceryList = new List();
it should be compiled/run like:
MyList groceryList = new MyList();
I know annotations can do something of this sort. Is it possible to use them in this case? If yes, how?
This is known as downcasting.
The short answer is that if they created the object with the new command, such as in your example, then no, you will not be able to cast it.
What you can do, is define a constructor in MyList class that accepts the object-to-be-converted as a parameter and uses it to create a new object. The list is a bit special because you can create new lists from existing ones . For example:
public MyList (List oldList)
{
super(oldList); //this will copy the objects of the list to your custom list
//But you could do any other operations to create the new object from the parameter(s)
...
}
and use it as
MyList groceryList = new MyList(oldList);
While upcasting in java is mostly safe, Downcasting in Java is not something you should frequently use, unless really needed, since the subclass may not support some attributes or methods that the superclass can.
Related
I have heard several times that when instantiating objects you should do:
"Interface" name = new "Class"();
For example for the class linkedlist that implements List:
List<String> name = new LinkedList<String>();
LinkedList implements many interfaces, including queue, deque, etc. What is the difference between the above code and
LinkedList<String> name = new LinkedList<String>();
or
Queue<String> name = new LinkedList<String>();
Why must the type be specified twice as well; it seems redundant but oracledocs don't seem to mention it.
LinkedList<String> name = new LinkedList<String>(); is redundant in Java 7. It can be rewritten to LinkedList<String> name = new LinkedList<>();.
The reason you want to write something similar to:
// Java 7 way:
List<String> name = new LinkedList<>();
is to provide you with the freedom of changing your data collection later, if you change your mind. Your code is much more flexible this way. What you should note about this, is that the methods you are able to use are limited to the left-hand side type (List in this case). This means that you may not get all the functionality you want, if you use a type that is higher in the hierarchy (Object being the extreme example).
Firstly, an Interface is a abstract type that is used to specify what a classes must implement. Any class the implements an interface must satisfy its contract by implementing its method and is of that type.Therefore, by implementing the List interface LinkList is a type of list.
By coding to the interface and not to the concrete class your code becomes more loosely coupled. This means that your code is not bound to the LinkList but rather the List interface and can be changed to anything that implements the list interface at anytime. Therefore, if for some reason the LinkList no longer meets you requirements and you need, lets say a ArrayList instead since it also implements the List interface you can just change to :
List<String> name = new ArrayList<String>();
And all your other programming logic would remain the same,since both classes have the same methods because they implement the same interface.
LinkedList<String> name = new LinkedList<>();
Will expose the methods that are defined in LinkedList and its superclasses.
Queue<String> name = new LinkedList<>();
Will expose the methods that are defined in Queue and the interfaces it extends.
You should define the object as a class/interface that holds everything (methods, variables, etc) that you need, while also making it as abstract as possible.
This hides implementation details and allows for easier switching between implementation, for example.
Note that you don't have to specify the type in the initialization due to the diamond operator.
What is the difference between the above code and
LinkedList<String> name = new LinkedList<String>();
or
Queue<String> name = new LinkedList<String>();
There are a few key differences.
The difference between using the List interface and using a LinkedList object is that I'm defining my interaction with the implementing object to adhere to the List interface. Ultimately, I don't care what the implementation is*, so long as it behaves like a List of some kind.
If I use the concrete LinkedList object, then I not only have to care what the type is, but I can use more things than I probably should - since it implements the Queue interface too, I can do queue-like operations on it, which may or may not be appropriate.
Ultimately, your code should be SOLID; here, we adhere to the dependency inversion principle, which allows us to depend on the interface as opposed to the concrete implementation. It allows us to subsitute the LinkedList for an ArrayList should we want to.
*: Of course you should care what the underlying implementation is, for performance reasons. But, you may not care yet.
This isn't as simple as it looks. If you use:
List<Foo> name = new LinkedList<Foo>();
if you ever wanted to switch from linked lists to arraylists it would be less maintenance.
About the redundancy, List name = new LinkedList() declares name of type List and invokes the LinkedList constructor. You could have as follows:
List<Foo> name = someRandomObject.someRandomHelperMethod();
This helper method "just happens" to return a list, so there is no redundancy.
With Java 7 the apparently-redundant generic args can be skipped:
List<Foo> someL = new ArrayList<>();
as opposed to
List<Foo> someL = new ArrayList<Foo>();
If you code to interfaces you can easily switch implementations easily. If an ArrayList suits your needs better than a LinkedList then you can change one line only. If you need a particular method that is in the LinkedList class (or any other of the sub types) then it is perfectly valid to have
LinkedList<String> name = new LinkedList<String>()
As for the redundancy if you are referring to the generic type declaration then I would recommend you look at the Guava libraries. These have some nice static import methods to remove this. For example for an ArrayList it would be
List<String> name = newArrayList()
instead of
List<String> name = new ArrayList<String>()
There is a similar method for LinkedList too.
In Java 7 there is also the diamond operators but this is still a bit more verbose than the static import from Guava.
List<String> c = new ArrayList<String>();
I don't understand why they did this,i mean they could have used,
List<String> c=new List<String>();
OR
ArrayList<String> c=new List<String>();
What is the use of this type of syntax and how to use it...
It is actually good that we have a List interface. That way we have the option of using the different type of lists (ArrayList, linkedlist, etc) and inherit the common methods among them.
For example, every list needs to have an add and remove method. But depending on the list, the implementation will vary. An ArrayList will add an item differently than a LinkedList.
So the List interface helps Java coders abstract the common details between lists that will later on have different implementations.
I hope this helps.
You could look at it this way. The interface List provides the common methods every list implementation has, whereas a concrete type like ArrayList provides a specific behaviour on how the list functions.
So List<String> c = new ArrayList<String>(); means a general List of Strings, which has methods like add(), clear() and get() but which acts like an ArrayList.
With using an interface like this you could switch the behaviour of that list at runtime. That means you could do something like this:
List<String> list = new ArrayList<String>();
list = new LinkedList<String>();
That is not possible if you declared list as ArrayList from the beginning.
ArrayList<String> list = new ArrayList<String>();
list = new LinkedList<String>();
This will generate a compiler-error Type mismatch: cannot convert from LinkedList<String> to ArrayList<String>.
To be more technical, interfaces define sort of a "contract", which means that every class implementing that interface has to provide its defined methods. So if you use an interface, you can be sure that any created object implementing it has the same common methods, since they have to submit to the "contract". But how that object behaves and how the provided methods are implemented is completely up to you.
Is there a way to subclass the ArrayList class to only allow objects of a specific class (or subclass thereof).
Specifically, I have a base class called RecordStatus and I need to create ArrayLists with objects based on this class.
I know it would be easy to create a class based on ArrayList<RecordStatus> but then, every time I retrieve an element from the array, I need to cast it to the original class.
Is there an easier way to do this?
Is there a way to subclass the ArrayList class to only allow objects
of a specific class (or subclass thereof). Specifically, I have a base
class called RecordStatus and I need to create ArrayLists with objects
based on this class.
That's exactly what the generic construct in Java allows you to do. Note that you don't have to cast the instances coming out of your ArrayList<RecordStatus> as long as all subclasses of RecordStatus have the same API. You only have to do that if the subclasses have different methods/fields. For example, if RecordStatus has a method setStatus, and so does a subclass, no casting is necessary, as the dynamic dispatch of Java's polymorphism will make sure the method that gets implemented is correct based on the type of the instance on which the method is invoked at runtime.
You shouldn't need to cast anything if you set up your types correctly. For example, this should work:
List<RecordStatus> myList = new ArrayList<RecordStatus>();
//Add values to the list
RecordStatus myRecordStatus = myList.get(0);
But if you really want to subclass ArrayList, you can do the following:
private class MyArrayList<R extends RecordStatus> extends ArrayList<R> {
...
}
ArrayList<? extends RecordStatus> is as close as you can get.
I've created arrayList without troubles using a line like this
List<RecordStatus> list = new ArrayList<RecordStatus>();
Try Collections.checkedList(List<E> list, Class<E> type). This will ensure the Type-Safety.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why should the interface for a Java class be prefered?
In Java, is there a difference between these two lines? If so, what is it, and when should I use either one? Is there a preferred convention?
Note that ArrayList implements List.
List<String> bunchOfStrings = new ArrayList<String>();
ArrayList<String> bunchOfStrings = new ArrayList<String>();
In Java, is there a difference between these two lines?
Yes, there is a slight difference, and the List<String> variant is preferred.
Is there a preferred convention?
The convention says that you should "program against interfaces". The reason is that it becomes much easier to swap the actual implementation (in this case from ArrayList to say LinkedList).
In both case you are instantiating an ArrayList. The difference is that in the first case you are referring it as a List (the interface that ArrayList implements ), so you don't have access to specific method of ArrayList class, but only interfaces method.
use thi first:
List<String> bunchOfStrings = new ArrayList<String>();
This way you can switch different List implementation (ArrayList, Vector):
public class AClass(){
List<String> bunchOfStrings;
public List<String> getList(){
bunchOfStrings = new ArrayList<String>();
//or you can switch to : bunchOfStrings = new Vector<String>();
return bunchOfString;
}
}
You should use the most generic type possible. So in this case that's List. The only time you would use a more specific type is if that type had methods defined on it that the more generic type does not.
The reason is that if a method accepts a type, like List, the user of the method can provide any type of List they want. If a method only accepts an ArrayList, the user can't use any other type of List.
If you declare bunchOfStrings as a List, you can't call any of the ArrayList methods (without casting), even though it is pointing to an ArrayList object -- you can only call methods that are declared in the List class.
For this reason, you might think that it's better to always declare your variable type to be as specific as possible, but declaring it as a List is generally preferable because it allows you to change the underlying implementation of your List without having to change anything else in your code. You can easily modify your code as follows without breaking anything else in your code:
List<String> bunchOfStrings = new LinkedList<String>();
As a rule of thumb, only ever declare the type of your variable to be a specific subclass if you...
...need access to methods that are only available in the subclass.
...need to pass the object instance to a method that only accepts objects of that subclass.
This is called Polymorphism. It is very useful and has no real drawbacks.
Pros:
You can send this instance variable to any method that wants a "List" object.
Using List in a method declaration, you are opening up the method to anything that is a sub-type of List, instead of just of type ArrayList.
Cons:
You would have to cast your variable to an ArrayList to access or set any features/methods/fields that are in ArrayList (but not in List). But those things are still available.
Consider the following two Java files that contain a simplified version of my issue
#a.java
package a;
public interface I {
//...
}
#b.java
package b;
public interface I {
//... (different stuff from a.I)
}
You'll notice within my project there are two interfaces named "I". This cannot be changed.
I am in a situation where I need to use both types inside a single class. Now of course, I could just reference each of their types as a.I and b.I, but I'm trying to avoid it for nothing other than maintaining readability.
I want to do something like this
interface B extends b.I {
}
This could let me use the interface of I by using B and, and a.I as just I by importing. The problem is that this doesn't work, let's take this concrete example using
interface MyList extends List<String> {
}
MyList l = new ArrayList<String>();
This yields a type error. Why doesn't Java "know" that MyList extends List?
Also, I've tried casting in the above example, but it generates a ClassCastException
Thoughts?
This is valid:
List<String> list = new MyList();
This is not:
MyList l = new ArrayList<String>();
ArrayList is not a MyList. They just have a common superinterface. That's why it doesn't work. Java "knows" MyList is a List but that doesn't mean you can assign a List to it.
Consider:
public interface MyList extends List<String> {
void foo();
}
MyList l = new ArrayList<String>();
l.foo();
Obviously ArrayList does not have the foo() method.
Java does know that MyList extends List<String>, but it also knows perfectly well that ArrayList<String> does NOT implement MyList. I would strongly recommend removing ambiguities in the simplest, clearest, cleanest, most readable way: use a.I and b.I!
You can't cast an ArrayList<String> into a MyList because MyList is not a super-class or super-interface of ArrayList<String>. Pretend you actually added a method to MyList, say MyList.swizzle(). What would happen if Java allowed the cast and then you called l.swizzle()?
I don't think you're going to find a satisfactory solution to this since Java does not have an import as type renaming statement. But implementing an interface to add its members to your class's namespace is contraindicated in Java 1.5: if you're going to go down that route, give static import a try instead. It is the preferred idiom nowadays for doing what you're trying to do.