I have the following code:
HashMap<Integer, String> h = new HashMap<Integer, String>();
h.put(1, "a");
h.put(2, "b");
h.put(3, "c");
h.put(4, "d");
System.out.println(h); //{1=a, 2=b, 3=c, 4=d}
Collection<String> vals = h.values();
System.out.println(vals); //[a, b, c, d]
Iterator<String> itr = vals.iterator();
while (itr.hasNext()) //a b c d
{
System.out.print(itr.next() + " ");
}
My Questions:
h.values() returns a Collection view of values in h. Since vals is an interface, how can we assign some values to an interface (they cannot be instantiated)? Where is the class that is implementing this interface? Where is the object of that class?
Similar question for itr. We know vals.iterator() returns first element of the collection. How can we assign it to an interface instance?
The underlying principle that governs the answers to your questions is called the Liskov's Substitution Principle which applies in this case to assign the value that is of an instance of a given interface (Collection, Iterator) to a reference whose type is a class that implements that interface (e.g. AbstractCollection, Some anonymous class etc).
If you see the HashMap#values() method code, you'll see in Java 8 source code:
public Collection<V> values() {
Collection<V> vs;
return (vs = values) == null ? (values = new Values()) : vs;
}
final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
...
}
Thus, you are being returned either
an instance of Values class which extends an AbstractCollection which implements Collection, or
an instance of a concrete subclass of AbstractCollection (see: values = new AbstractCollection<V>() at line 386 in AbstractMap.java in Java 8 source code.
Again, according to the LSP, this is all valid. To understand how all this is wired up, you'll need to grok the JDK code base.
More Answers
h.values() returns a Collection view of values in h. Since vals is an interface, how can we assign some values to an interface (they cannot be instantiated)?
To be precise, vals is not an interface, but an instance thereof. It's true that you can not instantiate an interface say Listener using the new operator like listener l = new Listener(), but according to the LSP, you can always instantiate a concrete implementation of the Listener interface and assign it to a variable whose type is Listener, like for example, Listener listener = new SerialListener();
Where is the class that is implementing this interface?
In this case, it is the Values class or AbstractCollection class as shown above.
Where is the object of that class?
In several cases, it is an instance of the anonymous inner class that is instantiated at the time of its definition.
We know vals.iterator() returns first element of the collection.
Not quite right. It returns an instance of a class that implements the Iterator interface. If and when you call the next() method on the returned object, you get the first element of the collection (assuming it is not empty).
How can we assign it to an interface instance?
The idea is the same. If the variable on the left hand side of an assignment statement (left of = sign) refers to an interface, then the right hand side can refer to a reference to an object that implements that interface, directly or indirectly (via inheritance hierarchy).
Related
This is my first problem I can't solve by searching. It's a general OOP problem, but the code is in java. Perhaps I miss an essential point?
Assume there is a baseclass and a subclass. An object of the baseclass is in many lists. There is a transformer class with one duty to transform the object into a subclass object. The transformer should not know anything about the lists. But as a result of the transformation the new subclass object should be in all the lists. (replace the former base class object)
Can this be done somehow?
class BaseClass {
//
}
class SubClass extends BaseClass{
//
}
class Transformer{
BaseClass base;
public Transformer(BaseClass base){
this.base = base;
}
public void transform(){
//transforms the Object to a subtype-object
// ???
// (move the references of the old object to the new one)
this.base = new SubClass(); //something like this (but not so!!!)
}
}
class Programm{
private List<BaseClass> list1 = new ArrayList<>();
private List<BaseClass> list2 = new ArrayList<>();
private List<BaseClass> list3 = new ArrayList<>();
//many more Lists
private List<BaseClass> listn = new ArrayList<>();
public void main() {
BaseClass myObject = new BaseClass();
list1.add(myObject);
list2.add(myObject);
list3.add(myObject);
listn.add(myObject);
Transformer transformer = new Transformer(myObject);
transformer.transform();
//required result
// All Lists contain the transformed Object (from Type SubClass)
}
}
What you're trying to do is luckily impossible (imagine if your objects started changing classes in the middle of your code). You can create a subclass object based on a superclass object (if you can sensibly fill in any missing properties), but you can't turn an existing object into its subclass (such that the reference equality would work as you're hoping in your example code, i.e. converting myObject would affect all the lists).
I don't know how you came up with this idea, but somewhere along the way you've gone down the wrong path. If you tell us what you're trying to achieve, we can provide you with a better solution.
Edit:
Since you're doing checkers and you need to crown a piece, you have the simple choice of adding a boolean crowned property to pieces, and writing logic based on that.
In a more complex situation you could for example use the strategy pattern, where you would have a Piece class, and they would have a Type property that specifies the actual type of the piece. This way the object you put in lists (Piece) always stays the same, but if you replace its Type property, it would seem as if the piece magically changes it's type!
How do I let the user insert a String and check for classes with the same "name"?
Imagine I have a method marked as public A[] getB(String bString) and two classes, A and B, where B extends A.
In this method I want to search through an existing A[] for objects that are upcast from being from the class B and return an A[] with said objects.
I searched through the internet and found out that the class Class has the method forName(), but I don't really understand how to use it. For example, I do this:
Class<?> cl = Class.forName(bString);
Where bString is a String that contains B, B being another class.
My questions are:
What exactly is the object "cl" now?
How could I now check if objects are of the same class as it?
What exactly is the object "cl" now?
cl is an instance of Class class.
How could I now check if objects are of the same class as it?
you have 2 object o1 and o2 you can use getClass()
o1 != null && o2 != null && o1.getClass().equals(o2.getClass())
The method Class.forName(String) returns a Class object for the corresponding class, if known. To quote from its documentation:
Returns the Class object associated with the class or interface with the given string name.
An example would be:
Class threadClass = Class.forName("java.lang.Thread");
Note that the name of the class needs to be fully qualified, not just Thread but java.lang.Thread.
The object you are getting is, as said, a representation of the corresponding class. You can use it to dynamically create instances, check methods, and so on. Here is its documentation and here is an example:
Class<?> threadClass = Class.forName("java.lang.Thread");
// Dynamically create a thread, unchecked cast
Thread thread = (Thread) threadClass.newInstance();
You can check whether two objects are of the same class by using the getClass (documentation) method which every object has:
if (first.getClass().equals(second.getClass()) {
// Same
} else {
// Different
}
However note that this comparison is strict. It would throw false if you compare Integer and Number although Integer extends Number. If you want a less strict variant you may use the instanceof operator:
if (first instanceof second) {
// Is type of
} else {
// Not type of
}
are you sure you wouldn't rather use isInstance?
You could change your method to take a Class instead of a String, since that's what you're really using, a Class.
public A[] getB(Class type){
// I'm assuming you have an array of all As somewhere, called Aarray here
List<A> BList = new ArrayList<>();
for(int i = 0; i < Aarray.length; i++){
if(type.isInstance(Aarray[i])){
BList.add(Aarray[i]);
}
}
return BList.toArray();
}
Given a class of the below structure:
public class Section extends IterableWidgetTemplate<Item>{
private List<WebElement> items1;
// other non iterable methods
private int indexOf(final Item item) {
int i = Iterables.indexOf(this, new Predicate<Item>() {
. . .
});
return i;
}
where Iterables is a Guava com.google.common.collect.Iterables that, according to its documentation, contains static utility methods that operate on objects of type Iterable.
Now in the class that I described above, this is passed as an iterable to the private int indexOf() method.
Questions:
What am I going to iterate over in this object? Am I right in my assumption that the Iterables class will use the only iterable method that is available in the object that is being passed to it? So in this case we have the List<WebElement> variable inside this object.
If the answer to 1. is "yes", what would have happened if the Section class had more than one iterable variable? Which one of them will be used for iteration?
Iterables.indexOf() takes as its first parameter an object which implements the Iterable interface. So, what Iterables.indexOf() iterates over is defined by the object passed in as a parameter, in your example the Section class. It's not using a variable however - it will call the Iterable.iterator() method on your Section object. It's not possible to have more than one of those methods so there can be no cases where there's confusion about what Iterables.indexOf() will iterate over.
I am trying to understand how the following iteration is working, in other words how can we iterate over the this (I have seen this implemented at someone else's program). The method getEl is part of a class C that implements Iterable. Class C itself does not have any containers of type A, but has a private variable of type A. Class A on the other hand has iterable containers (sets of type A and sets of another type D).
public void getEl() {
for(A el : this) {
//do something
}
}
Can someone help me understand what is going on here?
You can iterate over this (whatever type it is) if this also implements Iterable<T>.
Class C implements Iterable<A>, which contains the method iterator() that returns an Iterator<A>.
You can use the enhanced for loop on any object that implements Iterable.
It's equivalent to :
Iterator<A> iter = this.iterator();
while (iter.hasNext()) {
A el = iter.next();
...
}
for ( : ) is just syntax sugar for calling iterator() on the given object, and using the returned iterator object to go through a set of elements (which is entirely determined by the implementation of said iterator). Since this is an instance of a class that implements Iterable, you would look at its iterator() method.
Mostly, it is confusing to see this being used here. However,
C foo = this;
for (A el : foo) {}
Is just the same.
Ok, so here is my problem:
I have a list containing interfaces - List<Interface> a - and a list of interfaces that extend that interface: List<SubInterface> b. I want to set a = b. I do not wish to use addAll() or anything that will cost more memory as what I am doing is already very cost-intensive. I literally need to be able to say a = b. I have tried List<? extends Interface> a, but then I cannot add Interfaces to the list a, only the SubInterfaces. Any suggestions?
I want to be able to do something like this:
List<SubRecord> records = new ArrayList<SubRecord>();
//add things to records
recordKeeper.myList = records;
The class RecordKeeper is the one that contains the list of Interfaces (NOT subInterfaces)
public class RecordKeeper{
public List<Record> myList;
}
This works :
public class TestList {
interface Record {}
interface SubRecord extends Record {}
public static void main(String[] args) {
List<? extends Record> l = new ArrayList<Record>();
List<SubRecord> l2 = new ArrayList<SubRecord>();
Record i = new Record(){};
SubRecord j = new SubRecord(){};
l = l2;
Record a = l.get( 0 );
((List<Record>)l).add( i ); //<--will fail at run time,see below
((List<SubRecord>)l).add( j ); //<--will be ok at run time
}
}
I mean it compiles, but you will have to cast your List<? extends Record> before adding anything inside. Java will allow casting if the type you want to cast to is a subclass of Record, but it can't guess which type it will be, you have to specify it.
A List<Record> can only contain Records (including subRecords), A List<SubRecord> can only contain SubRecords.
But A List<SubRecord> is not a List<Record> has it cannot contains Records, and subclasses should always do what super classes can do. This is important as inheritance is specilisation, if List<SubRecords> would be a subclass of List<Record>, it should be able to contain ` but it'S not.
A List<Record> and a List<SubRecord> both are List<? extends Record>. But in a List<? extends Record> you can't add anything as java can't know which exact type the List is a container of. Imagine you could, then you could have the following statements :
List<? extends Record> l = l2;
l.add( new Record() );
As we just saw, this is only possible for List<Record> not for any List<Something that extends Record> such as List<SubRecord>.
Regards,
Stéphane
Just to explain why Java does not permit this:
A List<Record> is a list in which you can put any object implementing Record, and every object you get out will implement Record.
A List<SubRecord> is a list in which you can put any object implementing SubRecord, and every object you get out will implement SubRecord.
If it would be allowed to simply use a List<SubRecord> as a List<Record>, then the following would be allowed:
List<SubRecord> subrecords = new ArrayList<SubRecord>();
List<Record> records = subrecords;
records.add(new Record()); // no problem here
SubRecord sr = subrecords.get(0); // bang!
You see, this would not be typesafe. A List (or any opject of a parametrized class, in fact) can not typesafely change its parameter type.
In your case, I see these solutions:
Use List<Record> from start. (You can add SubRecord objects to this without problems.)
as a variation of this, you can use List<? super Subrecord> for the method which adds stuff. List<Record> is a subtype of this.
copy the list:
List<Record> records = new ArrayList<Record>(subrecords);
To exand a bit on th variation:
void addSubrecords(List<? super Subrecord> subrecords) {
...
}
List<Record> records = new ArrayList<Record>();
addSubrecords(records);
recordkeeper.records = records;
THIS WORK, BUT YOU SHOULD BE WARN !!!!
#Override
// Patient is Interface
public List<Patient> getAllPatients() {
// patientService.loadPatients() returns a list of subclasess of Interface Patient
return (List<Patient>)(List<? extends Patient>)patientService.loadPatients();
}
You can cast from List of Objects to List of Interface in this way.
But, if you get this list somewhere in your code and if you try to add something to this list, what would you add? Inteface or Subclass of this interface ? You actually loose information of the type of list, because you let it hold Interface, so you can add anything that implement this interface, but the list is holding the subclasses only, and you could easily get class cast exception if you try to do operations like add or get on this list with some other subclass. The solution is: Change The type of source list to list<Interface> instead of cast, then you are free to go :)
You can't do that and be safe because List<Interface> and List<SubInterface> are different types in Java. Even though you can add types of SubInterface to a list of Interface, you can't equate the two lists with different interfaces even if they're sub/super interfaces of eachother.
Why is it that you want to do b = a so bad? Do you just want to store a reference to the SubInterface list?
On a side note, I suggest you read this documentation on the oracle site: http://download.oracle.com/javase/tutorial/java/generics/index.html
It explains and goes deep into generics very well.
So, the rather simple solution a friend of mine found was this:
recordKeeper.myList = (List<Record>)(List<? extends Record>)records;
This works as I understand it because it takes baby steps. List<SubRecord> is a List<? extends Record>, and List<? extends Record> is a List<Record>. It might not be pretty, but it works nonetheless.
There's no way to do it that is type safe.
A List<SubInterface> cannot have arbitrary Interfaces added to it. It is a list of SubInterfaces after all.
If you are convinced that this is safe to do even though it is not type safe you can do
#SuppressWarnings("unchecked")
void yourMethodName() {
...
List<Interface> a = (List<Interface>) b;
...
}