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.
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.
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.
I came to know the Unbounded Wild card but I didn't understand usage of it in realworld.
In Below program using and with out using this Unbounded Wildcard will be same at compile time.Then why we need Unbounded wild cards ?Please help to understand.
public class UnboundedWildCards {
public static void main(String args[])
{
List<Integer> intLst = new ArrayList<Integer>();
intLst.add(1);
intLst.add(11);
List<Double> doubleLst = new ArrayList<Double>();
doubleLst.add(1.1);
doubleLst.add(11.11);
List lst = new ArrayList();
lst.add(new Object());
lst.add(new Double(2.3));
lst.add(new Integer(2));
print(intLst);
print(doubleLst);
print(lst);
unBoundprint(intLst);
unBoundprint(doubleLst);
unBoundprint(lst);
}
public static void print(List lst)
{
for(Object o : lst)
System.out.println(o);
}
public static void unBoundprint(List<?> lst)
{
for(Object o : lst)
System.out.println(o);
}
}
Are you asking why do we need the notation
List<?>
when the simpler
List
is equivalent?
Using the wildcard is more explicit but the simpler syntax is required for backwards compatibility with pre-generics code. So you can use either interchangeably but there is also a third way of declaring this list which is also equivalent.
List<? extends Object> list;
This list will contain only objects of type Object. Since everything in Java extends from Object this is basically the same as saying unbounded.
Personally of the three I would probably use the first one because it is concise while still explicitly stating what the List should contain. If you just declared it as a List without a generic argument then it could be mistaken for a pre-generics list.
When would you ever want to use this? From experience I have only used this kind of unbounded list with legacy code. I was always taught to only put objects of one common type into a list (like a list of customers etc). However, people don't always write nice code and at times I've had to deal with lists containing different types. In these cases it was hard to move to a proper genericised list so I had to make do with an unbounded list.
It is possible that you may have a legitimate cause for an unbounded list. It depends what you want to do with those objects. If once they've been added to the list you only need to call methods from the Object class (like toString) or perhaps the List interface (like size), then perhaps you have a genuine use case for an unbounded list.
There are two scenarios where an unbounded wildcard is a useful approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In fact, Class is so often used because most of the methods in Class do not depend on T.
with examples
http://docs.oracle.com/javase/tutorial/java/generics/unboundedWildcards.html
At first it is important to understand that List<Object> and List<?> are not same. List<Object> is not super class of List<Anything that extends object> but List<?> or List<? extends Object> is super class of List<Anything that extends object>.
After keeping above point in mind go through printList example from this oracle's link https://docs.oracle.com/javase/tutorial/java/generics/unboundedWildcards.html
I need in my program collection in collection in collection. So something like this:
ArrayList<ArrayList<ArrayList<String>>>
You can see this does not look good. Mainly when i am using a lot of generics. So i created something like this:
public class ThreeDimensionArray extends ArrayList<TwoDimensionArray> { }
class TwoDimensionArray extends ArrayList<ArrayList<String>> { }
is this solution bad in some way or is it ok?
It's not great, but it is ok. It's rather masking what you are doing - and its a bit wasteful as you are creating a concrete class to define something that type erasure would have turned into a standard List at compile time.
Really you should be using List rather than ArrayList and the diamond operator, both changes will make the original tidier:
List<List<List<String>>> 3dList = new ArrayList<>();
If you do go down the defined class route at least use generics -
class TwoDimensionArray<T> extends ArrayList<ArrayList<T>> { }
Then you can use it for multiple types.
I'm studying for the SCJP/OCPJP and I came across a sample question that seams strange to me.
The sample code instantiated two generic collections:
List<?> list = new ArrayList<?>();
List<? extends Object> list2 = new ArrayList<? extends Object>();
The "correct" answer to the question was that this code would compile but adding to either collection would produce a runtime error.
When I try to compile code like this I just get errors. The Java tutorial does not even show this type of code, it instead usually uses wildcards as a part of an upcast.
Collection<?> c = new ArrayList<String>();
Are the two generic collections above even legitimate code? The second by my logic would only disallow interfaces. The first one looks completely useless. Why use a generic that makes no attempt at control?
Check out the excellent Java generics tutorial PDF. More specifically the section about wildcards contains the answer to your question, and I quote
Collection<?> c = new ArrayList<String>();
c.add( new Object() );
Since we don’t know what the element type of c stands for, we cannot
add objects to it. The add() method takes arguments of type E, the
element type of the collection. When the actual type parameter is ?,
it stands for some unknown type. Any parameter we pass to add would
have to be a subtype of this unknown type. Since we don’t know what
type that is, we cannot pass anything in. The sole exception is null,
which is a member of every type.
If you want to declare Type at runtime, you can do something like this:
public class Clazz1<T> {
private final List<T> list = new ArrayList<T>();
private List<T> getList() {
return list;
}
/**
* #param args
*/
public static void main(String[] args) {
Clazz1<Integer> clazzInt = new Clazz1<Integer>();
clazzInt.getList().add(2);
System.out.println(clazzInt.getList());
Clazz1<String> clazzString = new Clazz1<String>();
clazzString.getList().add("test");
System.out.println(clazzString.getList());
}
}
I answered this somewhat before in this answer. ? cannot be used in the instantiation. I'm not sure why it says the code would compile, none of the java compilers I have used would allow that. You could do what is shown above by the following:
List<?> list = new ArrayList();
That would compile and run, but you couldn't do:
list.add("hello world"); //This wouldn't compile
new produces a concrete instance of an object. The concrete instance can have only one type, including any generics. Knowing this, wildcards cannot work with new.