I have a method in my Android app that can either display from a List of Drawables or Strings (representing the image URLs).
I tried to make two constructors but got the type erasure error. Now I am using a generic argument and check a member for being a String to represent the URL, like so. In the alternate case I assume that it will be a List of Drawables. Something like this:
setImages(List<?> images) {
this.images = images;
if (String.class.isInstance(images.get(0) ) ) {
isImageUrl = true;
}
}
Is there a way to do this better, somehow preserve type safety ?
Why not just use 2 separate methods?
void setImages(List<Drawable> images) {
// do something
}
void setImagesFromStrings(List<String> images) {
// do something else
}
No, there is no real way to do that.
There has been some interesting solution here, but I don't think it applyes for you.
Personnally, I prefer to pass the class as a parameter for the method like
setImages(List<? extends T> images, Class<T> clazz) {
this.images = images;
if ( clazz == String.class ) ) {
isImageUrl = true;
}
}
A better object oriented way to solve you problem would be to have an intermediate interface that provides the method you are looking for, but this will force you to wrap String into something else
interface Displayable {
public boolean isRealImage();
}
class StringImage implements Displayable {
public String name;
public boolean isRealImage() { return false; }
}
class DrawableImage implements Displayable {
public Drawable drawable;
public boolean isRealImage() { return true; }
}
setImages(List<? implements Displayable> images) {
this.images = images;
if (images.get(0).isRealImage()) {
isImageUrl = true;
}
}
Of course this solution, while quite overkill, is meant to allow you whatever you need to do with your classes.
Related
I have been struggling to grasp this concept in Java. I have a list of objects I need to print. Either a string or bitmap. Each has its own way to be printed. My current interface would look like this:
public interface IPrintJob {
void print();
}
I have PrintJobText, and PrintJobBitmap classes which each implements IPrintJob. I need to be able to add them both to the same list. Can I do it with
ArrayList<IPrintJob> printjobs
Is this the right approach ? Should this be done with generics ? How would PrintJobText/PrintJobBitmap classes look ? I'm a bit lost after trawling the net for an understanding on the best way to handle this.
One example could be like this.. (not completely sure what you mean with a bitmap in this case though, so just made it a boolean)
public interface IPrintJob {
void print();
}
public class PrintJobText implements IPrintJob {
private String text;
PrintJobText(String text) {
this.text = text;
}
void print() {
System.out.println(text);
}
}
public class PrintJobBitmap implements IPrintJob {
private boolean bit;
PrintJobBitmap(boolean bit) {
this.bit = bit;
}
void print() {
System.out.println(bit ? "true" : "false");
}
}
List<IPrintJob> printjobs = new ArrayList<>();
printJobs.add(new PrintJobText("test1");
printJobs.add(new PrintJobBitmap(true);
printJobs.forEach(IPrintJob::print);
Of course the implementation of the print method can be anything. The system out is just an example.
Depends on what you mean by
Each has its own way to be printed
in my opinion. If you just mean what this answer demonstrates, you could also simply override toString() in both of the classes like this:
public class PrintJobText {
private String text;
PrintJobText(String text) {
this.text = text;
}
#Override
public String toString() {
return text;
}
}
public class PrintJobBitmap {
private boolean bit;
PrintJobBitmap(boolean bit) {
this.bit = bit;
}
#Override
public String toString() {
return String.valueOf(bit);
}
}
And simply store the objects in a List<Object> or some other common super-class.
Now does that mean you should do it this way? Probably not. At least don't store the objects in a List<Object>, because what if you wanted to add more functionality to your interface down the line?
Not only would you need to refactor a bunch of type definitions, but before the change nothing would have stopped you from adding instances of classes to the list that don't make any sense to be there, so now you either have to figure out a way to implement the new methods for those classes as well or restructure your code so those classes never get added to the list in the first place.
Another pitfall is that classes could forget to override toString() because there's no way to enforce them to do so.
Another possible definition of the interface could like this:
public interface IPrintJob {
String getPrintValue();
}
This would cut both the problems I mentioned above and is slightly cleaner than having a void print() as it removes the duplication of System.out.println(...) in the implementations.
Create a custom class that could contain attributes of either a string or a bitmap to contain the relevant object but under a different guise I guess, you can then create an array list of these custom objects, and use if ( object instanceof string ) then // do string code, and vice versa for bitmaps.
I have two ArrayLists - ArrayList1 and ArrayList2. Each of them is filled with objects - Object1 and Object2, respectively.
Both of these objects have method 'getText'.
Object1:
public String getText() { return "1";}
Object2:
public String getText() { return "2";}
At certain point I would like to loop through each of these lists using the same method (just with different parameter).
loopThroughList(1)
loopThroughList(2)
What is the syntax if I want to call a method, but I don't know which object it is going to be? This is the code I have so far:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getText());
}
It says Cannot resolve method getText. I googled around and found another solution:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
But this gives me NoSuchMethodException error. Even though the 'getText' method is public.
EDIT: To get the correct list, I am calling the method 'getList' of a different object (lists) that returns either ArrayList1 or ArrayList2 (depending on the provided parameter).
class Lists
public getList(list) {
if (list == 1) {
return ArrayList1;
}
else if (list == 2) {
return ArrayList2;
}
}
Define an interface for the getText method
public interface YourInterface {
String getText();
}
Implement the interface on the respective classes
public class Object1 implements YourInterface {
#Override
public String getText() {
return "1";
}
}
public class Object2 implements YourInterface {
#Override
public String getText() {
return "2";
}
}
Modify your getList method to return List<YourInterface>
public static List<YourInterface> getList(int list){
List<YourInterface> result = new ArrayList<>();
if(list == 1){
// your initial type
List<Object1> firstList = new ArrayList<>();
result.addAll(firstList);
} else {
// your initial type
List<Object2> secondList = new ArrayList<>();
result.addAll(secondList);
}
return result;
}
Declaration for loopThroughList
public static void loopThroughList(List<YourInterface> list){
list.forEach(yourInterface -> System.out.println(yourInterface.getText()));
}
Sample usage.
public static void main(String[] args) {
loopThroughList(getList(1));
loopThroughList(getList(2));
}
Interfaces work great here, but there a couple of other options if you're dealing with legacy code and cannot use interfaces.
First would be to cast the list items into their respective types:
for (Object o : lists.getList(listNumber)) {
if(o instanceof Object1) {
Object1 o1 = (Object1)o;
System.out.println(o1.getText());
}
else if(o instanceof Object2) {
Object1 o2 = (Object2)o;
System.out.println(o2.getText());
}
else {
System.out.println("Unknown class");
}
}
You can also use reflection to see if the object has a getText method and then invoke it:
for (Object o : lists.getList(listNumber)) {
try {
System.out.println(o.getClass().getDeclaredMethod("getName").invoke(o));
}
catch(Exception e) {
System.out.println("Object doesn't have getText method");
}
}
This is awful. Can you elaborate on what specifically you are trying to do? Java is strong typed by design, and you are trying to get around it. Why? Instead of Object, use the specific class, or interface as previously suggested. If that's not possible, and you must use lists of Objects, use instanceof and casting eg:
for (Object o : lists.getList(listNumber)) {
if (o instanceof Object1) {
Object1 o1 = (Object1) o;
System.out.println(o1.getText());
} else if (o instanceof Object2) {
Object2 o2 = (Object2) o;
System.out.println(o2.getText());
}
}
This is where interfaces come in.
interface HasText {
public String getText();
}
class Object1 implements HasText {
#Override
public String getText() {
return "1";
}
}
class Object2 implements HasText {
#Override
public String getText() {
return "2";
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2());
for (HasText ht : list) {
System.out.println(ht);
}
}
If one of your objects is not in your control you can use a Wrapper class.
class Object3DoesNotImplementHasText {
public String getText() {
return "3";
}
}
class Object3Wrapper implements HasText{
final Object3DoesNotImplementHasText it;
public Object3Wrapper(Object3DoesNotImplementHasText it) {
this.it = it;
}
#Override
public String getText() {
return it.getText();
}
}
private void test() {
List<HasText> list = Arrays.asList(new Object1(), new Object2(), new Object3Wrapper(new Object3DoesNotImplementHasText()));
for (HasText ht : list) {
System.out.println(ht);
}
}
Just to add more to this answer and give you some more to think on this (Will try to do it in a simple, non-formal way). Using interfaces is the proper way of doing such operation. However, I want to stand on the "bad idea":
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
What you are doing here, is using a mechanism called Reflection:
Reflection is a feature in the Java programming language. It allows an
executing Java program to examine or "introspect" upon itself, and
manipulate internal properties of the program. For example, it's
possible for a Java class to obtain the names of all its members and
display them.
What you actually attempted, is using that mechanism, to retrieve the method through a Class reflection object instance of your Class (sounds weird, isn't it?).
From that perspective, you need to think that, if you want to invoke your method, you now have, in a sense, a meta-Class instance to manipulate your objects. Think of it like an Object that is one step above your Objects (Similarly to a dream inside a dream, in Inception). In that sense, you need to retrieve the method, and then invoke it in a different (meta-like) way:
java.lang.reflect.Method m = o.getClass().getMethod("getText");
m.invoke(o);
Using that logic, you could possibly iterate through the object list, check if method exists, then invoke your method.
This is though a bad, BAD idea.
Why? Well, the answer relies on reflection itself: reflection is directly associated with runtime - i.e. when the program executes, practically doing all things at runtime, bypassing the compilation world.
In other words, by doing this, you are bypassing the compilation error mechanism of Java, allowing such errors happen in runtime. This can lead to unstable behavior of the program while executing - apart from the performance overhead using Reflection, which will not analyze here.
Side note: While using reflection will require the usage of Checked Exception handling, it still is not a good idea of doing this - as you practically try to duck tape a bad solution.
On the other hand, you can follow the Inheritance mechanism of Java through Classes and Interfaces - define an interface with your method (let's call it Textable), make sure that your classes implement it, and then use it as your base object in your list declaration (#alexrolea has implemented this in his answer, as also #OldCurmudgeon has).
This way, your program will still make the method call decision making at Runtime (via a mechanism called late binding), but you will not bypass the compilation error mechanism of Java. Think about it: what would happen if you define a Textable implementation without providing the class - a compile error! And what if you set a non-Textable object into the list of Textables? Guess what! A compile error again. And the list goes on....
In general, avoid using Reflection when you are able to do so. Reflection is useful in some cases that you need to handle your program in such a meta-way and there is no other way of making such things. This is not the case though.
UPDATE: As suggested by some answers, you can use instanceof to check if you have a specific Class object instance that contains your method, then invoke respectively. While this seems a simple solution, it is bad in terms of scaling: what if you have 1000 different classes that implement the same method you want to call?
your objects have to implement a common interface.
interface GetTextable {
String getText();
}
class One implements GetTextable {
private final String text;
public One(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
class Two implements GetTextable {
private final String text;
public Two(final String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
#Test
public void shouldIterate() throws Exception {
List<GetTextable> toIterate = Arrays.asList(new One("oneText"), new Two("twoText"));
for(GetTextable obj: toIterate) {
System.out.println(obj.getText());
}
}
I have a question regarding to the andriod #IntDef Annotation. I know
that in its basic usage, it should replace the enum. But what if
I have a parameterized enum with multiple hardwired values for example
public enum MyEnum {
YES(true, 1),
NO(false, 0);
private boolean boolState;
private boolean intState;
MyEnum(boolean boolState, int intState) {
this.boolState = boolState;
this.intState = intState;
}
public boolean getBoolState() {
return boolState;
}
public int getIntState() {
return intState;
}
}
How would this be replaced by an Enumerated Annotation in Android?
Is it even suggestive to do something like that in this case? I searched
everywhere, but I haven't found any answer for that.
Thank you in advance!
I don't think you would be able to find anything because:
IntDef is a way of replacing an integer enum where there's a parameter
that should only accept explicit int values.
you can read more about it here. Enumerated annotations are for simple types, you could use it for strings also StringDef. Use enum when you need its features. Don't avoid it strictly. For your case I think creating class instead of enum would look like this:
public class MyEnum {
public static final MyEnum YES = new MyEnum(true, 1);
public static final MyEnum NO = new MyEnum(false, 0);
private boolean boolState;
private int intState;
MyEnum(boolean boolState, int intState) {
this.boolState = boolState;
this.intState = intState;
}
public boolean getBoolState() {
return boolState;
}
public int getIntState() {
return intState;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyEnum myEnum = (MyEnum) o;
return boolState == myEnum.boolState && intState == myEnum.intState;
}
}
and you could use constants in your code. But if using enums you will have type checking (you'll be able to accept only listed values) and method overloading (every enum constant can have its own implementation of a method). If you want to use less space and that is the only reason why you want to avoid using enum I would suggest you that it's not worth it.
I follow a rule with enums in Android development:
if it has no params, use an intdef/stringdef,
if it has params, use an enum
If there is a way around using an enum, I'll certainly consider it where it doesn't undermine the code.
A lot was made from the video Colt Mcanlis posted: https://www.youtube.com/watch?v=Hzs6OBcvNQE&feature=youtu.be
however it had some fairly shaky numbers in it as pointed out by Jake Wharton: https://plus.google.com/+JakeWharton/posts/bTtjuFia5wm
The main drawback of enums is that they use more memory than constants would, but if that enum aids in better code, I say use it rather than micro-optimise. Just don't go overboard using them and be aware of their footprint.
I'm coming late, but anyways, since intdef ins an annotation, you can create an annotation using a custom class and then use it in the same way. given the fact an annotation needs primitives, you'll have to pass an interface as the annotation class type, and use subclasses as the value array.
example:
public interface GenericContainer<T, X> {
public T getValueOne();
public X getValueTwo();
}
then an implementation for true/1
public class TrueContainer implements GenericContainer<Boolean, Integer> {
#Override
public Boolean getValueOne() {
return true;
}
#Override
public Integer getValueTwo() {
return 1;
}
}
and other for false/0
public class FalseContainer implements GenericContainer<Boolean, Integer> {
#Override
public Boolean getValueOne() {
return false;
}
#Override
public Integer getValueTwo() {
return 0;
}
}
finally, use them:
#Retention(RetentionPolicy.SOURCE)
#GenericDef({TrueContainer.class, FalseContainer.class})
public #interface genericTest{}
boolean test = isTest(new FalseContainer());
I have 2 Interfaces:
public interface Flash { public void flash(int level); } and
public interface SuperFlash extends Flash { public void flash(int level, boolean repeat); }
Then I have a custom collection class which should hold any number of things implementing Flash or SuperFlash. The class declaration looks something like
public class FlashyThings<? extends Flash>.
So the class can hold instances of type Flash and its subtype(s).
Inside the class FlashyThings, I am using an ArrayList to hold all of these objects:
private ArrayList<? extends Flash> things;
So far so good, now, when I try to iterate over the collection, is there a way to know/infer the dynamic type of the objects without using instanceof (as in the next snippet)?
for (Flash f : this.things) {
if (f instanceof SuperFlash) { // <-- :(
// SuperFlash things
} else {
// Flash things
}
}
This is the upper bounded side of the medal, now to the lower bounded side
To begin with, I had to change the class declaration to
public class FlashyThings
as lower bounded wildcards are not allowed in the class declaration. The ArrayList declaration now looks like:
private ArrayList<? super SuperFlash> things;
Now iterating over the collection becomes:
for (Object o : this.things) { // <-- :((
// All things are of type Object which is *really* not cool
if (o instanceof SuperFlash) { // <-- :(
// SuperFlash things
} else {
// Flash things
}
}
So I'm pretty much stuck where I began.
What would be the recommended way to iterate over such a construct? To summarise, what I want to achieve having is
the interface hierarchy described at the very top
the class FlashyThings being parameterisable
iterating over the ArrayList things, taking into account the dynamic type of its contents (without having to do the instanceof check)
What you need to do is create an abstract FlashyThing that does as much of the shared methods as possible in the abstract class, leaving only the stuff that is dependent on knowing you have a Flash or SuperFlash to the subclass. For example (publics and privates left out for brevity):
abstract class AbstractFlashyThing<F extends Flash> {
List<F> flashes;
AbstractFlashyThing() {
flashes = new ArrayList<F>();
}
void doOperations() {
for (F flash : flashes) {
doOperation(flash);
}
}
abstract void doOperation(F flash);
}
Note how the generic type F is used as a place holder wherever possible.
Example subclass
class SuperFlashyThing extends AbstractFlashyThing<SuperFlash> {
#Override
void doOperation(SuperFlash superFlash) {
// do super flash stuff
}
}
Subclass is a concrete implementation rather than a generic class, so its instatiation is as follows.
SuperFlashyThing thing = new SuperFlashyThing();
// as opposed to the following
SuperFlashyThing<SuperFlash> thing = new SuperFlashyThing<SuperFlash>();
Maybe I don't quite understand the problem, but why are you making everything so complicated, instead of just using polymorphism? This is what the Object Oriented Paradigm is designed to do. Example:
Flash.java
public class Flash {
public void doSomething() {
System.out.println("Flash doSomething()");
}
}
SuperFlash.java
public class SuperFlash extends Flash {
#Override
public void doSomething() {
System.out.println("SuperFlash doSomething()");
}
}
FlashyThings.java
public class FlashyThings {
private ArrayList<Flash> things = new ArrayList<>();
public ArrayList<Flash> getThings() {
return things;
}
public void doSomething(){
for (Flash thing : things) {
thing.doSomething();
}
}
}
ExampleMain.java
public class ExampleMain {
public static void main(String[] args) {
Flash first = new Flash();
SuperFlash second = new SuperFlash();
Flash third = new Flash();
FlashyThings things = new FlashyThings();
things.getThings().add(first);
things.getThings().add(second);
things.getThings().add(third);
things.doSomething();
}
}
What about using an enum ?
public enum FlashType
{
Flash, SuperFlash;
}
Add a method for checking the flash type of any object of type Flash:
public interface Flash
{
void flash(int level);
FlashType getType();
}
Then iterate over private ArrayList<? extends Flash> things;
for (Flash f : this.things)
{
if (f.getType() == FlashType.SuperFlash)
{
// SuperFlash things
}
else if (f.getType() == FlashType.Flash)
{
// Flash things
}
}
or iterate over ArrayList<? super SuperFlash> things;
for (Object o : this.things)
{
final Flash f = (Flash)o;//this cannot failed: SuperFlash extends Flash
if (f.getType() == FlashType.SuperFlash)
{
// SuperFlash things
}
else if (f.getType() == FlashType.Flash)
{
// Flash things
}
}
I'm relatively new to Java and generics. I'm trying to understand if I'm doing something wrong or not in writing a generic method. I have the following code (greatly simplified):
public class ContentIniter {
public ContentType getContentType();
}
public interface Content {
}
public class Show implements Content {
}
public class Movie implements Content {
}
public enum ContentType {
Movie, Show
}
public class Channel {
public List<Show> getShows() {
return getContentByType(ContentType.Show)
}
public List<Movie> getMovies() {
return getContentByType(ContentType.Movie)
}
private <T> List<T> getContentByType(ContentType contentType) {
List<T> typeContents = Lists.newArrayList();
List<ContentIniter> allContentIniters = someMethod(); // Returns initers for both shows and movies
for (Content contentIniter : allContentIniters) {
if (contentIniter.getContentType().equals(contentType)) {
switch (contentType) {
case Movie:
typeContents.add((T) new Movie(contentIniter));
break;
case Show:
typeContents.add((T) new Show(contentIniter));
break;
}
}
}
return typeContents;
}
}
My question relates to the line:
typeContents.add((T) new Movie(contentIniter));
The only way I've been able to get the code to compile is if I cast the content object to T. But that seems yucky to me (and I don't understand why the compiler can't infer the type based on the calls). Moreover, even though the code works, IntelliJ complains of an unchecked cast.
Is there a better way to write the generic method?
UPDATE: Screwed up the code a bit when I tried to simplify it. Fixed the reference to typeContents. Also, I added a bit more complexity so that it better reflects the reality, in hopes of explaining why I wasn't simply checking for instanceof.
UPDATE 2: Realized there was yet another error...ContentIniter doesn't implement Content. It's also worth noting, ContentIniter is just a made up object. If it seems weird, think of it as an Event or other Strategy that Content objects use to delegate certain behaviors.
You're not using generics properly, you're mixing them with your enumeration when it's really not necessary. Ideally you would be calling getContentByType<Show>() and then determine the list of the correct type from allContents using reflection.
Try something more along the lines of like (untested):
private <T> List<T> getContents() {
List<T> typeContents = Lists.newArrayList();
List<Content> allContents = someMethod(); // Returns both shows and movies
for (Content content : allContents) {
if (content instanceof T) {
typeContents.add((T) content);
}
}
return typeContents;
}
And call:
List<Show> shows = getContents<Show>();
You can then restrict the types that are called on it to only those that extend Content.
private <T extends Content> List<T> getContents() {
...
}
Actually the answer is simpler than you think : you just have to check whether your instance of Content is a Show or a Movie to make your compiler happy :
if (content instanceof Movie)
contents.add((Movie) content);
if (content instanceof Show)
contents.add((Show) content);
Anyway, I would say that the way that you wrote your generic method is correct. But since there is a native way to check for the type of an instance (instanceof), you should use it :)
EDIT : I still think you should use instanceof.
Plus, you should use a List<Content> instead of a List<ContentIniter>, because Content is a more global type : if someone comes up with another implementation of Content, he won't have to change your code. Actually, you're doing the same thing when you use the Interface List instead of an ArrayList for example, because List is less specific than ArrayList.
Also, using an enum is not a mistake : if you want to use one, you can. But it shouldn't be used to determine the type of an instance. The type of an instance is contained in the instance itself, period. Still, I'll say that Daniel Imms' solution is more elegant than mine, and takes better advantage of Java type features.
public interface Content {
public STContentType getContentType();
}
public class ContentIniter implements Content {
}
// You can keep the enum, as long as it's not used
// to check for the type of an instance of ContentIniter
public enum ContentType {
Movie, Show
}
public class Show implements Content {
}
public class Movie implements Content {
}
public class Channel {
public List<Show> getShows() {
return getContentByType(ContentType.Show)
}
public List<Movie> getMovies() {
return getContentByType(ContentType.Movie)
}
private <T> List<T> getContentByType(ContentType contentType) {
List<T> typeContents = Lists.newArrayList();
// Using more generic type Content
List<Content> allContentIniters = someMethod(); // Returns initers for both shows and movies
for (Content contentIniter : allContentIniters) {
// If it's a Show and I asked for Shows
if (contentIniter instanceof Show && contentType == ContentType.Show)) {
typeContents.add(contentIniter);
}
// If it's a Movie and I asked for Movies
if (contentIniter instanceof Movie && contentType == ContentType.Movie){
typeContents.add(contentIniter);
}
}
return typeContents;
}
}
Use of enum seems strange here and the way you do lost advantage of using generics.
The initer things is making things even more strange and messy.
It may looks more natural with something like this:
public interface Content {
}
public class Show implements Content {
}
public class Movie implements Content {
}
//......
private <T extends Content> List<T> getContentByType(Class<T> contentType) {
List<T> result = Lists.newArrayList();
List<Content> allContents = someMethod(); // ContentIniter is just a mess
// Get all content you have!
for (Content content: contents) {
if (contentType.isAssignableFrom(content.getClass())) {
result.add(content);
}
}
return result;
}
The way to use is
List<Show> result = channel.getContent(Show.class);
I removed my original answer after the code example change.
I really don't think you can avoid the cast and the #SuppressWarnings("unchecked").
As long as you know what you're doing, this is probably the best solution.
The alternative is to do without the getByContentType method and just have a bit of duplicated logic on the getShows() and getMovies() methods.
For example:
public List<Show> getShows() {
List<Show> shows = new ArrayList<Show>();
List<ContentIniter> allContentIniters = someMethod();
for(ContentIniter initer: allContentIniters) {
if(initer.getContentType().equals(ContentType.Show)) {
shows.add(new Show(initer));
}
}
return shows;
}
public List<Movie> getMovies() {
List<Movie> movies = new ArrayList<Movie>();
List<ContentIniter> allContentIniters = someMethod();
for(ContentIniter initer: allContentIniters) {
if(initer.getContentType().equals(ContentType.Movie)) {
movies.add(new Movie(initer));
}
}
return movies;
}