Given the following code, how can I iterate over an object of type ProfileCollection?
public class ProfileCollection implements Iterable {
private ArrayList<Profile> m_Profiles;
public Iterator<Profile> iterator() {
Iterator<Profile> iprof = m_Profiles.iterator();
return iprof;
}
...
public Profile GetActiveProfile() {
return (Profile)m_Profiles.get(m_ActiveProfile);
}
}
public static void main(String[] args) {
m_PC = new ProfileCollection("profiles.xml");
// properly outputs a profile:
System.out.println(m_PC.GetActiveProfile());
// not actually outputting any profiles:
for(Iterator i = m_PC.iterator();i.hasNext();) {
System.out.println(i.next());
}
// how I actually want this to work, but won't even compile:
for(Profile prof: m_PC) {
System.out.println(prof);
}
}
Iterable is a generic interface. A problem you might be having (you haven't actually said what problem you're having, if any) is that if you use a generic interface/class without specifying the type argument(s) you can erase the types of unrelated generic types within the class. An example of this is in Non-generic reference to generic class results in non-generic return types.
So I would at least change it to:
public class ProfileCollection implements Iterable<Profile> {
private ArrayList<Profile> m_Profiles;
public Iterator<Profile> iterator() {
Iterator<Profile> iprof = m_Profiles.iterator();
return iprof;
}
...
public Profile GetActiveProfile() {
return (Profile)m_Profiles.get(m_ActiveProfile);
}
}
and this should work:
for (Profile profile : m_PC) {
// do stuff
}
Without the type argument on Iterable, the iterator may be reduced to being type Object so only this will work:
for (Object profile : m_PC) {
// do stuff
}
This is a pretty obscure corner case of Java generics.
If not, please provide some more info about what's going on.
First off:
public class ProfileCollection implements Iterable<Profile> {
Second:
return m_Profiles.get(m_ActiveProfile);
Related
I am wondering if i can replace the generic type upon class initialization ( without inheritance ).
The case is as below .
I have bunch of generic actor + builder class in my module and distribute this to people who wants to use it in my team while keeping the actor and the entry point of fluent interface generic.
The requirement is how can people supply their own builder ( not extending ) to do the stuff they want.
Current state:
class MessageBuilder {
public MessageBuilder msg(String msg) {
//do something
}
}
class Actor {
public MessageBuilder newMessage() {
return new MessageBuilder();
}
}
class Main {
#Test
public void testActor() {
Actor actor = new Actor();
actor.newMessage().msg("sss").send();
}
}
Desired state:
class MessageBuilder{
public MessageBuilder msg(String msg) {
//do something
}
//more fluent api...
}
// project specific - dont want to extend from generic one as this should be contains its own fluent interface
class MyCustomMessageBuilder {
public MyCustomMessageBuilder rawstr(String rawstr) {
//do something
}
}
class Actor<T> {
public T newMessage() {
return (T)builderFactory.getInstance();
}
}
class Main {
#Test
public void testActor() {
Actor<MyCustomMessageBuilder> actor = new Actor(BuilderFactory);
actor.newMessage().rawstr("sss").send();
}
}
It's not possible without some known tricks.
First, Java implements Generics with type erasure (more information on type erasure), therefore the compiler will:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
In practice, this means that Actor<Builder1> and Actor<Builder2> are the exact same class after it gets compiled. In both cases, newMessage is implemented as follows:
class Actor {
public Object newMessage() {
...
}
}
It's not possible for newMessage to have different implementations based on the type parameter and it's not possible for newMessage to ask for the type of T because it gets removed.
Having said that, you can pass in type information:
class Actor<T> {
private Class<T> klass;
public Actor(Class<T> klass) {
this.klass = klass;
}
public T newMessage() {
return klass.newInstance();
}
}
class Main {
#Test
public void testActor() {
Actor<MyCustomMessageBuilder> actor = new Actor<>(MyCustomMessageBuilder.class);
actor.newMessage().rawstr("sss").send();
}
}
I'd go with a factory approach. The builder should be supplied by a factory:
class Actor<MsgBuilder> {
private final Supplier<MsgBuilder> messageBuilderFactory;
public Actor(Supplier<MsgBuilder> builderFactory) {
this.messageBuilderFactory = builderFactory;
}
public MsgBuilder newMessage() {
return messageBuilderFactory.get();
}
}
This way offers flexibility in creating the message builder without sacrificing type safety and also no need for ugly casting.
Calling the method name sales() in codes below cannot be accessed.
The objects in arraylist are the class Group1which uses generic arguments. And,division_a.list.get(0)shoud have the Group1 object. And,division_a.list.get(0).getComponent()should returnComponent1object. Then thesales()method should be usable.
But, the exception message shows "The methodsales()` is undefined for the type capture#2-of ?" It's a mystry for me that division_a.list.get(0).getComponent() does not return objects of Component1 class, although the return type is defined as "public T getComponent().."
import java.util.ArrayList;
public class Division_a {
public ArrayList<Group1<?>> list=null;
public Division_a() {
list=new ArrayList();
}
public void put(Group1<?> group1) {
list.add(group1);
}
public static void main(String[] args) {
Group1<Component1> groupcomponent1 = new Group1<>(new Component1());
Division_a division_a = new Division_a();
division_a.put(groupcomponent1);
division_a.list.get(0).getComponent().sales(); //excetion occur
}
}
class Component1 {
public void sales() {
System.out.println("component1 sold");
}
}
class Group1<T> {
public T component;
Group1(T component){
this.component=component;
}
public T getComponent() { //return type T
return component;
}
public void setComponent(T component) {
this.component=component;
}
}
The sales method is only available in Component1. So if you need to call that method you should have either Component1 of any subtype of that. If you want to make it either Component1 or a subtype of it then you have to use a bounded wildcard instead of using an unbounded wildcard which can literally be anything. Here's the corrected code.
public ArrayList<Group1<? extends Component1>> list = null;
public void put(Group1<? extends Component1> group1) {
list.add(group1);
}
So, you need to understand how class erasure works in java. The generic information is never actually passed to the container, it's only enforced on the compiler side. Here is a good tutorial explaining it.
The easiest way to accomplish what you're looking to accomplish is to have an appropriate interface, like:
public interface WithSales {
Sales sales();
}
and make sure that your components implmeent them. Then you declare your wrappers appropriately, so your list declaration would look like:
public List<Group1<? extends WithSales>> list = new ArrayList<>();
Then the rest of your code would work fine as long as all of the instances of Component implement WithSales
I have following code:
public class A {
private String type;
String getType() { return type;}
}
Now in many code places I have code like this
switch (a.geType()) {
case "A" : return new Bla();
case "B" : return new Cop();
}
or somewhere else
switch (a.geType()) {
case "A" : return new Coda();
case "B" : return new Man();
}
(Note that I know I should use an Enumeration in production code).
What I want to achive is that when a new type is added to class A the compiler should flag all the switch statements that need to be adjusted?
Is there a java idiomatic way to do this?
when a new type is added to class A the compiler should flag all the switch statements that need to be adjusted?
A good approach to this would be replacing switch statements with a more robust implementation of multiple dispatch, such as the Visitor Pattern:
interface VisitorOfA {
Object visitA(A a);
Object visitB(B b);
}
class A {
Object accept(VisitorOfA visitor) {
return visitor.visitA(this);
}
}
class B extends A {
Object accept(VisitorOfA visitor) {
return visitor.visitB(this);
}
}
With this infrastructure in place, you can remove your switch statements, replacing them with implementations of the visitor:
Object res = a.accept(new VisitorOfA() {
public Object visitA(A a) { return new Bla(); }
public Object visitB(B b) { return new Cop(); }
});
When you add a new subtype to A, say, class C, all you need to do is adding a new method to VisitorOfA:
Object visitC(C c);
Now the compiler will spot all places where this new method has not been implemented, helping you avoid problems at runtime.
Don't forget about good old-fashioned polymorphism. Having a "type" field with switch statements in a class is often a smell that indicates that subclassing might be useful. Consider:
public abstract class CommonSuperClass {
public abstract One getOne();
public abstract Two getTwo();
}
public class A extends CommonSuperClass {
#Override public One getOne() { return new Bla(); }
#Override public Two getTwo() { return new Coda(); }
}
public class B extends CommonSuperClass {
#Override public One getOne() { return new Cop(); }
#Override public Two getTwo() { return new Man(); }
}
If you were to add a new subclass C, you're required to provide implementations for the abstract methods (unless you make C itself be abstract).
You could have a map of string / suppliers:
Map<String, Supplier<Object>> map = new HAshMap<> ();
map.put("A", Bla::new);
map.put("B", Cop::new);
And your sample code would become:
return map.get(a.getType()).get(); //need null check
In perspective of abstraction, there is another approach for you to use. One way is via Polymorphism as shown here.
Some simple example:
public void EverythingYouWant (Animal animal) {
return animal.move();
}
When it's more about refactoring replace type code/checking with State/Strategy patterns. It's good solution to first consider is there any reason that prevents subclassing.
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;
}
How can we restrict the arraylist to accept only a specfic type of object prior to generic
Write a wrapper function that accepts only the allowed type, and hide the collection. That was standard best-practice pre-Java-5.
private final List strings = new ArrayList();
public void add(String s)
{
strings.add(s);
}
public String remove(String s)
{
return (String) strings.remove(s);
}
// etc...
Yes, this sucks.
Might I ask: is there a reason you're not using generics? They are bytecode-compatible with Java 1.4
Two options, (I am assuming C# here, but all applies to pretty much all OO languages).
1) Inherit from collection type of choice (or its interfaces), override all methods to throw exception on wrong type, something like this:
public class MyType
{
// Your type here
}
public class MyTypeCollection : ArrayList
{
public override int Add(object value)
{
if (!(value is MyType))
{
throw new ArgumentException("value must be of type MyType");
}
return base.Add(value);
}
public int Add(MyType myType)
{
return base.Add(myType);
}
// Other overrides here
}
or
2) (probably better), create your own type altogether and implement interfaces as desirable for collections and use a non-generic, non-typed collection internally. Something like this:
public class MyTypeCollection2 : IEnumerable
{
private readonly ArrayList _myList = new ArrayList();
public void Add(MyType myType)
{
_myList.Add(myType);
}
// Other collection methods
public IEnumerator GetEnumerator()
{
yield return _myList.Cast<MyType>();
}
}
Make sure to implement all interfaces you will care about. In the .NET Framework the interfaces implemented for ArrayList are: IList, ICloneable
Hope this helps.