3

I come from a Python background and in Python you can pass in the type of an object as a parameter. But in Java you cannot do this, any tips on how to get something like this working?

private void function(Type TypeGoesHere)
    Stock s = new TypeGoesHere();
    s.analyze();
}
budi
  • 6,351
  • 10
  • 55
  • 80
  • possible duplicate of [how do i pass Class as a parameter in java?](http://stackoverflow.com/questions/4872978/how-do-i-pass-class-as-a-parameter-in-java) – MalaKa Jul 01 '15 at 16:09
  • More generally, searching "Java reflection" (like in [this question](http://stackoverflow.com/questions/37628/what-is-reflection-and-why-is-it-useful)) should give you some relevant information. – anol Jul 01 '15 at 16:17

3 Answers3

2

In Java you can pass a Class. You can do it like this:

private void function(Class c)

This is not very common procatice though. You can probably get wha you need by looking into Strategy pattern, or proper use of Object Oriented Programming (polymorphism).

If you are looking for a way to build some objects, look into Factory pattern.

If you want to create a generic class- look into this detailed answer: https://stackoverflow.com/a/1090488/1611957

Community
  • 1
  • 1
bjedrzejewski
  • 2,378
  • 2
  • 25
  • 46
2

Java does not support Python’s way of referencing functions and classes. To achieve this behaviour, you have to use two advanced techniques: generics and reflection. Explaining these concepts is beyond the scope of a SO answer. You should read a Java guide to learn about them.

Yet here is an example how this would look like, assuming that the given class has a no-argument constructor:

public <T extends Stock> void analyzeNewStock(Class<T> clazz) throws Exception {
  Stock s = clazz.newInstance();
  s.analyze();
}

Then call this function with analyzeNewStock(MyStock.class).

As this is a rather complicated and error-prone approach, you’d rather define an interface that creates Stock instances:

public interface StockProvider {
  Stock createStock(String value);
}

public class MyStockProvider implements StockProvider {
  private final String valueTwo;

  public MyStockProvider(String valueTwo) {
    this.valueTwo = valueTwo;
  }

  @Override
  public Stock createStock(String valueOne) {
    return new MyStock(valueOne, valueTwo);
  }
}

public class MyOtherClass {
  public void analyzeNewStock(StockProvider provider) {
    provider.createStock("Hi!").analyze();
  }

  public static void main(String[] args) {
    analyzeNewStock(new MyStockProvider("Hey!"));
  }
}
Robin Krahl
  • 5,268
  • 19
  • 32
  • How would the code look like if there are parameters being passed into the Stock class? – budi Jul 01 '15 at 16:26
  • @budi I updated the second example. The implementation depends on whether the parameters always have the same value (`valueTwo`) or can be different (`valueOne`). – Robin Krahl Jul 01 '15 at 16:29
  • @budi If you want to use the first example (I would not advise to do so), you would write e. g. `clazz.getConstructor(String.class, String.class).newInstance("Hey", "ho");`. – Robin Krahl Jul 01 '15 at 16:34
  • I got it working, your code works great, thanks! It's disappointing that there's no easier way to do this in Java (I miss Python dearly). – budi Jul 01 '15 at 16:52
  • There is no need for generics in this answer. If you follow what erasure will do to this code, simply passing in a base type argument of "Stock" will have the same effect as the generics version. – kervin Jul 01 '15 at 16:55
  • @kervin `Class` is a generic class, so you’ll have to deal with generics (if you don’t want to use raw types). `Class` would only accept `Stock.class` AFAIS. If you want to also allow `Stock`’s subclasses, you’ll have to use `Class extends Stock>`. – Robin Krahl Jul 01 '15 at 16:58
1

You could use generics. For example:

private <T> void function(Class<T> clazz) {
    try{
        T t = clazz.newInstance();
        //more code here
    }catch(InstantiationException | IllegalAccessException ex){
        ex.printStackTrace();
    }
}

The Class<T> clazz shows what type to instantiate. The try/catch is just to prevent errors from stopping your code. The same idea is expanded in this SO post. More info here.

However, I'm not really sure why you would want to do this. There should easily be a workaround using a simple interface. Since you already know that you want an object with type Stock, you could pass an implementation of the interface. For example:

//interface to implement
public interface Stock {
    public void analyze();
}

//rewrite of function
private void function(Stock s){
    s.analyze();
}

And using two ways to call function:

//first way
public class XYZ implements Stock{
    public void analyze(){
        //some code here
    }
}

//calling the function
function(new XYZ());

//second way
function(new Stock(){
    public void analyze(){
        //your code here
    }
});
Community
  • 1
  • 1
jfdoming
  • 975
  • 10
  • 25