105 votes

Comment passer un type en tant que paramètre de méthode en Java

En Java, comment pouvez-vous passer un type en tant que paramètre (ou le déclarer en tant que variable)?

Je ne veux pas passer une instance du type mais le type lui-même (par exemple int, String, etc).

En C#, je peux faire ceci:

private void foo(Type t)
{
    if (t == typeof(String)) { ... }
    else if (t == typeof(int)) { ... }
}

private void bar()
{
    foo(typeof(String));
}

Y a-t-il un moyen en Java de le faire sans passer une instance du type t?
Ou dois-je utiliser mes propres constantes int ou enum?
Ou y a-t-il un meilleur moyen?

Modifier : Voici l'exigence pour foo:
En fonction du type t, il génère une chaîne courte, xml différente.
Le code dans le if/else sera très petit (une ou deux lignes) et utilisera quelques variables de classe privées.

137voto

BalusC Points 498232

Vous pourriez passer une Class.

private void foo(Class cls) {
    if (cls == String.class) { ... }
    else if (cls == int.class) { ... }
}

private void bar() {
    foo(String.class);
}

Mise à jour : la manière orientée objet dépend de l'exigence fonctionnelle. Le meilleur choix serait une interface définissant foo() et deux implémentations concrètes implémentant foo(), puis simplement appeler foo() sur l'implémentation que vous avez. Une autre façon pourrait être une Map, Action> sur laquelle vous pourriez appeler actions.get(cls). Cela peut facilement être combiné avec une interface et des implémentations concrètes: actions.get(cls).foo().

23voto

JohnnyLambada Points 4554

J'avais une question similaire, donc j'ai travaillé sur une réponse complète et exécutable ci-dessous. Ce que je devais faire, c'est transmettre une classe (C) à un objet (O) d'une classe non liée et avoir cet objet (O) émettre de nouveaux objets de la classe (C) vers moi lorsque je les demandais.

L'exemple ci-dessous montre comment cela est fait. Il y a une classe MagicGun que vous chargez avec n'importe quel sous-type de la classe Projectile (Pebble, Bullet ou NuclearMissle). L'intéressant est que vous le chargez avec des sous-types de Projectile, mais pas d'objets réels de ce type. Le MagicGun crée l'objet réel lorsqu'il est temps de tirer.

La sortie

Vous avez ennuyé la cible!
Vous avez troué la cible!
Vous avez anéanti la cible!
cliquer
cliquer

Le code

import java.util.ArrayList;
import java.util.List;

public class PassAClass {
    public static void main(String[] args) {
        MagicGun gun = new MagicGun();
        gun.loadWith(Pebble.class);
        gun.loadWith(Bullet.class);
        gun.loadWith(NuclearMissle.class);
        //gun.loadWith(Object.class);   // Ne compilera pas -- Object n'est pas un Projectile
        for(int i=0; i<5; i++){
            try {
                String effect = gun.shoot().effectOnTarget();
                System.out.printf("Vous avez %s la cible!\n", effect);
            } catch (GunIsEmptyException e) {
                System.err.printf("cliquer\n");
            }
        }
    }
}

class MagicGun {
    /**
     * projectiles contient une liste de classes qui étendent Projectile. En raison de l'effacement, il
     * ne peut pas contenir une List donc nous avons besoin du SuppressWarning. Cependant,
     * la seule façon d'ajouter est la méthode "loadWith" qui le rend sûr en termes de types.
     */
    private @SuppressWarnings("rawtypes") List projectiles = new ArrayList();
    /**
     * Chargez le MagicGun avec une nouvelle classe Projectile.
     * @param projectileClass La classe du Projectile à créer lorsqu'il est temps de tirer.
     */
    public void loadWith(Class projectileClass){
        projectiles.add(projectileClass);
    }
    /**
     * Tirer avec le MagicGun avec le prochain Projectile. Les projectiles sont tirés en premier.
     * @return Un nouvel objet Projectile créé.
     * @throws GunIsEmptyException
     */
    public Projectile shoot() throws GunIsEmptyException{
        if (projectiles.isEmpty())
            throw new GunIsEmptyException();
        Projectile projectile = null;
        // Nous savons que cela doit être un Projectile, donc le SuppressWarnings est correct
        @SuppressWarnings("unchecked") Class projectileClass = projectiles.get(0);
        projectiles.remove(0);
        try{
            // http://www.java2s.com/Code/Java/Language-Basics/ObjectReflectioncreatenewinstance.htm
            projectile = projectileClass.newInstance();
        } catch (InstantiationException e) {
            System.err.println(e);
        } catch (IllegalAccessException e) {
            System.err.println(e);
        }
        return projectile;
    }
}

