开发者

Java: generics method and type identification

开发者 https://www.devze.com 2023-03-10 18:22 出处:网络
I\'m not very used to generics, so I\'m a little confused here about how I\'m supposed to solve this problem. I\'ve written a method that tries to call different methods at runtime. But I\'m getting a

I'm not very used to generics, so I'm a little confused here about how I'm supposed to solve this problem. I've written a method that tries to call different methods at runtime. But I'm getting a ClassCastException although the code seems syntactically correct.

I have the following classes (some getters and setters were omitted for brevity):

public interface Transporte extends Serializable {
  private int id;
  private String name;
  public abstract int getId() { return this.id; }
  public abstract String 开发者_运维问答getName() { return this.name; }
}
public class Barco implements Transporte { /* ... */ }
public class Estacao implements Transporte { /* ... */ }
public class Paragem implements Transporte { /* ... */ }

public class Entidade extends Serializable {
  private List<Barco> barcos;
  private List<Estacao> estacoes;
  private List<Paragem> paragens;
  public List<Barco> getBarcos() { return this.barcos; }
  public List<Estacao> getEstacoes() { return this.estacoes; }
  public List<Paragem> getParagens() { return this.paragens; }
}

And the method I'm trying to implement and have difficulties with:

public <T extends Transporte> List<T> intersectTransportes(Entidade entidade, List<T> transportes) {
  if(entidade==null || transportes==null) return null;

  T typeOfTransport = (T) new Object(); /* <--- HERE'S THE PROBLEM (?) */
  List<T> result = new ArrayList<T>();
  List<Integer> ids = null;

  if(typeOfTransport instanceof Barco) ids = entidade.getIdBarcos(); else
  if(typeOfTransport instanceof Estacao) ids = entidade.getIdEstacoes(); // else ...

  // now do the work
  for(Transporte t : transportes) {
    for(Integer id : ids) {
      if(t.getId()==id) result.add((T) t);
    }
  }

  return result;
}

Please notice that I'm using <T extends Transporte> instead of <T implements Transporte> as I'd expect Java to allow. But that latter syntax is invalid, so I have to use implements instead...

The method is being invoked as illustrated here:

List<Estacao> allStations;
List<Estacao> myStations = intersectTransportes(entidade, allStations);

What I'm trying to do here is to identify the actual type used at runtime when invoking the method. In this case, insersectTransportes should be able to recognize the particular List of Transporte-implementing objects I'm using.

I suspect that I'm supposed to use something other than

T typeOfTransporte = (T) new Object(); 

since obviously that's the line where the runtime exception is being produced. However, I'm not quite sure how to solve this. Any indications to the solution (or specific bibliography approaching this problem) is appreciated.


The problem is:

  • a) you can't new your generic type - it's erased at runtime
  • b) Object does not extend Transporte, so it cant be cast to T


You need to pass the class to your method:

public <T extends Transporte> List<T> intersectTransportes(Entidade entidade, List<T> transportes, Class<T> clazz) {

...
T typeOfTransporte = clazz.newInstance();


T typeOfTransport = (T) new Object(); /* <--- HERE'S THE PROBLEM (?) */

The problem is rather obvious, an object is not a "Type of Transport" (does not implement or extends the Transport interface).

You will get the same error with this example: String myStr = (String) new Object();

T typeOfTransport = (T) new Barco(); //new Barco() or anything that implements Transport interface

You must instantiate a specific class there, but not any class like Object. The class must implement Transport interface.


Of course there is a problem with (T) new Object(). When you call new Object() it creates instance of class Object, thats it. You cant just cast it to something useful.

Try writing your method like this:

public <T extends Transporte> List<T> intersectTransportes(Entidade entidade, List<T> transportes, Class<T> clasz)

and use reflection.


You should pass in a Factory that deals with creating the new Transporte, with a method (probably using a switch) createNew(Class<? extends T> transporteClass).

You should also look into using either commons-collections or the guava libraries, which have the kind of intersection methods you're looking for, saving you the trouble of writing this code.

0

精彩评论

暂无评论...
验证码 换一张
取 消