abstract class Projectile {
    public abstract String effectOnTarget();
}

class Pebble extends Projectile {
    @Override public String effectOnTarget() {
        return "ennuyé";
    }
}

class Bullet extends Projectile {
    @Override public String effectOnTarget() {
        return "troué";
    }
}

class NuclearMissle extends Projectile {
    @Override public String effectOnTarget() {
        return "anéanti";
    }
}

class GunIsEmptyException extends Exception {
    private static final long serialVersionUID = 4574971294051632635L;
}

15voto

duffymo Points 188155

Oh, mais c'est moche, du code non orienté objet. Dès que vous voyez "if/else" et "typeof", vous devriez penser à la polymorphie. C'est la mauvaise voie à suivre. Je pense que les génériques sont vos amis ici.

Combien de types prévoyez-vous de traiter?

UPDATE:

Si vous parlez uniquement de String et int, voici une façon de le faire. Commencez par l'interface XmlGenerator (assez avec "foo"):

package generics;

public interface XmlGenerator
{
   String getXml(T value);
}

Et l'implémentation concrète XmlGeneratorImpl:

    package generics;

public class XmlGeneratorImpl implements XmlGenerator
{
    private Class valueType;
    private static final int DEFAULT_CAPACITY = 1024;

    public static void main(String [] args)
    {
        Integer x = 42;
        String y = "foobar";

        XmlGenerator intXmlGenerator = new XmlGeneratorImpl(Integer.class);
        XmlGenerator stringXmlGenerator = new XmlGeneratorImpl(String.class);

        System.out.println("integer: " + intXmlGenerator.getXml(x));
        System.out.println("string : " + stringXmlGenerator.getXml(y));
    }

    public XmlGeneratorImpl(Class clazz)
    {
        this.valueType = clazz;
    }

    public String getXml(T value)
    {
        StringBuilder builder = new StringBuilder(DEFAULT_CAPACITY);

        appendTag(builder);
        builder.append(value);
        appendTag(builder, false);

        return builder.toString();
    }

    private void appendTag(StringBuilder builder) { this.appendTag(builder, false); }

    private void appendTag(StringBuilder builder, boolean isClosing)
    {
        String valueTypeName = valueType.getName();
        builder.append("<").append(valueTypeName);
        if (isClosing)
        {
            builder.append("/");
        }
        builder.append(">");
    }
}

Si je lance ceci, j'obtiens le résultat suivant:

integer: 42
string : foobar

Je ne sais pas si c'est ce que vous aviez en tête.

12voto

Mark Elliot Points 31871

Vous devez passer une Class...

private void foo(Class t){
    if(t == String.class){ ... }
    else if(t == int.class){ ... }
}

private void bar()
{
   foo(String.class);
}

6voto

Dieter Points 959

Si vous voulez passer le type, alors l'équivalent en Java serait

java.lang.Class

Si vous voulez utiliser une méthode faiblement typée, alors vous utiliseriez simplement

java.lang.Object

et l'opérateur correspondant

instanceof

par exemple

private void foo(Object o) {

  if(o instanceof String) {

  }

}//foo

Cependant, en Java il y a des types primitifs, qui ne sont pas des classes (par exemple int dans votre exemple), donc vous devez faire attention.

La vraie question est ce que vous voulez réellement accomplir ici, sinon il est difficile de répondre:

Ou est-ce qu'il y a une meilleure façon?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X